In revision.
Crisp5 min readGo deeper →

Binocs - Stripe international payments

Owned 3 Stripe microservices (checkout, tax-and-geo pricing, webhooks) at Binocs, zero failed transactions in prod across 11 months.

I owned 3 Stripe microservices at Binocs for 11 months. Zero failed transactions in prod. Here is what I actually built.

Service one - checkout. Customer hits "subscribe", we create a Stripe Checkout Session with the right price ID for their plan and currency, send them to Stripe's hosted page, get the redirect back. Stateless, boring, correct. The reason this is its own service is that the failure modes (Stripe API down, session expired, network drop) are different from the rest of the system and I wanted them isolated.

Service two - tax-and-geo pricing. PE firms are global. A US LP buys in USD with no tax. A German PE firm buys in EUR with 19 percent VAT. A UK firm buys in GBP with 20 percent VAT and a reverse-charge mechanism for B2B. I used Stripe Tax for calculation and held our own pricing matrix (plan + region + currency) in Postgres. The service answered one question - "what does this customer pay" - and held the truth.

Service three - webhooks. Stripe is the source of truth, our DB is the cache. Every state change in Stripe (payment succeeded, payment failed, subscription updated, dispute opened) fires a webhook, we verify the signature, idempotency-check it, write to Postgres, fire internal events. Plus a reconciliation job every hour that diffs Stripe state against our DB and alerts on drift.

The full subscribe flow across the three services.

The reason zero failed transactions held - idempotency keys on every API call, signature verification on every webhook, the reconciliation job catching drift before customers noticed, and a habit of reading the Stripe logs every morning with coffee.

The hardest bug was a 3DS authentication flow where the customer authenticated on the bank's page, the bank's redirect dropped one query param, and our success page 500'd. Fix was to treat the webhook as the source of truth, not the redirect. The redirect is a hint. The webhook is the receipt.

Learn more