Payment state machine: pending, paid, failed, refunded i disputed
Blog • Web razvoj • • 8 min čitanja

Payment state machine: pending, paid, failed, refunded i disputed

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

Payment statusi opisuju gde se jedna naplata trenutno nalazi i šta sistem sme da uradi sledeće. Pending ne znači nužno da je novac izgubljen, paid ne znači da treba slepo verovati odgovoru iz browsera, a failed, refunded i disputed imaju različite posledice po porudžbinu, korisnika i finansijsko izveštavanje.

Najpraktičnije je posmatrati plaćanje kao state machine, odnosno skup dozvoljenih stanja i prelaza između njih. Takav model sprečava da aplikacija isporuči robu za neuspešnu naplatu, prikaže porudžbinu kao plaćenu pre konačne potvrde ili dvaput izvrši istu poslovnu akciju. Kod implementacije kartičnog plaćanja treba razdvojiti status kod payment provajdera od internog statusa porudžbine i precizno definisati kako se oni usklađuju.

Šta je payment state machine

State machine za plaćanja ima tri osnovna elementa:

  • stanje – na primer pending ili paid;
  • događaj – na primer uspešna autorizacija, webhook, odbijanje ili zahtev za refundaciju;
  • prelaz – dozvoljena promena iz jednog stanja u drugo.

Važno je da svaka promena ima izvor i vreme. Umesto da se u bazi samo prepiše vrednost status = paid, korisno je čuvati identifikator transakcije, identifikator događaja, izvor promene, iznos, valutu, vreme prijema i eventualnu poruku greške. Tako se kasnije može objasniti zbog čega je porudžbina dobila određeni status.

Ne postoji jedan univerzalan spisak statusa koji svi procesori koriste istim nazivom. Jedan servis može koristiti requires_action, drugi authorized, treći captured ili settled. Zato je dobro napraviti internu normalizaciju: spoljne statuse mapirati na ograničen skup poslovno razumljivih stanja, uz čuvanje originalnog statusa provajdera.

Osnovni payment statusi i njihovo značenje

Pending: obrada još nije završena

Pending označava da ishod plaćanja još nije dovoljno pouzdan da bi se transakcija tretirala kao konačno uspešna ili neuspešna. Razlog može biti čekanje na odgovor procesora, dodatnu autentifikaciju korisnika, asinhronu potvrdu ili internu proveru rizika.

U ovom stanju aplikacija ne bi trebalo da isporuči digitalni proizvod, potvrdi rezervaciju koja mora biti garantovana ili oslobodi robu iz skladišta bez dodatne zaštite. Korisniku treba prikazati jasnu informaciju da se rezultat proverava, uz bezbedan način da se status osveži. Automatsko osvežavanje ne sme da pokrene novu naplatu.

Pending takođe nije dobar signal za beskonačno čekanje. Potrebno je definisati koliko dugo se transakcija smatra aktivnom, šta se dešava kada istekne rok i kako korisnik može da pokuša ponovo. Ponovljeni pokušaj treba povezati sa istom porudžbinom, ali ga ne treba tretirati kao istu transakciju bez odgovarajuće idempotency zaštite.

Paid: naplata je potvrđena

Paid je interno poslovno stanje koje treba postaviti tek kada aplikacija primi pouzdanu potvrdu iz server-to-server kanala ili drugog verifikovanog izvora. Povratak korisnika na success stranicu može biti koristan za korisničko iskustvo, ali ne bi trebalo da bude jedini dokaz da je novac naplaćen.

U zavisnosti od procesa, paid može značiti uspešnu autorizaciju, konačno terećenje kartice ili potvrđenu naplatu prema pravilima konkretnog provajdera. Ako postoji razlika između autorizacije i capture koraka, model treba da je zabeleži. Time se izbegava mešanje rezervisanih sredstava sa stvarno naplaćenim iznosom.

Prelaz u paid treba da bude idempotentan. Ako isti webhook stigne više puta ili se korisnik vrati na stranicu nekoliko puta, kreiranje fakture, slanje digitalnog proizvoda i promena statusa porudžbine moraju se izvršiti najviše jednom. Detaljnije o tom problemu govori vodič Idempotency u plaćanjima: kako sprečiti duplu naplatu.

Failed: pokušaj naplate nije uspeo

Failed znači da konkretan pokušaj nije doveo do uspešne naplate. Uzrok može biti odbijena kartica, nedovoljno sredstava, neuspešna autentifikacija, tehnička greška ili istekla sesija. Nije svaki razlog pod kontrolom aplikacije, pa korisnička poruka treba da bude razumljiva, ali bez nepotrebnog otkrivanja osetljivih detalja.

Treba razlikovati neuspešan pokušaj od trajno zatvorene porudžbine. Jedna porudžbina može imati više pokušaja, od kojih je prvi failed, a naredni paid. Zato se status pokušaja plaćanja i status porudžbine često čuvaju odvojeno. Porudžbina može ostati otvorena za novi pokušaj dok konkretna payment transakcija ostaje failed.

Za retry logiku definišite kada je novi pokušaj dozvoljen, kako se sprečava dvostruko terećenje i koji se podaci prenose u novi payment intent ili sesiju. Automatski retry nije dobar izbor za svaku grešku: ponavljanje nakon tehničkog timeouta zahteva drugačiji tretman od ponavljanja nakon jasnog odbijanja.

Refunded: sredstva su vraćena

Refunded označava da je pokrenut i, u poslovnom smislu, obrađen povraćaj novca. Međutim, refundacija može biti parcijalna ili potpuna, a vreme kada će sredstva postati vidljiva korisniku zavisi od procesora i banke. Zato je korisno čuvati originalni iznos, refundirani iznos, preostali iznos za refundaciju i identifikator refundacije.

Za parcijalnu refundaciju bolji model nije jednostavno prepisivanje statusa u refunded. Može se koristiti status partially_refunded ili izvedeno stanje na osnovu zbirnog iznosa refundacija. Više refundacija mora imati zaštitu od duplog izvršavanja, naročito kada refund zahtev može da bude ponovljen posle timeouta.

Refundacija takođe ne treba automatski da briše finansijski trag. Porudžbina, payment pokušaj i refund događaj imaju različite uloge u izveštavanju. Za preciznije usklađivanje sa settlement izvodima i finansijskim sistemom pogledajte tekst Settlement i reporting: šta backend treba da čuva za finansije.

Disputed: korisnik ili banka osporavaju naplatu

Disputed nije isto što i failed ili refunded. Dispute nastaje nakon naplate, kada korisnik ospori transakciju ili banka pokrene postupak prema pravilima kartične šeme. Novac može biti privremeno povučen, a trgovac dobija rok i proceduru za odgovor. Ishod može biti prihvaćen spor, uspešna odbrana ili druga odluka procesora.

U ovom stanju ne treba tiho menjati originalnu porudžbinu u failed. Dispute je zaseban finansijski događaj koji treba povezati sa originalnim payment ID-jem, iznosom, razlogom, rokovima i statusom odgovora. Poslovne odluke, poput blokiranja naloga ili obustave isporuke, treba donositi prema pravilima konkretnog proizvoda, a ne samo na osnovu jedne oznake.

Primer dozvoljenih prelaza

Jedan jednostavan model može izgledati ovako:

Trenutno stanjeDogađajSledeće stanjeNapomena
createdPokušaj je započetpendingČeka se potvrda ili dodatna akcija
pendingVerifikovana potvrda naplatepaidPokrenuti jednokratne poslovne akcije
pendingOdbijanje ili istekfailedDozvoliti novi pokušaj prema pravilima
paidOdobrena potpuna refundacijarefundedSačuvati refund događaj
paidPokrenut disputedisputedPratiti rok i ishod postupka
disputedUspešna odbranapaidOriginalna naplata ostaje validna

Ovo je samo ilustracija, a ne obavezna šema. U stvarnoj integraciji mogu biti potrebna dodatna stanja kao što su requires_action, authorized, captured, partially_refunded ili cancelled. Ključna odluka nije broj naziva, već to da su prelazi eksplicitni i da sistem zna koje akcije su dozvoljene u svakom stanju.

Webhook i browser nisu isti izvor istine

Payment tok je često asinhron. Korisnik može zatvoriti prozor, mreža može prekinuti redirect, a provajder može poslati konačan događaj nekoliko trenutaka kasnije. Zbog toga backend treba da prima, proverava i obrađuje webhook događaje, umesto da se oslanja samo na podatke koje browser šalje nakon checkouta.

Webhook handler treba da proveri autentičnost događaja, pronađe odgovarajuću internu transakciju, upiše događaj i bezbedno izvrši dozvoljeni prelaz. Obrada mora biti otporna na ponavljanje, promenu redosleda i kašnjenje. Ne treba pretpostaviti da će svaki događaj stići tačno jednom ili u idealnom redosledu.

Praktične obrasce za prijem, deduplikaciju i obradu ovih događaja možete povezati sa vodičem Payment webhooks: kako pouzdano obraditi asinhrone statuse. Za svaki događaj korisno je imati log sa vremenom prijema, tipom događaja, spoljnim ID-jem i rezultatom obrade, bez beleženja podataka kartice koji nisu potrebni.

Kako modelovati status u bazi

Minimalni model obično treba da razdvoji najmanje tri entiteta:

  • porudžbina – šta korisnik kupuje i da li je poslovni proces završen;
  • payment pokušaj – konkretna autorizacija ili naplata kod provajdera;
  • payment događaj – nepromenljiv zapis o webhooku, refundaciji, disputu ili drugoj promeni.

Na payment pokušaju čuvajte interni ID, eksterni ID provajdera, iznos i valutu, normalizovani status, originalni status provajdera, vreme kreiranja i vreme poslednje promene. Na događaju čuvajte jedinstveni ID za deduplikaciju, tip, payload koji je dozvoljeno arhivirati i rezultat obrade. Osetljive podatke treba ograničiti na ono što je potrebno za rad i usklađenost sistema.

Status ne treba menjati direktnim SQL upisima iz više nepovezanih delova aplikacije. Prelaz može biti centralizovan u servisu ili sloju domena koji proverava da li je promena dozvoljena. Tako je lakše testirati pravila, pratiti greške i sprečiti da UI ili administratorski panel preskoče važnu kontrolu.

Kako statusi utiču na korisničko iskustvo

Poruka korisniku treba da prati realno stanje, ali ne mora da izlaže tehničke nazive. Za pending je prikladno objasniti da se plaćanje proverava i da korisnik ne ponavlja klik bez potrebe. Za failed treba ponuditi konkretan sledeći korak, kao što je provera podataka ili izbor drugog načina plaćanja. Za paid treba prikazati potvrdu tek kada backend ima verifikovan signal.

Administratorski interfejs može prikazivati i normalizovani i originalni status. Operateru su često potrebni payment ID, vreme poslednjeg događaja, iznos, valuta, razlog neuspeha i status refundacije. Korisniku, s druge strane, ne treba prikazivati interne greške, sirove webhook payload-e ili podatke koji mogu ugroziti privatnost.

Testiranje tranzicija pre puštanja u rad

Testovi treba da pokriju više od uspešnog checkouta. Proverite najmanje sledeće scenarije:

  • uspešan prelaz iz pending u paid;
  • ponovljen isti webhook bez dvostruke isporuke ili fakturisanja;
  • webhook koji stiže pre povratka korisnika na sajt;
  • timeout nakon kog nije jasno da li je naplata izvršena;
  • failed pokušaj nakon kog korisnik započinje novi pokušaj;
  • potpuna i parcijalna refundacija;
  • dispute sa promenom ishoda;
  • nepoznat status ili događaj koji aplikacija još ne podržava.

Posebno testirajte da li se nepoznat događaj bezbedno beleži i stavlja na ručnu proveru, umesto da se proizvoljno mapira u paid. Proverite i monitoring: alarm treba da ukaže na neuobičajeno dugo pending stanje, neuspešnu obradu webhooka, razliku između iznosa i veliki broj refundacija ili disputâ.

Kako se state machine uklapa u integraciju platnih kartica

State machine je implementacioni sloj koji povezuje checkout, backend, payment provajdera, porudžbine i finansijsko izveštavanje. Ako se tek definiše arhitektura, važno je unapred dogovoriti koji status pokreće isporuku, koji status dozvoljava refundaciju i gde se proverava autentičnost događaja. Tek nakon toga ima smisla birati konkretne UI poruke i retry tokove.

Za širi pregled tehničkih odluka, granica odgovornosti i povezivanja payment provajdera sa sajtom, pogledajte integraciju platnih kartica. Ako payment tok treba da bude deo novog ili postojećeg korisničkog iskustva, relevantan je i kontekst izrade sajta, posebno kada checkout, korisnički nalog i administratorski deo dele isti poslovni model.

Najkorisniji sledeći korak je da se za konkretan projekat napravi tabela: svi eksterni statusi, njihova interna mapa, dozvoljeni prelazi, izvor istine i akcija koja se izvršava jednom. Takva specifikacija brzo otkriva nedorečenosti pre nego što se pojave kao pogrešna isporuka, duplo terećenje ili neusaglašeno finansijsko stanje.

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. Integracija platnih kartica

Treba vam Integracija platnih kartica kao konkretna usluga?

Pouzdana integracija platnih kartica, 3DS-a, tokenizacije, refundacija i webhook događaja za bezbedno online plaćanje u sajtu, aplikaciji ili web shopu.

DA. DIGITALNI SAVETNIK

Pitajte DA.

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