A webhook ingestion and processing system built with Encore.go, demonstrating Pub/Sub fan-out patterns.
This app has three services:
- ingest — Receives webhooks via HTTP, validates signatures, and publishes events to a Pub/Sub topic.
- processor — Subscribes to the topic, stores all events in Postgres, and exposes a query API.
- notifications — Subscribes to the same topic independently, stores important events (payments, releases, etc.) and provides stats. Demonstrates the fan-out pattern.
Both processor and notifications receive every event, but handle them differently. This is the fan-out pattern — one event published, multiple subscribers process it independently.
- Encore CLI
- Docker (for local Postgres databases)
- Optionally set webhook secrets for signature validation:
encore secret set --type dev,local,pr,prod WebhookSecretStripe
encore secret set --type dev,local,pr,prod WebhookSecretGitHub- Run the app:
encore runThe Postgres databases are provisioned automatically on startup. No manual database setup required.
Open http://localhost:4000 for usage instructions, or http://localhost:9400 for the Local Dashboard. When deployed to Encore Cloud, use the Service Catalog to call endpoints and view traces to see how requests flow between services.
When secrets are configured, incoming webhooks are verified using the official SDKs:
- Stripe — Uses the Stripe Go SDK (
webhook.ConstructEvent) to verify theStripe-Signatureheader. Stripe signs payloads using a timestamp and HMAC-SHA256 signature in the formatt=...,v1=.... - GitHub — Uses the go-github SDK (
github.ValidatePayloadFromBody) to verify theX-Hub-Signature-256header. GitHub signs payloads with HMAC-SHA256, prefixed withsha256=.
Without secrets configured, all webhooks are accepted without signature checks.
# Stripe webhook (without signature validation)
curl -X POST http://localhost:4000/webhooks/stripe \
-H "Content-Type: application/json" \
-d '{"type": "payment_intent.succeeded", "data": {"amount": 2000}}'
# GitHub webhook (without signature validation)
curl -X POST http://localhost:4000/webhooks/github \
-H "Content-Type: application/json" \
-H "X-GitHub-Event: push" \
-d '{"ref": "refs/heads/main", "commits": []}'To test with signature validation, set the secrets and include the appropriate headers:
# GitHub with signature
SECRET="your-github-secret"
PAYLOAD='{"ref":"refs/heads/main"}'
SIG="sha256=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')"
curl -X POST http://localhost:4000/webhooks/github \
-H "Content-Type: application/json" \
-H "X-Hub-Signature-256: $SIG" \
-H "X-GitHub-Event: push" \
-d "$PAYLOAD"For Stripe, use the Stripe CLI to forward and sign webhooks locally:
stripe listen --forward-to localhost:4000/webhooks/stripe
stripe trigger payment_intent.succeededcurl http://localhost:4000/eventscurl http://localhost:4000/events/1curl http://localhost:4000/notificationscurl http://localhost:4000/notifications/statsSee the self-hosting instructions for how to use encore build docker to create a Docker image and configure it.
Deploy your application to a free staging environment in Encore's development cloud using git push encore:
git add -A .
git commit -m 'Commit message'
git push encoreYou can also open your app in the Cloud Dashboard to integrate with GitHub, or connect your AWS/GCP account, enabling Encore to automatically handle cloud deployments for you.
encore test ./...