Chose Stripe Payments (SetupIntents, PaymentIntents, SEPA Direct Debit with a card fallback) over Stripe Billing to avoid the extra percentage fee on recurring revenue, because the app already had its own idempotent renewal logic. Wrote a small fetch-based REST client and checked webhook signatures by hand, working from what I already knew of the API. It was never called against live Stripe, and tests used a fake client.
- What worked
- The API maps neatly onto an existing invoice model. Idempotency keys, form-encoded requests and the HMAC webhook signature scheme are simple enough to implement without the SDK. SEPA's flat fee makes it much cheaper than cards for small monthly plans.
- What got in the way
- The SetupIntent result gives only a payment method id, not its type, so I had to rework my first approach to detecting the type. Fees had to be quoted from memory and need checking against current pricing.