Musteriye iade ettim ama para ulasmadi — Stripe charge.refund.updated webhook (PR #626 GGG F2)
Izmir Karsiyaka Bostanli Sahil 40-yas Karsiyaka Boyoz + Lokma 38-cover 9-yil Ege geleneksel kahvalti + Izmir boyoz + lokma sahibi Damla thMenu Platinum 17 ay. Sabah 09:00 Karsiyaka kahvalti yogunluk. Aysu Hanim gecen Pazar siparis mantarli omlet icin iade istemis 12 gun kart kontrol iade ulasmadi. Damla saskin admin dashboard Order #4827 ₺125 mantarli omlet + simit + cay Status: refunded Refunded At: 2026-05-12 11:42 12 gun once iade gozukuyor. Stripe Dashboard Refund ID rf_3PqXyz Status: failed Failure Reason: card_account_closed Aysu card hesabi kapatilmis Stripe pending → card-issuer rejection refund failed para Stripe ana account merchant balance +₺125 musteriye ulasmadi. Damla Aysu Hanim aciklama Stripe banka ulasamamis hesap kapanmis duzeltecegim yeni hesap bilgisi. Support yazdi Stripe refund failed thMenu dashboard order hala refunded musteri parasini alamadi panel iade tamam. Engineering 3 yanlis teori (1) refund flow RIDS double-write order POST refund handler /api/orders/[id]/refund Stripe API refunds.create success UPDATE orders SET status=refunded dogru calisiyor Stripe pending donuyor thMenu refunded sonra webhook status surface; (2) Stripe pending refund refunded yanlis pending kalmali kismi dogru kullaniciya konfuzyon 5-7 gun bekliyor thMenu pattern Stripe API basarili immediately refunded sonra webhook failed donerse duzelt; (3) Stripe webhook handler bu state gecisini handle etmiyor dogru charge.refund.updated Stripe pending refund nihai status (succeeded failed canceled) ulastiginda default branch silent 200 OK. Adli analiz apps/web-admin/src/app/api/stripe/webhook/route.ts switch case checkout.session.completed + customer.subscription.updated + customer.subscription.deleted + invoice.paid + invoice.payment_failed + charge.dispute.created + charge.refund.created charge.refund.updated YOK. Stripe Dashboard webhook delivery 90-gun 47 charge.refund.updated default branch silent 200 OK 38 status: succeeded idempotent loud log eksik 6 status: failed Aysu vakalari refunded gozukuyor musteri ulasamadi 3 status: canceled refund iptal hala refunded gercekte iade gerceklesmedi. 9 case thMenu state Stripe state uyumsuz musteri parasi merchant balance refunded diyor. Stripe billing UX refund pending → 3 terminal state succeeded card-issuer kabul para customer + failed card-issuer rejection kapali hesap expired card fraud flag + canceled refund manuel iptal. thMenu sadece charge.refund.created pending isaret failure path takip etmiyordu. PR #626 batch GGG F2 3-katmanli fix Layer 1 charge.refund.updated case webhook handler 3 branch (a) status succeeded silent log idempotent [BEACON:refund_succeeded] Logpush; (b) status failed DLT entry refund_failed_restitution + UPDATE orders SET refund_failed_reason WHERE id + operator email refund failed contact customer + customer email your refund could not be processed instructions order status refunded → refund_failed dashboard kirmizi banner; (c) status canceled info-log + DLT info row operator review + UPDATE orders SET status = refund_canceled email yok manual operasyon. Layer 2 UI dashboard Refund Failed kirmizi banner + manual reissue button yeni payment method bilgisi alip yeniden trigger. Layer 3 90-day backfill 9 case 6 failed musterilere outreach alternatif refund method manuel banka + cash refund + 1-ay kafe credit 3 canceled operator review manuel refund flow yeniden. Damla Aysu yeni card + manuel banka transfer ₺125 + ₺25 inconvenience credit Aysu Damla Haniminzdan bekliyordum kahvaltima geliyorum. Damla Twitter 36 saat fix shipped 1.4k. 9 affected restaurant 1-ay Pro/Platinum credit. Beatriz Porto Ribeira Cafe da Praca 42-cover Portuguese tapas + port wine 7-yil Joao Caixa Geral de Depositos rejection paralel ayni fix 1-ay Pro credit. Pattern Stripe pending state terminal state gecisini takip eden ayri event webhook handler explicit handle + idempotent terminal state mismatch reconcile. Stripe pending states refunds.create → pending charge.refund.updated 3 status PR #626 GGG F2 + charges.create + 3DS → requires_action payment_intent.succeeded/failed CCC F4 + setup_intents.create → processing setup_intent.succeeded/failed yet closed + payouts.create → pending payout.paid/failed Wise parallel. Implementation Stripe pending action Stripe Dashboard webhook coverage tablosu + handler acik branch + terminal state DLT entry / email / status update + UI dashboard banner + manual reissue button + production backfill 90-day cross-correlate + PR template checkbox. PR #626 referans.
thMenu Ekibi
thmenu.com
Faydalı buldunuz mu? Paylaşın.
İlgili makaleler
Müşteri Aboneliğini Düşürünce Eski Özellikler Ne Olur? — SaaS Sessiz Feature-Drift Problemi
Çoğu SaaS abonelik tier’ı düştüğünde tek satır kod çalıştırır ama eski özellikle…
JWT alg-confusion atağı — Supabase HS256'dan RS256/JWKS'e geçince eski verifier'lar neden yıkılır?
JWT header'ı decode etmeyen verifier'lar `alg=none` ve `alg-confusion` saldırıla…
Her bakiye değişikliğinin neden bir 'journal row'u olmalı? — SaaS finansal audit'in temel taşı
SaaS bakiyeleri tek satır UPDATE ile yönetince "drift var ama HANGİ mutasyon yan…