Agents
Agents are the reusable voice personas that power calls. Each agent stores its prompt, persona/playbook structure, provider routing, post-call defaults, and feature flags.
List Agents
GET /v1/agentsReturns a paginated list of agents for the authenticated tenant.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Max records to return (max 200) |
offset | integer | 0 | Records to skip |
Example Request
curl "https://api.rymi.live/v1/agents?limit=10&offset=0" \
-H "Authorization: Bearer YOUR_API_KEY"Response 200
{
"agents": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Priya - Sales Specialist",
"voice": "Aoede",
"llm_provider": "gemini",
"llm_model": "gemini-2.5-flash",
"agent_role": "operator",
"language": "en-US",
"created_at": "2026-03-01T10:00:00Z"
}
],
"total": 1,
"offset": 0,
"limit": 10
}Errors
| Status | Meaning |
|---|---|
401 | Missing or invalid API key |
Model and Voice Catalog
GET /v1/agents/llm-optionsReturns the tenant-visible model catalog and voice list available for agent configuration. Use this to populate dropdowns and pickers before creating or updating agents.
Example Request
curl https://api.rymi.live/v1/agents/llm-options \
-H "Authorization: Bearer YOUR_API_KEY"Response 200
{
"models": [
{ "id": "gemini-2.5-flash", "provider_id": "google" },
{ "id": "gpt-4o-mini", "provider_id": "openai" }
],
"voices": [
{ "id": "Aoede", "provider": "google", "name": "Aoede" },
{ "id": "21m00Tcm4TlvDq8ikWAM", "provider": "elevenlabs", "name": "Rachel" }
]
}Agent Roles
Agents use an agent role to select their default STT, LLM, TTS, routing mode, and fallback stack. Set it with agent_role on create or update.
The top role is executive across the UI, API, and routing rules.
| Role | API Value | Best For | Default Behavior |
|---|---|---|---|
| Operator | operator | Simple call handling, FAQs, lead capture, reminders | Cost-efficient standard pipeline with fallback providers |
| Specialist | specialist | Sales, support, qualification, domain-specific workflows | Higher-accuracy STT, complexity-aware LLM routing, Google Gemini Pro TTS; ElevenLabs available as premium override |
| Executive | executive | Complex conversations, realtime behavior, high-value interactions | Realtime-capable routing with premium fallback stack |
Provider selection is snapshotted into provider_config. Passing an explicit provider_config.tiers override lets advanced users control primary and fallback providers per agent role.
Create Agent
POST /v1/agentsRequest Body
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | — | Human-readable agent name (max 100 characters) |
system_prompt | string | No | — | Raw system prompt. If you omit persona and playbook, Rymi can extract structure from this prompt |
voice | string | No | Role default | TTS voice ID from GET /v1/agents/llm-options |
language | string or null | No | null (auto-detect) | Preferred start language locale (e.g., en-US, hi-IN). Use null for auto |
agent_role | string | No | operator | operator, specialist, executive, or concierge |
llm_provider | string | No | Role default | gemini, openai, anthropic, or sarvam |
llm_model | string | No | Role default | Model ID for the active agent role |
stt_provider | string | No | Role default | Speech-to-text provider |
stt_model | string | No | Role default | STT model ID |
tts_provider | string | No | Role default | Text-to-speech provider |
tts_model | string | No | Role default | TTS model ID |
persona | Persona object | No | — | Structured role, tone, audience, and voice config |
playbook | Playbook object | No | — | Opener, qualification flow, scripts, CTA, and escalation rules |
advanced | Advanced object | No | — | Runtime tuning (endpointing, turn timing) |
features | Features object | No | — | Feature flags (recording, transcription) |
post_call | Post-call object | No | — | Default post-call intelligence config |
provider_config | object | No | — | Explicit routing role config override |
Persona Object
| Field | Type | Description |
|---|---|---|
role | string | Agent's role description (e.g., "Insurance sales specialist") |
tone | string | Communication tone (e.g., "friendly", "professional", "empathetic") |
audience | string | Target audience description |
voiceConfig | object | Voice settings: { "voiceId": "Aoede", "language": "en-US" } |
personality | string | Personality traits and behavioral notes |
constraints | string[] | Behavioral constraints (e.g., ["Never discuss competitor pricing"]) |
Playbook Object
| Field | Type | Description |
|---|---|---|
opener | string | Opening message the agent uses to start the conversation |
qualification | object | Qualification flow with questions (string[]) and criteria (string[]) |
scripts | object | Named script sections keyed by scenario (e.g., { "objection_handling": "..." }) |
cta | string | Primary call-to-action the agent drives toward |
escalation | object | Escalation rules: { "trigger": "...", "action": "transfer" | "end_call" } |
closing | string | Closing message or sign-off script |
Advanced Object
| Field | Type | Default | Description |
|---|---|---|---|
endpointing_threshold | number | 0.5 | Silence threshold (seconds) before the agent considers the user done speaking |
turn_timeout | number | 10 | Max seconds the agent waits for user input before prompting |
interruption_policy | string | "allow" | "allow" or "block" — whether the user can interrupt the agent mid-speech |
Features Object
| Field | Type | Default | Description |
|---|---|---|---|
recording | boolean | true | Enable call recording |
transcription | boolean | true | Enable real-time transcription |
Post-call Object
| Field | Type | Default | Description |
|---|---|---|---|
summary.enabled | boolean | true | Generate a summary after each call |
summary.prompt | string | — | Custom instructions for the summary LLM (e.g. "highlight objections") |
structured_extraction.json_schema | object | — | JSON Schema defining the structured data to extract from the transcript |
structured_extraction.prompt | string | — | Custom instructions for the extraction LLM (auto-generated from schema if omitted) |
evaluation.rubric | string | — | Numbered list of quality criteria for call scoring |
model.provider | string | — | LLM provider for post-call analysis: gemini or openai. Defaults to platform setting |
model.model | string | — | Specific model ID (e.g. gemini-2.5-flash, gpt-4o-mini). Defaults to platform setting |
Example — Minimal
curl -X POST https://api.rymi.live/v1/agents \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Support Agent"
}'Example — Full Configuration
curl -X POST https://api.rymi.live/v1/agents \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Priya - Sales Specialist",
"system_prompt": "You are Priya, a friendly insurance sales agent who speaks Hindi with a Delhi accent.",
"voice": "Aoede",
"language": "hi-IN",
"agent_role": "specialist",
"llm_provider": "gemini",
"llm_model": "gemini-2.5-flash",
"persona": {
"role": "Insurance sales specialist",
"tone": "friendly",
"audience": "Hindi-speaking consumers in North India",
"voiceConfig": { "voiceId": "Aoede", "language": "hi-IN" },
"personality": "Warm, patient, and persuasive",
"constraints": ["Never guarantee claim approval", "Always disclose policy terms"]
},
"playbook": {
"opener": "Namaste! Main Priya hoon, Acme Insurance se. Kaise madad kar sakti hoon?",
"qualification": {
"questions": ["What type of coverage are you looking for?", "How many family members need coverage?"],
"criteria": ["Has expressed interest in health insurance", "Is the primary decision maker"]
},
"cta": "Book a follow-up call with our advisor",
"escalation": { "trigger": "Customer requests supervisor", "action": "transfer" },
"closing": "Thank you for your time! We will send the policy details to your email."
},
"advanced": {
"endpointing_threshold": 0.6,
"turn_timeout": 12,
"interruption_policy": "allow"
},
"features": {
"recording": true,
"transcription": true
},
"post_call": {
"recording": { "enabled": true },
"summary": { "enabled": true },
"structured_extraction": {
"json_schema": {
"type": "object",
"properties": {
"interested_plan": { "type": "string" },
"family_size": { "type": "integer" },
"booked_followup": { "type": "boolean" }
}
}
},
"evaluation": {
"criteria": "Did the agent successfully qualify the lead and book a follow-up?"
}
}
}'Response 201
{
"status": "created",
"id": "550e8400-e29b-41d4-a716-446655440000"
}Errors
| Status | Meaning |
|---|---|
400 | Validation error (missing name, invalid agent_role, etc.) |
401 | Missing or invalid API key |
402 | Insufficient credits |
Get Agent
GET /v1/agents/:idReturns the full agent configuration including the compiled prompt.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | uuid | Agent ID |
Example Request
curl https://api.rymi.live/v1/agents/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer YOUR_API_KEY"Response 200
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Priya - Sales Specialist",
"voice": "Aoede",
"language": "hi-IN",
"persona": {
"role": "Insurance sales specialist",
"tone": "friendly",
"audience": "Hindi-speaking consumers in North India",
"voiceConfig": { "voiceId": "Aoede", "language": "hi-IN" }
},
"playbook": {
"opener": "Namaste! Main Priya hoon, Acme Insurance se.",
"cta": "Book a follow-up call with our advisor"
},
"compiled_prompt": "You are Priya...",
"llm_provider": "gemini",
"llm_model": "gemini-2.5-flash",
"agent_role": "specialist",
"provider_config": {
"active_role": "specialist"
},
"post_call": {
"recording": { "enabled": true },
"summary": { "enabled": true }
},
"created_at": "2026-03-01T10:00:00Z"
}Errors
| Status | Meaning |
|---|---|
401 | Missing or invalid API key |
404 | Agent not found for this tenant |
Update Agent
PUT /v1/agents/:idPass only the fields you want to change. Unspecified fields remain unchanged.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | uuid | Agent ID |
Request Body
Accepts the same fields as Create Agent. All fields are optional.
Example Request
curl -X PUT https://api.rymi.live/v1/agents/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"system_prompt": "Updated instructions for handling renewals...",
"agent_role": "specialist",
"post_call": {
"summary": { "enabled": true },
"structured_extraction": {
"json_schema": {
"type": "object",
"properties": {
"renewal_confirmed": { "type": "boolean" }
}
}
}
}
}'Response 200
{
"status": "updated"
}Errors
| Status | Meaning |
|---|---|
400 | Validation error |
401 | Missing or invalid API key |
404 | Agent not found for this tenant |
Clone Agent
POST /v1/agents/:id/cloneCreates a duplicate of an existing agent. The clone gets " (Copy)" appended to its name and is otherwise identical — same persona, playbook, advanced config, post-call settings, and provider stack. The original is unchanged.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | uuid | Agent ID to clone |
Example Request
curl -X POST https://api.rymi.live/v1/agents/550e8400-e29b-41d4-a716-446655440000/clone \
-H "Authorization: Bearer YOUR_API_KEY"Response 201
{
"status": "created",
"id": "7f3e9a12-b4c1-41f2-a890-556677889900"
}Errors
| Status | Meaning |
|---|---|
401 | Missing or invalid API key |
403 | Agent belongs to a different tenant |
404 | Agent not found |
List Agent Calls
GET /v1/agents/:id/callsReturns a paginated list of calls made with a specific agent. Useful for per-agent performance monitoring and debugging.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | uuid | Agent ID |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Max records to return (max 200) |
offset | integer | 0 | Records to skip |
status | string | All statuses | Filter by call status: queued, ringing, in_progress, completed, or failed |
Example Request
curl "https://api.rymi.live/v1/agents/550e8400-e29b-41d4-a716-446655440000/calls?limit=20&status=completed" \
-H "Authorization: Bearer YOUR_API_KEY"Response 200
{
"calls": [
{
"id": "call_abc123",
"agent_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"started_at": "2026-03-01T10:00:00Z",
"ended_at": "2026-03-01T10:05:00Z",
"bill_duration": 300,
"total_cost": 0.30
}
],
"total": 1,
"offset": 0,
"limit": 20,
"agent_id": "550e8400-e29b-41d4-a716-446655440000"
}Errors
| Status | Meaning |
|---|---|
401 | Missing or invalid API key |
403 | Publishable keys cannot access call history, or agent does not belong to you |
404 | Agent not found |
Delete Agent
DELETE /v1/agents/:idWARNING
Deleting an agent cascade-deletes all associated number mappings. Active calls using this agent are not affected.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | uuid | Agent ID |
Example Request
curl -X DELETE https://api.rymi.live/v1/agents/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer YOUR_API_KEY"Response 200
{
"status": "deleted",
"id": "550e8400-e29b-41d4-a716-446655440000"
}Errors
| Status | Meaning |
|---|---|
401 | Missing or invalid API key |
404 | Agent not found for this tenant |
Generate Agent Draft
POST /v1/agents/generateDescribe your ideal agent in plain English and Rymi generates a draft persona/playbook bundle plus a compiled prompt preview. Studio clients can also send the current draft and opt into clarifying questions before generation.
Request Body
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
prompt | string | Yes | — | Natural-language description of the agent you want |
mode | string | No | create | create for a new agent or edit to refine an existing config |
allow_clarifying_questions | boolean | No | false | When true, Rymi may return questions instead of generating a weak draft |
options.voice | string | No | — | Preferred voice ID or name |
options.llm_provider | string | No | — | Preferred LLM provider hint |
options.llm_model | string | No | — | Preferred model hint |
current_config | object | No | — | Current agent config snapshot for edit mode |
Example — Create Mode
curl -X POST https://api.rymi.live/v1/agents/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A friendly female sales agent who speaks Hindi with a Delhi accent and can sell insurance plans",
"options": {
"llm_provider": "gemini",
"voice": "Aoede"
},
"mode": "create",
"allow_clarifying_questions": false
}'Response 200 — Generated
{
"generated": true,
"draft": {
"name": "Delhi Insurance Sales Agent",
"voice": "Aoede",
"llm_provider": "gemini",
"persona": {
"role": "Insurance sales specialist",
"tone": "friendly",
"audience": "Hindi-speaking consumers in North India"
},
"playbook": {
"opener": "Namaste! Main aapki insurance needs mein madad kar sakti hoon.",
"cta": "Book a follow-up with our advisor"
}
},
"compiled_prompt_preview": "You are a friendly female sales agent..."
}Response 200 — Clarifying Questions
If allow_clarifying_questions is true and the brief is too thin:
{
"generated": false,
"clarifying_questions": [
"What primary action should the agent drive toward?",
"How should we know the call was successful?"
],
"quality_gates": {
"blockers": ["Primary CTA is missing."],
"warnings": ["Audience context is thin."]
}
}Example — Edit Mode
curl -X POST https://api.rymi.live/v1/agents/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Make the tone more formal and add an escalation rule for angry customers",
"mode": "edit",
"current_config": {
"name": "Support Agent",
"persona": { "role": "Customer support", "tone": "friendly" },
"playbook": { "opener": "Hi! How can I help?" }
}
}'Errors
| Status | Meaning |
|---|---|
400 | Missing prompt or invalid mode |
401 | Missing or invalid API key |
500 | Generation failed |
Configuration Reference
The canonical agent payload shape. Every field is optional on PUT /v1/agents/:id (partial updates). On POST /v1/agents only name is required.
Top-level Fields
| Field | Type | Default | Description |
|---|---|---|---|
name | string | required | Display name for the agent |
voice | string | "Aoede" | Voice ID (use GET /v1/agents/llm-options for available voices) |
language | string | "en-US" | BCP-47 language code |
agent_role | string | "operator" | One of operator, specialist, executive, concierge |
llm_provider | string | "gemini" | Conversation LLM: gemini, openai, anthropic, sarvam |
llm_model | string | "gemini-2.5-flash" | Model ID for the conversation LLM |
stt_provider | string | — | Speech-to-text provider override |
stt_model | string | — | STT model override |
tts_provider | string | — | Text-to-speech provider override |
tts_model | string | — | TTS model override |
persona Object
Who the agent is, how it sounds, and what it knows.
| Field | Type | Description |
|---|---|---|
role | string | Job title (e.g. "Sales Specialist") |
audienceDescription | string | Who the agent talks to |
toneOverride | string | Speaking style (e.g. "warm and concise") |
companyName | string | Company name injected into the system prompt |
companyWebsite | string | Company website URL |
companyDescription | string | What the company does |
knowledgeBase | string[] | URLs or text passages the agent references |
successCriteria | string[] | What a successful call looks like |
voiceConfig.bargeInEnabled | boolean | Whether the caller can interrupt mid-sentence |
callerPersonas | object[] | Caller type variants: { type, approach } |
playbook Object
Conversation flow, objections, scripts, and call-to-action.
| Field | Type | Description |
|---|---|---|
opener | string | First thing the agent says |
qualificationFlow | object[] | Questions and what to listen for: { question, listensFor } |
requiredSlots | object[] | Data to collect: { name, description, required } |
objectionHandlers | object[] | How to handle pushback: { trigger, response } |
scripts | object[] | Canned responses for specific situations: { title, when, content } |
closingCTA | string | Primary call-to-action at end of call |
fallbackCTA | string | Fallback if primary CTA fails |
escalationRule | string | When/how to escalate to a human |
advanced Object
Runtime, speech, and safety configuration.
| Field | Type | Default | Description |
|---|---|---|---|
maxCallDuration | number | 1800 | Max call length in seconds |
maxTurnLength | number | 60 | Max agent speaking time per turn (seconds) |
silencePromptDelay | number | 8 | Seconds of silence before nudging the caller |
postSilenceHangup | number | 15 | Seconds of silence before hanging up |
replyDelay | number | 0 | Milliseconds to pause before responding |
startSpeakingPhrasing | string | "agent_greets" | agent_greets or wait_for_user |
startSpeakingThreshold | number | — | VAD sensitivity for when agent starts speaking |
stopSpeakingThreshold | number | — | VAD sensitivity for when caller stops speaking |
resumeAfterInterruption | boolean | true | Resume interrupted sentence after caller stops |
smartEndpointing | boolean | true | AI-powered end-of-turn detection |
waitAfterSentence | number | — | ms to wait after a sentence ends |
waitAfterNoPunctuation | number | — | ms to wait when no sentence-ending punctuation |
waitAfterNumbers | number | — | ms to wait after numbers (they often continue) |
stt_confidence_threshold | number | — | Minimum confidence to accept a transcription |
stt_numeral_formatting | boolean | true | Format numbers as numerals in transcript |
stt_profanity_filter | boolean | false | Filter profanity from transcript |
stt_keywords | string | — | Comma-separated keywords to boost STT accuracy |
offLimitsTopics | string | — | Topics the agent must never discuss |
prohibitedClaims | string | — | Claims the agent must never make |
features Object
| Field | Type | Default | Description |
|---|---|---|---|
recording_enabled | boolean | false | Record both sides of each call |
transcription_enabled | boolean | true | Transcribe and store each call |
require_consent | boolean | true | Announce recording at call start |
post_call Object
| Field | Type | Default | Description |
|---|---|---|---|
summary.enabled | boolean | true | Generate a call summary |
summary.prompt | string | — | Custom summary instructions |
structured_extraction.json_schema | object | — | JSON Schema for data extraction |
structured_extraction.prompt | string | — | Custom extraction instructions (auto-generated if omitted) |
evaluation.rubric | string | — | Numbered scoring criteria |
model.provider | string | — | gemini or openai for post-call LLM |
model.model | string | — | Model ID for post-call LLM |
Validate Publish
POST /v1/agents/validate-publishCheck whether an agent is ready to go live. Returns a validation report without persisting any changes.
Body
| Field | Type | Description |
|---|---|---|
agent_id | uuid | Optional. Merge validation with a persisted agent's config |
name | string | Agent name to validate |
voice | string | Voice ID to validate |
persona | object | Persona config |
playbook | object | Playbook config |
Example
curl -X POST https://api.rymi.live/v1/agents/validate-publish \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"agent_id": "550e8400-e29b-41d4-a716-446655440000"}'Apply Changes
POST /v1/agents/apply-changesValidates and resolves a flat key/value change-set against the AgentConfig field registry. Enforces field types, edit-mode blocklist, and implies rules. Does not persist — follow up with PUT /v1/agents/:id.
Body
| Field | Type | Description |
|---|---|---|
currentConfig | object | The agent's current flat config |
changes | array | [{key, value}] field changes to apply |
mode | string | "create" or "edit" |
lenient | boolean | Skip unknown-field hard-fail (not recommended) |
Example
curl -X POST https://api.rymi.live/v1/agents/apply-changes \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"currentConfig": {"name": "Support", "voice": "Aoede"},
"changes": [{"key": "voice", "value": "Charon"}],
"mode": "edit"
}'Response
{
"valid": true,
"config": { "name": "Support", "voice": "Charon" },
"applied": [{ "key": "voice", "value": "Charon" }]
}Enrich Company
POST /v1/agents/enrich-companyUses AI with Google Search grounding to generate a company description from a website URL, suitable for an agent's persona.
Body
| Field | Type | Description |
|---|---|---|
companyName | string | Company name |
websiteUrl | string | Company website URL |
Example
curl -X POST https://api.rymi.live/v1/agents/enrich-company \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"companyName": "Acme Corp", "websiteUrl": "https://acme.example.com"}'Response
{
"enriched": true,
"companyDescription": "Acme Corp is a leading provider of...",
"knowledgeBase": []
}
