Note de teren
Inginerie · Martie 2026

Chei de idempotență: cum faci API-urile de plată sigure la reîncercare

O cerere de plată care expiră este cel mai periculos răspuns pe care îl poate da un API. Tranzacția poate să fi trecut sau poate să nu fi trecut — clientul nu are cum să afle. Dacă reîncerci orbește, riști să taxezi clientul de două ori; dacă renunți, riști să pierzi o vânzare care deja a reușit. Cheile de idempotență există tocmai pentru a face această ambiguitate sigură.

O cheie, un singur efect

O cheie de idempotență este un token unic pe care clientul îl generează și îl atașează unei cereri care modifică starea — de obicei un UUID per operațiune logică, trimis într-un antet. Contractul serverului este simplu: prima cerere care poartă o anumită cheie este procesată normal; orice cerere ulterioară care poartă aceeași cheie returnează rezultatul stocat al primei, fără a executa din nou efectul secundar. Clientul este taxat o singură dată, indiferent de câte ori ajunge cererea. Cheia este asociată operațiunii, nu apelului HTTP, astfel încât un checkout și reîncercările lui împart o singură cheie, în timp ce două checkout-uri distincte nu se ciocnesc niciodată.

Generarea cheii pe partea de client este ceea ce face acest mecanism să funcționeze. Dacă serverul ar emite-o, un răspuns pierdut ar lăsa clientul fără tokenul de care are nevoie ca să reîncerce în siguranță. Clientul creează cheia înainte de prima încercare, o păstrează alături de operațiunea în așteptare și o refolosește la fiecare reîncercare până când primește un răspuns definitiv. Abia atunci renunță la cheie și merge mai departe.

Stocarea rezultatelor fără condiții de cursă

Pe server, cheia este asociată unei înregistrări într-un sistem de stocare durabil: amprenta cererii, un status și răspunsul final. Prima cerere inserează acest rând în aceeași tranzacție care efectuează plata, astfel încât cheia și efectul ei se confirmă sau se anulează împreună. Reîncercările concurente — frecvente atunci când un client trimite o a doua încercare înainte ca prima să se termine — sunt serializate printr-o constrângere de unicitate pe cheie; cel care pierde cursa fie așteaptă rezultatul aflat în curs, fie i se cere să reîncerce în scurt timp. De asemenea, calculăm o amprentă a corpului cererii, astfel încât o cheie refolosită cu parametri diferiți să fie respinsă, nu să returneze în tăcere răspunsul stocat greșit.

O reîncercare ar trebui să fie plictisitoare. Dacă reluarea unei cereri poate schimba rezultatul, API-ul nu este gata — este o vulnerabilitate care așteaptă o rețea instabilă.
— Protocore · Inginerie de plăți

Detaliile care mușcă sunt cele operaționale. Cheile au nevoie de o fereastră de retenție suficient de lungă încât să supraviețuiască oricărei reîncercări rezonabile, dar suficient de scurtă încât să mărginească spațiul de stocare — noi le păstrăm 24 de ore și respingem întârziații după acest interval. Înregistrările în curs au nevoie de un timeout, ca o primă încercare prăbușită să nu blocheze cheia pentru totdeauna. Iar întregul mecanism trebuie documentat clar, pentru că un client care nu trimite chei nu primește niciuna dintre protecții. Făcută corect, idempotența transformă cel mai prost obicei al rețelei — pierderea răspunsului după ce munca a fost deja făcută — într-un non-eveniment pe care clientul nu îl vede niciodată.

Ai un sistem de construit?

Spune-ne care e problema. Revenim cu o arhitectură și un plan.

Începe un proiect