Calls
Read call and voicemail history, and place outbound phone calls handled by your AI agent.
Calls and voicemails are activities inside a conversation. This resource gives you a flat history across every thread, and lets you place outbound calls that your AI agent (Astra) handles.
#List calls
/v1/api/callsReturns call and voicemail history across all conversations, newest first.
Scope: conversations:read
Query parameters
limitinteger — 1–200, default 50.
Returns { calls: [...] }. Each entry has:
iduuid — The activity ID.conversationIduuid — Open it with Retrieve a conversation to get the transcript and summary.type"call" | "voicemail"direction"inbound" | "outbound"statusstring | null — For examplecompleted,missed,forwarded.durationSecinteger | nullexternalE164string — The other party's number.contactNamestring | nullforwardedTostring | null — Where the call was forwarded, if it was.callerNamestring | null — Caller ID name (CNAM), when available.createdAttimestamp
curl "https://api.ody.co/v1/api/calls?limit=20" \
-H "Authorization: Bearer $ODY_API_KEY"const calls = await ody.calls.list({ limit: 20 });calls = client.calls.list(limit=20)#Place an AI call
/v1/api/callsYour published AI agent dials to from one of your numbers (by default the line connected to the agent), holds the conversation, and hangs up. The finished call lands on the contact's timeline with a recording, transcript and AI summary, exactly like an inbound AI-answered call. Subscribe to call.completed and call.summary.completed to get the outcome.
Billing matches inbound AI calls: 100 AI credits for a call up to 10 minutes, plus 10 credits for each additional started minute. A call that connects but lasts under 15 seconds costs 10 credits, and unanswered calls are free. (Workspaces not yet moved to the credit price list pay a flat 100 credits per call, with calls under 15 seconds free.) With a test key nothing is dialed and the response has simulated: true.
Scope: calls:place
Body
tostring required — Destination in E.164.fromstring — Caller ID: one of your active numbers. Defaults to the agent-connected line.
Returns 201 with { call: { id, to, from, status }, simulated? }. call.id is the carrier call ID.
Errors (409): the workspace has no plan, the agent isn't published, there's no active number, or the destination is international and international calling isn't enabled.
curl https://api.ody.co/v1/api/calls \
-H "Authorization: Bearer $ODY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"to":"+15125550123"}'const { call } = await ody.calls.place({ to: "+15125550123" });res = client.calls.place(to="+15125550123"){
"call": {
"id": "v3:6aL…",
"to": "+15125550123",
"from": "+15125550100",
"status": "queued"
}
}What the agent says on an outbound call comes from its configuration. Before you call, set its jobs (for example "Confirm tomorrow's appointment and offer to reschedule") with PATCH /agent, then publish.