Erori
API-ul folosește coduri HTTP standard și un body JSON consistent pentru erori.
Coduri de status
| Cod | Semnificație |
|---|---|
| 200 | Succes. |
| 201 | Resursa a fost creată. |
| 204 | Succes, fără body. |
| 400 | Cerere invalidă la nivel de protocol (rar — majoritatea problemelor de validare apar ca 422). |
| 401 | Autentificarea a eșuat. Vezi ghidul de autentificare. |
| 403 | Autentificat dar fără autorizație — permisiune lipsă, tenant suspendat, etc. |
| 404 | Resursa nu există sau nu aparține tenantului tău. |
| 422 | Validarea a eșuat. Body-ul conține mesajele de eroare per câmp. |
| 429 | Limita de rată depășită. Vezi limite de rată. |
| 500 | Eroare de server — încearcă din nou; dacă persistă, deschide un tichet cu id-ul cererii. |
Forma body-ului de eroare
Pentru erori care nu sunt de validare:
{
"error": "Descriere lizibilă a problemei."
}Pentru erori de validare (HTTP 422), forma standard Laravel:
{
"message": "The customer name field is required. (and 1 more error)",
"errors": {
"customer_name": [
"The customer name field is required."
],
"items.0.product_id": [
"The selected items.0.product_id is invalid."
]
}
}message conține primul mesaj de eroare (plus (and N more errors) când sunt mai multe); errors listează toate mesajele, grupate pe câmp. Construiește-ți validarea în jurul obiectului errors, nu al șirului message.
Idempotență
POST /api/v1/orders, POST /api/v1/asns și POST /api/v1/products acceptă antetul Idempotency-Key (alternativ, câmpul idempotency_key din corp; antetul are prioritate). Reîncercarea după o eroare de rețea cu aceeași cheie nu creează un duplicat:
| Situație | Răspuns |
|---|---|
| Aceeași cheie, același conținut | 200 cu corpul răspunsului inițial și antetul Idempotent-Replayed: true. Nu se scrie nimic. |
| Aceeași cheie, conținut diferit | 409 cu { "error": "idempotency_conflict" }. Nu se scrie nimic. |
| Cheie mai lungă de 128 de caractere | 422 cu { "error": "invalid_idempotency_key" }. |
| Fără cheie | Comportamentul obișnuit: nicio protecție la reluare. |
Cheia este valabilă per cheie API și per resursă: aceeași valoare folosită de alt client, sau pe alt tip de resursă, este independentă. Se memorează doar crearea reușită; o cerere refuzată (de exemplu 422) nu consumă cheia, deci o poți corecta și retrimite cu aceeași cheie. Celelalte endpoint-uri POST care creează resurse nu sunt acoperite: folosește id-ul resursei rezultate pentru deduplicare în sistemul tău sau verifică existența resursei înainte de a reîncerca.
Exemplu:
curl -X POST https://tenant.notsowms.ro/api/v1/asns \
-H "Authorization: Bearer tenant.7c4a8d09ca3762af61e59520943dc26494f8941b" \
-H "Idempotency-Key: asn-2026-0042-v1" \
-H "Content-Type: application/json" \
-d '{ "reference": "ASN-2026-0042", "lines": [{ "sku": "BRK-PAD-001", "expected_quantity": 20 }] }'Excepție: POST /api/v1/billing/invoices face upsert după external_id, deci este sigur la reîncercare — același external_id actualizează rândul existent în loc să dubleze.