Complete API reference
Everything needed to build with Rabbitt Voice API v1.0.0: create credentials, configure agents, run phone calls or interviews, collect reports, handle failures, and take the integration to production. The endpoint catalog below contains all 26 currently supported operations.
Start here
All public operations use JSON over HTTPS and are relative to this base URL:
https://api.rabbitt.ai/api/v1- An organization administrator creates a key in the API keys workspace. Key management is a dashboard operation; API keys cannot mint more API keys.
- Store the one-time plaintext value in a server-side secret manager.
- Choose only the scopes required by the workflow.
- Call
GET /usageto confirm credits, agent capacity, and concurrent-call limits before accepting production work. - Create one reusable agent, then create calls or interview sessions from it.
- Poll resource and report endpoints until asynchronous work is complete.
export RABBITT_API_KEY="rb_live_xxxxxxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
export RABBITT_API_BASE="https://api.rabbitt.ai/api/v1"
curl "$RABBITT_API_BASE/usage" \
-H "Authorization: Bearer $RABBITT_API_KEY" \
-H "Accept: application/json"Authentication and scopes
Send the API key in the Authorization header on every request. A key belongs to exactly one organization, and access is the intersection of its scopes and the current permissions of its owner.
Authorization: Bearer rb_live_xxxxxxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxScopes used by public v1
| Scope | Capability | Operations |
|---|---|---|
agents:read | List and retrieve agents | GET /agents, GET /agents/{id} |
agents:manage | Create, update, and delete agents | POST /agents, PATCH/DELETE /agents/{id} |
executions:read | Read calls, interviews, transcripts, reports, and create interview sessions | Call read routes and every interview route |
campaigns:manage | Place or end calls and manage campaign state | POST /calls, POST /calls/{id}/hangup, every campaign route |
organization:read | Read credits and quotas | GET /usage |
Use separate least-privilege keys per service and environment. Keys beginning withrb_test_ and rb_live_ are visibly distinguishable, but the prefix alone is not a simulation guarantee: a test key can still mutate data or place a call when accepted by a configured environment. Use a dedicated test organization, credits, and destination numbers for staging.
Embed origins
If a key will mint interview embed tokens, register every exact browser origin on the key, such as https://app.example.com. Paths are ignored. HTTPS is required except for localhost development, and an empty allowlist denies token creation.
Request conventions
- Send and accept
application/json. - Resource IDs are 24-character hexadecimal strings.
- Phone numbers use E.164, for example
+919876543210. - Timestamps are ISO 8601 UTC strings.
- Unknown JSON fields are rejected on strict create operations.
- List routes use
pageandlimit; defaults are 1 and 25, and the maximum limit is 100. - Persist the returned
id. UseexternalReffor your own candidate, order, ticket, or job identifier where supported.
Pagination envelope
{
"object": "list",
"dataType": "call",
"data": [],
"pagination": {
"page": 1,
"limit": 25,
"total": 0,
"totalPages": 0,
"hasMore": false
}
}Available filters are type for agents; agentId andstatus for calls; externalRef and status for interviews; and agentId and status for campaigns.
A minimal server client
const baseUrl = process.env.RABBITT_API_BASE ?? "https://api.rabbitt.ai/api/v1";
export async function rabbitt(path, init = {}) {
const response = await fetch(baseUrl + path, {
...init,
headers: {
Accept: "application/json",
Authorization: `Bearer ${process.env.RABBITT_API_KEY}`,
...(init.body ? { "Content-Type": "application/json" } : {}),
...init.headers,
},
});
const body = await response.json().catch(() => ({}));
if (!response.ok) {
const error = new Error(body.error?.message ?? `Rabbitt HTTP ${response.status}`);
error.status = response.status;
error.code = body.error?.code;
error.param = body.error?.param;
error.requestId = body.request_id;
throw error;
}
return body;
}End-to-end phone-call workflow
1. Create a reusable phone agent
const agent = await rabbitt("/agents", {
method: "POST",
body: JSON.stringify({
type: "phone",
name: "Appointment reminder",
instructions:
"Call {{customerName}} to confirm the appointment. Be concise and polite.",
language: "english",
phone: {
direction: "outbound",
greeting: "Hello, this is Bright Dental calling about your appointment.",
voicemailBehavior: "mark_no_answer",
maxAttempts: 2,
retryDelayMinutes: 60
}
})
});
console.log(agent.id);Provider overrides are optional. When omitted, the server uses the configured LLM, STT, and TTS defaults. Keep an agent reusable and pass recipient-specific values as call variables.
2. Check credit and concurrency
const usage = await rabbitt("/usage");
if (usage.credits.remainingMinutes <= 0) {
throw new Error("Rabbitt organization has no remaining credit minutes");
}3. Place the call
const call = await rabbitt("/calls", {
method: "POST",
body: JSON.stringify({
agentId: agent.id,
phoneNumber: "+919876543210",
contactName: "Asha Menon",
externalRef: "booking-8842",
variables: { customerName: "Asha Menon" }
})
});
console.log(call.id, call.status);The request returns after the carrier accepts dialing, not after the conversation. A call moves through created, active, andcompleted. To stop an active call, sendPOST /calls/{id}/hangup.
4. Wait for the report
export async function waitForCallReport(callId, timeoutMs = 15 * 60_000) {
const deadline = Date.now() + timeoutMs;
const baseUrl = process.env.RABBITT_API_BASE ?? "https://api.rabbitt.ai/api/v1";
while (Date.now() < deadline) {
const response = await fetch(`${baseUrl}/calls/${callId}/report`, {
headers: { Authorization: `Bearer ${process.env.RABBITT_API_KEY}` }
});
if (response.status === 200) return response.json();
if (response.status !== 202) {
const body = await response.json().catch(() => ({}));
throw new Error(body.error?.code ?? `Rabbitt HTTP ${response.status}`);
}
await new Promise((resolve) => setTimeout(resolve, 5000));
}
throw new Error(`Timed out waiting for call ${callId}`);
}End-to-end interview workflow
1. Create a voice interview agent
const interviewAgent = await rabbitt("/agents", {
method: "POST",
body: JSON.stringify({
type: "voice",
mode: "interview",
name: "Customer support interview",
instructions:
"Interview the candidate about customer support experience. Ask one question at a time.",
language: "english",
maxDurationMinutes: 20,
voice: {
goal: "Assess communication and problem-solving",
evaluationCriteria: ["clarity", "empathy", "problem solving"]
}
})
});2. Create one interview per candidate
const interview = await rabbitt("/interviews", {
method: "POST",
body: JSON.stringify({
agentId: interviewAgent.id,
candidateName: "Asha Menon",
candidateEmail: "asha@example.com",
mode: "voice",
expiresInHours: 72,
externalRef: "candidate-2188"
})
});
// Hosted flow: send interview.interviewUrl to the candidate.
console.log(interview.interviewUrl);3A. Use the hosted interview
Send the returned interviewUrl to the candidate. The URL contains only a candidate-scoped capability, never your API key. Poll GET /interviews/{id}for created, active, or completed.
3B. Or embed it in your application
Register your browser origins on the API key, then mint a token server-side shortly before rendering the interview:
const embed = await rabbitt(`/interviews/${interview.id}/embed-token`, {
method: "POST",
body: JSON.stringify({ expiresInSeconds: 900 })
});
// Return only embed.token (or embed.embedUrl) to your authenticated page.
// Never return RABBITT_API_KEY.
return { token: embed.token, interviewId: interview.id };<div id="rabbitt-interview" style="min-height: 680px"></div>
<script src="https://voice.rabbitt.ai/embed.js"></script>
<script>
const session = RabbittInterview.mount(
document.getElementById("rabbitt-interview"),
{
token: EMBED_TOKEN_FROM_YOUR_SERVER,
interviewId: INTERVIEW_ID_FROM_YOUR_SERVER,
onEvent(event) {
if (event.type === "session.ended") {
console.log("Report id", event.payload.reportId);
}
}
}
);
// Optional controls: session.start(), end(), mute(), unmute(), setTheme("dark")
</script>The loader validates both message origin and iframe identity and handles resizing. See the embed protocol guide for every event payload and a framework-free iframe implementation.
4. Read the interview report
Poll GET /interviews/{id}/report. It returns 202 while analysis is pending and 200 when ready. Add ?includeTranscript=true when the same response should include the turn-by-turn transcript.
Campaign workflow
Campaigns provide paced bulk calling with retry and concurrency settings. The public API can create, inspect, update, launch, pause, resume, cancel, and archive campaigns.
const campaign = await rabbitt("/campaigns", {
method: "POST",
body: JSON.stringify({
name: "January overdue invoices",
agentId: agent.id,
timezone: "Asia/Kolkata",
settings: {
retryLimit: 3,
retryDelayMinutes: 60,
concurrency: 5
}
})
});Valid actions are launch, pause, resume,cancel, and archive. Invalid state transitions return 409. Read stats.total, pending, completed, andfailed from GET /campaigns/{id}.
Polling, transcripts, and reports
Public API v1 is polling-based; it does not currently define partner webhooks. Poll every few seconds with bounded timeouts and stop when the resource is completed or a report request returns 200.
| Need | Operation | Ready signal |
|---|---|---|
| Call state | GET /calls/{id} | status: completed |
| Call transcript | GET /calls/{id}/transcript | Turns appear as the call progresses |
| Call report | GET /calls/{id}/report | HTTP 200; HTTP 202 means pending |
| Interview state | GET /interviews/{id} | status: completed |
| Interview report | GET /interviews/{id}/report | HTTP 200; use includeTranscript=true |
A report can include an outcome, summary, captured fields, sentiment, evaluation scores, or phone dispositions depending on agent type and configuration. Treat fields not relevant to that report family as absent. Do not assume a report exists merely because the call or interview has ended.
Errors and retries
Every public failure uses this envelope:
{
"error": {
"type": "invalid_request_error",
"code": "VALIDATION_ERROR",
"message": "phoneNumber is required",
"param": "body.phoneNumber"
},
"request_id": "req_01..."
}Branch first on HTTP status or error.type, then on the stableerror.code. Show message to developers, not end users, and include request_id when contacting support. Never log authorization headers, embed tokens, transcripts, or sensitive request bodies.
| Status | Retry policy | Action |
|---|---|---|
400 | Do not retry unchanged | Fix the field named by error.param, when present. |
401 | Do not retry | Replace a missing, malformed, expired, or revoked API key. |
402 | Do not retry | Add organization credit before placing another call. |
403 | Do not retry | Grant the required scope or correct organization access. |
404 | Do not retry blindly | Verify the resource ID and organization. |
409 | Reconcile first | Resolve a duplicate name or invalid campaign transition. |
429 | Retry with backoff | Honor Retry-After when present and add jitter. |
5xx/network | Retry safe reads | Reconcile mutations before retrying; v1 has no idempotency-key contract. |
Rate limits, credits, and quotas
- Rate limits are per API key in one-minute windows.
- The default is 120 requests per minute; administrators can configure a key.
- HTTP 429 uses
rate_limit_errorand codeRATE_LIMITED. - Credits are shared organization minutes. Call creation can return HTTP 402.
GET /usagereturns remaining credits plusmaxAgents,maxUsers, andmaxConcurrentCalls.
Cache usage briefly for display, but treat the call-creation response as authoritative because concurrent workloads can consume credit or capacity between preflight and execution.
Complete endpoint catalog
This catalog is generated from the committed OpenAPI contract. Select an operation for exact path/query/body fields, response statuses, and cURL, Node.js, and Python samples.
Agents
Voice and phone agents — the reusable definition of who the AI is and what it should accomplish.
Calls
Outbound and inbound telephony calls placed by a phone agent.
- GET
/callsexecutions:readList calls - POST
/callscampaigns:managePlace an outbound call - GET
/calls/{id}executions:readRetrieve a call - GET
/calls/{id}/transcriptexecutions:readRetrieve a call transcript - GET
/calls/{id}/reportexecutions:readRetrieve a call report - POST
/calls/{id}/hangupcampaigns:manageEnd a call in progress
Interviews
Candidate interview sessions, including embeddable ones.
Campaigns
Bulk outbound calling over a list of recipients.
- GET
/campaignscampaigns:manageList campaigns - POST
/campaignscampaigns:manageCreate a campaign - GET
/campaigns/{id}campaigns:manageRetrieve a campaign - PATCH
/campaigns/{id}campaigns:manageUpdate a campaign - POST
/campaigns/{id}/launchcampaigns:manageLaunch a campaign - POST
/campaigns/{id}/pausecampaigns:managePause a campaign - POST
/campaigns/{id}/resumecampaigns:manageResume a campaign - POST
/campaigns/{id}/cancelcampaigns:manageCancel a campaign - POST
/campaigns/{id}/archivecampaigns:manageArchive a campaign
Usage
Credit balance and organization quotas.
Production checklist
- Create separate least-privilege keys per application and environment.
- Store keys in a secret manager and exercise zero-downtime rotation.
- Use a dedicated safe organization, credits, and phone numbers for staging.
- Keep API calls on your server; send only short-lived embed tokens to browsers.
- Register exact embed origins and verify microphone permissions on HTTPS.
- Validate E.164 numbers and every declared agent variable before dialing.
- Bound polling, apply jittered backoff, and respect per-key rate limits.
- Reconcile timed-out mutations before retrying to prevent duplicate calls.
- Monitor credit and concurrent-call capacity with
GET /usage. - Log status, error code, and request ID only; redact credentials and conversation data.
- Test 401, 402, 403, 404, 409, 429, timeout, revocation, and partial-provider failure paths.
- Confirm legal consent, calling windows, recording, retention, and data-handling requirements for every destination.
OpenAPI document
The machine-readable OpenAPI 3.1 document is public and served by the API. Use it for client generation and contract checks, but keep the workflow and retry rules from this guide in your application design.
https://api.rabbitt.ai/api/v1/openapi.jsonFor focused background, see Authentication, Errors, Rate limits, and the interview embed guide.