Integrarea a peste 20 de curieri parteneri: ce am învățat

Rulăm în prezent integrări cu peste douăzeci de curieri parteneri – FAN, Cargus, Sameday, DPD, GLS, Dragon Star, Speedy, Econt, MyGLS, DHL Express, DHL eCommerce, NovaPosta, InPost, Meest, Elta, Express One BG, SpeedyBG, OverseasHR, MilspedSerbia, PallEx, DSC, ECSC, Speedex și alți câțiva pe care îi adăugăm la cerere. Niciunul nu implementează același API. Cei mai mulți nu se pun de acord nici măcar asupra felului în care arată o livrare ca structură de date. Câțiva își schimbă endpointurile fără preaviz.

Dacă construiești integrări chiar și cu un singur partener, lecțiile care rămân valabile la douăzeci merită știute de la început.

Întâi standardizezi modelul de statusuri, apoi integrezi

Decizia cu cel mai mare efect pe care am luat-o la început a fost să definim un model standardizat cu 8 statusuri, în care se traduce orice integrare externă. Arată așa: creată, ridicată, în tranzit, în hub, în livrare, livrată, excepție, returnată. Orice partener extern, oricât de barocă i-ar fi taxonomia de statusuri, e normalizat într-una dintre aceste opt stări.

Unii parteneri vin cu peste douăzeci de coduri de status. Alții cu cinci. Unii emit „livrat la vecin” ca status separat; alții îl emit ca notă text liber pe un eveniment generic „livrat”. Fără stratul standardizat, fiecare consumator al datelor din aval – dashboardul tău, portalul de clienți, sistemul de facturare, reconcilierea rambursurilor – trebuie să cunoască ciudățeniile fiecărui partener. Cu stratul standardizat, sistemele din aval consumă un singur model, iar traducerea o împingi în amonte, în stratul de integrare.

Asta e diferența dintre o integrare care durează o săptămână și una care durează o lună – și dintre un sistem pe care îl poți depana în producție și unul pe care nu.

Callbackurile push sunt ținta; pollingul e soluția de rezervă

Cei mai mulți curieri parteneri oferă atât actualizări de status prin webhook (push), cât și un endpoint de interogare a statusului (pull). Unde putem alege, folosim push. Unde partenerul nu oferă push, interogăm după un program care îi respectă limitele de apeluri (rate limits) – de regulă la fiecare cincisprezece minute pentru expedițiile în tranzit, urcând la fiecare două minute pentru expedițiile care ar trebui livrate în fereastra curentă.

Costul ascuns al pollingului: la douăzeci de parteneri și zeci de mii de expediții în curs pe fiecare partener, ajungi repede la un sistem care își consumă cea mai mare parte din CPU întrebând API-uri externe despre schimbări de stare care nu s-au produs. Soluția e pollingul pe grupe: grupezi expedițiile după fereastra de livrare estimată și interoghezi doar grupele în care o schimbare de stare e plauzibilă.

Al doilea cost ascuns: furtunile de reîncercări la depășirea limitelor. Când API-ul unui partener te limitează, o logică naivă de retry agravează problema. Fiecare integrare pe care o rulăm are propriul circuit breaker și propria curbă de backoff, cu parametrii reglați după limitele documentate (și nedocumentate) ale partenerului.

Traducerea codurilor de status e un artefact viu

Tabela de traducere a fiecărui partener – codurile lor către modelul nostru cu 8 statusuri – nu e ceva ce scrii o dată și uiți. Partenerii adaugă coduri noi, le retrag pe cele vechi, schimbă semantica fără să schimbe șirul de caractere și, uneori, încep să emită un cod existent într-un alt context. O dată pe trimestru, undeva în rețeaua noastră de parteneri, se schimbă ceva.

Tratăm tabela de traducere ca pe cod: versionată, trecută prin code review, cu teste de regresie pe payloaduri reale capturate. Când apare un cod nou în producție, integrarea emite o excepție „status nemapat”, care ajunge la operațional într-o oră, nu printr-o reclamație de la client.

Pare greoi până când te arzi cu alternativa – eșecul tăcut în care un status e emis, coletul rămâne blocat într-o stare nemapată și afli despre asta pentru că dashboardul unui client arată un număr de expediții în tranzit care nu s-a mișcat de zece zile.

Cum proiectezi pentru partenerii care nu au API

Trei dintre integrările noastre sunt cu parteneri care nu aveau un API utilizabil când am început. Tiparul care a funcționat: schimb bidirecțional de fișiere CSV prin SFTP, normalizat prin același model cu 8 statusuri, interogat din oră în oră, cu un flux de corecție manuală prin care operaționalul semnalează nepotrivirile evidente. Doi dintre cei trei au lansat între timp API-uri adevărate și am migrat; unul merge în continuare, fără probleme, pe CSV. Ambele fluxuri ajung în același strat standardizat.

Lecția: „nu au API” nu trebuie să fie motivul pentru care o integrare nu se livrează. Standardizat e stratul de integrare, nu partenerul.

Ce se strică la volum mare

La douăzeci de parteneri și câteva milioane de expediții pe lună, cumulat pe toți clienții, modurile de defectare sunt:

  • Deriva schemei – partenerii schimbă tipul unui câmp fără preaviz (string în int, valoare unică în array). Am început să validăm schema pe webhookurile primite și să respingem payloadurile care nu respectă contractul.
  • Instabilitatea autentificării – rotații de tokenuri nedocumentate, resetări ale credențialelor de client după schimbări interne la partener. Fiecare integrare are un monitor de sănătate a credențialelor, care alertează când autentificarea începe să eșueze după un tipar, nu doar pe cereri izolate.
  • Confuzia de fus orar – parteneri care emit UTC amestecați cu parteneri care emit ora locală fără indicator de fus orar, parteneri care trec de la una la alta în funcție de endpoint. Fiecare timestamp e normalizat la granița integrării; nimic din aval nu are încredere într-un timestamp nenormalizat.
  • Eșecuri de idempotență – parteneri care nu deduplică livrarea webhookurilor și emit același eveniment de cinci ori într-un minut. Fiecare webhook are o cheie de idempotență, iar platforma deduplică intern.

Cum arată asta pentru clienții noștri

Când un client CourierManager adaugă un partener în configurația lui, integrarea e deja construită, deja întreținută și deja mapată pe modelul standardizat de statusuri. O activează cu o pereche de credențiale și o regulă de rutare. Nu scrie cod de integrare; nu întreține o tabelă de traducere; nu e trezit la 2 noaptea când un partener scoate un cod de status nou.

Acesta e, de fapt, produsul. Pagina de funcționalități spune „20+ integrări”. Numărul contează pentru că clientul nu trebuie să construiască niciuna dintre ele.


Coordonezi mai mulți curieri parteneri sub un singur brand? Vezi platforma pentru integratori → – aceeași arhitectură care face ca 20+ integrări să fie gestionabile la noi face ca orchestrarea să fie gestionabilă la tine.