API, webhooks և backend Տեխնիկական քեյս Հրապարակվել է July 14, 2026 8 րոպե ընթերցում

Քեյս. Laravel և Django վճարային backend՝ webhooks-ով և վերադարձներով

Ինչպես նախագծել payment backend, որը դիմանում է կրկնվող իրադարձություններին, ցանցային խափանումներին և ձեռքով գործողություններին՝ առանց պատվերը կրկին մատուցելու:

Քեյս. Laravel և Django վճարային backend՝ webhooks-ով և վերադարձներով

Հոդվածի ֆոկուսը

Քեյս. Laravel և Django վճարային backend՝ webhooks-ով և վերադարձներովAPI, webhooks և backendLaravel payment gateway ArmeniaDjango payment integration Armeniapayment webhook

Սկզբնական խնդիր. մեկ contract պատվերի և provider-ի միջև

Backend-ը չպետք է provider-ին փոխանցի browser-ից կամայական գումար կամ փոխի պատվերը առանց ստուգելի payment state-ի:

Order API -> payment attempt -> provider checkout
Laravel-ը կամ Django-ն ներքին պատվերի վիճակը պահում է արտաքին վճարման վիճակից առանձին:

Սերվերը վավերացնում է պատվերը, գումարը, արժույթը և թույլատրելի գործողությունը, ապա ստեղծում է payment attempt ներքին id-ով և idempotency key-ով: Միայն դրանից հետո է ձևավորվում անվտանգ checkout URL:

Ներքին order id-ն, payment attempt id-ն և provider payment id-ն պահվում են միասին: Սա անվտանգ է դարձնում կրկնվող հարցումները և հեշտացնում է աջակցման ու հաշվառման որոնումը:

  • Frontend-ից եկած վերջնական գումարին չվստահել:
  • Order-ը, payment attempt-ը և refund-ը պահել առանձին էություններ:
  • Արժույթն ու կլորացման կանոնները ֆիքսել backend-ում:
  • Նույն idempotency key-ի համար վերադարձնել նույն create-payment արդյունքը:

Լուծումը. state machine և idempotent webhook handler-ներ

Webhook-ը կարող է գալ մի քանի անգամ, return URL-ից հետո կամ այլ հերթականությամբ, ուստի բիզնես վիճակը փոխվում է միայն թույլատրելի անցումներով:

Pending -> paid or failed -> refund review
Յուրաքանչյուր իրադարձություն ստուգվում, պահվում և գնահատվում է թույլատրելի անցումների աղյուսակով:

Backend-ը ստուգում է ստորագրությունը, գումարը, արժույթը, correlation id-ն և աղբյուրը, ապա որոշում է՝ արդյոք ստացված անցումը թույլատրելի է: Ուշացած failed callback-ը չի կարող փոխարինել paid-ին, իսկ կրկնվող paid-ը չի կարող կրկին մատուցել պատվերը:

Laravel job-ը կամ Django worker-ը երկրորդային գործողությունները կարող է կատարել ասինխրոն՝ ծանուցում, CRM sync, ֆիսկալ գործողություն կամ հասանելիության բացում: Կրիտիկական webhook պատասխանը մնում է արագ:

  • Պահել raw event-ը և նորմալացված ստուգման արդյունքը:
  • Webhook ընդունումը առանձնացնել ծանր ֆոնային գործողություններից:
  • Չլուծված անհամապատասխանությունների համար կիրառել retry policy և manual review:
  • Հաստատված paid-ից առաջ անդառնալի գործողություն չկատարել:

Գործարկումից հետո. վերադարձներ, դիտարկելիություն և հաշտեցում

Թիմին անհրաժեշտ է payment attempts-ի, refunds-ի, retries-ի և provider report-ի տարբերությունների գրանցամատյան:

Payment ledger -> webhook log -> reconciliation report
Յուրաքանչյուր գործողություն որոնելի է ներքին id-ով, արտաքին id-ով և correlation id-ով՝ առանց զգայուն տվյալների բացահայտման:

Վերադարձը սկսվում է սկզբնական վճարման, հասանելի գումարի և օպերատորի դերի ստուգումից: Request-ից հետո backend-ը ստեղծում է առանձին refund record և վերջնական արդյունքը հաստատում է նույն անվտանգ կարգավիճակի մեխանիզմով:

Կառուցվածքային լոգերը, հերթերի մետրիկաները և provider report-ի ամենօրյա հաշտեցումը բացահայտում են ոչ միայն API սխալները, այլ նաև provider-ում անցած, սակայն ներքին համակարգ չհասած վճարումները:

  • Չլոգավորել քարտային տվյալներ կամ գաղտնիքներ:
  • Օպերատորին տալ որոնում ըստ order id-ի, payment id-ի և correlation id-ի:
  • Առանձնացնել նախաձեռնված և հաստատված վերադարձները:
  • Webhook retries-ն ու manual review խնդիրները դիտարկել առանձին:

FAQ

Արդյո՞ք պետք է payment attempt, եթե պատվերն արդեն կա:

Այո: Պատվերն ու payment attempt-ը տարբեր կյանքի ցիկլեր ունեն. մեկ պատվերը կարող է ունենալ մի քանի փորձ, չեղարկում կամ վերադարձ:

Ինչպե՞ս մշակել կրկնվող webhook-ը:

Ստուգել ստորագրությունն ու event id-ն, պահել այն audit-ի համար, ապա կիրառել միայն թույլատրելի idempotent state transition:

Կարելի՞ է CRM sync-ը կատարել webhook-ի ներսում:

Ավելի լավ է արագ ընդունել և ստուգել իրադարձությունը, իսկ CRM sync-ը կատարել կայուն հերթով retry և error logging մեխանիզմով: