Skip to content

Apeluri ​

16 endpoint-uri. Fiecare cale de mai jos este relativă la URL-ul de bază al API-ului și include deja prefixul /api/v1 — vezi convențiile pentru autentificare, paginare, erori și idempotență.

Endpoint
GET/callsList the organization's calls with filter, sort and pagination, returning a summary row per call plus page meta
POST/callsPlace an assistant-driven outbound call and return the created call detail, idempotent on a repeated key
GET/calls/{call}Fetch one call in full, including legs, recording state, metadata, variables and analysis fields
DELETE/calls/{call}Delete a call record and return the deleted id
GET/calls/{call}/artifactsList the stored artifacts for a call with type, status, size, checksum and purge state
GET/calls/{call}/artifacts/{artifact}/downloadSigned fallback download used when the storage driver cannot sign a URL itself
GET/calls/{call}/costsBreak a call's cost down by component and provider, alongside the per-category totals stored on the call
GET/calls/{call}/debugExport a sanitized diagnostic bundle for a call with the assistant snapshot, legs, events, metrics and costs
POST/calls/{call}/endEnd an in-progress call through the state machine and return the resulting call summary
GET/calls/{call}/eventsList a call's lifecycle events, optionally filtered by type or restricted to errors
GET/calls/{call}/messagesList the conversation turns of a call with role, timing, tool calls and transcription confidence
GET/calls/{call}/metricsList a call's per-turn latency metrics alongside the aggregate STT, LLM, TTS and end-to-end summary
GET/calls/{call}/recordingReturn a short-lived signed URL for a call's best available recording plus its duration, channels and MIME type
DELETE/calls/{call}/recordingPurge a call's audio artifacts, leaving the artifact rows as evidence they existed
GET/calls/{call}/transcriptReturn a call's full transcript text with flags saying whether it was redacted or purged
GET/calls/searchSearch calls using the same filters, sorting and pagination as GET /calls

Endpoint-uri ​

List the organization's calls with filter, sort and pagination, returning a summary row per call plus page meta ​

GET/calls
  • Necesită call.read.
  • Only whitelisted filters are read; unknown query params and unknown sort columns are ignored silently rather than rejected
bash
curl -X GET "$CALLAGENT_API_URL/calls" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/calls`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/calls');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.get(
    f"{os.environ['CALLAGENT_API_URL']}/calls",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Răspunsuri

StatusCorp
200data-wrapped array

Erori

StatusCând apare
403The key or user lacks the call.read scope

Exemplu de răspuns, generat din schemă:

json
{
  "data": [
    {
      "id": null,
      "status": "string",
      "direction": "string",
      "transport": "string",
      "from": "+40712345678",
      "to": "+40712345678",
      "assistant_id": "01JQ0000000000000000000000",
      "customer_id": "01JQ0000000000000000000000",
      "queue_id": "01JQ0000000000000000000000",
      "operator_id": "01JQ0000000000000000000000",
      "provider": "string",
      "started_at": "2026-01-01T12:00:00+00:00",
      "connected_at": "2026-01-01T12:00:00+00:00",
      "ended_at": "2026-01-01T12:00:00+00:00",
      "duration_seconds": 30,
      "billable_seconds": 30,
      "ended_reason": "string",
      "cost_total": "string",
      "cost_currency": "string",
      "latency": {},
      "created_at": "2026-01-01T12:00:00+00:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "per_page": 25,
    "total": 1,
    "last_page": 1
  }
}

Place an assistant-driven outbound call and return the created call detail, idempotent on a repeated key ​

POST/calls
  • Necesită call.create.
  • Acceptă un header Idempotency-Key; reluarea unei chei returnează rezultatul inițial în loc să execute de două ori.
  • A carrier or policy refusal is NOT an error status: the response is still 201 with status/ended_reason showing the failure

Corpul cererii

CâmpTipObligatoriuNote
tostringdamax 128 chars
fromstring | null—max 128 chars
assistant_idstring | null—
assistant_version_idstring | null—
assistant_overridesstring[] | null—
squad_idstring | null—
phone_number_idstring | null—
sip_trunk_idstring | null—
customer_idstring | null—
campaign_idstring | null—
transportpstn · sip · web · mobile · null | null—
providerstring | null—max 32 chars
variablesstring[] | null—
metadatastring[] | null—
idempotency_keystring | null—max 128 chars
answering_machine_detectionboolean | null—Outbound-only. Omitted, both follow the assistant and the platform default: AMD is asked of the carrier when the assistant's voicemail plan wants a provider verdict, and the ring timeout comes from telephony.defaults.outbound_ring_timeout.
ring_timeout_secondsinteger | null—min 5. max 300
bash
curl -X POST "$CALLAGENT_API_URL/calls" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
       "to": "+40712345678",
       "from": "+40712345678",
       "assistant_id": "01JQ0000000000000000000000",
       "assistant_version_id": "01JQ0000000000000000000000",
       "squad_id": "01JQ0000000000000000000000",
       "phone_number_id": "01JQ0000000000000000000000",
       "sip_trunk_id": "01JQ0000000000000000000000"
     }'
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/calls`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "to": "+40712345678",
    "from": "+40712345678",
    "assistant_id": "01JQ0000000000000000000000",
    "assistant_version_id": "01JQ0000000000000000000000",
    "squad_id": "01JQ0000000000000000000000",
    "phone_number_id": "01JQ0000000000000000000000",
    "sip_trunk_id": "01JQ0000000000000000000000"
  }),
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/calls');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
    'to' => '+40712345678',
    'from' => '+40712345678',
    'assistant_id' => '01JQ0000000000000000000000',
    'assistant_version_id' => '01JQ0000000000000000000000',
    'squad_id' => '01JQ0000000000000000000000',
    'phone_number_id' => '01JQ0000000000000000000000',
    'sip_trunk_id' => '01JQ0000000000000000000000',
]),
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.post(
    f"{os.environ['CALLAGENT_API_URL']}/calls",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    json={
      "to": "+40712345678",
      "from": "+40712345678",
      "assistant_id": "01JQ0000000000000000000000",
      "assistant_version_id": "01JQ0000000000000000000000",
      "squad_id": "01JQ0000000000000000000000",
      "phone_number_id": "01JQ0000000000000000000000",
      "sip_trunk_id": "01JQ0000000000000000000000"
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Răspunsuri

StatusCorp
201data-wrapped object

Erori

StatusCând apare
403Missing call.create scope, or the API key is restricted to other assistants
422The payload failed validation (to is required; ids must be ULIDs)

Exemplu de răspuns, generat din schemă:

json
{
  "data": {}
}

Fetch one call in full, including legs, recording state, metadata, variables and analysis fields ​

GET/calls/{call}
  • Necesită call.read.

Parametri de cale

NumeTipObligatoriuNote
callstringda
bash
curl -X GET "$CALLAGENT_API_URL/calls/01JQ0000000000000000000000" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/calls/01JQ0000000000000000000000`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/calls/01JQ0000000000000000000000');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.get(
    f"{os.environ['CALLAGENT_API_URL']}/calls/01JQ0000000000000000000000",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Răspunsuri

StatusCorp
200data-wrapped object

Erori

StatusCând apare
403The key or user lacks the call.read scope
404No call with that id in this organization

Exemplu de răspuns, generat din schemă:

json
{
  "data": {}
}

Delete a call record and return the deleted id ​

DELETE/calls/{call}
  • Necesită call.delete.
  • Acest răspuns nu este împachetat în data.
  • Body is a bare {"deleted": true, "id": "..."} object, not the {"data": ...} envelope the rest of the calls API uses

Parametri de cale

NumeTipObligatoriuNote
callstringda
bash
curl -X DELETE "$CALLAGENT_API_URL/calls/01JQ0000000000000000000000" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/calls/01JQ0000000000000000000000`, {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/calls/01JQ0000000000000000000000');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.delete(
    f"{os.environ['CALLAGENT_API_URL']}/calls/01JQ0000000000000000000000",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Răspunsuri

StatusCorp
200Bare JSON object, not data-wrapped

Erori

StatusCând apare
403The key or user lacks the call.delete scope
404No call with that id in this organization

Exemplu de răspuns, generat din schemă:

json
{
  "deleted": true,
  "id": null
}

List the stored artifacts for a call with type, status, size, checksum and purge state ​

GET/calls/{call}/artifacts
  • Necesită call.read.
  • Returns metadata only; no download URL is included. Use GET /calls/{call}/recording or a signed download URL

Parametri de cale

NumeTipObligatoriuNote
callstringda
bash
curl -X GET "$CALLAGENT_API_URL/calls/01JQ0000000000000000000000/artifacts" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/calls/01JQ0000000000000000000000/artifacts`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/calls/01JQ0000000000000000000000/artifacts');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.get(
    f"{os.environ['CALLAGENT_API_URL']}/calls/01JQ0000000000000000000000/artifacts",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Răspunsuri

StatusCorp
200data-wrapped array

Erori

StatusCând apare
403The key or user lacks the call.read scope
404No call with that id in this organization

Exemplu de răspuns, generat din schemă:

json
{
  "data": [
    {
      "id": null,
      "type": "string",
      "status": "string",
      "mime_type": "string",
      "size_bytes": "string",
      "duration_seconds": "string",
      "checksum_sha256": "string",
      "channels": "string",
      "created_at": "2026-01-01T12:00:00+00:00",
      "purged_at": "2026-01-01T12:00:00+00:00"
    }
  ]
}

Signed fallback download used when the storage driver cannot sign a URL itself ​

GET/calls/{call}/artifacts/{artifact}/download
  • Handler-ul nu impune niciun scope — orice cheie validă îl poate apela.
  • Acest răspuns nu este împachetat în data.
  • Runs without api.key and tenant middleware and queries withoutGlobalScopes: the URL signature is the only authorization

Parametri de cale

NumeTipObligatoriuNote
callstringda
artifactstringda
bash
curl -X GET "$CALLAGENT_API_URL/calls/01JQ0000000000000000000000/artifacts/01JQ0000000000000000000000/download" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/calls/01JQ0000000000000000000000/artifacts/01JQ0000000000000000000000/download`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/calls/01JQ0000000000000000000000/artifacts/01JQ0000000000000000000000/download');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.get(
    f"{os.environ['CALLAGENT_API_URL']}/calls/01JQ0000000000000000000000/artifacts/01JQ0000000000000000000000/download",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Răspunsuri

StatusCorp
200Not JSON — text/html

Erori

StatusCând apare
403The URL signature is missing, altered or expired
404Unknown call or artifact, or the artifact is not readable

Break a call's cost down by component and provider, alongside the per-category totals stored on the call ​

GET/calls/{call}/costs
  • Necesită call.read.
  • The body carries a top-level summary key beside data; a client reading only data misses the totals

Parametri de cale

NumeTipObligatoriuNote
callstringda
bash
curl -X GET "$CALLAGENT_API_URL/calls/01JQ0000000000000000000000/costs" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/calls/01JQ0000000000000000000000/costs`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/calls/01JQ0000000000000000000000/costs');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.get(
    f"{os.environ['CALLAGENT_API_URL']}/calls/01JQ0000000000000000000000/costs",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Răspunsuri

StatusCorp
200data-wrapped array

Erori

StatusCând apare
403The key or user lacks the call.read scope
404No call with that id in this organization

Exemplu de răspuns, generat din schemă:

json
{
  "data": [
    {
      "component": "string",
      "provider": "string",
      "model": "string",
      "quantity": "string",
      "unit": "string",
      "unit_cost": "string",
      "cost": "string",
      "currency": "string",
      "billable": true
    }
  ],
  "summary": {
    "total": "string",
    "stt": "string",
    "llm": "string",
    "tts": "string",
    "telephony": "string",
    "other": "string",
    "currency": "string"
  }
}

Export a sanitized diagnostic bundle for a call with the assistant snapshot, legs, events, metrics and costs ​

GET/calls/{call}/debug
  • Necesită call.read.
  • Acest răspuns nu este împachetat în data.
  • Returns a bare object (exported_at, schema_version, notice, call, ...) with no data envelope, and sets Content-Disposition: attachment

Parametri de cale

NumeTipObligatoriuNote
callstringda
bash
curl -X GET "$CALLAGENT_API_URL/calls/01JQ0000000000000000000000/debug" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/calls/01JQ0000000000000000000000/debug`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/calls/01JQ0000000000000000000000/debug');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.get(
    f"{os.environ['CALLAGENT_API_URL']}/calls/01JQ0000000000000000000000/debug",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Răspunsuri

StatusCorp
200Bare JSON object, not data-wrapped

Erori

StatusCând apare
403The key or user lacks the call.read scope
404No call with that id in this organization

Exemplu de răspuns, generat din schemă:

json
{
  "exported_at": "2026-01-01T12:00:00+00:00",
  "schema_version": 1,
  "notice": "string",
  "call": {},
  "assistant_snapshot": {},
  "legs": [
    {
      "id": null,
      "type": "string",
      "direction": "string",
      "status": "string",
      "provider": "string",
      "provider_leg_id": "01JQ0000000000000000000000",
      "from_number": "+40712345678",
      "to_number": "+40712345678",
      "codec": "string",
      "sample_rate": "string",
      "started_at": "2026-01-01T12:00:00+00:00",
      "answered_at": "2026-01-01T12:00:00+00:00",
      "bridged_at": "2026-01-01T12:00:00+00:00",
      "ended_at": "2026-01-01T12:00:00+00:00",
      "ended_reason": "string",
      "quality": {}
    }
  ],
  "messages": [
    {}
  ],
  "events": [
    {}
  ],
  "metrics": [
    {
      "name": "Support Line",
      "component": "string",
      "turn_index": 1,
      "value_ms": 1,
      "value": 1,
      "unit": "string",
      "provider": "string",
      "model": "string",
      "offset_ms": 1,
      "started_at": "2026-01-01T12:00:00+00:00",
      "first_byte_at": "2026-01-01T12:00:00+00:00",
      "completed_at": "2026-01-01T12:00:00+00:00",
      "error_code": "string",
      "error_message": "string"
    }
  ],
  "costs": [
    {
      "component": "string",
      "provider": "string",
      "model": "string",
      "quantity": "string",
      "unit": "string",
      "cost": "string",
      "currency": "string"
    }
  ],
  "tools": [
    {}
  ],
  "mcp": [
    {}
  ],
  "provider_errors": [
    {}
  ],
  "artifacts": [
    {
      "id": null,
      "type": "string",
      "status": "string",
      "size_bytes": "string",
      "duration_seconds": "string",
      "checksum_sha256": "string",
      "stored": true
    }
  ]
}

End an in-progress call through the state machine and return the resulting call summary ​

POST/calls/{call}/end
  • Necesită call.end.
  • Optional reason body field; an unrecognised value silently falls back to api_request. An already-ended call returns 200 with a message key

Parametri de cale

NumeTipObligatoriuNote
callstringda
bash
curl -X POST "$CALLAGENT_API_URL/calls/01JQ0000000000000000000000/end" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/calls/01JQ0000000000000000000000/end`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/calls/01JQ0000000000000000000000/end');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.post(
    f"{os.environ['CALLAGENT_API_URL']}/calls/01JQ0000000000000000000000/end",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Răspunsuri

StatusCorp
200JSON object

Erori

StatusCând apare
403The key or user lacks the call.end scope
404No call with that id in this organization

Exemplu de răspuns, generat din schemă:

json
{
  "data": {
    "id": null,
    "status": "string",
    "direction": "string",
    "transport": "string",
    "from": "+40712345678",
    "to": "+40712345678",
    "assistant_id": "01JQ0000000000000000000000",
    "customer_id": "01JQ0000000000000000000000",
    "queue_id": "01JQ0000000000000000000000",
    "operator_id": "01JQ0000000000000000000000",
    "provider": "string",
    "started_at": "2026-01-01T12:00:00+00:00",
    "connected_at": "2026-01-01T12:00:00+00:00",
    "ended_at": "2026-01-01T12:00:00+00:00",
    "duration_seconds": 30,
    "billable_seconds": 30,
    "ended_reason": "string",
    "cost_total": "string",
    "cost_currency": "string",
    "latency": {
      "stt_ms": 1,
      "llm_ttft_ms": 1,
      "tts_ttfa_ms": 1,
      "e2e_ms": 1
    },
    "created_at": "2026-01-01T12:00:00+00:00"
  }
}

List a call's lifecycle events, optionally filtered by type or restricted to errors ​

GET/calls/{call}/events
  • Necesită call.read.
  • Query params: type (repeatable), errors_only, limit (default 2000, no upper bound enforced). Not paginated

Parametri de cale

NumeTipObligatoriuNote
callstringda
bash
curl -X GET "$CALLAGENT_API_URL/calls/01JQ0000000000000000000000/events" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/calls/01JQ0000000000000000000000/events`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/calls/01JQ0000000000000000000000/events');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.get(
    f"{os.environ['CALLAGENT_API_URL']}/calls/01JQ0000000000000000000000/events",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Răspunsuri

StatusCorp
200data-wrapped array

Erori

StatusCând apare
403The key or user lacks the call.read scope
404No call with that id in this organization

Exemplu de răspuns, generat din schemă:

json
{
  "data": [
    {
      "id": null,
      "type": "string",
      "category": "string",
      "severity": "string",
      "at": "2026-01-01T12:00:00+00:00",
      "offset_ms": "string",
      "sequence": "string",
      "leg_id": "01JQ0000000000000000000000",
      "generation_id": "01JQ0000000000000000000000",
      "payload": "string"
    }
  ]
}

List the conversation turns of a call with role, timing, tool calls and transcription confidence ​

GET/calls/{call}/messages
  • Necesită transcript.read.
  • Requires transcript.read, not call.read, and returns every message unpaginated

Parametri de cale

NumeTipObligatoriuNote
callstringda
bash
curl -X GET "$CALLAGENT_API_URL/calls/01JQ0000000000000000000000/messages" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/calls/01JQ0000000000000000000000/messages`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/calls/01JQ0000000000000000000000/messages');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.get(
    f"{os.environ['CALLAGENT_API_URL']}/calls/01JQ0000000000000000000000/messages",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Răspunsuri

StatusCorp
200data-wrapped array

Erori

StatusCând apare
403The key or user lacks the transcript.read scope
404No call with that id in this organization

Exemplu de răspuns, generat din schemă:

json
{
  "data": [
    {
      "id": null,
      "role": "string",
      "sequence": "string",
      "turn_index": "string",
      "offset_ms": "string",
      "duration_ms": "string",
      "content": "string",
      "tool_name": "Support Line",
      "tool_arguments": "string",
      "tool_result": "string",
      "interrupted": "string",
      "is_final": "string",
      "language": "string",
      "confidence": "string"
    }
  ]
}

List a call's per-turn latency metrics alongside the aggregate STT, LLM, TTS and end-to-end summary ​

GET/calls/{call}/metrics
  • Necesită call.read.
  • The body carries a top-level summary key beside data; a client reading only data misses the aggregate latencies

Parametri de cale

NumeTipObligatoriuNote
callstringda
bash
curl -X GET "$CALLAGENT_API_URL/calls/01JQ0000000000000000000000/metrics" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/calls/01JQ0000000000000000000000/metrics`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/calls/01JQ0000000000000000000000/metrics');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.get(
    f"{os.environ['CALLAGENT_API_URL']}/calls/01JQ0000000000000000000000/metrics",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Răspunsuri

StatusCorp
200data-wrapped array

Erori

StatusCând apare
403The key or user lacks the call.read scope
404No call with that id in this organization

Exemplu de răspuns, generat din schemă:

json
{
  "data": [
    {
      "name": "Support Line",
      "component": "string",
      "turn_index": 1,
      "value_ms": 1,
      "value": 1,
      "unit": "string",
      "provider": "string",
      "model": "string",
      "offset_ms": 1,
      "exceeds_target": true
    }
  ],
  "summary": {
    "stt_ms": 1,
    "llm_ttft_ms": 1,
    "tts_ttfa_ms": 1,
    "e2e_ms": 1,
    "e2e_max_ms": 1,
    "turns": 1,
    "interruptions": 1
  }
}

Return a short-lived signed URL for a call's best available recording plus its duration, channels and MIME type ​

GET/calls/{call}/recording
  • Necesită recording.read.
  • Picks one file by preference (recording_full, then stereo, then mono); URL lifetime is callagent.storage.signed_url_ttl_minutes, default 15

Parametri de cale

NumeTipObligatoriuNote
callstringda
bash
curl -X GET "$CALLAGENT_API_URL/calls/01JQ0000000000000000000000/recording" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/calls/01JQ0000000000000000000000/recording`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/calls/01JQ0000000000000000000000/recording');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.get(
    f"{os.environ['CALLAGENT_API_URL']}/calls/01JQ0000000000000000000000/recording",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Răspunsuri

StatusCorp
200data-wrapped object

Erori

StatusCând apare
403The key or user lacks the recording.read scope
404No such call, or the call has no ready recording artifact

Exemplu de răspuns, generat din schemă:

json
{
  "data": {
    "artifact_id": null,
    "type": "string",
    "url": "https://example.com/hook",
    "expires_at": "2026-01-01T12:00:00+00:00",
    "duration_seconds": 30,
    "channels": 1,
    "mime_type": "string"
  }
}

Purge a call's audio artifacts, leaving the artifact rows as evidence they existed ​

DELETE/calls/{call}/recording
  • Necesită recording.delete.
  • Acest răspuns nu este împachetat în data.
  • Body is a bare {"deleted": <int>} where the value is a COUNT of purged artifacts, not a boolean; 0 means nothing was there to purge

Parametri de cale

NumeTipObligatoriuNote
callstringda
bash
curl -X DELETE "$CALLAGENT_API_URL/calls/01JQ0000000000000000000000/recording" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/calls/01JQ0000000000000000000000/recording`, {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/calls/01JQ0000000000000000000000/recording');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.delete(
    f"{os.environ['CALLAGENT_API_URL']}/calls/01JQ0000000000000000000000/recording",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Răspunsuri

StatusCorp
200Bare JSON object, not data-wrapped

Erori

StatusCând apare
403The key or user lacks the recording.delete scope
404No call with that id in this organization

Exemplu de răspuns, generat din schemă:

json
{
  "deleted": 1
}

Return a call's full transcript text with flags saying whether it was redacted or purged ​

GET/calls/{call}/transcript
  • Necesită transcript.read.
  • text can be null while the response is still 200: check the purged and redacted flags rather than assuming content

Parametri de cale

NumeTipObligatoriuNote
callstringda
bash
curl -X GET "$CALLAGENT_API_URL/calls/01JQ0000000000000000000000/transcript" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/calls/01JQ0000000000000000000000/transcript`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/calls/01JQ0000000000000000000000/transcript');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.get(
    f"{os.environ['CALLAGENT_API_URL']}/calls/01JQ0000000000000000000000/transcript",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Răspunsuri

StatusCorp
200data-wrapped object

Erori

StatusCând apare
403The key or user lacks the transcript.read scope
404No call with that id in this organization

Exemplu de răspuns, generat din schemă:

json
{
  "data": {
    "call_id": null,
    "text": "string",
    "redacted": true,
    "purged": true
  }
}
GET/calls/search
  • Necesită call.read.
  • Routed to the identical CallController@index handler as GET /calls; there is no search-specific behaviour
bash
curl -X GET "$CALLAGENT_API_URL/calls/search" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Accept: application/json"
js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/calls/search`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
    Accept: 'application/json',
  },
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(`${error.type}: ${error.message}`);
}

const { data } = await response.json();
php
<?php

$handle = curl_init(getenv('CALLAGENT_API_URL') . '/calls/search');

curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
        'Accept: application/json',
    ],
]);

$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);

if ($status >= 400) {
    throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}

$data = $body['data'];
python
import os, requests

response = requests.get(
    f"{os.environ['CALLAGENT_API_URL']}/calls/search",
    headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
data = response.json()["data"]

Răspunsuri

StatusCorp
200data-wrapped array

Erori

StatusCând apare
403The key or user lacks the call.read scope

Exemplu de răspuns, generat din schemă:

json
{
  "data": [
    {
      "id": null,
      "status": "string",
      "direction": "string",
      "transport": "string",
      "from": "+40712345678",
      "to": "+40712345678",
      "assistant_id": "01JQ0000000000000000000000",
      "customer_id": "01JQ0000000000000000000000",
      "queue_id": "01JQ0000000000000000000000",
      "operator_id": "01JQ0000000000000000000000",
      "provider": "string",
      "started_at": "2026-01-01T12:00:00+00:00",
      "connected_at": "2026-01-01T12:00:00+00:00",
      "ended_at": "2026-01-01T12:00:00+00:00",
      "duration_seconds": 30,
      "billable_seconds": 30,
      "ended_reason": "string",
      "cost_total": "string",
      "cost_currency": "string",
      "latency": {},
      "created_at": "2026-01-01T12:00:00+00:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "per_page": 25,
    "total": 1,
    "last_page": 1
  }
}

Scrisă după cod. Ce nu este încă implementat este marcat ca atare, niciodată descris ca funcțional.