Manual API
Ultima actualizare: 11 august 2026
API-ul HTTP îți dă din propriul sistem exact ce vezi în panou: entitățile din spatele certificatului tău SPV, documentele primite de la ANAF și XML-ul lor original.
Este inclus în planurile Platinum și Contabil. Pe celelalte planuri tokenul se poate crea, dar orice cerere primește 403 — nu 401, ca să nu cauți o problemă de credențiale pe care nu o ai.
De ce ai nevoie
- Un cont cu planul Platinum sau Contabil.
- Un token API, creat din Setări → Integrări. Se afișează o singură dată, la creare.
- Cel puțin o entitate cu monitorizarea pornită — API-ul răspunde numai despre CIF-urile pe care le monitorizezi.
Nu ai nevoie de nimic din partea ANAF. Certificatul, OAuth-ul și interogarea SPV rămân la noi; tu vorbești doar cu API-ul acesta.
Adresa de bază și versiunea
https://alertespv.ro/api/v1Versiunea este în cale de la prima zi. Câmpuri noi pot apărea oricând într-un răspuns, așa că citește-le pe nume și ignoră-le pe cele necunoscute. Câmpurile existente nu își schimbă înțelesul și nu dispar fără o versiune nouă în cale.
Toate răspunsurile sunt JSON, cu o singură excepție: descărcarea XML-ului, care întoarce fișierul așa cum l-a emis ANAF.
Autentificare
Tokenul se trimite ca antet „Authorization: Bearer …". Nu există sesiuni, cookie-uri sau chei în query string.
curl -s https://alertespv.ro/api/v1/entities \
-H "Authorization: Bearer spva_cheia_ta" \
-H "Accept: application/json"- Tokenul începe întotdeauna cu „spva_", ca să fie recunoscut într-un log sau într-un paste greșit.
- Maximum 5 tokenuri active per cont. Revocarea este imediată.
- Nu îl păstrăm în clar — dacă l-ai pierdut, creezi altul și îl revoci pe cel vechi.
- Coloana „ultima folosire" din Setări → Integrări îți spune dacă un token mai e folosit înainte să îl revoci.
Tokenul deschide toate documentele fiscale ale contului. Ține-l pe server, într-o variabilă de mediu — niciodată în cod versionat, într-o aplicație mobilă sau în JavaScript rulat în browser.
| Situație | Răspuns | Ce înseamnă |
|---|---|---|
| Antet lipsă sau fără prefixul „spva_" | 401 | Missing or malformed API token. |
| Token necunoscut sau revocat | 401 | Unknown API token. |
| Token valid, plan fără API | 403 | The API is not part of your current plan. |
Limite și paginare
120 de cereri pe minut per cont. Peste limită răspunsul este 429, cu antetul „Retry-After" care spune câte secunde să aștepți. Limita este mult peste ce cere o sincronizare zilnică și mult sub ce costă o buclă cu un bug.
- Listele paginate acceptă „per_page" între 1 și 100; implicit 100.
- Pagina se cere cu „page". Numărul total de pagini este în „meta.last_page".
- Ordinea documentelor este descrescătoare după data creării la ANAF, apoi după id.
GET /entities — entitățile și sloturile
Întoarce tot ce vede certificatul tău — firme și persoane fizice — împreună cu starea sloturilor din plan. O entitate există în listă chiar dacă nu este monitorizată; monitorizarea este ce consumă un slot.
{
"data": [
{
"id": 12,
"cif": "44674942",
"kind": "company",
"name": "EXEMPLU SRL",
"monitored": true,
"enabled": true,
"last_polled_at": "2026-08-11T07:00:12+00:00",
"slot_releasable_from": "2026-09-09"
}
],
"slots": { "used": 1, "limit": 25, "free": 24 }
}| Câmp | Tip | Ce este |
|---|---|---|
| id | număr | Identificatorul entității la noi. El se folosește în „/entities/{id}/start". |
| cif | text | CIF-ul sau CNP-ul, fără prefixul „RO". |
| kind | text | „company" sau „person". |
| name | text sau null | Denumirea, așa cum o dă ANAF. |
| monitored | boolean | Dacă entitatea ocupă acum un slot din plan. |
| enabled | boolean | Dacă interogarea este pornită. Oprită, entitatea încă poate ocupa slotul. |
| last_polled_at | ISO 8601 sau null | Ultima interogare reușită la ANAF. |
| slot_releasable_from | dată sau null | Prima zi în care slotul se poate elibera, dacă monitorizarea rămâne oprită. |
POST /entities/{id}/start și /stop
Pornirea consumă un slot care nu se întoarce imediat. Răspunsul spune explicit dacă s-a luat unul („slot_taken"), pentru că un script este exact apelantul care pornește treizeci de entități fără să fi citit nimic înainte.
curl -s -X POST https://alertespv.ro/api/v1/entities/12/start \
-H "Authorization: Bearer spva_cheia_ta" \
-H "Accept: application/json"- „slot_taken": false înseamnă că entitatea ocupa deja un slot — apelul a fost idempotent, nu ai plătit de două ori.
- Oprirea răspunde întotdeauna cu „slot_released": false. Slotul se eliberează abia la o graniță de lună de abonament, la cel puțin 30 de zile de la pornire, și numai dacă monitorizarea era oprită atunci.
- O entitate care aparține altui cont răspunde 403, nu 404.
GET /documents — documentele
Documentele CIF-urilor pe care le monitorizezi, cu sumarul extras din XML. Un „cif" care nu e printre ele este ignorat tăcut ca filtru — lista rămâne limitată la ce ai voie să vezi.
| Parametru | Valoare | Efect |
|---|---|---|
| cif | text | Restrânge la un singur CIF monitorizat. |
| from | dată | De la începutul acelei zile, după data creării la ANAF. |
| to | dată | Până la sfârșitul acelei zile, inclusiv. |
| per_page | 1–100 | Câte rânduri pe pagină. Implicit 100. |
| page | număr | Pagina cerută. Implicit 1. |
curl -s -G https://alertespv.ro/api/v1/documents \
-H "Authorization: Bearer spva_cheia_ta" \
--data-urlencode "cif=44674942" \
--data-urlencode "from=2026-08-01" \
--data-urlencode "to=2026-08-11" \
--data-urlencode "per_page=50"- „type" și „details" vin de la ANAF exact cum le dă el: „FACTURA PRIMITA", „FACTURA TRIMISA", „ERORI FACTURA". Tratează-le ca text, nu ca enumerare închisă.
- „summary" este null când documentul nu a fost arhivat încă sau când XML-ul nu este o factură pe care o putem citi (raport de erori fără conținut, format nerecunoscut).
- „summary.kind" este „invoice", „credit_note", „errors" sau „unsupported".
- „counterpartyRole" spune cine este partenerul: „supplier" la o factură primită, „customer" la una trimisă. Aceeași factură are roluri diferite pentru cele două firme, dacă ambele sunt monitorizate.
- Sumele sunt text, nu numere: „990.08" rămâne exact atât. Nu le trece prin float dacă le pui într-o contabilitate.
- „anaf_id" plus „cif" identifică unic documentul la ANAF; „id" este identificatorul lui la noi.
GET /documents/{id}/xml — fișierul original
Întoarce XML-ul așa cum l-a emis ANAF, ca fișier de descărcat, cu numele „{cif}-{anaf_id}.xml". Nu este JSON și nu este modificat în niciun fel — este exact copia pe care o arhivăm.
curl -s -OJ https://alertespv.ro/api/v1/documents/8814/xml \
-H "Authorization: Bearer spva_cheia_ta"| Răspuns | Când | Ce faci |
|---|---|---|
| 403 | Documentul aparține unui CIF pe care nu îl monitorizezi. | Verifică lista din /entities. |
| 404 | Documentul nu a fost arhivat niciodată. | Nimic de descărcat; „archived": false îți spunea asta dinainte. |
| 410 | A fost arhivat, dar a ieșit din retenția planului. | Rândul rămâne, fișierul nu. Descarcă mai devreme sau treci pe un plan cu retenție mai mare. |
Coduri de răspuns
| Cod | Înseamnă |
|---|---|
| 200 | Cererea a reușit. |
| 401 | Token lipsă, malformat, necunoscut sau revocat. |
| 403 | Planul nu include API-ul, sau resursa aparține altui cont. |
| 404 | Resursa nu există. |
| 409 | Toate sloturile din plan sunt ocupate în luna de abonament curentă. |
| 410 | Fișierul a existat și a fost șters la expirarea retenției. |
| 422 | Parametri invalizi. Corpul conține câmpul și motivul. |
| 429 | Peste 120 de cereri pe minut. Așteaptă cât spune „Retry-After". |
Rețetă: documentele de ieri, cu XML-ul lor
Tiparul obișnuit al unei sincronizări zilnice: ceri documentele dintr-un interval, ții minte ce ai luat deja după „id", și descarci XML-ul doar pentru cele arhivate.
# Ieri, toate CIF-urile monitorizate, prima pagina.
YESTERDAY=$(date -d yesterday +%F)
curl -s -G https://alertespv.ro/api/v1/documents \
-H "Authorization: Bearer $ALERTESPV_TOKEN" \
--data-urlencode "from=$YESTERDAY" \
--data-urlencode "to=$YESTERDAY" \
--data-urlencode "per_page=100" | jq '.data[] | {id, cif, type, archived}'Dacă vrei să afli despre documente în momentul în care apar, nu la o oră fixă, folosește webhook-urile. API-ul este pentru sincronizări și pentru interogări la cerere; webhook-ul este pentru „spune-mi acum".