Příliš široká skip-podmínka ve webhooku spolkne reálnou platbu (faktura se nevystaví)
import { Aside } from ‘@astrojs/starlight/components’;
Symptom
Sekce “Symptom”Zákazníkovi se strhne předplatné z karty (banka i brána potvrzují platbu, subscription = aktivní), ale v systému se nevygeneruje faktura. Hromadně postihne účty, které platí mimo „čistý” scénář (vypršelý trial, opožděná aktivace) — desítky plateb bez dokladu, účetní/právní problém.
Root cause
Sekce “Root cause”Handler na invoice.paid měl přeskakovat fakturu za start trialu (0 Kč, jen účetní událost). Skip ale použil i typ události:
const amountPaid = invoice.amount_paid || 0;if (amountPaid === 0 || billingReason === 'subscription_create') { // ← příliš široké break; // nevygeneruje fakturu}Háček: u zákazníka, jehož trial už vypršel, brána při založení subscription strhne plnou částku hned — a ta platba je na faktuře s billing_reason='subscription_create' (amount_paid > 0). Plošný skip podle subscription_create tedy spolkl i tyhle reálné platby. Čistý scénář (nový trial → 0 Kč subscription_create → skip → za 14 dní subscription_cycle s platbou) fungoval, takže bug zůstal dlouho skrytý.
Fix
Sekce “Fix”Skipovat výhradně podle částky:
if (amountPaid === 0) { // jen skutečné 0 Kč trial-start události break;}// jinak vygeneruj fakturu (subscription_create s platbou i subscription_cycle)Náprava existujících: dohledat v lozích/bráně všechny přeskočené subscription_create faktury, které byly reálně zaplaceny (amount_paid > 0), a pro ty bez dokladu fakturu zpětně vygenerovat (idempotentně přes unikátní stripe_invoice_id). Re-trigger lze udělat podepsaným re-POSTem původní webhook události na endpoint.
Jak se tomu vyvarovat v jiných systémech
Sekce “Jak se tomu vyvarovat v jiných systémech”- Detection: grep webhook logů na „skip”/„ignored” u platebních událostí; pro každou přeskočenou ověř v bráně
amount_paid. Cross-check: počet zaplacených subscription faktur v bráně vs. počet vystavených dokladů v systému — rozdíl = spolknuté platby. - Anti-pattern: skip platebního webhooku podle
billing_reason/event.type/ názvu plánu místo podle reálné částky; předpoklad „subscription_create = vždy trial = 0 Kč”. - Lepší přístup: rozhodnutí „vystavit doklad?” odvozuj jen od
amount_paid > 0. Přidej smírčí kontrolu (reconciliation) — pravidelně porovnej zaplacené faktury v bráně s vystavenými doklady a alertuj na rozdíl.
Sister bugs / související
Sekce “Sister bugs / související”Patří k rodině „webhook tiše spolkne kritický krok” — viz [[silent-constraint-rejection-error-as-value]]. Vždy: u peněz nikdy nespoléhej na typ události, ale na potvrzenou částku, a měj reconciliation.