Docs

API reference

Read contacts, calls and analytics, add contacts and place calls from your own systems. These are all 9 endpoints an API token can reach, generated from the API itself.

All docs

Before you start

  • Base URL: https://aicallstudio.com. Every path below starts with /api, with no trailing slash.
  • Make a token in your dashboard under Settings, Developers. It is shown once: store it like a password.
  • Your plan must include API access. Without it every request answers 402, and the token works again once the plan includes it.
  • A token acts for the whole workspace, not for one person, and reaches only the endpoints on this page. Anything else answers 403.

Authentication

Send the token on every request in the Authorization header. Tokens start with mtc_.

The header
Authorization: Bearer mtc_YOUR_TOKEN

Scopes

A token is given scopes when it is made. Each endpoint needs one; a token without it gets 403. You can only give a token what you may do yourself.

Scopes
ScopeOn the Developers pageEndpoints
analytics:readRead analytics: Summaries and breakdownsGET /api/analytics/classification-breakdown, GET /api/analytics/disposition-breakdown, GET /api/analytics/summary
calls:readRead calls: Call logs and analyticsGET /api/analytics/calls
calls:writePlace calls: Start calls through the APIPOST /api/calls/dial
contacts:readRead contacts: List and export contactsGET /api/contacts, GET /api/contacts/export
contacts:writeWrite contacts: Create and import contactsPOST /api/contacts, POST /api/sources/import/csv

Sandbox tokens

A token made as a sandbox token starts with mtc_sandbox_. It never writes, and it never reads your workspace's real data. There is no sample data behind it yet, so today it only proves that the token and its scopes are right: a request it is allowed to make answers 403 with a message saying so, and a request outside its scopes answers 403 naming the scope. Use a live token to read or change data.

Limits and errors

Each token may make 60 requests a minute, across every endpoint. The next request answers 429 with a Retry-After header giving the seconds to wait. Some endpoints have their own limit as well, stated on the endpoint.

Every error is JSON with a detail: a sentence you can show or log. For 422 it may be a list of the fields at fault.

An error
{ "detail": "This token does not have the 'contacts:write' scope." }

Contacts

List contacts

GET/api/contactsScope contacts:read

List your contacts, a page at a time.

Every filter is optional, and they combine. A page holds at most 200 contacts: read total, then ask for the next page until you have them all. Deleted contacts are never listed.

Query parameters
ParameterTypeWhat it is
pageinteger, at least 1Default: 1.
page_sizeinteger, 1 to 200Default: 50.
searchstring, or nullWords found anywhere in the name, email or number, in any order. A number matches in any format.
statusstring, or nullThe contact's status, such as new.
classificationstring, or nullLead classification: hot, warm or cold.
sourcestring, or nullWhere the contact came from, exactly as the contact's source field says.
dispositionstring, or nullThe contact's latest outcome key.
min_scoreinteger, or nullHas a call scored at least this (0 to 100).
max_scoreinteger, or nullHas a call scored at most this (0 to 100).
min_durationinteger, or nullHas a call at least this many seconds long.
max_durationinteger, or nullHas a call at most this many seconds long.
campaign_idstring (uuid), or nullHas a call placed by this campaign.
lead_setstring, or nullThe lead set the contact was imported into.
dndboolean, or nulltrue: only Do-Not-Call contacts; false: only callable ones.
needsone of: callback, stale_high, or nullcallback: a call back is owed; stale_high: hot, callable, and not rung in the last 7 days.
added_fromstring (date-time), or nullAdded at or after this time (ISO 8601).
added_tostring (date-time), or nullAdded at or before this time (ISO 8601).
added_daysinteger, 1 to 366, or nullAdded in the last N days
agent_idstring (uuid), or nullHas a call answered by this AI agent.
team_idstring (uuid), or nullHas a call answered by this AI team.
answered_byone of: agent, team, or nullHas a call answered by any AI agent working alone, or by any AI team.
assigned_tostring, or nullGiven to: a team member's user id, or none
last_message_statusstring, up to 12 characters, or nullThe latest campaign message to the contact has this status (delivered, read, replied, failed...)
sortone of: name, source, score, last_called, addedDefault: name.
orderone of: asc, descDefault: asc.
viewone of: active, heldheld: contacts held over the plan's contact limit. Default: active.
Answer (200): these fields
FieldTypeWhat it is
totalrequiredintegerContacts matching the filters, across every page.
pagerequiredinteger—
page_sizerequiredinteger—
sortrequiredstring—
orderrequiredstring—
itemsrequiredlist of objects—
items[].idrequiredstring (uuid)—
items[].namerequiredstring—
items[].phonerequiredstring—
items[].emailrequiredstring, or null—
items[].lead_typerequiredstring, or null—
items[].statusrequiredstring—
items[].classificationrequiredstring, or null—
items[].dispositionrequiredstring, or null—
items[].dnd_flagrequiredboolean—
items[].sourcestring, or null—
items[].languagestring, or null—
items[].created_atstring (date-time), or null—
items[].last_called_atstring (date-time), or null—
items[].scorenumber, or null—
items[].assigned_user_idstring (uuid), or null—
Errors
CodeWhen
401The token is missing, unknown or revoked, or its workspace was deleted.
402The workspace's plan does not include API access. The token is paused, not revoked: it works again as soon as the plan includes API access.
403The token does not have this endpoint's scope, it is a sandbox token, the workspace is suspended, or the request came from a network the workspace does not allow.
422A field is missing or not in the form this endpoint takes. detail says which, and why.
429This token has made more than 60 requests a minute. The Retry-After header says how many seconds to wait.
GET /api/contacts with curl
curl "https://aicallstudio.com/api/contacts?page_size=50" \
  -H "Authorization: Bearer mtc_YOUR_TOKEN"

Create a contact

POST/api/contactsScope contacts:write

Add one contact.

name and phone are required. One number is one contact: the same number in another format ("98765 43210", "+919876543210") is refused with 409. A number deleted earlier brings that contact back with its history. Adding a contact starts the workspace's New Contact workflows, as adding one by hand does, and those may call or message the person.

Request body (application/json)
FieldTypeWhat it is
namerequiredstring, up to 255 charactersThe person's name.
phonerequiredstring, up to 20 characters8 to 15 digits, optionally starting with +. Stored in one canonical form.
emailstring, or nullOptional. Must look like name@example.com.
custom_fieldsobjectYour own fields for this contact, by field name. A contact type's required fields must be here.
lead_typestring, or nullThe contact type's key, which decides the fields it needs. Blank: general.
sourcestring, or nullWhere the contact came from, in your words.
dnd_flagbooleantrue puts the number on Do-Not-Call: it is never rung. Default: false.
statusstringDefault: new.
classificationstring, or nullhot, warm or cold.
dispositionstring, or nullAn outcome key defined in your workspace.
languagestring, or nullThe language the person prefers, as a code or a name, such as hi-IN or Hindi.
Answer (201): these fields
FieldTypeWhat it is
idrequiredstring (uuid)—
org_idrequiredstring (uuid)—
namerequiredstring—
phonerequiredstring—
emailrequiredstring, or null—
custom_fieldsrequiredobject—
lead_typerequiredstring, or null—
sourcerequiredstring, or null—
dnd_flagrequiredboolean—
statusrequiredstring—
classificationrequiredstring, or null—
dispositionrequiredstring, or null—
languagestring, or null—
best_timeobject, or null—
assigned_user_idstring (uuid), or null—
Errors
CodeWhen
401The token is missing, unknown or revoked, or its workspace was deleted.
402The workspace's plan does not include API access. The token is paused, not revoked: it works again as soon as the plan includes API access. The plan's contact limit is reached.
403The token does not have this endpoint's scope, it is a sandbox token, the workspace is suspended, or the request came from a network the workspace does not allow.
409A contact already has this number, in any format.
422A field is missing or not in the form this endpoint takes. detail says which, and why.
429This token has made more than 60 requests a minute. The Retry-After header says how many seconds to wait.
POST /api/contacts with curl
curl -X POST "https://aicallstudio.com/api/contacts" \
  -H "Authorization: Bearer mtc_YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Asha Verma","phone":"+919876543210"}'

Export contacts

GET/api/contacts/exportScope contacts:read

Download every contact matching the filters as one file, CSV or Excel.

The same filters as listing contacts, in one file with no paging. Pass ids to export just those contacts (at most 1,000), still inside the other filters.

Query parameters
ParameterTypeWhat it is
formatstringcsv or xlsx. Default: csv.
searchstring, or nullWords found anywhere in the name, email or number, in any order. A number matches in any format.
statusstring, or nullThe contact's status, such as new.
classificationstring, or nullLead classification: hot, warm or cold.
sourcestring, or nullWhere the contact came from, exactly as the contact's source field says.
dispositionstring, or nullThe contact's latest outcome key.
min_scoreinteger, or nullHas a call scored at least this (0 to 100).
max_scoreinteger, or nullHas a call scored at most this (0 to 100).
min_durationinteger, or nullHas a call at least this many seconds long.
max_durationinteger, or nullHas a call at most this many seconds long.
campaign_idstring (uuid), or nullHas a call placed by this campaign.
lead_setstring, or nullThe lead set the contact was imported into.
dndboolean, or nulltrue: only Do-Not-Call contacts; false: only callable ones.
needsone of: callback, stale_high, or nullcallback: a call back is owed; stale_high: hot, callable, and not rung in the last 7 days.
added_fromstring (date-time), or nullAdded at or after this time (ISO 8601).
added_tostring (date-time), or nullAdded at or before this time (ISO 8601).
added_daysinteger, 1 to 366, or nullAdded in the last N days
agent_idstring (uuid), or nullHas a call answered by this AI agent.
team_idstring (uuid), or nullHas a call answered by this AI team.
answered_byone of: agent, team, or nullHas a call answered by any AI agent working alone, or by any AI team.
assigned_tostring, or nullGiven to: a team member's user id, or none
last_message_statusstring, up to 12 characters, or nullThe latest campaign message to the contact has this status (delivered, read, replied, failed...)
idsstring, or nullComma-separated contact ids: export just this selection

Answer: 200. The file, as an attachment: CSV by default, an Excel workbook with format=xlsx.

Errors
CodeWhen
401The token is missing, unknown or revoked, or its workspace was deleted.
402The workspace's plan does not include API access. The token is paused, not revoked: it works again as soon as the plan includes API access.
403The token does not have this endpoint's scope, it is a sandbox token, the workspace is suspended, or the request came from a network the workspace does not allow.
422A field is missing or not in the form this endpoint takes. detail says which, and why.
429This token has made more than 60 requests a minute. The Retry-After header says how many seconds to wait.
GET /api/contacts/export with curl
curl "https://aicallstudio.com/api/contacts/export" \
  -H "Authorization: Bearer mtc_YOUR_TOKEN" \
  -o contacts.csv

Import contacts from a file

POST/api/sources/import/csvScope contacts:write

Import contacts from a spreadsheet: one contact per row.

Send the file as multipart/form-data. Rows without a name or a dialable phone number are skipped and listed in errors. A number already in the workspace updates that contact, or is skipped with dedupe=skip. New contacts over the plan's contact limit are saved but held, and counted in held. New contacts start the New Contact workflows, which may call or message them. One import runs in a workspace at a time, and an address may start at most 3 a minute.

Request body (multipart/form-data)
FieldTypeWhat it is
filerequiredfileA .csv or .xlsx file with a header row. It needs a name and a phone column. At most 50 MB.
lead_setstring, or nullA lead set to put every imported contact in.
clean_namesbooleantrue tidies each name: title case, honorifics and extra spaces removed. Default: false.
dedupestringA number that is already a contact: update (the default) refreshes that contact, skip leaves it. Default: update.
lead_typestring, or nullThe contact type every row is imported as.
mappingstring, or nullJSON: which column fills each field, as {"field name": "Column header"}.
Answer (200): these fields
FieldTypeWhat it is
source_idrequiredstring (uuid)The import, as a lead source in your workspace.
createdrequiredintegerNew contacts added.
updatedrequiredintegerExisting contacts refreshed from the file.
skippedrequiredintegerRows not imported: rows with a problem (see errors), and existing contacts with dedupe=skip.
heldintegerNew contacts over the plan's contact limit: saved, and held until the plan has room. Default: 0.
errorsrequiredlist of stringWhy each skipped row was skipped, by row number.
Errors
CodeWhen
400The file is not .csv or .xlsx, is empty, cannot be read, or has no name or phone column.
401The token is missing, unknown or revoked, or its workspace was deleted.
402The workspace's plan does not include API access. The token is paused, not revoked: it works again as soon as the plan includes API access.
403The token does not have this endpoint's scope, it is a sandbox token, the workspace is suspended, or the request came from a network the workspace does not allow.
413The file is over 50 MB.
422A field is missing or not in the form this endpoint takes. detail says which, and why.
429This token has made more than 60 requests a minute. The Retry-After header says how many seconds to wait.
POST /api/sources/import/csv with curl
curl -X POST "https://aicallstudio.com/api/sources/import/csv" \
  -H "Authorization: Bearer mtc_YOUR_TOKEN" \
  -F "file=@contacts.csv"

Calls

List calls

GET/api/analytics/callsScope calls:read

The call log, a page at a time, newest first, with totals for everything that matches.

Each call comes with its outcome, score, summary, cost and who answered it, and stats counts every matching call, not just this page. By default the last 30 days; date_from and date_to (IST calendar days) pick a range instead. Test calls are left out unless asked for. A page holds at most 200 calls. A recording link expires: fetch the call again when you need it.

Query parameters
ParameterTypeWhat it is
pageinteger, at least 1Default: 1.
page_sizeinteger, 1 to 200Default: 50.
sortstringBy start time: newest or oldest first. Default: newest.
daysinteger, 1 to 365The last this many days, 1 to 365. date_from overrides it. Default: 30.
statusstring, or nullThe call's status, such as completed, no_answer, busy or failed.
classificationstring, or nullLead classification: hot, warm or cold.
agent_idstring, or nullCalls answered by this AI agent.
team_idstring, or nullCalls answered by this AI team.
contact_idstring, or nullCalls with this contact.
directionstring, or nullinbound or outbound.
campaign_idstring, or nullCalls this campaign placed.
dispositionstring, or nullCalls with this outcome key.
initiatorstring, or nullWhat started the call, comma-separated: manual,campaign,web,inbound,workflow,workspace,test,api,callback
missedboolean, or nulltrue: calls where nobody spoke to the customer (not answered, a machine, or a failed attempt); false: the others.
searchstring, or nullText to find in the contact's name, a number on the call, or the summary.
date_fromstring (date), or nullIST calendar day, YYYY-MM-DD. Beats days.
date_tostring (date), or nullIST calendar day, inclusive.
campaign_onlybooleanOnly calls a campaign placed. Default: false.
didstring, or nullComma-separated: your own numbers. Matches every stored spelling of each line (+91…, 91…, 0…, national).
handoverone of: yes, no, answered, missed, not_rung, or nullHanded to a person: yes, no, answered (someone came on), missed (someone was rung, nobody came on) or not_rung (nobody was rung: outside the hours).
handover_userstring (uuid), or nullOnly hand-overs this staff member answered.
answered_byone of: agent, team, staff, or nullAny AI agent working alone, any AI team, or staff (a person's own call from the Workspace, no AI on it).
staff_userstring (uuid), or nullCalls this staff member took: hand-overs they answered and calls they dialled from the Workspace.
idsstring, or nullComma-separated call ids (at most 500): the rows someone selected.
desk_idstring (uuid), or nullCalls attributed to this desk: to or from one of its numbers, or handed over through an 'A desk' step and taken by someone on it.
channelone of: phone, web, or nullWhat carried the call: phone (a phone line) or web (in a browser). With direction=inbound, web is the website widget's calls.
hide_testbooleanLeave out test calls (the default, as on Home and Analytics). initiator=test shows them regardless. Default: true.
scoredone of: yes, no, or nullWhether the call has a score (Call Scoring's coverage).
qaone of: graded, not_graded, pass, review, fail, disputed, or nullCall QA: graded, not_graded, or by the call's QA band (the worst of its grades: pass, review, fail), or disputed (a grade with an open dispute).
modeone of: ai, power, or nullCampaign mode: power (calls a power-dialer campaign placed for your staff) or ai (every other call).
insightsone of: none, read, or nullConversation insights: none (connected, 15 seconds or longer, with a transcript, not read yet: what Intelligence counts as unread) or read.
call_classone of: ai, human, hybrid, or nullWho worked the call: ai (the AI alone), human (people only) or hybrid (the AI, then a person who came on).
Answer (200): these fields
FieldTypeWhat it is
totalrequiredinteger—
pagerequiredinteger—
page_sizerequiredinteger—
itemsrequiredlist of objects—
items[].idrequiredstring (uuid)—
items[].directionstring, or nullinbound or outbound.
items[].initiatorstring, or nullWhat started the call: manual, campaign, web, inbound, workflow, workspace, test, api or callback. Null on older calls.
items[].statusstring, or null—
items[].started_atstring (date-time), or null—
items[].duration_secinteger, or null—
items[].billed_minutesnumber, or null—
items[].classificationstring, or nullLead classification: hot, warm or cold.
items[].dispositionstring, or nullThe call's outcome key.
items[].scorenumber, or nullLead score, 0 to 100.
items[].sentimentstring, or null—
items[].summarystring, or null—
items[].costnumber, or nullWhat the call cost in all, in rupees.
items[].languages_usedlist of string, or null—
items[].agent_idstring (uuid), or null—
items[].agent_namestring, or null—
items[].team_idstring (uuid), or null—
items[].team_namestring, or null—
items[].answered_bystring, or nullThe name of the agent, team or person who took the call.
items[].placed_bystring, or nullThe person who placed the call, when a person did.
items[].campaign_idstring (uuid), or null—
items[].campaign_namestring, or null—
items[].contact_idstring (uuid), or nullNull when there is no contact, or it was deleted.
items[].contact_deletedbooleanDefault: false.
items[].contact_namestring, or null—
items[].contact_phonestring, or null—
items[].didstring, or nullYour own number on the call.
items[].has_recordingbooleanDefault: false.
items[].recording_urlstring, or nullA link to play the recording. It expires: fetch it when you need it.
items[].missedbooleanNobody spoke to the customer: not answered, a machine, or a failed attempt. Default: false.
items[].disposed_bystring, or nullWho set the outcome.
items[].callback_requestedbooleanDefault: false.
items[].callback_timestring, or null—
items[].handoverstring, or nullHanded to a person: answered, missed or not_rung; null if never.
items[].qaobject, or nullThe call's quality grade; null when it was never graded.
statsrequiredobject—
stats.totalrequiredintegerCalls matching the filters, across every page.
stats.completedrequiredintegerOf those, calls someone picked up.
stats.talk_minutesrequiredinteger—
stats.total_costnumber, or nullWhat those calls cost in all, in rupees.
Errors
CodeWhen
401The token is missing, unknown or revoked, or its workspace was deleted.
402The workspace's plan does not include API access. The token is paused, not revoked: it works again as soon as the plan includes API access.
403The token does not have this endpoint's scope, it is a sandbox token, the workspace is suspended, or the request came from a network the workspace does not allow.
422A field is missing or not in the form this endpoint takes. detail says which, and why.
429This token has made more than 60 requests a minute. The Retry-After header says how many seconds to wait.
GET /api/analytics/calls with curl
curl "https://aicallstudio.com/api/analytics/calls?page_size=50&days=30" \
  -H "Authorization: Bearer mtc_YOUR_TOKEN"

Place a call

POST/api/calls/dialScope calls:write

Ring one number now, with an AI agent or team speaking. A real call, billed like any other.

Send phone (a 10-digit Indian mobile) or contact_id, and exactly one of agent_id or team_id. The same checks as any outbound call apply first: the plan, Do-Not-Call, the agent's calling hours and the calls-at-once limits. The answer means ringing has started, not that anyone picked up: the outcome arrives with the call.completed webhook and in the call log.

Request body (application/json)
FieldTypeWhat it is
phonestring, or nullA 10-digit Indian mobile number starting with 6 to 9, without +91. Send this or contact_id.
contact_idstring (uuid), or nullA contact to call, by id: the contact's own number is rung.
agent_idstring (uuid), or nullThe AI agent that speaks. Send this or team_id, not both.
team_idstring (uuid), or nullThe AI team that speaks. Send this or agent_id, not both.
Answer (200): these fields
FieldTypeWhat it is
statusrequiredstringAlways dialing: the number is being rung.
phonerequiredstringThe number rung, with +91.
answererrequiredstringThe name of the agent or team that will speak.
roomrequiredstringAn id for this call attempt.
Errors
CodeWhen
401The token is missing, unknown or revoked, or its workspace was deleted.
402The workspace's plan does not include API access. The token is paused, not revoked: it works again as soon as the plan includes API access. The plan has no calls left, or does not include this voice tier.
403The token does not have this endpoint's scope, it is a sandbox token, the workspace is suspended, or the request came from a network the workspace does not allow. The number cannot be called: on a Do-Not-Call or Do-Not-Disturb list, no consent, or outside the workspace's calling window.
404The agent, team or contact was not found, or is switched off.
409The call cannot start now: the plan's calls-at-once limit, the agent's own limit, the agent's calling hours, a draft or paused agent, or no phone line to call from.
422A field is missing or not in the form this endpoint takes. detail says which, and why.
429This token has made more than 60 requests a minute. The Retry-After header says how many seconds to wait.
502The call could not be started. Nothing was rung; try again.
503Calling is halted for a moment by the platform.
POST /api/calls/dial with curl
curl -X POST "https://aicallstudio.com/api/calls/dial" \
  -H "Authorization: Bearer mtc_YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"phone":"9876543210","agent_id":"YOUR_AGENT_ID"}'

Analytics

Calls by classification

GET/api/analytics/classification-breakdownScope analytics:read

Calls counted by lead classification (hot, warm, cold, unclassified), most common first.

By default the last 30 days; date_from and date_to (IST calendar days) pick a range instead.

Query parameters
ParameterTypeWhat it is
daysinteger, 1 to 365The last this many days, 1 to 365. date_from overrides it. Default: 30.
date_fromstring (date), or nullIST calendar day, YYYY-MM-DD. Beats days.
date_tostring (date), or nullIST calendar day, inclusive (default today).
agent_idstring (uuid), or nullOnly calls this AI agent answered.
team_idstring (uuid), or nullOnly calls this AI team answered.
modeone of: ai, power, or nullCampaign mode: power or ai.
desk_idstring (uuid), or nullCalls attributed to this desk: to or from one of its numbers, or handed over through an 'A desk' step and taken by someone on it.
staff_userstring (uuid), or nullOne team member's calls, as Call Logs' Person filter counts them: hand-overs they answered, calls they dialled from the Workspace, and calls passed or put through to them.
campaign_idstring (uuid), or nullCalls this campaign placed.
directionone of: inbound, outbound, or nullCalls in or out. A web call is inbound, as on Call Logs.
Answer (200): a list, each item with these fields
FieldTypeWhat it is
classificationrequiredstringhot, warm, cold, or unclassified.
countrequiredinteger—
Errors
CodeWhen
401The token is missing, unknown or revoked, or its workspace was deleted.
402The workspace's plan does not include API access. The token is paused, not revoked: it works again as soon as the plan includes API access.
403The token does not have this endpoint's scope, it is a sandbox token, the workspace is suspended, or the request came from a network the workspace does not allow.
422A field is missing or not in the form this endpoint takes. detail says which, and why.
429This token has made more than 60 requests a minute. The Retry-After header says how many seconds to wait.
GET /api/analytics/classification-breakdown with curl
curl "https://aicallstudio.com/api/analytics/classification-breakdown?days=30" \
  -H "Authorization: Bearer mtc_YOUR_TOKEN"

Calls by outcome

GET/api/analytics/disposition-breakdownScope analytics:read

Calls counted by outcome, most common first, each with its name in your workspace.

By default the last 30 days; date_from and date_to (IST calendar days) pick a range instead.

Query parameters
ParameterTypeWhat it is
daysinteger, 1 to 365The last this many days, 1 to 365. date_from overrides it. Default: 30.
date_fromstring (date), or nullIST calendar day, YYYY-MM-DD. Beats days.
date_tostring (date), or nullIST calendar day, inclusive (default today).
agent_idstring (uuid), or nullOnly calls this AI agent answered.
team_idstring (uuid), or nullOnly calls this AI team answered.
modeone of: ai, power, or nullCampaign mode: power or ai.
desk_idstring (uuid), or nullCalls attributed to this desk: to or from one of its numbers, or handed over through an 'A desk' step and taken by someone on it.
staff_userstring (uuid), or nullOne team member's calls, as Call Logs' Person filter counts them: hand-overs they answered, calls they dialled from the Workspace, and calls passed or put through to them.
campaign_idstring (uuid), or nullCalls this campaign placed.
directionone of: inbound, outbound, or nullCalls in or out. A web call is inbound, as on Call Logs.
Answer (200): a list, each item with these fields
FieldTypeWhat it is
dispositionrequiredstringThe outcome key, or unknown for calls with none.
labelrequiredstringThe outcome's name in your workspace.
groupstring, or nullThe group the outcome belongs to.
countrequiredinteger—
Errors
CodeWhen
401The token is missing, unknown or revoked, or its workspace was deleted.
402The workspace's plan does not include API access. The token is paused, not revoked: it works again as soon as the plan includes API access.
403The token does not have this endpoint's scope, it is a sandbox token, the workspace is suspended, or the request came from a network the workspace does not allow.
422A field is missing or not in the form this endpoint takes. detail says which, and why.
429This token has made more than 60 requests a minute. The Retry-After header says how many seconds to wait.
GET /api/analytics/disposition-breakdown with curl
curl "https://aicallstudio.com/api/analytics/disposition-breakdown?days=30" \
  -H "Authorization: Bearer mtc_YOUR_TOKEN"

Call summary

GET/api/analytics/summaryScope analytics:read

Call totals for the last days days: calls, connected calls, minutes, duration and score.

A connected call is one someone picked up; an answering machine does not count.

Query parameters
ParameterTypeWhat it is
daysinteger, 1 to 365The period: the last this many days, 1 to 365. Default: 30.
agent_idstring (uuid), or nullOnly calls this AI agent answered.
team_idstring (uuid), or nullOnly calls this AI team answered.
modeone of: ai, power, or nullCampaign mode: power or ai.
campaign_onlybooleanCount only calls a campaign placed. Default: false.
Answer (200): these fields
FieldTypeWhat it is
period_daysrequiredintegerThe period counted: the last days days.
total_callsrequiredinteger—
completed_callsrequiredintegerCalls someone picked up. The same number as connected_calls.
connected_callsrequiredintegerCalls someone picked up. An answering machine does not count.
completion_raterequirednumberConnected calls as a percentage of all calls, to one decimal place.
total_billed_minutesnumber, or nullMinutes billed for these calls.
avg_duration_secrequirednumber—
avg_qa_scorenumber, or nullAverage lead score of the scored calls; null when none was scored.
Errors
CodeWhen
401The token is missing, unknown or revoked, or its workspace was deleted.
402The workspace's plan does not include API access. The token is paused, not revoked: it works again as soon as the plan includes API access.
403The token does not have this endpoint's scope, it is a sandbox token, the workspace is suspended, or the request came from a network the workspace does not allow.
422A field is missing or not in the form this endpoint takes. detail says which, and why.
429This token has made more than 60 requests a minute. The Retry-After header says how many seconds to wait.
GET /api/analytics/summary with curl
curl "https://aicallstudio.com/api/analytics/summary?days=30" \
  -H "Authorization: Bearer mtc_YOUR_TOKEN"

Webhooks

Instead of asking for changes, give a URL under Settings, Developers and pick the events it should receive. Each event is a POST of JSON to that URL, signed with the webhook's own signing secret (it starts with whsec_ and is shown once, when the webhook is made or its secret is changed).

Events
EventWhen it is sent
call.completedCall completed. After every call, with transcript and score.
call.wrapped_upOutcome updated. When a person saves their outcome after Call completed went: an update of that call.
campaign.status_changedCampaign status. When a campaign starts, finishes or is cancelled.
testOnly when you press Send test event on the Developers page.

The body is always { "event", "data", "ts", "id" }: the event's name, its data, the time it happened (Unix seconds) and the delivery's id. Each request also carries these headers:

  • X-Aicallstudio-Signature: sha256= and the hex HMAC-SHA256 of the raw body, keyed with your signing secret.
  • X-Aicallstudio-Event: the event's name.
  • X-Aicallstudio-Delivery: one id per event, the same on every retry. Keep the ids you have handled and ignore a repeat.
call.completed, an example
{
  "event": "call.completed",
  "ts": 1772633868,
  "id": "4f1c2b9e8d7a4e3f9b6a5c4d3e2f1a0b",
  "data": {
    "call": {
      "id": "uuid",
      "status": "completed",
      "duration_seconds": 142,
      "direction": "outbound",
      "disposition": "ptp",
      "disposition_label": "Promise to pay",
      "classification": "hot",
      "score": 82,
      "summary": "Contact expressed strong interest.",
      "contact_id": "uuid",
      "campaign_id": null,
      "transcript": "Agent: Hi...\nLead: Yes I'm interested...\nStaff: Hello, this is Priya...",
      "transcript_turns": [
        { "speaker": "agent", "text": "Hi..." },
        { "speaker": "lead", "text": "Yes I'm interested..." },
        { "speaker": "staff", "name": "Priya", "text": "Hello, this is Priya..." }
      ],
      "placed_by": { "kind": "ai_agent", "id": "uuid", "name": "Collections desk" },
      "cost_inr": 4.75
    }
  }
}
call.wrapped_up, an example
{
  "event": "call.wrapped_up",
  "ts": 1772634211,
  "id": "9a8b7c6d5e4f43a2b1c0d9e8f7a6b5c4",
  "data": {
    "call": {
      "id": "uuid",
      "contact_id": "uuid",
      "disposition": "callback",
      "disposition_label": "Callback requested",
      "disposition_by": "staff",
      "previous_disposition": "interested",
      "wrap_up": {
        "disposition": "callback",
        "note": "Call after 6 pm",
        "fields": {},
        "callback": { "at": "2026-11-14T18:00:00+05:30" },
        "by_name": "Priya"
      }
    }
  }
}
campaign.status_changed, an example
{
  "event": "campaign.status_changed",
  "ts": 1772634500,
  "id": "1b2c3d4e5f6a47b8c9d0e1f2a3b4c5d6",
  "data": { "campaign_id": "uuid", "status": "running" }
}

Check the signature

Work out the signature from the raw body before parsing it, and refuse any request where it does not match.

Node.js
import crypto from "node:crypto";

// rawBody: the request body exactly as received (a Buffer), before any JSON parsing.
function isFromAiCallStudio(rawBody, signatureHeader, secret) {
  const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(expected), b = Buffer.from(signatureHeader || "");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

// isFromAiCallStudio(req.rawBody, req.get("X-Aicallstudio-Signature"), process.env.WEBHOOK_SECRET)
Python
import hashlib, hmac

def is_from_ai_call_studio(raw_body: bytes, signature_header: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature_header or "")

# is_from_ai_call_studio(request.body, request.headers["X-Aicallstudio-Signature"], WEBHOOK_SECRET)

Answers, retries and pausing

Answer with any 2xx within 10 seconds. Anything else, or no answer, is retried up to 5 times, after 1, 2, 4, 8, 16 minutes. After 50 failed deliveries in a row the webhook is paused and your workspace is told; nothing is sent until you resume it, and events in between are skipped, not sent later.

Costs and what to watch

  • Place a call rings a real person and is billed like any call, at your plan's rates.
  • Adding or importing contacts starts your New Contact workflows, as adding them by hand does, and those may call or message the person.
  • A token acts as the workspace, with everyone's data in reach of its scopes. Give each system its own token with only the scopes it needs, and revoke one you no longer use.

Put AI Call Studio on your phone lines.

Book a 30-minute walkthrough, or call us right now: +91 922 222 1378