Composable webhook delivery engine for Go

Relay your webhooks

Event catalog, guaranteed delivery, HMAC signatures, dead letter queues, rate limiting — out of the box.

$go get github.com/xraph/relay
Event
Validate
Fan-Out
api.acme.co
200 Delivered
hooks.stripe.io
503 Retry
notify.svc
422 DLQ
Guaranteed Delivery
HMAC-SHA256
DLQ + Replay
Rate Limiting
Features

Everything you need for webhook delivery

Relay handles the hard parts — retries, signatures, dead letters, rate limits — so you can focus on your business logic.

Event Catalog

Type-safe event registration with schema validation. Define your event types once, reference them everywhere.

catalog.go
r.Catalog().RegisterEventType(
"order.created",
relay.WithSchema(orderSchema),
relay.WithDescription("New order placed"),
)

Guaranteed Delivery

Configurable retry schedules with exponential backoff. No event is lost, ever.

retry.go
relay.WithRetrySchedule(
5*time.Second, "text-fd-muted-foreground/60 italic">// 1st retry
30*time.Second, "text-fd-muted-foreground/60 italic">// 2nd retry
2*time.Minute, "text-fd-muted-foreground/60 italic">// 3rd retry
15*time.Minute, "text-fd-muted-foreground/60 italic">// 4th retry
1*time.Hour, "text-fd-muted-foreground/60 italic">// 5th retry
)

Dead Letter Queue

Failed deliveries are captured automatically. Inspect, debug, and replay them on demand.

dlq.go
items, _ := r.DLQ().List(ctx,
dlq.WithEventType("order.created"),
dlq.WithLimit(10),
)
r.DLQ().Replay(ctx, items[0].ID)

HMAC Signatures

Every payload is signed with HMAC-SHA256. Receivers verify authenticity with a single call.

verify.go
valid := relay.VerifySignature(
payload,
header.Get("X-Relay-Signature"),
endpoint.Secret,
)

Rate Limiting

Per-endpoint token bucket rate limiting protects downstream services from being overwhelmed.

ratelimit.go
relay.WithRateLimit(
100, "text-fd-muted-foreground/60 italic">// requests per second
time.Second, "text-fd-muted-foreground/60 italic">// window
)

Pluggable Stores

Ship with in-memory for dev, swap to PostgreSQL for production. Bring your own store with a simple interface.

main.go
r, _ := relay.New(
relay.WithStore(postgres.New(db)),
relay.WithWorkers(8),
relay.WithLogger(slog.Default()),
)
Delivery Pipeline

From event to endpoint. Automatically.

Relay orchestrates the entire webhook delivery lifecycle — validation, fan-out, delivery, retries, and dead-letter routing.

Schema Validation

Every event is validated against its registered schema before delivery. Malformed payloads never reach your endpoints.

Smart Fan-Out

Events are distributed to all subscribed endpoints in parallel. Each endpoint has independent retry and rate-limit policies.

Decision Matrix

2xx = delivered. 429/5xx = retry with backoff. 4xx = dead letter. 410 = auto-disable endpoint.

Send()
order.created
Catalogvalidate
Fan-Outdistribute
api.acme.co
200 Delivered
hooks.stripe.io
503 Retry ↻
notify.svc
422 → DLQ
Delivered
Retry
DLQ
Disabled
Developer Experience

Simple API. Production power.

Send your first webhook in under 20 lines. Verify signatures on the receiver side with standard crypto.

Sender
main.go
1package main
2 
3import (
4 "log/slog"
5 "github.com/xraph/relay"
6 "github.com/xraph/relay/store/memory"
7)
8 
9func main() {
10 r, _ := relay.New(
11 relay.WithStore(memory.New()),
12 relay.WithWorkers(4),
13 relay.WithLogger(slog.Default()),
14 )
15 
16 "text-fd-muted-foreground/60 italic">// Register an event type
17 r.Catalog().Register("order.created")
18 
19 "text-fd-muted-foreground/60 italic">// Register an endpoint
20 r.Endpoints().Create(ctx, relay.Endpoint{
21 URL: "https:">//api.acme.co/webhooks",
22 EventTypes: []string{"order.created"},
23 })
24 
25 "text-fd-muted-foreground/60 italic">// Send an event
26 r.Send(ctx, relay.Event{
27 Type: "order.created",
28 Payload: orderJSON,
29 })
30}
Receiver
receiver.go
1package main
2 
3import (
4 "crypto/hmac"
5 "crypto/sha256"
6 "encoding/hex"
7 "io"
8 "net/http"
9)
10 
11func webhookHandler(w http.ResponseWriter, r *http.Request) {
12 body, _ := io.ReadAll(r.Body)
13 signature := r.Header.Get("X-Relay-Signature")
14 
15 "text-fd-muted-foreground/60 italic">// Verify HMAC-SHA256 signature
16 mac := hmac.New(sha256.New, []byte(secret))
17 mac.Write(body)
18 expected := hex.EncodeToString(mac.Sum(nil))
19 
20 if !hmac.Equal([]byte(signature), []byte(expected)) {
21 http.Error(w, "invalid signature", 401)
22 return
23 }
24 
25 "text-fd-muted-foreground/60 italic">// Process the verified webhook
26 processEvent(body)
27 w.WriteHeader(200)
28}

Start delivering webhooks

Add production-grade webhook delivery to your Go service in minutes. Relay handles retries, signatures, dead letters, and rate limiting out of the box.

$go get github.com/xraph/relay