CrioX PBXDocumentația API

Apeluri

Istoricul apelurilor primite și date: cine, cu cine, cât, și ce s-a întâmplat.

Un „apel” aici e o convorbire cu cineva din afară: un pacient care a sunat la cabinet, o comandă confirmată prin telefon, un apel pierdut la ora prânzului. Apelurile interne, dintre două interioare, nu apar. Fiecare apel are un id care nu se schimbă, aceleași câmpuri oriunde l-ai vedea, și rămâne în istoric cât ține retenția contului tău.

Lista apelurilor

GET/v1/calls

Apelurile, cele mai noi întâi, pe pagini. Fără niciun parametru primești ultimele 30 de zile, câte 50 pe pagină.

ParametruTipCe face
frommomentDe la acest moment, inclusiv. ISO 8601 (2026-10-01T00:00:00+03:00) sau secunde Unix. Fără el, ultimele 30 de zile.
tomomentPână la acest moment.
directioninbound · outboundDoar primite, sau doar date.
resultanswered · missed · busy · no_answer · cancelled · failedDoar apelurile cu acest rezultat. missed e o scurtătură: primite la care nu a vorbit nimeni, oricare ar fi cauza.
numbercifreNumărul celui din afară, sau o parte din el. Scrii cifrele cum le ai; +, spațiile și punctele se ignoră.
linecifreNumărul tău pe care a intrat sau de pe care a ieșit apelul. Util când ai mai multe numere și vrei doar unul.
agentinteriorInteriorul colegului care a vorbit: a răspuns, la un apel primit, sau a format, la unul dat.
limit1–200Câte apeluri pe pagină. Implicit 50.
cursorstringnext_cursor din pagina anterioară, trimis neschimbat.

Un parametru scris greșit nu e ignorat: primești 400 cu invalid_parameter și explicația. Așa, un filtru greșit nu îți umple sistemul cu apeluri pe care nu le-ai cerut.

Exemplu

Apelurile primite și nepreluate din 17 octombrie:

curl "https://api.criox.ro/v1/calls?direction=inbound&result=missed&from=2026-10-17T00:00:00%2B03:00&to=2026-10-18T00:00:00%2B03:00" \
  -H "Authorization: Bearer cxk_…"

Răspunsul, cu un singur apel ca să încapă aici:

{
  "data": [
    {
      "id": "c0ffee00-1b2c-4d3e-8f4a-5b6c7d8e9f01",
      "direction": "inbound",
      "started_at": "2026-10-17T08:12:41.000Z",
      "ended_at": "2026-10-17T08:15:27.000Z",
      "contact_number": "+40743755549",
      "contact_number_national": "0743755549",
      "contact_name": "Ion Popescu",
      "line_number": "+40215708509",
      "line_number_national": "0215708509",
      "agent_extension": "101",
      "agent_name": "Maria Ionescu",
      "queue_number": null,
      "queue_name": null,
      "result": "answered",
      "missed_reason": null,
      "after_hours": false,
      "wait_seconds": 12,
      "talk_seconds": 154,
      "duration_seconds": 166,
      "recorded": true,
      "crm_provider": "kommo",
      "crm_contact_id": "991",
      "crm_contact_url": "https://exemplu.kommo.com/contacts/detail/991",
      "destination_type": "extension",
      "destination_number": "101",
      "destination_name": "Maria Ionescu",
      "path": [
        { "type": "extension", "number": "101", "name": "Maria Ionescu", "key": null, "at": "2026-10-17T08:12:41.000Z", "seconds": 12, "result": "answered" }
      ]
    }
  ],
  "has_more": true,
  "next_cursor": "MTc2MDY4Mjc2MS5jMGZmZWUwMC0xYjJjLTRkM2UtOGY0YS01YjZjN2Q4ZTlmMDE"
}

Paginarea

Cât timp has_more e true, ceri pagina următoare cu cursor=next_cursor, cu aceleași filtre. Cursorul ține minte unde ai rămas, deci un apel care intră în istoric între două pagini nu te face să sari peste altul. Când nu mai e nimic, has_more e false și next_cursor e null.

O pagină poate avea mai puține rânduri decât limit și totuși has_more: true: apelurile interne se scot după ce pagina a fost tăiată. Oprește-te după has_more, nu după numărul de rânduri.

// Node.js: toate apelurile din octombrie, pagină cu pagină
let cursor = null;
do {
  const url = new URL("https://api.criox.ro/v1/calls");
  url.searchParams.set("from", "2026-10-01T00:00:00+03:00");
  if (cursor) url.searchParams.set("cursor", cursor);

  const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.CRIOX_KEY}` } });
  if (!res.ok) throw new Error(`CrioX a răspuns ${res.status}`);
  const page = await res.json();

  for (const call of page.data) await save(call);
  cursor = page.has_more ? page.next_cursor : null;
} while (cursor);

Un apel

GET/v1/calls/{id}

Un singur apel, după id. Cazul obișnuit: ai primit evenimentul call.completed, ai păstrat call_id, și vrei să-l recitești mai târziu, de exemplu după ce colegul a adăugat numele în agendă. Îl găsești cât timp îl ține retenția contului, nu doar 30 de zile.

curl https://api.criox.ro/v1/calls/c0ffee00-1b2c-4d3e-8f4a-5b6c7d8e9f01 \
  -H "Authorization: Bearer cxk_…"

Răspunsul e obiectul „apel” de mai jos, fără înveliș. Un id care nu există în contul tău primește 404 cu call_not_found; un id care nu e UUID primește 400.

Obiectul „apel”

Aceleași chei, în aceeași ordine, pe orice apel; null acolo unde nu se aplică sau nu se știe. E același obiect ca în evenimente, unde id se numește call_id. Modelul e simetric: contact_* e mereu cel din afară, agent_* e mereu colegul tău, line_* e mereu numărul tău, oricare ar fi sensul apelului.

CâmpTipCe înseamnă
iduuidId-ul apelului. Stabil; în evenimente e call_id.
directioninbound · outboundinbound = primit, outbound = dat.
started_atmomentCând a început apelul: când a sunat telefonul, la un primit, sau când s-a format numărul, la un dat. UTC.
ended_atmomentCând s-a închis. UTC.
contact_numberstring · nullNumărul celui din afară, în forma internațională (+40…). null când a sunat cu numărul ascuns.
contact_number_nationalstring · nullAcelași număr, în forma națională (07…). Pentru un număr străin, la fel ca cel de mai sus.
contact_namestring · nullNumele lui, dacă îl știm: din CRM-ul legat sau din agenda CrioX.
line_numberstring · nullNumărul tău: cel pe care a intrat apelul (primit) sau cel afișat celuilalt (dat). Internațional.
line_number_nationalstring · nullAcelași, național.
agent_extensionstring · nullInteriorul colegului care a răspuns (primit) sau a format (dat). null pe un apel la care nu a vorbit nimeni, și tot null când a răspuns asistentul AI sau mesageria vocală, nu un coleg. La un apel primit pe un grup, e cel care a ridicat, nu un membru oarecare.
agent_namestring · nullNumele colegului, cum e în CrioX.
queue_numberstring · nullCoada de call-center prin care a trecut apelul, dacă a trecut printr-una. Grupurile de sonerie nu apar aici.
queue_namestring · nullNumele cozii.
resultstringCe s-a întâmplat. Valorile, mai jos.
missed_reasonstring · nullDe ce nu a vorbit nimeni. Doar pe un apel primit nepreluat; altfel null. Valorile, mai jos.
after_hoursboolean · nullApelul a intrat în afara programului numărului. null pe un apel dat, sau când programul nu s-a putut citi.
wait_secondsinteger · nullCât a așteptat apelantul până a vorbit cu cineva. Pe un apel nepreluat, cât a sunat.
talk_secondsinteger · nullCât s-a vorbit. 0 când nu a vorbit nimeni.
duration_secondsinteger · nullDe la început la sfârșit, cu tot cu așteptare.
recordedboolean · nullExistă o înregistrare a convorbirii. Înregistrarea în sine nu se ia încă prin API; o asculți din CrioX.
crm_providerstring · nullCRM-ul în care e cunoscut contactul (kommo, istoma, medsoft), dacă ai unul legat și l-a găsit.
crm_contact_idstring · nullId-ul fișei lui în acel CRM.
crm_contact_urlstring · nullLegătura spre fișă, de pus pe un buton.
destination_typestring · nullUnde a trimis numărul apelul la intrare: extension, group, queue, ivr, assistant, voicemail sau external. Pe un apel dat, external. null când apelul s-a încheiat pe număr fără să fie trimis nicăieri. Detalii mai jos.
destination_numberstring · nullNumărul destinației: interiorul, grupul (8001), coada (7001), meniul (500), asistentul (6001), căsuța vocală sau numărul din afară. null când centrala nu l-a consemnat.
destination_namestring · nullNumele ei, când se știe: al cozii, al meniului, al colegului.
pathpas[] · nullTraseul apelului, pas cu pas, în ordinea în care s-a întâmplat. Forma unui pas e mai jos. null doar pe evenimentul call.answered, unde traseul nu se știe încă; listă goală când nu s-a consemnat niciun pas.

Valorile lui result

answeredA vorbit cineva.
busyOcupat.
no_answerA sunat și nu a răspuns nimeni.
cancelledApelantul a închis înainte să răspundă cineva.
failedApelul nu s-a putut face: număr greșit, rețea, refuz.

Valorile lui missed_reason

after_hoursA sunat în afara programului: ore, zi liberă sau o închidere pusă de tine.
limitRefuzat de o limită a contului, de exemplu toate liniile ocupate.
no_agentCoada nu avea pe nimeni disponibil.
busyOcupat.
abandonedA închis cât aștepta.
unansweredRestul: a sunat fără răspuns, a ajuns în mesageria vocală sau s-a oprit într-un meniu.

Nu există un câmp „a lăsat mesaj vocal”. Centrala nu leagă mesajul de apel, iar un câmp ghicit ar fi o minciună pe care ai automatiza. Când se va putea spune sigur, îl adăugăm.

Destinația și traseul

Un apel primit intră pe un număr, iar numărul îl trimite undeva: la un interior, la un grup de sonerie, într-o coadă, într-un meniu vocal, la asistentul AI, în mesageria vocală sau la un număr din afară. Acel „undeva” e destinația, cu tipul, numărul și numele ei. Rămâne destinația chiar dacă apelul l-a preluat până la urmă un coleg: pentru „cine a vorbit” sunt câmpurile agent_*. Pe un apel dat, destinația e numărul sunat.

TipCe eNumăr
extensionUn interior, telefonul unui coleg.100–499
groupUn grup de sonerie: mai multe interioare sună deodată sau pe rând.8001–8099
queueO coadă de call-center, cu agenți și așteptare.7001–7099
ivrUn meniu vocal: „apăsați 1 pentru…”.500–599
assistantAsistentul AI.6001–6099
voicemailMesageria vocală; numărul e al căsuței.căsuța
externalUn număr din afară: un mobil sunat de centrală în locul biroului, sau numărul sunat pe un apel dat.+40…

Traseul (path)

Tot ce s-a întâmplat cu apelul, în ordine: a intrat în meniu, a apăsat o tastă, a intrat în coadă, au sunat două interioare, a răspuns unul, a fost trecut la asistent. Fiecare pas are aceleași șapte chei, null unde nu se aplică:

CheieTipCe înseamnă
typestringAcelași vocabular ca destination_type.
numberstring · nullNumărul pasului: interiorul care a sunat, coada, grupul, numărul din afară.
namestring · nullNumele: al colegului, al cozii, al meniului. Pe o tastă, ce înseamnă tasta, dacă meniul o spune.
keystring · nullTasta apăsată, doar pe un pas ivr cu result: "key".
atmomentCând a început pasul. UTC.
secondsinteger · nullCât a ținut: cât a sunat interiorul, cât a stat în coadă, cât a ținut apelul după transfer.
resultstring · nullCe s-a întâmplat cu pasul; valorile, mai jos.

Valorile lui result, pe tip de pas:

ivrenter a intrat în meniu · key a apăsat o tastă · exit a ieșit fără să aleagă
queueanswered l-a preluat un agent · abandoned a închis cât aștepta · moved a fost scos din coadă și dus mai departe · timeout s-a terminat timpul · no_agent coada nu avea pe nimeni · exit_key a ieșit cu o tastă · other
extension, externalanswered · answered_elsewhere a răspuns alt telefon · no_answer · busy · offline telefonul nu era conectat · cancelled apelantul a închis · rejected · failed · null când nu se știe
group, assistant, voicemailnull: centrala nu consemnează un deznodământ al lor; ce a urmat se vede din pașii de după.

Un apel care a intrat într-un meniu, a ales „Programări”, a așteptat în coadă și l-a preluat al doilea coleg sunat:

{
  "destination_type": "ivr",
  "destination_number": null,
  "destination_name": "Meniu principal",
  "path": [
    { "type": "ivr",       "number": null,   "name": "Meniu principal", "key": null, "at": "2026-10-17T08:12:42.000Z", "seconds": null, "result": "enter" },
    { "type": "ivr",       "number": null,   "name": "Programări",      "key": "1",  "at": "2026-10-17T08:12:46.000Z", "seconds": null, "result": "key" },
    { "type": "queue",     "number": "7001", "name": "Programări",      "key": null, "at": "2026-10-17T08:12:46.000Z", "seconds": 7,    "result": "answered" },
    { "type": "extension", "number": "102",  "name": "Ion Popa",        "key": null, "at": "2026-10-17T08:12:47.000Z", "seconds": 4,    "result": "no_answer" },
    { "type": "extension", "number": "101",  "name": "Maria Ionescu",   "key": null, "at": "2026-10-17T08:12:51.000Z", "seconds": 2,    "result": "answered" }
  ]
}

Ce centrala nu a consemnat iese null, nu ghicit. Numărul unui grup se știe doar când apelul a fost trimis explicit la el; altfel grupul se vede ca mai multe interioare sunând deodată, cu destination_number: null. Numele grupurilor, ale asistenților și ale căsuțelor vocale nu sunt pe rândul apelului. Un meniu are nume, dar nu număr, decât dacă apelul s-a încheiat în el.

Întrebări frecvente

De ce lipsește un apel pe care îl văd în CrioX?

Trei cauze obișnuite: e un apel intern, între două interioare, și acelea nu intră în API; e mai vechi de 30 de zile și nu ai trimis from; sau pagina ta de istoric are un filtru pe care cererea nu îl are. Dacă nu e niciuna, scrie-ne cu id-ul apelului.

Cum iau toate apelurile de ieri?

Cu from și to pe ziua de ieri, în fusul tău orar, și paginare până la has_more: false. Exemplul de la paginare face exact asta pentru o lună.

Cum sincronizez continuu, fără să ratez nimic?

Primești evenimentele: ele vin în câteva secunde după fiecare apel, cu același obiect. Dacă totuși preferi să întrebi tu, întreabă o dată la câteva minute, cu from = momentul ultimului apel pe care îl ai, minus o oră, ca să prinzi și apelurile lungi care s-au închis mai târziu. Apelurile pe care le ai deja le recunoști după id.

Pot lua înregistrarea convorbirii?

Încă nu prin API. recorded îți spune dacă există; o asculți din CrioX. Accesul la înregistrări prin API e pe listă, cu reguli proprii, pentru că e altceva decât a ști că apelul a avut loc.

CrioX · suport@criox.ro · live.criox.ro