Idempotency u plaćanjima: kako sprečiti duplu naplatu
Blog • Web razvoj • • 8 min čitanja

Idempotency u plaćanjima: kako sprečiti duplu naplatu

Autor Autorski tim · DA. Diџital agencija
Ažurirano 29.09.2026
Vreme čitanja 8 min
Sadržaj Pregledajte teme u tekstu

Dupla naplata najčešće ne nastaje zato što je korisnik dva puta namerno platio, već zato što sistem nije siguran šta se dogodilo posle prekida veze, timeout-a ili ponovljenog klika na dugme za plaćanje. Zahtev može stići do payment gateway-a, ali odgovor ne mora stići nazad do vaše aplikacije. Ako server tada pošalje isti zahtev kao potpuno novu transakciju, postoji rizik da će kupac biti terećen dvaput.

Idempotency je obrazac kojim se ponovljeni zahtev za istu poslovnu operaciju obrađuje kao isti zahtev, a ne kao nova operacija. U kontekstu plaćanja to znači da retry posle mrežne greške ne sme automatski da kreira novu naplatu. Umesto toga, sistem koristi jedinstveni idempotency ključ, proverava prethodni rezultat i vraća postojeći ishod ili jasno stanje koje treba dodatno proveriti.

Ovo nije zamena za dobru integraciju platnog sistema. Idempotency je jedan deo pouzdane naplate, uz pravilno upravljanje statusima, webhook događajima, autorizacijom, refundacijama i zaštitom od dvostrukog klika. Za širi kontekst tehničkog povezivanja checkout-a, gateway-a i sajta pogledajte integraciju platnih kartica.

Zašto dolazi do duple naplate

Najopasniji slučaj je neizvesnost posle slanja zahteva. Aplikacija šalje zahtev za naplatu, ali pre nego što primi odgovor dolazi do prekida konekcije. Server tada ne zna da li je:

  • zahtev odbijen pre nego što je stigao do procesora;
  • zahtev prihvaćen, ali je odgovor izgubljen;
  • plaćanje obrađeno, ali je potrebno još vremena za konačan status;
  • došlo do tehničke greške koju treba ponoviti.

Ako se u svim tim situacijama napravi novi payment objekat ili pošalje nova charge instrukcija, drugi zahtev može biti protumačen kao nova kupovina. Sličan problem nastaje kada korisnik više puta klikne na dugme „Plati“, kada mobilna mreža kratkotrajno prekine vezu ili kada frontend ponovi poziv zbog timeout-a.

Važno je razlikovati ponavljanje HTTP zahteva od ponavljanja poslovne operacije. HTTP retry može biti opravdan za bezbedno čitanje podataka, ali naplata menja finansijsko stanje i mora imati dodatnu zaštitu. Sama provera da li je prethodni HTTP poziv vratio grešku nije dovoljna, jer mrežna greška ne govori nužno šta se dogodilo na strani payment provajdera.

Kako radi idempotency ključ

Idempotency ključ je jedinstveni identifikator koji aplikacija šalje uz zahtev za operaciju koja ne sme da se izvrši više puta. Ključ se obično generiše za jedan konkretan pokušaj plaćanja i čuva uz narudžbinu ili payment zapis. Kada provajder primi zahtev sa tim ključem, može da poveže ponovljeni zahtev sa prethodnim pokušajem.

Primer toka izgleda ovako:

  1. Korisnik potvrđuje kupovinu, a vaš backend kreira zapis narudžbine sa internim ID-em.
  2. Backend generiše idempotency ključ za operaciju naplate.
  3. Zahtev se šalje payment provajderu sa iznosom, valutom, referencom narudžbine i ključem.
  4. Ako odgovor stigne, rezultat se čuva u vašoj bazi.
  5. Ako dođe do timeout-a, backend ponavlja zahtev sa istim ključem, umesto da generiše novi.
  6. Provajder vraća prethodni rezultat ili status koji aplikacija treba dalje da proveri, u skladu sa svojim pravilima.

Ključ ne treba generisati iznova pri svakom retry-u. Ako se za isti poslovni pokušaj svaki put napravi novi ključ, sistem više ne može pouzdano da prepozna da je reč o istoj naplati.

Ključ treba vezati za operaciju, ne samo za korisnika

Jedan kupac može legitimno obaviti više različitih kupovina. Zato email adresa, ID korisnika ili broj sesije nisu dovoljni kao idempotency ključ. Ključ treba da predstavlja konkretnu nameru naplate, na primer pokušaj plaćanja za jednu narudžbinu ili jednu autorizaciju određenog iznosa.

Istovremeno, ne treba nekritički koristiti isti ključ za različite operacije. Kreiranje naplate, refundacija i otkazivanje autorizacije imaju različite poslovne efekte i treba ih odvojeno identifikovati. Tačno ponašanje ključa, rok njegovog čuvanja i pravila za ponovljenu upotrebu zavise od payment provajdera, pa ih treba proveriti u aktuelnoj dokumentaciji pre implementacije.

Idempotency nije samo frontend zaštita

Onemogućavanje dugmeta nakon prvog klika jeste korisna UX mera, ali nije pouzdana zaštita od duple naplate. Korisnik može otvoriti dve kartice, poslati zahtev sa drugog uređaja ili ponoviti poziv direktno iz aplikacije. Frontend takođe može izgubiti stanje tokom redirect-a ili osvežavanja stranice.

Zaštita mora postojati na backend-u, na granici između vaše aplikacije i payment sistema. Backend treba da:

  • proveri da li narudžbina već ima uspešnu ili u toku naplatu;
  • spreči paralelno kreiranje više payment pokušaja za istu narudžbinu;
  • čuva idempotency ključ i odgovor provajdera;
  • razlikuje tehnički timeout od potvrđenog neuspeha;
  • ne označava narudžbinu kao plaćenu samo zato što je korisnik vraćen na success URL.

U praksi je često potrebna kombinacija idempotency ključa kod provajdera i jedinstvenog ograničenja u lokalnoj bazi. Na primer, jedna narudžbina može imati najviše jedan aktivan payment pokušaj, dok se istorija prethodnih pokušaja čuva radi provere, podrške i usklađivanja podataka.

Retry logika: kada ponoviti, a kada proveriti status

Retry ne treba da bude univerzalan odgovor na svaku grešku. Bezbedno ponavljanje zavisi od toga da li je prethodni zahtev definitivno odbijen ili je ishod nepoznat.

SituacijaPreporučena reakcija
Validaciona greška, nevažeći iznos ili neispravni podaciNe ponavljati isti zahtev bez ispravke; prikazati ili evidentirati grešku.
Definitivno odbijena karticaNe kreirati automatski novu naplatu; korisniku omogućiti drugi način plaćanja ili novi pokušaj.
Timeout bez poznatog ishodaPonoviti sa istim idempotency ključem ili prvo proveriti status kod provajdera.
Privremena greška provajderaKoristiti ograničen retry sa backoff-om, u skladu sa dokumentacijom provajdera.
Status „pending“ ili asinhrona obradaSačekati webhook ili eksplicitno proveriti status; ne kreirati novu naplatu samo zato što nema konačnog odgovora.

Kod nepoznatog ishoda najvažnije je ne donositi zaključak samo na osnovu lokalnog timeout-a. Pre nego što se pokrene novi pokušaj, sistem može proveriti payment zapis po sopstvenoj referenci ili pozvati endpoint za proveru statusa, ako ga provajder nudi. Ako je plaćanje već uspešno, aplikacija treba da nastavi obradu narudžbine bez nove naplate.

Backoff i granice ponavljanja

Retry mehanizam treba da ima ograničen broj pokušaja, rastući vremenski razmak i jasnu tačku nakon koje se slučaj prebacuje u stanje za ručnu ili asinhronu obradu. Beskonačno ponavljanje može opteretiti i vašu aplikaciju i payment provajdera, a kod pogrešno implementiranih ključeva povećava rizik od dodatnih problema.

Za obradu rezultata nije dovoljno imati samo „uspešno“ i „neuspešno“. Model treba da razlikuje, na primer, inicirano, autorizovano, obrađuje se, uspešno naplaćeno, odbijeno, refundirano i osporeno. Detaljnije objašnjenje ovakvog modela nalazi se u vodiču Payment state machine: pending, paid, failed, refunded i disputed.

Veza između idempotency-ja i webhook događaja

Payment gateway može poslati konačan rezultat asinhrono, nakon što je početni zahtev već završen ili nakon što korisnik napusti checkout. Zato webhook endpoint treba da bude idempotentan na isti način kao i zahtev za naplatu.

Isti webhook može stići više puta, može stići van očekivanog redosleda ili može biti ponovljen nakon privremenog pada vašeg endpoint-a. Obrada treba da koristi ID događaja ili drugu pouzdanu referencu kako isti događaj ne bi dva puta isporučio robu, aktivirao pretplatu ili poslao potvrdu kupcu. Pre promene statusa potrebno je proveriti da li je tranzicija dozvoljena i da li je događaj autentičan.

Webhook ne treba automatski da znači „naplata je uspešna“ samo zato što je zahtev primljen. Potrebno je verifikovati potpis ili drugi mehanizam autentičnosti koji propisuje provajder, zatim proveriti payment ID, iznos, valutu, narudžbinu i očekivani status. Više o tome kako se ovakvi događaji pouzdano primaju i obrađuju pročitajte u tekstu Payment webhooks: kako pouzdano obraditi asinhrone statuse.

Šta treba čuvati u aplikaciji

Idempotency funkcija zavisi od toga da aplikacija može da pronađe prethodni pokušaj i razume njegov ishod. Minimalni model podataka obično uključuje:

  • interni ID narudžbine;
  • interni ID payment pokušaja;
  • idempotency ključ;
  • ID transakcije ili payment objekta kod provajdera;
  • iznos i valutu u trenutku pokušaja;
  • status i razlog neuspeha, ako postoji;
  • vreme kreiranja i poslednje promene;
  • podatke o webhook događajima koji su već obrađeni.

Ove podatke ne treba koristiti za skladištenje punog broja kartice. Podaci kartice treba da se obrađuju kroz mehanizme payment provajdera i odgovarajuće bezbednosne kontrole. Kada je potrebno zapamtiti način plaćanja za buduću kupovinu, relevantna je tokenizacija kartica bez čuvanja broja kartice, ali tokenizacija sama po sebi ne rešava duple zahteve za naplatu.

Praktičan scenario: korisnik vidi grešku, ali je novac rezervisan

Zamislimo da kupac potvrdi porudžbinu. Payment provajder prihvati zahtev, ali odgovor ne stigne do backend-a. Checkout prikaže tehničku grešku i kupac ponovo klikne na „Plati“.

Bez idempotency zaštite, drugi poziv može kreirati novu naplatu. Sa pravilno implementiranim ključem, drugi poziv se prepoznaje kao ponavljanje iste operacije. Aplikacija tada može dobiti prethodni rezultat ili status koji zahteva proveru. Narudžbina se ne označava kao uspešna dok se ne potvrdi odgovarajući payment status, ali se ne šalje ni novi finansijski zahtev naslepo.

Ako kupac ipak vidi rezervaciju ili naplatu, korisnički interfejs treba jasno da prikaže da se status proverava, umesto da ga navodi da odmah ponovi plaćanje. Za složenije checkout tokove, stabilna tehnička osnova sajta i backend-a jednako je važna kao i sam payment API; zato se implementacija često planira zajedno sa arhitekturom izrade sajta, kada je to deo šireg projekta.

Kontrolna lista za implementaciju

  1. Definišite šta je jedna poslovna operacija naplate i kada se generiše ključ.
  2. Generišite idempotency ključ na backend-u i ponavljajte zahtev sa istim ključem.
  3. Uvedite jedinstvenu vezu između narudžbine i aktivnog payment pokušaja.
  4. Razlikujte definitivno odbijanje od nepoznatog ishoda posle timeout-a.
  5. Proverite pravila konkretnog gateway-a: trajanje ključa, ponašanje pri promeni parametara i podržane operacije.
  6. Implementirajte proveru statusa i webhook obradu kao odvojene, ali povezane mehanizme.
  7. Zaštitite webhook endpoint, evidentirajte obrađene događaje i sprečite duplu obradu.
  8. Testirajte prekid konekcije, dvostruki klik, paralelne zahteve, ponovljeni webhook i kašnjenje statusa.
  9. Obezbedite logove i način za rešavanje slučajeva u kojima lokalni i provajderov status nisu usklađeni.

Pravi cilj idempotency-ja nije da svaki problem sakrije od korisnika, već da neizvestan tehnički događaj ne preraste u finansijsku grešku. Kada se ključ, lokalni model statusa, retry pravila i webhook obrada projektuju zajedno, sistem može bezbednije da podnese realne prekide mreže i ponovljene zahteve. Sledeći korak je mapiranje konkretnih payment scenarija u vašoj prodavnici ili aplikaciji i provera kako ih podržava izabrani gateway.

Podelite tekst
LinkedIn X Facebook
DA.
Autor i urednik sadržaja

DA. Editorial Team

SEO, PPC, web razvoj i dizajn tim DA. Tekstove zasnivamo na iskustvu iz aktivnih projekata, Search Console podacima, platformskim promenama i praktičnim testovima.

Google Preferred Sources

Pratite DA. kao izvor koji želite da viđate češće.

Dodajte da.org.rs u svoje Preferred Sources i olakšajte Google-u da vam češće prikaže DA. sadržaj kada je relevantan za vaše pretrage.

Dodaj DA. kao izvor
DA. Web razvoj

Treba vam sajt koji je brz, jasan i spreman za rast?

Od prezentacionih sajtova do custom CMS i web rešenja, gradimo tehničku osnovu za SEO, kampanje i konverzije.

DA. DIGITALNI SAVETNIK

Pitajte DA.

Recite mi cilj, problem ili sledeći potez. Usmeriću vas na relevantan DA vodič ili uslugu.