Calls
Call history, transcripts, per-call results, search and export. Placing calls needs calls:create; reading needs calls:read.
Place a call
Section titled “Place a call”POST /voice/session
Starts a call with one of your agents: a phone call (callType sip; placed through the agent’s telephony provider when it has one) or a browser web call (callType web, returns a token to join). The agent must belong to the API key’s organisation and be active. This is billable: the wallet must hold the minimum call balance or the request fails with 402. Pass callTime to schedule the call instead of placing it now. Rate limited per host.
Scope: calls:create
Body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
agentId |
string | yes | |
participantName |
string | yes | Person being called. Stored capitalised (first letter upper, rest lower). |
callType |
string: web, sip, websocket | yes | sip for a phone call (automatically sent over the agent’s telephony provider when it has a provider and calling number), web for a browser call. |
participantNumber |
string | no | Number to call in E.164, for example +919876543210. Required when callType is sip. |
useCase |
string | no | Optional business purpose, such as ad leads. Stored on this call for Results filters and exports. |
customVariables |
object | no | String variables filled into {{placeholders}} in the agent’s prompts and greeting, and stored on the call. campaignId here links the call to a campaign. |
orgId |
string | no | Ignored; the organisation is taken from the agent. |
roomName |
string | no | Ignored; the room name is generated. |
callingNumber |
string | no | Which of your numbers to call from (matches a SIP configuration’s number). Defaults to the agent’s number. |
callTime |
string | no | Schedule the call for this future UTC time (ISO 8601). Must be in the future. |
master_settings |
object | no | Free-form settings passed to the agent runtime for this call only. |
functionTools |
object | no | Per-call function tools. For web and SIP calls they REPLACE the agent’s own tools for this call. |
Example request
curl -X POST "https://api.foan.ai/api/v1/voice/session" \ -H "Authorization: Bearer $FOAN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"agentId":"cmf3k2j9x0001abcd1234efgh","participantName":"Priya Sharma","callType":"sip","participantNumber":"+919876543210","customVariables":{"name":"Priya","order_id":"ORD-10492"}}'Response 201
{ "success": true, "data": { "success": true, "roomName": "call-7f3a9c2e", "sessionId": "66f1c2e8a4b5c6d7e8f90123", "callType": "websocket", "status": "initiated" }, "message": "SIP call initiated and websocket ready"}Errors
| Code | When |
|---|---|
| 400 | Validation error (for example participantNumber missing for sip), inactive agent, chat agent used for a phone call, no calling number or SIP configuration, or callTime not in the future. |
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 402 | Wallet balance below the minimum needed to place calls, or account suspended. |
| 403 | Missing calls:create scope, agent belongs to another organisation, or the destination country is blocked by the number’s calling scope. |
| 404 | Agent not found. |
| 409 | Duplicate request: the same agent, number and user dispatched within the last 5 seconds. |
| 429 | Rate limited. |
| 502 | The telephony provider rejected the call. |
| 503 | Real-time media service unavailable for web or SIP calls. |
Call a contact back
Section titled “Call a contact back”POST /voice/callback
Places (or schedules) a new outbound phone call to the same person as an earlier call, identified by that call’s room name. For chat conversations the chat agent’s configured callback voice agent makes the call. The calling agent must belong to the API key’s organisation. Billable, same wallet checks as placing a call.
Scope: calls:create
Body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
roomName |
string | yes | Call ID (room name) of the original call or chat. |
dialingNumber |
string | no | Which of your numbers to call from. Defaults to the number the earlier call used, then the agent’s number. |
dateTime |
string | no | Future UTC time to schedule the callback. Omit to call immediately. |
metaData |
object | no | Any JSON; stored on the new call as customVariables.callbackMetaData (stringified). |
Example request
curl -X POST "https://api.foan.ai/api/v1/voice/callback" \ -H "Authorization: Bearer $FOAN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"roomName":"call-7f3a9c2e","dateTime":"2026-09-26T05:30:00.000Z","metaData":{"reason":"Customer asked for a call tomorrow morning"}}'Response 201
{ "success": true, "data": { "success": true, "callType": "sip", "roomName": "call-9b1d4e7a", "sessionId": "66f1c2e8a4b5c6d7e8f90789", "message": "Call scheduled for 2026-09-26T05:30:00.000Z", "originalRoomName": "call-7f3a9c2e", "originalSessionId": "66f1c2e8a4b5c6d7e8f90123", "scheduledFor": "2026-09-26T05:30:00.000Z" }, "message": "Callback scheduled for 2026-09-26T05:30:00.000Z"}Errors
| Code | When |
|---|---|
| 400 | roomName missing, original call has no phone number, chat agent has no callback agent configured, or dateTime not in the future. |
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 402 | Wallet balance too low or account suspended. |
| 403 | Missing calls:create scope, or the call belongs to another organisation. |
| 404 | No call with that room name, or agent not found. |
| 409 | Duplicate dispatch within 5 seconds. |
| 429 | Rate limited |
Call status counts
Section titled “Call status counts”GET /voice-sessions/stats
Counts your organisation’s calls by raw status bucket, optionally for one agent or transport.
Scope: calls:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
orgId |
query | string | no | Your organisation ID. Optional with an API key (defaults to the key’s organisation); any other organisation answers 404. |
agentId |
query | string | no | Only calls handled by this agent. |
callType |
query | string: sip, web, chat, websocket | no | Only this transport. |
excludeCallType |
query | string: sip, web, chat, websocket | no | Exclude this transport (ignored when callType is set). |
Example request
curl -X GET "https://api.foan.ai/api/v1/voice-sessions/stats" \ -H "Authorization: Bearer $FOAN_API_KEY"Response 200
{ "success": true, "data": { "total": 1250, "answered": 820, "notAnswered": 190, "failed": 160 }}Errors
| Code | When |
|---|---|
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 403 | The key lacks the calls:read scope. |
| 404 | orgId is not your organisation. |
| 429 | Rate limited |
| 500 | An unknown callType or excludeCallType value (not validated) fails the query. |
Create a call record
Section titled “Create a call record”POST /voice-sessions
Creates a call record only; it does not place a call or start any audio (use POST /voice/session for that). orgId must be the API key’s organisation. Also increments the agent’s call count. Rate limited per host. agentResult and metaData.flowResult in the body are ignored: a call’s result is written only by Foan.
Scope: calls:create
Body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
roomName |
string | yes | Unique room name / Call ID. |
orgId |
string | yes | Must be the API key’s organisation. |
agentId |
string | yes | |
participantName |
string | yes | |
createdById |
string | no | Optional; defaults to the API key’s owner. |
phoneNumber |
string | no | |
callType |
string: sip, web, chat, websocket | no | |
callDirection |
string: INBOUND, OUTBOUND | no | |
campaignId |
string | no | |
customVariables |
object | no | Free-form variables. |
metaData |
object | no | Free-form metadata. |
Example request
curl -X POST "https://api.foan.ai/api/v1/voice-sessions" \ -H "Authorization: Bearer $FOAN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"roomName":"call-7f3a9c2e","orgId":"cmf3k2j9x0000orgabcd1234","agentId":"cmf3k2j9x0001abcd1234efgh","participantName":"Priya Sharma","phoneNumber":"+919876543210","callType":"web"}'Response 201
{ "success": true, "data": { "id": "66f1c2e8a4b5c6d7e8f90123", "roomName": "call-7f3a9c2e", "orgId": "cmf3k2j9x0000orgabcd1234", "agentId": "cmf3k2j9x0001abcd1234efgh", "campaignId": null, "participantName": "Priya sharma", "phoneNumber": "+919876543210", "createdById": "cmf3k2j9x0002user5678abcd", "createdAt": "2026-09-24T09:30:00.000Z", "endedAt": null, "customVariables": { "name": "Priya", "order_id": "ORD-10492" }, "scheduledTime": null, "scheduledStatus": null, "callingNumber": null, "metaData": {}, "callType": "web", "callDirection": "OUTBOUND", "callStatus": null, "callDuration": null, "callOutcome": null, "callOutcomeDetail": null, "isBilled": false, "billedAt": null, "agentName": "Order confirmation", "greetingMessage": "Hi Priya, this is Nina calling about your recent order. Is this a good time?", "recordingUrl": null, "overview": null, "actions": { "tracking": "not_recorded", "items": [] } }, "message": "Voice session created successfully"}Errors
| Code | When |
|---|---|
| 400 | Missing required fields, or chat/voice agent type mismatch. |
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 403 | Missing calls:create scope or orgId is not the key’s organisation. |
| 429 | Rate limited. |
| 500 | Organisation, agent or user not found, duplicate roomName, or an unknown field in the body. |
Get a call record
Section titled “Get a call record”GET /voice-sessions/{sessionId}
Returns the full stored record of one call, with the organisation, agent and creator attached. The call must belong to the API key’s organisation, otherwise 404.
Scope: calls:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
sessionId |
path | string | yes | Call (voice session) ID, a 24-character hex ID. |
Example request
curl -X GET "https://api.foan.ai/api/v1/voice-sessions/{sessionId}" \ -H "Authorization: Bearer $FOAN_API_KEY"Response 200
{ "success": true, "data": { "id": "66f1c2e8a4b5c6d7e8f90123", "roomName": "call-7f3a9c2e", "orgId": "cmf3k2j9x0000orgabcd1234", "agentId": "cmf3k2j9x0001abcd1234efgh", "campaignId": null, "participantName": "Priya sharma", "phoneNumber": "+919876543210", "createdById": "cmf3k2j9x0002user5678abcd", "createdAt": "2026-09-24T09:30:00.000Z", "endedAt": "2026-09-24T09:32:05.000Z", "customVariables": { "name": "Priya", "order_id": "ORD-10492" }, "scheduledTime": null, "scheduledStatus": null, "callingNumber": null, "metaData": {}, "callType": "websocket", "callDirection": "OUTBOUND", "callStatus": "COMPLETED", "callDuration": 125000, "callOutcome": "completed", "callOutcomeDetail": null, "isBilled": true, "billedAt": "2026-09-24T09:35:00.000Z", "agentName": "Order confirmation", "greetingMessage": "Hi Priya, this is Nina calling about your recent order. Is this a good time?", "recordingUrl": "/api/v1/voice-sessions/66f1c2e8a4b5c6d7e8f90123/recording", "overview": { "score": 8, "classification": "Relevant", "user_sentiment": "Interested", "summary": [ "Called to confirm order delivery address.", "Customer confirmed the address.", "Order will be dispatched today." ], "result": { "code": "interested", "quote": "Haan, same address pe bhej do", "quote_en": "Yes, send it to the same address", "evidence_status": "verified", "callback_at": null } }, "actions": { "tracking": "not_recorded", "items": [] }, "organisation": { "id": "cmf3k2j9x0000orgabcd1234", "name": "Example Retail Pvt Ltd", "type": "BUSINESS" }, "agent": { "id": "cmf3k2j9x0001abcd1234efgh", "name": "Order confirmation", "language": "en-US", "gender": "FEMALE" }, "createdBy": { "id": "cmf3k2j9x0002user5678abcd", "name": "Priya Sharma", "email": "priya@example.com" } }}Errors
| Code | When |
|---|---|
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 403 | Missing calls:read scope. |
| 404 | Call not found or not in your organisation. |
| 429 | Rate limited |
| 500 | sessionId is not a valid 24-character hex ID (not validated). |
Get a call record by Call ID
Section titled “Get a call record by Call ID”GET /voice-sessions/room/{roomName}
Returns the stored record of one call looked up by its room name (Call ID). The call must belong to the API key’s organisation, otherwise 404.
Scope: calls:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
roomName |
path | string | yes | Room name (Call ID). |
Example request
curl -X GET "https://api.foan.ai/api/v1/voice-sessions/room/{roomName}" \ -H "Authorization: Bearer $FOAN_API_KEY"Response 200
{ "success": true, "data": { "id": "66f1c2e8a4b5c6d7e8f90123", "roomName": "call-7f3a9c2e", "orgId": "cmf3k2j9x0000orgabcd1234", "agentId": "cmf3k2j9x0001abcd1234efgh", "campaignId": null, "participantName": "Priya sharma", "phoneNumber": "+919876543210", "createdById": "cmf3k2j9x0002user5678abcd", "createdAt": "2026-09-24T09:30:00.000Z", "endedAt": "2026-09-24T09:32:05.000Z", "customVariables": { "name": "Priya", "order_id": "ORD-10492" }, "scheduledTime": null, "scheduledStatus": null, "callingNumber": null, "metaData": {}, "callType": "websocket", "callDirection": "OUTBOUND", "callStatus": "COMPLETED", "callDuration": 125000, "callOutcome": "completed", "callOutcomeDetail": null, "isBilled": true, "billedAt": "2026-09-24T09:35:00.000Z", "agentName": "Order confirmation", "greetingMessage": "Hi Priya, this is Nina calling about your recent order. Is this a good time?", "recordingUrl": "/api/v1/voice-sessions/66f1c2e8a4b5c6d7e8f90123/recording", "overview": { "score": 8, "classification": "Relevant", "user_sentiment": "Interested", "summary": [ "Called to confirm order delivery address.", "Customer confirmed the address.", "Order will be dispatched today." ], "result": { "code": "interested", "quote": "Haan, same address pe bhej do", "quote_en": "Yes, send it to the same address", "evidence_status": "verified", "callback_at": null } }, "actions": { "tracking": "not_recorded", "items": [] } }}Errors
| Code | When |
|---|---|
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 403 | Missing calls:read scope. |
| 404 | Call not found or not in your organisation. |
| 429 | Rate limited |
Mark a call as ended
Section titled “Mark a call as ended”POST /voice-sessions/room/{roomName}/end
Marks a call record as COMPLETED, sets endedAt to now and callDuration to the time since the record was created. It does not hang up a live phone call. The call must belong to the API key’s organisation, otherwise 404.
Scope: calls:create
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
roomName |
path | string | yes | Room name (Call ID). |
Body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
reason |
string | no | Stored as metaData.endReason. |
Example request
curl -X POST "https://api.foan.ai/api/v1/voice-sessions/room/{roomName}/end" \ -H "Authorization: Bearer $FOAN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"reason":"Customer requested to end"}'Response 200
{ "success": true, "data": { "id": "66f1c2e8a4b5c6d7e8f90123", "roomName": "call-7f3a9c2e", "orgId": "cmf3k2j9x0000orgabcd1234", "agentId": "cmf3k2j9x0001abcd1234efgh", "campaignId": null, "participantName": "Priya sharma", "phoneNumber": "+919876543210", "createdById": "cmf3k2j9x0002user5678abcd", "createdAt": "2026-09-24T09:30:00.000Z", "endedAt": "2026-09-24T09:32:05.000Z", "customVariables": { "name": "Priya", "order_id": "ORD-10492" }, "scheduledTime": null, "scheduledStatus": null, "callingNumber": null, "metaData": {}, "callType": "websocket", "callDirection": "OUTBOUND", "callStatus": "COMPLETED", "callDuration": 125000, "callOutcome": "completed", "callOutcomeDetail": null, "isBilled": true, "billedAt": "2026-09-24T09:35:00.000Z", "agentName": "Order confirmation", "greetingMessage": "Hi Priya, this is Nina calling about your recent order. Is this a good time?", "recordingUrl": "/api/v1/voice-sessions/66f1c2e8a4b5c6d7e8f90123/recording", "overview": { "score": 8, "classification": "Relevant", "user_sentiment": "Interested", "summary": [ "Called to confirm order delivery address.", "Customer confirmed the address.", "Order will be dispatched today." ], "result": { "code": "interested", "quote": "Haan, same address pe bhej do", "quote_en": "Yes, send it to the same address", "evidence_status": "verified", "callback_at": null } }, "actions": { "tracking": "not_recorded", "items": [] } }, "message": "Voice session ended successfully"}Errors
| Code | When |
|---|---|
| 400 | reason is not a string. |
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 403 | Missing calls:create scope. |
| 404 | Call not found or not in your organisation. |
| 429 | Rate limited |
List call records (raw)
Section titled “List call records (raw)”GET /voice-sessions/organization/{orgId}
Lists your organisation’s raw call records, newest first, with offset pagination. Scheduled calls that have not run yet are excluded. For most uses prefer GET /call-history/sessions/organization/{orgId}, which adds filters and transcript counts.
Scope: calls:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
orgId |
path | string | yes | Your organisation ID. Must be the API key’s own organisation, otherwise 403. |
limit |
query | integer | no | Records per page. |
offset |
query | integer | no | Records to skip. |
callType |
query | string: sip, web, chat, websocket | no | Only this transport. |
Example request
curl -X GET "https://api.foan.ai/api/v1/voice-sessions/organization/{orgId}" \ -H "Authorization: Bearer $FOAN_API_KEY"Response 200
{ "success": true, "data": [ { "id": "66f1c2e8a4b5c6d7e8f90123", "roomName": "call-7f3a9c2e", "orgId": "cmf3k2j9x0000orgabcd1234", "agentId": "cmf3k2j9x0001abcd1234efgh", "campaignId": null, "participantName": "Priya sharma", "phoneNumber": "+919876543210", "createdById": "cmf3k2j9x0002user5678abcd", "createdAt": "2026-09-24T09:30:00.000Z", "endedAt": "2026-09-24T09:32:05.000Z", "customVariables": { "name": "Priya", "order_id": "ORD-10492" }, "scheduledTime": null, "scheduledStatus": null, "callingNumber": null, "metaData": {}, "callType": "websocket", "callDirection": "OUTBOUND", "callStatus": "COMPLETED", "callDuration": 125000, "callOutcome": "completed", "callOutcomeDetail": null, "isBilled": true, "billedAt": "2026-09-24T09:35:00.000Z", "agentName": "Order confirmation", "greetingMessage": "Hi Priya, this is Nina calling about your recent order. Is this a good time?", "recordingUrl": "/api/v1/voice-sessions/66f1c2e8a4b5c6d7e8f90123/recording", "overview": { "score": 8, "classification": "Relevant", "user_sentiment": "Interested", "summary": [ "Called to confirm order delivery address.", "Customer confirmed the address.", "Order will be dispatched today." ], "result": { "code": "interested", "quote": "Haan, same address pe bhej do", "quote_en": "Yes, send it to the same address", "evidence_status": "verified", "callback_at": null } }, "actions": { "tracking": "not_recorded", "items": [] } } ], "pagination": { "limit": 50, "offset": 0, "total": 1 }}Errors
| Code | When |
|---|---|
| 400 | limit or offset out of range. |
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 403 | The key lacks the calls:read scope, or the resource belongs to another organisation. |
| 429 | Rate limited |
| 500 | Unknown callType value (not validated). |
List an agent’s call records (raw)
Section titled “List an agent’s call records (raw)”GET /voice-sessions/agent/{agentId}
Lists raw call records handled by one agent, newest first. The agent must belong to the API key’s organisation. Scheduled calls not yet run are excluded.
Scope: calls:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
agentId |
path | string | yes | Agent ID. |
limit |
query | integer | no | Records per page. |
offset |
query | integer | no | Records to skip. |
callType |
query | string: sip, web, chat, websocket | no | Only this transport. |
Example request
curl -X GET "https://api.foan.ai/api/v1/voice-sessions/agent/{agentId}" \ -H "Authorization: Bearer $FOAN_API_KEY"Response 200
{ "success": true, "data": [ { "id": "66f1c2e8a4b5c6d7e8f90123", "roomName": "call-7f3a9c2e", "orgId": "cmf3k2j9x0000orgabcd1234", "agentId": "cmf3k2j9x0001abcd1234efgh", "campaignId": null, "participantName": "Priya sharma", "phoneNumber": "+919876543210", "createdById": "cmf3k2j9x0002user5678abcd", "createdAt": "2026-09-24T09:30:00.000Z", "endedAt": "2026-09-24T09:32:05.000Z", "customVariables": { "name": "Priya", "order_id": "ORD-10492" }, "scheduledTime": null, "scheduledStatus": null, "callingNumber": null, "metaData": {}, "callType": "websocket", "callDirection": "OUTBOUND", "callStatus": "COMPLETED", "callDuration": 125000, "callOutcome": "completed", "callOutcomeDetail": null, "isBilled": true, "billedAt": "2026-09-24T09:35:00.000Z", "agentName": "Order confirmation", "greetingMessage": "Hi Priya, this is Nina calling about your recent order. Is this a good time?", "recordingUrl": "/api/v1/voice-sessions/66f1c2e8a4b5c6d7e8f90123/recording", "overview": { "score": 8, "classification": "Relevant", "user_sentiment": "Interested", "summary": [ "Called to confirm order delivery address.", "Customer confirmed the address.", "Order will be dispatched today." ], "result": { "code": "interested", "quote": "Haan, same address pe bhej do", "quote_en": "Yes, send it to the same address", "evidence_status": "verified", "callback_at": null } }, "actions": { "tracking": "not_recorded", "items": [] } } ], "pagination": { "limit": 50, "offset": 0, "total": 1 }}Errors
| Code | When |
|---|---|
| 400 | limit or offset out of range. |
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 403 | The key lacks the calls:read scope, or the resource belongs to another organisation. |
| 404 | Agent not found or deleted. |
| 429 | Rate limited |
| 500 | Unknown callType value (not validated). |
Get a call’s event log
Section titled “Get a call’s event log”GET /voice-sessions/{sessionId}/conversation
Returns the message log stored for a call, oldest first. For phone and web calls this holds system events (participant joined, left, declined), not the spoken transcript; use GET /call-history/sessions/room/{roomName}/transcripts for the transcript. The call must belong to the API key’s organisation, otherwise 404.
Scope: calls:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
sessionId |
path | string | yes | Call (voice session) ID. |
Example request
curl -X GET "https://api.foan.ai/api/v1/voice-sessions/{sessionId}/conversation" \ -H "Authorization: Bearer $FOAN_API_KEY"Response 200
{ "success": true, "data": [ { "id": "66f1c2e8a4b5c6d7e8f90456", "sessionId": "66f1c2e8a4b5c6d7e8f90123", "speaker": "SYSTEM", "content": "Participant Priya sharma joined", "timestamp": "2026-09-24T09:30:04.000Z", "audioUrl": null, "duration": null, "confidence": null, "language": null, "processed": false, "sentiment": null, "keywords": [] } ]}Errors
| Code | When |
|---|---|
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 403 | Missing calls:read scope. |
| 404 | Call not found or not in your organisation. |
| 429 | Rate limited |
| 500 | sessionId is not a valid 24-character hex ID. |
Search one call’s event log
Section titled “Search one call’s event log”GET /voice-sessions/search/conversations
Case-insensitive text search inside one call’s message log (up to 50 matches, newest first). The call must belong to the API key’s organisation. To search spoken transcripts across all calls use GET /call-history/search/organization/{orgId}.
Scope: calls:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
query |
query | string | yes | Text to look for. |
sessionId |
query | string | yes | Call (voice session) ID to search within. |
Example request
curl -X GET "https://api.foan.ai/api/v1/voice-sessions/search/conversations" \ -H "Authorization: Bearer $FOAN_API_KEY"Response 200
{ "success": true, "data": [ { "id": "66f1c2e8a4b5c6d7e8f90456", "sessionId": "66f1c2e8a4b5c6d7e8f90123", "speaker": "SYSTEM", "content": "Participant Priya sharma joined", "timestamp": "2026-09-24T09:30:04.000Z", "audioUrl": null, "duration": null, "confidence": null, "language": null, "processed": false, "sentiment": null, "keywords": [] } ]}Errors
| Code | When |
|---|---|
| 400 | query or sessionId missing. |
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 403 | Missing calls:read scope. |
| 404 | Call not found or not in your organisation. |
| 429 | Rate limited |
| 500 | sessionId is not a valid 24-character hex ID. |
Get a call’s message counters
Section titled “Get a call’s message counters”GET /voice-sessions/{sessionId}/analytics
Returns the basic counters kept for a call (message counts, confidence, sentiment fields). The call must belong to the API key’s organisation, otherwise 404. For the AI call summary use the overview on the call list.
Scope: calls:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
sessionId |
path | string | yes | Call (voice session) ID. |
Example request
curl -X GET "https://api.foan.ai/api/v1/voice-sessions/{sessionId}/analytics" \ -H "Authorization: Bearer $FOAN_API_KEY"Response 200
{ "success": true, "data": { "id": "66f1c2e8a4b5c6d7e8f90abc", "sessionId": "66f1c2e8a4b5c6d7e8f90123", "totalMessages": 3, "userMessages": 0, "agentMessages": 0, "averageResponseTime": null, "longestSilence": null, "averageConfidence": null, "interruptionCount": 0, "overallSentiment": null, "sentimentScores": null, "topKeywords": [], "detectedTopics": [], "audioQualityScore": null, "networkIssues": false, "createdAt": "2026-09-24T09:30:00.000Z", "updatedAt": "2026-09-24T09:32:05.000Z" }}Errors
| Code | When |
|---|---|
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 403 | Missing calls:read scope. |
| 404 | Call not found, not in your organisation, or no counters recorded. |
| 429 | Rate limited |
| 500 | sessionId is not a valid 24-character hex ID. |
Export calls to Excel
Section titled “Export calls to Excel”GET /call-history/sessions/organization/{orgId}/export
Downloads your organisation’s calls matching the same filters as the call list as an .xlsx file (up to 10,000 calls, no pagination). Columns for calls: Agent Name, Name, Call Type (Phone/Web/Chat), Number, Campaign, Date & Time (India time), Duration (mm:ss min), Status, Direction, Call Outcome, Actions. With callType=chat the sheet is “Chat History” and the columns are Agent Name, Name, Date & Time, Messages, Status, Actions. The sheet has no Call ID, score, summary or transcript columns: for those, page through the call list (each row carries roomName, overview and customVariables) and fetch transcripts per call. An agentId from another organisation answers 404.
Scope: calls:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
orgId |
path | string | yes | Your organisation ID. Must be the API key’s own organisation, otherwise 403. |
agentId |
query | string | no | Only calls handled by this agent. |
campaignsOnly |
query | boolean | no | Only calls placed by a campaign. |
type |
query | string: history, scheduled | no | history = placed or finished calls (newest first); scheduled = calls still waiting to be placed (soonest first). Any other value is treated as history. |
search |
query | string | no | Case-insensitive match on agent name, participant name, phone number or Call ID (room name). |
callType |
query | string: sip, websocket, web, chat | no | Only this transport. Phone calls are usually websocket or sip. |
excludeCallType |
query | string: sip, websocket, web, chat | no | Exclude this transport. Ignored when callType is set. |
outcome |
query | string: answered, no_answer, busy, rejected, voicemail, failed | no | Filter by what happened on the line. answered = completed or hung_up; rejected = rejected or canceled; failed = failed, provider_failed, provider_throttled, agent_no_audio or unknown. Unknown values are ignored. |
callDirection |
query | string: INBOUND, OUTBOUND | no | Only inbound or outbound calls. OUTBOUND also includes older calls with no direction recorded. Other values are ignored. |
startDate |
query | string | no | Calls created on or after this ISO 8601 time. |
endDate |
query | string | no | Calls created on or before this ISO 8601 time. |
campaignId |
query | string | no | Only calls from this campaign. |
page |
query | integer | no | Validated but ignored. |
limit |
query | integer | no | Validated but ignored; the export always returns up to 10,000 rows. |
Example request
curl -X GET "https://api.foan.ai/api/v1/call-history/sessions/organization/{orgId}/export" \ -H "Authorization: Bearer $FOAN_API_KEY"Response 200
Errors
| Code | When |
|---|---|
| 400 | Invalid filter value (callType, dates, booleans, limit), or agentId given more than once. |
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 403 | The key lacks the calls:read scope, or the resource belongs to another organisation. |
| 404 | agentId is not an agent of this organisation |
| 429 | Rate limited |
| 500 | Export failed. |
List calls
Section titled “List calls”GET /call-history/sessions/organization/{orgId}
Lists your organisation’s calls, newest first, with filters for agent, campaign, transport, direction, outcome, date range and free-text search. Each row includes the outcome, the AI overview (score, summary, result) and transcript message counts. Use type=scheduled to list calls waiting to be placed. An agentId from another organisation answers 404.
Scope: calls:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
orgId |
path | string | yes | Your organisation ID. Must be the API key’s own organisation, otherwise 403. |
page |
query | integer | no | Page number. |
limit |
query | integer | no | Calls per page. |
agentId |
query | string | no | Only calls handled by this agent. |
campaignsOnly |
query | boolean | no | Only calls placed by a campaign. |
type |
query | string: history, scheduled | no | history = placed or finished calls (newest first); scheduled = calls still waiting to be placed (soonest first). Any other value is treated as history. |
search |
query | string | no | Case-insensitive match on agent name, participant name, phone number or Call ID (room name). |
callType |
query | string: sip, websocket, web, chat | no | Only this transport. Phone calls are usually websocket or sip. |
excludeCallType |
query | string: sip, websocket, web, chat | no | Exclude this transport. Ignored when callType is set. |
outcome |
query | string: answered, no_answer, busy, rejected, voicemail, failed | no | Filter by what happened on the line. answered = completed or hung_up; rejected = rejected or canceled; failed = failed, provider_failed, provider_throttled, agent_no_audio or unknown. Unknown values are ignored. |
callDirection |
query | string: INBOUND, OUTBOUND | no | Only inbound or outbound calls. OUTBOUND also includes older calls with no direction recorded. Other values are ignored. |
startDate |
query | string | no | Calls created on or after this ISO 8601 time. |
endDate |
query | string | no | Calls created on or before this ISO 8601 time. |
Example request
curl -X GET "https://api.foan.ai/api/v1/call-history/sessions/organization/{orgId}" \ -H "Authorization: Bearer $FOAN_API_KEY"Response 200
{ "success": true, "data": [ { "id": "66f1c2e8a4b5c6d7e8f90123", "roomName": "call-7f3a9c2e", "agentId": "cmf3k2j9x0001abcd1234efgh", "agentName": "Order confirmation", "orgId": "cmf3k2j9x0000orgabcd1234", "participantName": "Priya sharma", "phoneNumber": "+919876543210", "callStatus": "COMPLETED", "startTime": "2026-09-24T09:30:00.000Z", "createdAt": "2026-09-24T09:30:00.000Z", "endedAt": "2026-09-24T09:32:05.000Z", "callDuration": 125000, "callOutcome": "completed", "callOutcomeDetail": null, "recordingUrl": "/api/v1/voice-sessions/66f1c2e8a4b5c6d7e8f90123/recording", "customVariables": { "name": "Priya", "order_id": "ORD-10492" }, "callDirection": "OUTBOUND", "callType": "websocket", "scheduledTime": null, "scheduledStatus": null, "campaignId": null, "campaign": null, "followUpRound": null, "overview": { "score": 8, "classification": "Relevant", "user_sentiment": "Interested", "summary": [ "Called to confirm order delivery address.", "Customer confirmed the address.", "Order will be dispatched today." ], "result": { "code": "interested", "quote": "Haan, same address pe bhej do", "quote_en": "Yes, send it to the same address", "evidence_status": "verified", "callback_at": null } }, "actions": { "tracking": "not_recorded", "items": [] }, "totalMessages": 14, "userMessages": 6, "assistantMessages": 8, "totalTokens": 0, "firstMessageAt": "2026-09-24T09:30:06.000Z", "lastMessageAt": "2026-09-24T09:32:01.000Z" } ], "pagination": { "page": 1, "limit": 20, "total": 1, "totalPages": 1, "hasMore": false }}Errors
| Code | When |
|---|---|
| 400 | Invalid page, limit, callType, excludeCallType, boolean or date value, or agentId given more than once. |
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 403 | The key lacks the calls:read scope, or the resource belongs to another organisation. |
| 404 | agentId is not an agent of this organisation |
| 429 | Rate limited |
| 500 | Unexpected error. |
Get a call transcript
Section titled “Get a call transcript”GET /call-history/sessions/room/{roomName}/transcripts
Returns one call (by Call ID) with its full spoken transcript in order and message stats. The call must belong to the API key’s organisation, otherwise 404.
Scope: calls:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
roomName |
path | string | yes | Room name (Call ID). |
Example request
curl -X GET "https://api.foan.ai/api/v1/call-history/sessions/room/{roomName}/transcripts" \ -H "Authorization: Bearer $FOAN_API_KEY"Response 200
{ "success": true, "data": { "session": { "id": "66f1c2e8a4b5c6d7e8f90123", "roomName": "call-7f3a9c2e", "agentId": "cmf3k2j9x0001abcd1234efgh", "orgId": "cmf3k2j9x0000orgabcd1234", "participantName": "Priya sharma", "agentName": "Order confirmation", "agentIdentity": "You are Nina, a friendly order confirmation assistant for an online store.", "agentTask": "Confirm the order ORD-10492 and the delivery address, then thank the customer.", "pronunciation": null, "greetingMessage": "Hi Priya, this is Nina calling about your recent order. Is this a good time?", "closingMessage": "Thank you, have a great day!", "escalationMessage": null, "callStatus": "COMPLETED", "createdAt": "2026-09-24T09:30:00.000Z", "endedAt": "2026-09-24T09:32:05.000Z", "callDuration": 125000, "recordingUrl": "/api/v1/voice-sessions/66f1c2e8a4b5c6d7e8f90123/recording", "customVariables": { "name": "Priya", "order_id": "ORD-10492" }, "overview": { "score": 8, "classification": "Relevant", "user_sentiment": "Interested", "summary": [ "Called to confirm order delivery address.", "Customer confirmed the address.", "Order will be dispatched today." ], "result": { "code": "interested", "quote": "Haan, same address pe bhej do", "quote_en": "Yes, send it to the same address", "evidence_status": "verified", "callback_at": null } }, "actions": { "tracking": "not_recorded", "items": [] } }, "transcripts": [ { "id": "trn_01", "role": "assistant", "text": "Hi Priya, this is Nina calling about your recent order. Is this a good time?", "speaker": { "id": "agent", "name": "Nina" }, "timestamps": { "createdAt": "2026-09-24T09:30:06.000Z", "receivedAt": "2026-09-24T09:30:06.200Z" } }, { "id": "trn_02", "role": "user", "text": "Haan, boliye.", "speaker": { "id": "user", "name": "Priya sharma" }, "timestamps": { "createdAt": "2026-09-24T09:30:09.000Z", "receivedAt": "2026-09-24T09:30:09.100Z" } } ], "stats": { "totalMessages": 14, "userMessages": 6, "assistantMessages": 8, "totalTokens": 0, "duration": 115 } }}Errors
| Code | When |
|---|---|
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 403 | Missing calls:read scope. |
| 404 | Call not found or not in your organisation. |
| 429 | Rate limited |
Get a call transcript by call ID
Section titled “Get a call transcript by call ID”GET /call-history/sessions/{sessionId}
Same as the transcript route but looked up by the call (voice session) ID: returns the call, its full transcript and stats. The call must belong to the API key’s organisation, otherwise 404.
Scope: calls:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
sessionId |
path | string | yes | Call (voice session) ID. |
Example request
curl -X GET "https://api.foan.ai/api/v1/call-history/sessions/{sessionId}" \ -H "Authorization: Bearer $FOAN_API_KEY"Response 200
{ "success": true, "data": { "session": { "id": "66f1c2e8a4b5c6d7e8f90123", "roomName": "call-7f3a9c2e", "agentId": "cmf3k2j9x0001abcd1234efgh", "orgId": "cmf3k2j9x0000orgabcd1234", "participantName": "Priya sharma", "agentName": "Order confirmation", "agentIdentity": "You are Nina, a friendly order confirmation assistant for an online store.", "agentTask": "Confirm the order ORD-10492 and the delivery address, then thank the customer.", "pronunciation": null, "greetingMessage": "Hi Priya, this is Nina calling about your recent order. Is this a good time?", "closingMessage": "Thank you, have a great day!", "escalationMessage": null, "callStatus": "COMPLETED", "createdAt": "2026-09-24T09:30:00.000Z", "endedAt": "2026-09-24T09:32:05.000Z", "callDuration": 125000, "recordingUrl": "/api/v1/voice-sessions/66f1c2e8a4b5c6d7e8f90123/recording", "customVariables": { "name": "Priya", "order_id": "ORD-10492" }, "overview": { "score": 8, "classification": "Relevant", "user_sentiment": "Interested", "summary": [ "Called to confirm order delivery address.", "Customer confirmed the address.", "Order will be dispatched today." ], "result": { "code": "interested", "quote": "Haan, same address pe bhej do", "quote_en": "Yes, send it to the same address", "evidence_status": "verified", "callback_at": null } }, "actions": { "tracking": "not_recorded", "items": [] } }, "transcripts": [ { "id": "trn_01", "role": "assistant", "text": "Hi Priya, this is Nina calling about your recent order. Is this a good time?", "speaker": { "id": "agent", "name": "Nina" }, "timestamps": { "createdAt": "2026-09-24T09:30:06.000Z", "receivedAt": "2026-09-24T09:30:06.200Z" } }, { "id": "trn_02", "role": "user", "text": "Haan, boliye.", "speaker": { "id": "user", "name": "Priya sharma" }, "timestamps": { "createdAt": "2026-09-24T09:30:09.000Z", "receivedAt": "2026-09-24T09:30:09.100Z" } } ], "stats": { "totalMessages": 14, "userMessages": 6, "assistantMessages": 8, "totalTokens": 0, "duration": 115 } }}Errors
| Code | When |
|---|---|
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 403 | Missing calls:read scope. |
| 404 | Call not found or not in your organisation. |
| 429 | Rate limited |
| 500 | sessionId is not a valid 24-character hex ID. |
Call and transcript totals
Section titled “Call and transcript totals”GET /call-history/stats/organization/{orgId}
Returns call counts by raw status bucket and transcript totals for your organisation, optionally for one agent.
Scope: calls:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
orgId |
path | string | yes | Your organisation ID. Must be the API key’s own organisation, otherwise 403. |
agentId |
query | string | no | Only this agent. |
Example request
curl -X GET "https://api.foan.ai/api/v1/call-history/stats/organization/{orgId}" \ -H "Authorization: Bearer $FOAN_API_KEY"Response 200
{ "success": true, "data": { "sessions": { "total": 1250, "answered": 820, "notAnswered": 190, "failed": 160 }, "transcripts": { "totalSessions": 790, "totalMessages": 11850, "userMessages": 5200, "assistantMessages": 6650, "totalTokens": 0, "averageMessagesPerSession": 15, "averageTokensPerSession": 0 } }}Errors
| Code | When |
|---|---|
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 403 | The key lacks the calls:read scope, or the resource belongs to another organisation. |
| 429 | Rate limited |
| 500 | Unexpected server error. |
Search transcripts
Section titled “Search transcripts”GET /call-history/search/organization/{orgId}
Case-insensitive text search across every transcript line in your organisation, newest first. Each result is one transcript line; use room.name to open the call.
Scope: calls:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
orgId |
path | string | yes | Your organisation ID. Must be the API key’s own organisation, otherwise 403. |
query |
query | string | yes | Text to search for. |
page |
query | integer | no | Page number. |
limit |
query | integer | no | Lines per page. |
Example request
curl -X GET "https://api.foan.ai/api/v1/call-history/search/organization/{orgId}" \ -H "Authorization: Bearer $FOAN_API_KEY"Response 200
{ "success": true, "data": [ { "id": "trn_02", "agentId": "cmf3k2j9x0001abcd1234efgh", "callId": "3f2a9c1e-5b7d-4e2a-9c1f-7a3b5d9e1c20", "orgId": "cmf3k2j9x0000orgabcd1234", "role": "user", "text": "Please deliver after 6 pm", "room": { "name": "call-7f3a9c2e", "sid": "RM_a1b2c3d4" }, "speaker": { "id": "user", "name": "Priya sharma" }, "timestamps": { "createdAt": "2026-09-24T09:31:10.000Z", "receivedAt": "2026-09-24T09:31:10.100Z" }, "meta": {}, "usage": null } ], "pagination": { "page": 1, "limit": 20, "total": 1, "totalPages": 1 }}Errors
| Code | When |
|---|---|
| 400 | query missing, or invalid page/limit. |
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 403 | The key lacks the calls:read scope, or the resource belongs to another organisation. |
| 429 | Rate limited |
| 500 | Unexpected server error. |
Get call latency metrics
Section titled “Get call latency metrics”GET /call-history/sessions/room/{roomName}/metrics
Returns one call’s summary with its latency metrics (turn, speech and model response times, median and 95th percentile). The call must belong to the API key’s organisation, otherwise 404.
Scope: calls:read
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
roomName |
path | string | yes | Room name (Call ID). |
Example request
curl -X GET "https://api.foan.ai/api/v1/call-history/sessions/room/{roomName}/metrics" \ -H "Authorization: Bearer $FOAN_API_KEY"Response 200
{ "success": true, "data": { "roomName": "call-7f3a9c2e", "callId": "call-7f3a9c2e", "orgId": "cmf3k2j9x0000orgabcd1234", "agentId": "cmf3k2j9x0001abcd1234efgh", "participantName": "Priya sharma", "phoneNumber": "+919876543210", "callStatus": "COMPLETED", "callDuration": 125000, "callDirection": "OUTBOUND", "callType": "websocket", "createdAt": "2026-09-24T09:30:00.000Z", "endedAt": "2026-09-24T09:32:05.000Z", "recordingUrl": null, "overview": { "score": 8, "classification": "Relevant", "user_sentiment": "Interested", "summary": [ "Called to confirm order delivery address.", "Customer confirmed the address.", "Order will be dispatched today." ], "result": { "code": "interested", "quote": "Haan, same address pe bhej do", "quote_en": "Yes, send it to the same address", "evidence_status": "verified", "callback_at": null } }, "metrics": { "turn_latency_ms_p50": 820, "turn_latency_ms_p95": 1450, "turn_latency_calculated": true, "tts_latency_ms_p50": null, "tts_latency_ms_p95": null, "tts_calls": 0, "llm_latency_ms_p50": null, "llm_latency_ms_p95": null, "llm_calls": 0 } }}Errors
| Code | When |
|---|---|
| 401 | Missing, invalid or revoked API key, or the key’s owner is deactivated or no longer in the organisation. |
| 403 | Missing calls:read scope. |
| 404 | Call not found or not in your organisation. |
| 429 | Rate limited |

