PostCargo REST API
Documentatie completa · v1.0 · Production-ready
API-ul PostCargo permite oricarui magazin online sau ERP sa integreze direct serviciile noastre de curierat: calcul preturi pe 12 curieri, generare AWB automata, tracking live, webhooks pentru status updates si retururi. Foloseste-l prin pluginuri oficiale (WooCommerce, Shopify) sau direct prin REST.
https://api.postcargo.ro
Cele mai populare endpoint-uri
Autentificare
API-ul foloseste doua tipuri de autentificare:
X-API-Key
Pentru integrari (WooCommerce, ERP, scripts). O cheie pe integrare, revocabila oricand.
X-API-Key: pcg_live_xxxxxxxxxxxxxxxx
Bearer JWT
Pentru actiuni administrative (gestionare chei, setari tenant). Obtinut prin login.
Authorization: Bearer eyJhbGc...
Format raspuns
Toate raspunsurile au structura:
{
"success": true,
"data": { ... },
"meta": { "page": 1, "total": 42 }
}
Erori:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Missing required field: weight"
}
}
Coduri eroare
| HTTP | Code | Cauza |
|---|---|---|
| 400 | VALIDATION_ERROR | Camp lipsa sau invalid |
| 401 | UNAUTHORIZED | Cheie API invalida sau expirata |
| 403 | FORBIDDEN | Permisiune insuficienta |
| 404 | NOT_FOUND | Resursa inexistenta |
| 429 | RATE_LIMITED | Prea multe cereri (vezi headerul Retry-After) |
| 500 | INTERNAL_ERROR | Eroare server (logata pe partea noastra) |
| 503 | COURIER_UNAVAILABLE | API curier offline temporar |
Rate limiting
Limita implicita: 100 cereri / minut per cheie API. Headerele de raspuns:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1714650000
Retry-After: 12
Limita poate fi crescuta pentru clientii cu volum mare. Contact: suport@postcargo.ro
Permisiuni
Cheile API pot avea permisiuni granulare. Implicit, cheile noi au ["*"] (acces complet).
pricing:readCalculeaza preturishipments:createCreeaza expediereshipments:readCiteste expedierishipments:cancelAnuleaza expediereawb:createGenereaza AWBawb:readDescarca AWB PDFtracking:readTrackingwebhooks:manageWebhooksapi_keys:manageGestioneaza chei (necesita JWT)tenant:manageSetari cont (necesita JWT)Auth & Conturi
/v1/auth/register
Public
Creeaza un cont nou + tenant + prima cheie API.
Contul necesita aprobare manuala
Fiecare cont API este verificat de echipa PostCargo. Pana la aprobare, contul are
status: "pending", nu primesti JWT, iar cheia API returnata este respinsa
cu 403. Primesti email cand contul este activat, apoi te autentifici cu
POST /v1/auth/login.
Body
{
"tenant_name": "Magazinul Meu SRL",
"email": "owner@magazin.ro",
"password": "parola_min_8",
"name": "Ion Popescu",
"phone": "0722123456"
}
phone este optional, dar grabeste verificarea contului.
Response 201
{
"success": true,
"data": {
"user": { "id": 1, "email": "owner@magazin.ro", "role": "owner" },
"tenant": { "id": 1, "name": "Magazinul Meu SRL", "slug": "magazinul-meu-srl", "status": "pending" },
"api_key": "pcg_live_a1b2c3d4e5...",
"status": "pending_approval",
"message": "Contul a fost creat si asteapta aprobarea echipei PostCargo."
}
}
Salveaza api_key acum: nu mai este afisata a doua oara. Devine functionala dupa aprobare.
/v1/auth/login
Public
Login cu email + parola. Returneaza JWT + refresh token.
curl -X POST https://api.postcargo.ro/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"owner@magazin.ro","password":"parola"}'
Erori specifice
| Cod | HTTP | Ce inseamna |
|---|---|---|
ACCOUNT_PENDING | 403 | Contul nu a fost aprobat inca. Aparea email la activare. |
ACCOUNT_SUSPENDED | 403 | Contul a fost suspendat. Contacteaza PostCargo. |
AUTHENTICATION_ERROR | 401 | Email sau parola greşite. |
/v1/auth/refresh
Reinnoieste JWT folosind refresh token.
{ "refresh_token": "rfk_..." }
/v1/auth/api-keys
JWT + API Key
Listeaza toate cheile API ale tenant-ului — cu request_count + last_used_at + last_used_ip.
{
"success": true,
"data": [
{
"id": 1,
"key_prefix": "pcg_live_a1b2",
"label": "WooCommerce - Magazin principal",
"permissions": ["*"],
"is_active": true,
"last_used_at": "2026-05-03T20:30:12+03:00",
"last_used_ip": "82.77.123.45",
"request_count": 1432,
"expires_at": null,
"created_at": "2026-05-01T18:00:00+03:00"
}
]
}
/v1/auth/api-keys
Genereaza o cheie noua. Cheia complet apare o singura data in raspuns; salveaza-o.
// Body
{
"label": "WooCommerce - magazin nou",
"permissions": ["pricing:read", "shipments:create", "awb:create"],
"expires_in_days": 365
}
// Response
{
"success": true,
"data": {
"id": 5,
"label": "WooCommerce - magazin nou",
"api_key": "pcg_live_xxxxxxxxxxxxxxxxxxxx",
"key_prefix": "pcg_live_xxxx"
}
}
/v1/auth/api-keys/{id}/logs
Loguri detaliate pe o cheie. Filtre disponibile: ?page=1&per_page=50&status=200&platform=woocommerce&from=2026-05-01&to=2026-05-31
{
"success": true,
"data": {
"key": { "id": 1, "label": "...", "request_count": 1432 },
"stats_24h": { "total": 245, "success": 240, "errors": 5, "avg_ms": 187 },
"logs": [
{
"id": 9876, "method": "POST", "endpoint": "/v1/pricing/quote",
"status_code": 200, "duration_ms": 215, "ip": "82.77.x",
"source_platform": "woocommerce", "created_at": "..."
}
]
},
"meta": { "page": 1, "per_page": 50, "total": 1432, "total_pages": 29 }
}
/v1/auth/api-keys/usage
Stats agregate (toate cheile, ultimele 7-90 zile). ?days=7
{
"data": {
"totals": { "total": 12450, "success": 12200, "errors": 250, "avg_ms": 195 },
"by_day": [{ "day": "2026-05-01", "total": 1820, "success": 1810, "errors": 10 }],
"by_platform": [{ "platform": "woocommerce", "total": 11230 }],
"top_endpoints": [{ "endpoint": "/v1/pricing/quote", "total": 6420 }]
}
}
/v1/auth/api-keys/{id}
Revoca cheia. Integrarea care o foloseste va inceta sa functioneze imediat.
/v1/auth/forgot-password
Public
Trimite pe email linkul de resetare a parolei. Raspunsul este acelasi si daca emailul nu exista, ca sa nu se poata afla ce conturi sunt inregistrate.
{ "email": "owner@magazin.ro" }
/v1/auth/reset-password/validate
Public
Verifica daca un token de resetare este inca valid, inainte de a afisa formularul. Parametru query: ?token=...
/v1/auth/reset-password
Public
Schimba parola folosind tokenul primit pe email. Tokenul se consuma o singura data si invalideaza sesiunile existente.
{ "token": "...", "password": "parola_noua_min_8" }
Public (fara auth)
/health
Public
{ "success": true, "data": { "status": "ok", "version": "1.0.0", "php": "8.3.30" } }
/v1/couriers
Public
Lista publica a celor 12 curieri integrati (logo, descriere, pret pornire, features).
Pricing
/v1/pricing/quote
Calculeaza pretul pentru toti curierii activi simultan. Recomandat pentru checkout in WooCommerce/Shopify.
Body
{
"from": { "city": "Bucuresti", "county": "Bucuresti", "postcode": "010101" },
"to": { "city": "Cluj-Napoca", "county": "Cluj", "postcode": "400001" },
"package": {
"type": "colet",
"weight": 2.5,
"length": 30, "width": 20, "height": 15,
"value_declared": 250,
"cod_amount": 0
},
"options": {
"saturday_delivery": false,
"open_on_delivery": false,
"insurance": true
}
}
Trimite length,
width si height:
curierii factureaza greutatea volumetrica (L x l x h / 5000) cand e mai mare decat cea reala, iar fara dimensiuni
un colet mare si usor este cotat sub tariful real.
Response
{
"success": true,
"data": [
{
"courier_code": "gls",
"courier_name": "GLS Romania",
"price": 19.57,
"price_without_vat": 19.57,
"price_with_vat": 23.68,
"vat_rate": 21,
"list_price_without_vat": 26.10,
"list_price_with_vat": 31.58,
"discount_percent": 25,
"discount_amount": 7.90,
"discount_name": "Reducere Cont Nou",
"discount_source": "site",
"estimated_days": "1-3",
"source": "live",
"currency": "RON"
}
]
}
Preţ, TVA si reducere
| Camp | Ce contine |
|---|---|
list_price_without_vat | Tariful de lista, inainte de reducere (fara TVA). |
price / price_without_vat | Cat se plateste, fara TVA, dupa reducere. Acesta e costul de transport pe care il pui in checkout. |
price_with_vat | Acelasi preţ, cu TVA inclus. |
discount_source | site = reducerea activa pe postcargo.ro, preluata automat. tenant = procent setat pentru contul tau. none = fara reducere. |
source | live = tarif real al curierului. estimated = tarif de rezerva din configuratie, folosit cand curierul nu raspunde; poate diferi de cel real. |
Reducerea se aplica peste suma cu TVA, exact ca pe postcargo.ro, apoi se recalculeaza valoarea fara TVA. Implicit este cea activa pe site; poate fi schimbata per cont de echipa PostCargo.
/v1/pricing/calculate
Pret pentru un singur curier specific. Body identic cu /quote, plus "courier": "fan-courier".
/v1/pricing/calculate-all
Preturile de la toti curierii activi pe contul tau, intr-un singur apel. Body identic cu /quote. Util pentru a afisa clientului toate opţiunile la checkout.
/v1/pricing/couriers
Curierii pentru care contul tau poate cere preturi, cu marja configurata. Diferenta faţă de /v1/couriers: acela e public si general, acesta reflecta configuraţia contului.
Localitati
Nomenclatorul de localitati folosit de postcargo.ro. Foloseste-l pentru autocomplete in checkout: tariful depinde de judet, iar un oras scris greşit duce la alt preţ sau la o expediere respinsa.
/v1/geo/cities
Localitatile care incep cu textul cautat. Parametri:
q (minim 1 caracter) si
limit (implicit 15, maxim 50).
curl "https://api.postcargo.ro/v1/geo/cities?q=clu&limit=5" \
-H "X-API-Key: pcg_live_..."
Response
{
"success": true,
"data": [
{
"value": "Cluj-Napoca (Cluj)",
"label": "Cluj-Napoca",
"id": 12345,
"county": "Cluj",
"county_id": 14,
"postal_code": "400001"
}
]
}
Trimite label ca oras si
county ca judet cand ceri preţul sau creezi expedierea.
Bucuresti se expediaza pe sector
Pentru q=bucuresti primesti cele
6 sectoare, fiecare cu sector: 1..6, nu orasul generic. Curierii
tarifeaza diferit pe sector, iar o adresa fara sector poate fi respinsa la ridicare.
/v1/geo/counties
Toate judetele, cu numele exact asteptat de API la calculul de preţ si la creare expediere.
Expedieri
/v1/shipments
Creeaza expediere fara generare AWB (status: draft). AWB se genereaza separat (vezi /v1/awb).
{
"courier_code": "fan-courier",
"external_id": "wc_order_1234",
"sender": {
"name": "Magazinul Meu", "phone": "0712345678",
"city": "Bucuresti", "county": "Bucuresti",
"address": "Str Exemplu 10", "postcode": "010101"
},
"recipient": {
"name": "Maria Popescu", "phone": "0723456789",
"city": "Cluj-Napoca", "county": "Cluj",
"address": "Str Aurel Vlaicu 25", "postcode": "400001"
},
"package": {
"type": "colet", "weight": 2.5,
"length": 30, "width": 20, "height": 15,
"value_declared": 250,
"cod_amount": 0,
"content": "Carti, articole personale"
}
}
/v1/shipments
Filtre: ?status=delivered&courier=fan-courier&page=1&per_page=50&from=2026-05-01
/v1/shipments/{id}
Detaliile complete (sender, recipient, package, awb, tracking history).
/v1/shipments/{id}/cancel
Anuleaza AWB-ul la curier si scoate expedierea din facturare. Body optional: {"reason": "Cumparator a anulat"}
Forma echivalenta: DELETE /v1/shipments/{id}. O expediere deja livrata sau anulata returneaza 400 VALIDATION_ERROR.
{
"success": true,
"data": {
"message": "Shipment cancelled",
"awb_cancelled_at_courier": true
}
}
Anularea se face intai la curier. Daca AWB-ul exista, il anulam la curier si abia apoi marcam expedierea cancelled. Cand curierul refuza (coletul e deja preluat, fereastra de anulare a expirat), primesti 502 COURIER_CANCEL_FAILED cu motivul lui, iar expedierea rămâne activa si facturabila.
Facturare. Expedierea anulata iese automat din facturarea consolidata, deci nu apare pe factura urmatoare. Daca era deja pe o factura emisa, raspunsul include billing_note: suma se corecteaza doar prin storno, nu prin anulare.
/v1/shipments/{id}
Acelasi efect ca POST /v1/shipments/{id}/cancel: anuleaza AWB-ul la curier, trece expedierea in cancelled si o scoate din facturare. Nu sterge inregistrarea, ca sa ramana in istoric.
/v1/shipments/{id}/tracking
Starea curenta a expedierii. Daca expedierea nu are inca AWB, raspunsul este 400 VALIDATION_ERROR — genereaza-l intai.
{
"success": true,
"data": {
"awb_number": "1234567890",
"status": "in_transit",
"courier_code": "fan-courier",
"recipient": { "name": "Ion Popescu", "city": "Cluj-Napoca", "county": "Cluj" },
"created_at": "2026-05-03 09:15:00",
"updated_at": "2026-05-03 18:30:00"
}
}
Valori posibile pentru status: draft, pending, awb_generated, picked_up, in_transit, out_for_delivery, delivered, returned, cancelled.
/v1/tracking/{awb}
Aceleasi date, dar cautate dupa numarul AWB in loc de id-ul expedierii. Util cand stochezi doar AWB-ul. Raspunsul este identic cu cel de mai sus.
AWB (Air Waybill)
/v1/shipments/{shipment_id}/awb
Genereaza AWB la curierul ales. Returneaza numarul AWB + calea PDF-ului.
Forma echivalenta, acceptata si ea: POST /v1/awb/{shipment_id}. Daca expedierea are deja AWB, raspunsul este 400 VALIDATION_ERROR.
{
"success": true,
"data": {
"awb_number": "1234567890",
"price": 24.20,
"cost_price": 18.00,
"status": "awb_generated",
"pdf_url": "/v1/shipments/8/awb/pdf"
}
}
/v1/shipments/{shipment_id}/awb/pdf
Returneaza PDF binar al AWB-ului. Headers: Content-Type: application/pdf.
Forma echivalenta: GET /v1/awb/{id}/pdf, unde {id} poate fi id-ul expedierii sau numarul AWB. Ruta cere acelasi header de autentificare ca restul API-ului, deci linkul nu poate fi deschis direct in browser.
Tenant (cont)
/v1/tenant/settings
Datele contului: nume, slug, domeniu, plan, stare si setarile proprii.
/v1/tenant/settings
Actualizeaza datele contului. Planul si starea contului se schimba doar de PostCargo.
{ "name": "Magazinul Meu SRL", "domain": "magazin.ro" }
/v1/tenant/billing
Datele fiscale ale contului si ce mai lipseste pentru a putea emite factura. status.is_complete spune daca poti expedia.
{
"success": true,
"data": {
"billing": {
"billing_company": "MAGAZINUL MEU SRL",
"billing_cui": "14399840",
"billing_reg_com": "J40/1234/2020",
"billing_address": "Str. Exemplu 12",
"billing_city": "Bucuresti",
"billing_county": "Bucuresti",
"billing_postal": "010011",
"billing_iban": "RO49AAAA1B31007593840000",
"billing_bank": "Banca Transilvania",
"billing_email": "facturi@magazin.ro"
},
"status": { "is_complete": true, "missing_fields": [], "missing_labels": [] }
}
}
/v1/tenant/billing
Salveaza datele fiscale. Poti trimite doar o parte din campuri; CUI-ul si IBAN-ul sunt validate (cifra de control), iar prefixul RO din CUI si spatiile din IBAN se normalizeaza automat.
POST /v1/shipments raspunde cu 422 BILLING_DATA_REQUIRED pana cand sunt completate.
{
"billing_company": "MAGAZINUL MEU SRL",
"billing_cui": "RO14399840",
"billing_address": "Str. Exemplu 12",
"billing_city": "Bucuresti",
"billing_county": "Bucuresti",
"billing_iban": "RO49 AAAA 1B31 0075 9384 0000",
"billing_bank": "Banca Transilvania"
}
/v1/tenant/couriers
Lista celor 12 curieri PostCargo cu detalii (logo, descriere, features, pret pornire) si flag is_enabled pentru tenant.
/v1/tenant/couriers/{code}
Activeaza/dezactiveaza un curier pentru contul tau. Body: {"is_active": true}
/v1/tenant/couriers/{code}
Scoate complet curierul din configuraţia contului. Expedierile deja create cu el rămân neatinse.
/v1/tenant/stats
Stats agregate: total expedieri, by status, by courier, ultimele 5.
/v1/tenant/seo
Setarile pentru pagina publica de tracking a coletelor tale (titlu, descriere, widget).
/v1/tenant/seo
Actualizeaza setarile SEO ale paginii de tracking.
Webhooks
/v1/webhooks
Lista webhook-urilor configurate.
/v1/webhooks
Configureaza un webhook care primeste evenimente (shipment.created, shipment.delivered, awb.generated, etc).
{
"url": "https://magazin.ro/postcargo-webhook",
"events": ["shipment.delivered", "shipment.cancelled"],
"secret": "secret_pentru_HMAC"
}
/v1/webhooks/{id}
Sterge webhook-ul. Nu mai primeşti evenimente pe acel URL.
Integrari (publice)
/v1/integrations
Public
Lista pluginurilor disponibile (WooCommerce activ; Shopify, PrestaShop in lucru).
/v1/integrations/woocommerce/info
Public
Versiune curenta plugin, cerinte WP/WooCommerce, marime, data ultimului build.
/v1/integrations/woocommerce/download
Public
Descarca postcargo-shipping.zip direct. Auto-build cand sursa devine mai noua decat .zip-ul cached.