Convenții API
Tot ce este la fel pe fiecare endpoint, ca paginile de referință să nu repete. Citește asta o dată.
URL de bază
Fiecare cale din referință este relativă la un URL de bază care se termină deja în /api/v1.
Exemplele din referință folosesc $CALLAGENT_API_URL pentru bază și $CALLAGENT_API_KEY pentru cheie, așa că fiecare dintre ele rulează exact așa cum e scris odată ce acestea două sunt exportate:
export CALLAGENT_API_URL="http://localhost:8000/api/v1"
export CALLAGENT_API_KEY="ca_sk_your_private_key_here"Autentificare
O cheie bearer pe fiecare request:
Authorization: Bearer ca_sk_…Cheile vin cu două prefixe — ca_sk_ (privată, server-side) și ca_pk_ (publică, sigură în browser, schimbată la POST /client-tokens pe un JWT de scurtă durată). Scope-urile, restricțiile de origin și de IP, rotația și client token-urile sunt toate pe Autentificare.
Tenancy
Organizația este dedusă din cheie. Nu există niciun parametru organization_id nicăieri în acest API, deci nu ai ce să falsifici. O resursă care aparține altei organizații întoarce 404 — identic cu un id care nu a existat niciodată, pentru că un 403 ar confirma că resursa există.
Paginare
Endpoint-urile de listare întorc un paginator Laravel:
{
"data": [ … ],
"links": { "first": "…", "last": "…", "prev": null, "next": "…" },
"meta": { "current_page": 1, "per_page": 25, "total": 412, "last_page": 17, "…": "…" }
}Urmărește links.next în loc să incrementezi un număr de pagină.
Doi parametri pentru dimensiunea paginii
Parametrul nu este același peste tot, iar pagina de referință a fiecărui endpoint îl numește pe cel pe care îl citește:
limitpe suprafața Engage — campanii, liste de suprimare, contacte.per_pagepe Platform și Billing — chei API, webhooks, clienți, facturi.
Ambii au implicit 25 și se plafonează la 100. Trimiterea celui greșit nu este o eroare; este ignorat în tăcere și primești 25 de rânduri.
Denumirea câmpurilor
API-ul este snake_case (first_message_mode, phone_number_id). Pachetul @callagent/contracts și fișierele YAML de config-as-code sunt camelCase (firstMessageMode, phoneNumberId), iar CLI-ul convertește între ele.
Spațiile de chei care îți aparțin — metadata, variable_values, headers HTTP, parameters de tool — sunt transmise mai departe neatinse, așa că o cheie de metadata order_id rămâne order_id.
Trei locuri unde pe fir e camelCase oricum
Sunt reale și actuale. Trimite ce spune pagina de referință, nu ce implică convenția:
POST /telephony/callsprimește un body integral camelCase —assistantId,phoneNumberId,customSipHeaders,idempotencyKeyși restul — în timp ce întoarce snake_case.POST /callseste echivalentul snake_case al aceleiași operațiuni.POST /campaigns/{id}/pauseși/cancelcitescendLiveCalls. Restul ambelor body-uri (reason,farewell) este snake_case.- Fiecare endpoint de scriere din telefonie — numere de telefon, trunchiuri SIP, gateway-uri, DID-uri, rute inbound și outbound, conturi de telefonie — validează chei de request camelCase (
friendlyName,outboundCallerIdNumber,inboundSourceAcl) și întoarce snake_case. Extensiile de contact centre sunt excepția și sunt snake_case peste tot.
A doua capcană de denumire, care nu ține de case: POST /campaigns/{id}/contacts primește numărul fiecărui contact ca phone, în timp ce lista de contacte și exportul CSV îl întorc ca phone_number.
Erori
O singură formă peste tot, cu cheia pe error.type:
{
"error": {
"type": "validation_error",
"message": "The request payload failed validation.",
"errors": { "name": ["The name field is required."] },
"documentation_url": "https://docs.callagent.dev/api/errors#validation",
"request_id": "01JQ…"
}
}Ramifică pe statusul HTTP și pe error.type. error.code este un al doilea vocabular, mai mare, care apare la eșecurile de provider, la evenimentele de apel și în payload-urile de webhook — vezi erori, care explică diferența și le listează pe amândouă.
Trimite X-Request-Id pe un request și îți este returnat în corpul erorii. Aceea este metoda sigură de a corela un eșec cu propriile tale loguri, pentru că request_id lipsește din răspunsurile 2xx și din erorile ridicate de middleware-ul de autentificare.
Idempotență
Un singur endpoint respectă header-ul
Idempotency-Key este citit de POST /calls și de nicăieri altundeva. Trimiterea lui către orice alt endpoint nu are niciun efect, iar un POST reîncercat acolo va acționa de două ori.
Două endpoint-uri primesc în schimb o cheie de idempotență ca câmp în body: POST /calls (idempotency_key, care are prioritate față de header) și POST /billing/credits (idempotency_key, transmis mai departe către Stripe). POST /telephony/calls primește idempotencyKey, camelCase.
Idempotency-Key: 6f1c0a5e-…Rejucarea unei chei pe POST /calls întoarce apelul original, tot cu 201, în loc să formeze numărul a doua oară. Nu există expirare — cheia trăiește cât rândul apelului — și nici amprentare a request-ului, așa că rejucarea unei chei cu un body diferit întoarce în tăcere primul apel în loc să raporteze un conflict. Folosește o cheie derivată din propria ta unitate idempotentă de lucru.
Peste tot în rest, fă retry-urile sigure verificând înainte să creezi, sau folosind un PUT acolo unde există unul.
Rate limits
300 de request-uri pe minut per cheie API implicit, variind în funcție de plan, cu bugetul pe fiecare răspuns:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287Un 429 poartă Retry-After în secunde. Numerele reale, plafoanele per plan și un helper de retry sunt pe rate limits.
Versionare
Calea poartă versiunea (/api/v1); documentul OpenAPI poartă o versiune de specificație datată, care este trimisă și la livrările de webhook ca X-CallAgent-Api-Version.
Cum se citește referința generată
Paginile de referință sunt generate din docs/api/openapi.json, pe care control plane-ul îl exportă din propriile rute, form request-uri și resurse API. Din asta decurg patru lucruri, de care paginile țin cont:
Fiecare endpoint listat există. O verificare reconciliază specificația cu tabela de rute live la fiecare rulare și eșuează la o operațiune pe care nu o servește nicio rută, sau la o rută pe care nu o documentează nicio operațiune. Nu se documentează nimic ce nu a fost confirmat.
Linia „Scope” este ce impune handler-ul, nu ce ar trebui să impună. Scope-urile sunt verificate per endpoint, nu printr-un middleware general, iar destul de multe endpoint-uri nu impun niciunul. Acolo unde o pagină spune asta, este un fapt despre cod. Vezi observația de pe Autentificare.
Tabelul „Errors” este ce poate atinge efectiv handler-ul. Exportatorul deduce eșecurile din type hints și ratează tot ce este ridicat înăuntrul unui serviciu, așa că acele tabele sunt scrise pornind de la controllere.
401și429sunt omise din fiecare dintre ele pentru că sunt globale — orice endpoint le poate întoarce.Array-urile fără tip sunt obiecte JSON. Exportatorul tipizează un cast PHP
arrayca array JSON fără schemă de element. În fiecare astfel de caz modelul declarăarray<string, mixed>— un array asociativ, care se codifică drept obiect JSON. De aceea referința randează acele câmpuri caobject(transcriber,model,voice, blocurile*_plan,metadata). Formele autoritative pentru ele sunt schemele zod din@callagent/contracts, rezumate pe Assistants.
Cum rămâne onest
node scripts/check-api-drift.mjs reexportă specificația din rute, o compară cu documentul comis și le reconciliază pe amândouă cu php artisan route:list. Eșuează la o specificație învechită, la o rută nedocumentată sau la o rută documentată care nu există.
Documentul brut
Descarcă openapi.json — OpenAPI 3.1, același fișier pe care îl citește orice generator de SDK. Indexul de referință poartă numărul curent de căi, operațiuni și scheme.