Payments··7 min read

Integrating Payments Across Stripe and MAIB Without Coupling Your Domain

A provider-agnostic approach to checkout, webhooks, idempotency, and reconciliation, drawn from shipping Stripe and MAIB integrations in production.

By Syed Aasim Shah

Own the payment interface

How do you integrate multiple payment providers without coupling your domain?

Define a small internal payments interface — create charge, capture, refund, handle webhook — and implement it once per provider. The rest of the application talks only to that interface, never to Stripe or MAIB directly.

Across projects like Ajar (Stripe) and Bite.md (MAIB), the pattern that held up was an application-owned payments module. It exposes a handful of operations the domain actually needs and hides every provider-specific detail — API shapes, error codes, signature schemes — behind an adapter.

This keeps provider SDKs out of business logic, makes it possible to add or swap a gateway without touching order or subscription code, and gives you one place to enforce logging, retries, and reconciliation.

Treat webhooks as the source of truth

How should payment webhooks and idempotency be handled?

Verify every webhook signature, make handlers idempotent by keying on the provider event ID, and treat the webhook — not the client redirect — as the authoritative signal that a payment succeeded.

Clients drop connections, close tabs, and double-submit. The redirect back from a checkout page is a hint, not a fact. The payment is only real when the verified webhook says so, so order fulfilment and subscription state are driven from webhook handlers.

Every handler records the provider event ID before doing work and ignores IDs it has already processed. That makes redelivery safe, which both Stripe and MAIB will do, and it prevents a retried webhook from charging twice or granting access twice.

Reconcile instead of trusting

Why do you need payment reconciliation?

Periodically compare your records against the provider's list of charges and refunds. Reconciliation catches missed webhooks, partial failures, and disputes that would otherwise silently desync your billing state.

Even with verified webhooks, events get missed — an outage, a deploy at the wrong moment, a handler bug. A scheduled job that pulls the provider's recent transactions and diffs them against local records surfaces those gaps quickly.

The same job is where refunds, chargebacks, and currency or fee adjustments get folded back into reporting, so finance numbers match the gateway dashboard rather than drifting from it over time.

References

Related reading

Need this built? See services or start a project.

← Back to all posts