Webhook Receiver
Grit ships a hardened webhook receiver: signature verification for Stripe, GitHub, and generic HMAC providers, automatic deduplication on (provider, external_id), and a replay path so retries are always safe.
Reference docs: Webhooks →
Verify signatures
Reject forged calls — Stripe, GitHub, and generic HMAC verifiers ship in the box.
Dedup events
A unique (provider, external_id) index makes duplicate deliveries a no-op.
Replay safely
Re-process a stored event without asking the provider to resend it.
Handle the payload
Map a verified event to your domain logic — fulfil orders, sync repos, notify users.
What is a webhook?
A webhook is an HTTP request a third party sends to you when something happens on their side — a Stripe payment succeeds, a GitHub branch is pushed, a Twilio message is delivered. Instead of you polling their API, they push the event.
Verifying the signature
Providers sign each request with a shared secret. Grit recomputes the signature over the raw request body and compares it in constant time. A mismatch is rejected with 401 before any handler runs.
HMAC(secret, body). Only someone who knows the secret can produce a valid code for a given body, so a matching HMAC proves the request is authentic and unmodified.// Grit verifies before dispatch; you just register the secret.
// Stripe: Stripe-Signature header, secret = whsec_...
// GitHub: X-Hub-Signature-256 header, secret = your webhook secret
// Generic: X-Signature header = hex(hmac_sha256(secret, rawBody))
if !verify(provider, rawBody, signatureHeader, secret) {
c.JSON(401, gin.H{"error": "invalid signature"})
return
}Dedup & replay
Every verified event is stored with the provider's own event id. A unique index on (provider, external_id) means a duplicate delivery is silently ignored — the handler runs exactly once.
// First delivery -> insert row, run handler
// Retry / duplicate -> insert hits the unique (provider, external_id)
// index, is skipped, handler does NOT run again
//
// Replay (manual) -> re-run the handler against the STORED payload,
// no call back to the provider requiredPractice
Challenge: Send a forged request
POST a fake JSON body to your webhook endpoint with no (or a wrong) signature header. What status code do you get? Confirm no handler logic ran.
Challenge: Use the Stripe CLI
Run stripe listen --forward-to localhost:8080/api/webhooks/stripe and trigger a test event. Does it verify and process? Find the stored event row in GORM Studio.
Challenge: Force a duplicate
Replay the same Stripe event id twice. Confirm the handler ran only once. Which column enforces that?
Challenge: Replay a stored event
Trigger a replay of a previously received event. Did your handler re-run against the stored payload? Why is replaying from storage safer than asking the provider to resend?
Enjoying the course?
Help us grow, star us on GitHub, subscribe on YouTube, and follow on LinkedIn.
