Browse the docs

API reference

Calls

Every call of the account, inbound, outbound or from a browser, with its outcome flags, summary, transcript, recording and estimated cost.

List calls

GET/v1/calls
Bearer API key

List all calls for the authenticated tenant with pagination, most recently started first. Filter by campaignId to list the calls of a given campaign, by customerPhoneNumber to list the calls exchanged with a given customer, or by outcome (endedReason, minDuration, isReached, isSignificant, isSuccessful, isSilent) to classify results.

Authorization

Authorizationstringrequired

Bearer <API key>, a key created at app.callshift.ai/api-keys.

Query parameters

pageinteger
minimum 1default 1example 1
limitinteger
from 1 to 100default 50example 50
agentIdstring<uuid>
example 550e8400-e29b-41d4-a716-446655440000
campaignIdstring<uuid>
example 550e8400-e29b-41d4-a716-446655440000
customerPhoneNumberstring

Customer phone number in international format. Returns the calls placed to (outbound) or received from (inbound) that number.

example +33612345678
statusenum<string>
example COMPLETED
AllowedCOMPLETEDERRORFORWARDEDIN_PROGRESSREADYREJECTEDSCHEDULED
typeenum<string>
example inbound
Allowedinboundoutboundwebcall
fromstring<date-time>
example 2024-01-01T00:00:00Z
tostring<date-time>
example 2024-12-31T23:59:59Z
endedReasonstring

Exact match on endedReason.

example voicemail
minDurationinteger | null

Only calls with billingSeconds greater than or equal to this value.

minimum 0example 30
isReachedenum<string>
example true
Allowedtruefalse
isSignificantenum<string>
example true
Allowedtruefalse
isSuccessfulenum<string>
example true
Allowedtruefalse
isSilentenum<string>
example true
Allowedtruefalse

Responses

Calls listed successfully

dataobject[]required
Show child attributes
idstring<uuid>required
example 550e8400-e29b-41d4-a716-446655440000
agentIdstring<uuid> | nullrequired
agentNamestring | nullrequired
customerPhoneNumberstring | nullrequired
statusenum<string>required
example COMPLETED
AllowedCOMPLETEDERRORFORWARDEDIN_PROGRESSREADYREJECTEDSCHEDULED
typeenum<string>required
example inbound
Allowedinboundoutboundwebcall
startedAtstring<date-time> | nullrequired
endedAtstring<date-time> | nullrequired
endedReasonstring | nullrequired

Why the call ended. Known values: agent-line-entity-mismatch, contact-opted-out, cps-limit-exceeded, dial-failed, stuck-in-progress, twilio-call-permission, customer-busy, customer-declined, customer-did-not-answer, customer-number-not-found, customer-unavailable, exceeded-max-duration, max-duration-exceeded, no-international-permission, outbound-call-forbidden, sip-server-error, unknown-reason, voicemail. The value is passed through from the voice provider, so new values can appear; treat unknown values as a generic failure rather than rejecting them.

example customer-did-not-answer
createdAtstring<date-time>required
billingSecondsnumber | nullrequired

Billable duration in seconds, rounded up from the connected time. costEstimationCents prices it at the overage rate of your plan.

example 84
costEstimationCentsinteger | nullrequired

Indicative cost of the call in euro cents, rounded to the nearest cent. Not a contractual amount: use it to compare calls and forecast spend, and the billing page for what was actually charged.

It adds up:

  • billingSeconds at your plan's per-minute overage rate (rounded up to a full minute first on minute-based plans);
  • the dial fee, on a campaign dial, whatever its outcome.

It ignores the minutes included in your plan: a call they cover is not charged its minutes, but still shows their price here. A dial fee below a cent can round to 0 on a single call.

Null until the call has a billingSeconds, and when your account has no subscription with an overage rate.

example 70
recordingUrlstring | nullrequired

Direct, non-expiring URL of the call recording. No authentication is required beyond the URL itself. Null while the call is in progress or when no recording was produced.

example https://recordings.example.com/recordings/<callId>/<recordingId>.ogg
summarystring | nullrequired
isSilentboolean | nullrequired
isSuccessfulboolean | nullrequired
isReachedboolean | nullrequired
isSignificantboolean | nullrequired
phoneobject | nullrequired

Agent phone line used for the call. Matches the phone field of the call-ended webhook payload.

Show child attributes
idstring<uuid>required
example 550e8400-e29b-41d4-a716-446655440000
numberstring | nullrequired
example +33612345678
fromstring | nullrequired

Number the call originated from: the agent phone for outbound calls, the caller for inbound calls.

example +33612345678
tostring | nullrequired

Number the call was placed to: the customer for outbound calls, the agent phone for inbound calls.

example +33687654321
qualificationCriteriaobject | nullrequired

Information collected during the call, as configured in the agent's call analysis settings. Matches the qualificationCriteria field of the call-ended webhook payload.

pageCountnumberrequired
example 3

Invalid query parameters

successenum<boolean>required
Allowedfalse
errorobjectrequired
Show child attributes
nameenum<string>required
AllowedZodError
issuesobject[]required
Show child attributes
codestringrequired
example invalid_enum_value
pathstring | number[]required
messagestringrequired
example Invalid email

Unauthorized

errorstringrequired

Internal server error

errorstringrequired
GET
curl "https://api.callshift.ai/v1/calls?campaignId=550e8400-e29b-41d4-a716-446655440000&isReached=true&limit=50" \
  -H "Authorization: Bearer $CALLSHIFT_API_KEY"
const res = await fetch("https://api.callshift.ai/v1/calls?campaignId=550e8400-e29b-41d4-a716-446655440000&isReached=true&limit=50", {
  headers: {
    Authorization: `Bearer ${process.env.CALLSHIFT_API_KEY}`,
  },
});
const data = await res.json();
import os
import requests

res = requests.get(
    "https://api.callshift.ai/v1/calls?campaignId=550e8400-e29b-41d4-a716-446655440000&isReached=true&limit=50",
    headers={"Authorization": f"Bearer {os.environ['CALLSHIFT_API_KEY']}"},
)
print(res.json())
Response
{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "agentId": "550e8400-e29b-41d4-a716-446655440000",
      "agentName": "Alice",
      "customerPhoneNumber": "+33612345678",
      "status": "COMPLETED",
      "type": "inbound",
      "startedAt": "2026-10-30T09:12:00.000Z",
      "endedAt": "2026-10-30T09:12:00.000Z",
      "endedReason": "customer-did-not-answer",
      "createdAt": "2026-10-30T09:12:00.000Z",
      "billingSeconds": 84,
      "costEstimationCents": 70,
      "recordingUrl": "https://recordings.example.com/recordings/<callId>/<recordingId>.ogg",
      "summary": "Ada booked a visit for Saturday at 10am and asked for a confirmation SMS.",
      "isSilent": true,
      "isSuccessful": true,
      "isReached": true,
      "isSignificant": true,
      "phone": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "number": "+33612345678"
      },
      "from": "+33612345678",
      "to": "+33687654321",
      "qualificationCriteria": {
        "budget": "500k",
        "isDecisionMaker": true
      }
    }
  ],
  "pageCount": 3
}
{
  "success": false,
  "error": {
    "name": "ZodError",
    "issues": [
      {
        "code": "invalid_enum_value",
        "path": [
          "contacts",
          0,
          "email"
        ],
        "message": "Invalid email"
      }
    ]
  }
}
{
  "error": "Authentication error"
}
{
  "error": "Internal server error"
}

Get call details

GET/v1/calls/{callId}
Bearer API key

Retrieve detailed information about a specific call by ID.

Authorization

Authorizationstringrequired

Bearer <API key>, a key created at app.callshift.ai/api-keys.

Path parameters

callIdstring<uuid>required
example 550e8400-e29b-41d4-a716-446655440000

Responses

Call details retrieved successfully

idstring<uuid>required
example 550e8400-e29b-41d4-a716-446655440000
agentIdstring<uuid> | nullrequired
agentNamestring | nullrequired
campaignIdstring<uuid> | nullrequired
customerPhoneNumberstring | nullrequired
endedReasonstring | nullrequired

Why the call ended. Known values: agent-line-entity-mismatch, contact-opted-out, cps-limit-exceeded, dial-failed, stuck-in-progress, twilio-call-permission, customer-busy, customer-declined, customer-did-not-answer, customer-number-not-found, customer-unavailable, exceeded-max-duration, max-duration-exceeded, no-international-permission, outbound-call-forbidden, sip-server-error, unknown-reason, voicemail. The value is passed through from the voice provider, so new values can appear; treat unknown values as a generic failure rather than rejecting them.

example customer-did-not-answer
phoneIdstring<uuid> | nullrequired
phoneobject | nullrequired

Agent phone line used for the call. Matches the phone field of the call-ended webhook payload.

Show child attributes
idstring<uuid>required
example 550e8400-e29b-41d4-a716-446655440000
numberstring | nullrequired
example +33612345678
fromstring | nullrequired

Number the call originated from: the agent phone for outbound calls, the caller for inbound calls.

example +33612345678
tostring | nullrequired

Number the call was placed to: the customer for outbound calls, the agent phone for inbound calls.

example +33687654321
recordingUrlstring | nullrequired

Direct, non-expiring URL of the call recording. No authentication is required beyond the URL itself. Null while the call is in progress or when no recording was produced.

example https://recordings.example.com/recordings/<callId>/<recordingId>.ogg
summarystring | nullrequired
transcriptstring | nullrequired

Plain-text transcript, one line per turn prefixed by the speaker role. Not yet structured (no per-turn timestamps).

example User: Hello Assistant: Hi, how can I help?
isSilentboolean | nullrequired
isSuccessfulboolean | nullrequired
isReachedboolean | nullrequired
isSignificantboolean | nullrequired
qualificationCriteriaobject | nullrequired

Information collected during the call, as configured in the agent's call analysis settings. Matches the qualificationCriteria field of the call-ended webhook payload.

createdAtstring<date-time>required
billingSecondsnumber | nullrequired

Billable duration in seconds, rounded up from the connected time. costEstimationCents prices it at the overage rate of your plan.

example 84
costEstimationCentsinteger | nullrequired

Indicative cost of the call in euro cents, rounded to the nearest cent. Not a contractual amount: use it to compare calls and forecast spend, and the billing page for what was actually charged.

It adds up:

  • billingSeconds at your plan's per-minute overage rate (rounded up to a full minute first on minute-based plans);
  • the dial fee, on a campaign dial, whatever its outcome.

It ignores the minutes included in your plan: a call they cover is not charged its minutes, but still shows their price here. A dial fee below a cent can round to 0 on a single call.

Null until the call has a billingSeconds, and when your account has no subscription with an overage rate.

example 70
endedAtstring<date-time> | nullrequired
startedAtstring<date-time> | nullrequired
statusenum<string>required
example COMPLETED
AllowedCOMPLETEDERRORFORWARDEDIN_PROGRESSREADYREJECTEDSCHEDULED
typeenum<string>required
example inbound
Allowedinboundoutboundwebcall

Unauthorized

errorstringrequired

Call not found

errorstringrequired

Internal server error

errorstringrequired
GET
curl "https://api.callshift.ai/v1/calls/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer $CALLSHIFT_API_KEY"
const res = await fetch("https://api.callshift.ai/v1/calls/550e8400-e29b-41d4-a716-446655440000", {
  headers: {
    Authorization: `Bearer ${process.env.CALLSHIFT_API_KEY}`,
  },
});
const data = await res.json();
import os
import requests

res = requests.get(
    "https://api.callshift.ai/v1/calls/550e8400-e29b-41d4-a716-446655440000",
    headers={"Authorization": f"Bearer {os.environ['CALLSHIFT_API_KEY']}"},
)
print(res.json())
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "agentId": "550e8400-e29b-41d4-a716-446655440000",
  "agentName": "Alice",
  "campaignId": "550e8400-e29b-41d4-a716-446655440000",
  "customerPhoneNumber": "+33612345678",
  "endedReason": "customer-did-not-answer",
  "phoneId": "550e8400-e29b-41d4-a716-446655440000",
  "phone": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "number": "+33612345678"
  },
  "from": "+33612345678",
  "to": "+33687654321",
  "recordingUrl": "https://recordings.example.com/recordings/<callId>/<recordingId>.ogg",
  "summary": "Ada booked a visit for Saturday at 10am and asked for a confirmation SMS.",
  "transcript": "User: Hello\nAssistant: Hi, how can I help?",
  "isSilent": true,
  "isSuccessful": true,
  "isReached": true,
  "isSignificant": true,
  "qualificationCriteria": {
    "budget": "500k",
    "isDecisionMaker": true
  },
  "createdAt": "2026-10-30T09:12:00.000Z",
  "billingSeconds": 84,
  "costEstimationCents": 70,
  "endedAt": "2026-10-30T09:12:00.000Z",
  "startedAt": "2026-10-30T09:12:00.000Z",
  "status": "COMPLETED",
  "type": "inbound"
}
{
  "error": "Authentication error"
}
{
  "error": "Call not found"
}
{
  "error": "Internal server error"
}