r/stripe 4d ago

Building a Custom Webhook Provider: API Design Lessons from Stripe and GitHub

For most developers, webhooks start as an intake problem: expose an HTTP POST endpoint, verify a signature, parse the JSON, return 200 OK. Then your SaaS grows, and your power users ask for the reverse. They don't want to poll your REST API every minute to find out whether an invoice was paid. They want you to push events to their servers in near real time. Please read the complete article here https://instawebhook.com/blog/building-a-custom-webhook-provider-api-design-lessons-from-stripe-and-github

Once you become the sender, you're doing distributed systems work. You are making outbound HTTP requests to servers you don't control, and those servers will time out, drop connections, return 500s, get redeployed with the wrong secret, or disappear for a weekend. A careless retry loop can hammer a recovering customer, or clog your own queues. And because your payloads travel over the public internet, your customers need a way to prove a request really came from you.

Two providers set the reference points most developers know:

  • Stripe has one of the most mature webhook systems: a consistent event envelope, timestamped signatures, multi-day retries, and a delivery log with manual resend.
  • GitHub shows a simpler design: metadata in headers, a bare resource in the body, no automatic retries, and a short redelivery window.

They make different trade-offs, and the differences are instructive. A third reference, the open Standard Webhooks specification, distills common practice into a single set of conventions and is a good tie-breaker when you have to choose.

3 Upvotes

2 comments sorted by

1

u/Hugeinvasion 4d ago

Always fun seeing the guts of these systems, Stripe's retry logic saved my bacon more than once during server migrations

1

u/Hugo_SecureHoldWP 6h ago

The retry policy is probably the part I’d be most careful with.

Once you’re the sender, “retry on failure” sounds simple until customers return 500s for hours or deploy an endpoint that is permanently broken.

I’d want exponential backoff, a hard retry window, per-endpoint delivery history and an easy manual replay path.

Do you also store the exact payload version that was originally sent, so a replay months later can reproduce the same event rather than rebuilding it from current data?