Public Beta — Free forever tier

One URL. Any provider.
Route everywhere.

Stripe, GitHub, Shopify — point them all at one endpoint. JQ rules decide where each event goes: production, staging, or localhost:3000 via a built-in tunnel that never expires.

Stripe
GitHub
WhatsApp
Shopify
Twilio
Relayers
Production API
Staging Server
localhost:3000
<0ms
p95 ingest-to-delivery
Free forever tier
Open source CLI
Self-hostable
The problem

Webhooks break silently

You find out when a customer complains, not when the event 404s.

critical
01

The Tunnel Treadmill

ngrok free URLs rotate every 2 hours. You restart the tunnel, update the webhook URL in Stripe, and miss the 3 events that fired in between.

ERR tunnel session expired — 3 events lost
    stripe: 402, 402, 402
high
02

Integration Spaghetti

Stripe points at one URL, GitHub at another, Shopify at a third. Each has its own retry logic, error handling. One breaks — you find out days later.

WARN stripe endpoint → 502 (since 3d)
     0/47 events delivered
critical
03

The Debugging Black Hole

A charge.failed event fired at 2am. Was the payload malformed? Did your handler throw? The provider doesn't store request bodies. You'll never know.

GET /events/evt_3f8a2c/body
    404 — payload not retained by provider

Receive. Route. Transform. Deliver.

From POST to delivery in under 50ms. Here is the entire flow.

1
Step 1

Receive

Give every provider a stable endpoint URL. Relayers resolves the target endpoint from an immutable public ID.

POST https://api.relayers.app/v1/webhooks/wep_1234567890abcdef1234567890abcd
2
Step 2

Route

Write a JQ expression. If it returns true, the rule fires. Match on body, headers, or query params.

.headers["x-github-event"] == "push"
3
Step 3

Transform

Reshape the payload before it hits your service. Flatten nested objects, convert units, strip fields.

{event: .type, amount: .data.object.amount / 100}
4
Step 4

Deliver

Public URL, internal service, or localhost — all in the same rule set. Tunnels connect over WebSocket, no port forwarding.

wr tunnel --port 3000

Your webhook control plane

Every event logged. Every delivery traced. Every payload inspectable.

Endpoint Configuration

Use a generated public webhook URL for providers and keep a friendly slug for internal organization. Each endpoint tracks its own rules, destinations, and delivery stats.

app.relayers.app/endpoints/stripe-prod
Stripe Production
/stripe-prod
active
3
Rules
1,247
Events today
99.8%
Success rate

Event Inspector

Full request and response bodies for every event. Filter by status, search by payload content, replay failed events with one click.

app.relayers.app/events
ID
Type
Status
Time
evt_1a2b3c
invoice.paid
delivered
2s ago
evt_4d5e6f
push
delivered
15s ago
evt_7g8h9i
charge.failed
retrying
1m ago
evt_0j1k2l
message.received
delivered
3m ago

Delivery Timeline

Every delivery attempt logged with HTTP status, response time, and body. See exactly why attempt 1 returned 500 and attempt 3 succeeded.

app.relayers.app/events/evt_1a2b3c
Attempt 1500
120ms14:32:01
Attempt 2500
145ms14:32:31
Attempt 3200
89ms14:33:31

Transformation Editor

Write JQ, see input/output side by side. Test against real payloads before deploying. No guessing, no deploy-and-pray.

app.relayers.app/transformations/simplify-stripe
JQ Expression
{event: .type, amount: .data.object.amount / 100, currency: .data.object.currency}
Input
{"type": "charge.succeeded", "data": {"object": {"amount": 2500, "currency": "usd"}}}
Output
{"event": "charge.succeeded", "amount": 25, "currency": "usd"}

Tunnel Dashboard

Every connected daemon: hostname, port, status, last heartbeat. Know instantly if your local environment is receiving events.

app.relayers.app/devices
Hostname
Port
Status
Heartbeat
kled-macbook
:3000
connected
2s ago
ci-runner-01
:8080
connected
5s ago

Real routing rules from real projects

These are actual JQ rules you would write. Copy them.

Route WhatsApp Business API callbacks by message type. Text goes to your local chat handler during dev, media to a cloud processor, every message logged for compliance.

Routing Rule (JQ)

jq
.messages[0].type == "text"

Destinations

Text Handler
localhost:3000/whatsapp/text
tunnel
Media Processor
https://media.example.com/process
Audit Log
https://logs.example.com/whatsapp

Reshape payloads before delivery

Write a JQ expression. The input payload goes in, your custom schema comes out. No adapter code in your service.

Incoming Payload
{
  "type": "charge.succeeded",
  "data": {
    "object": {
      "id": "ch_1abc",
      "amount": 4999,
      "currency": "usd",
      "customer": "cus_xyz",
      "status": "succeeded"
    }
  }
}
JQ Rule
{
  event: .type,
  charge_id: .data.object.id,
  amount: (.data.object.amount / 100),
  currency: .data.object.currency,
  customer: .data.object.customer
}
Transformed Output
{
  "event": "charge.succeeded",
  "charge_id": "ch_1abc",
  "amount": 49.99,
  "currency": "usd",
  "customer": "cus_xyz"
}

Signatures, retries, idempotency, rate limits

The middleware you would write yourself, already running on every event.

Signature Verification

HMAC-SHA256, SHA-1, and SHA-512 validated on ingest. Invalid signatures return 401 before your rules even see the event.

Automatic Retries

Exponential backoff with jitter. Configure max attempts and interval per rule. A 500 on attempt 1 retries at 30s, 1m, 2m, 4m — up to your limit.

Idempotency

Set a dedup window per endpoint. Relayers extracts the idempotency key from the payload and discards duplicates before delivery fires.

Rate Limiting

Per-endpoint sliding window. Burst traffic queued in PostgreSQL-backed jobs, not dropped. When the window opens, events deliver in order.

Feature comparison

Relayers is the only webhook router with native localhost tunnels and JQ-based routing. Others charge $39-$490/mo for less.

FeatureRelayersHookdeckSvixConvoy
Receive + Route + DeliverSend only
Built-in localhost tunnelsCLI add-on
JQ routing rules
Payload transformationsJS only
Self-hostable
Starting priceFree$39/mo$490/mo$99/mo

Built-in tunnels

WebSocket tunnels to localhost. No ngrok, no expiring URLs. Run `wr tunnel --port 3000` and receive events locally.

JQ everywhere

One language for routing, filtering, and transformations. If you can write a jq pipe, you can configure Relayers.

Multi-tenant ready

Isolated tenant workspaces with scoped API keys. Each team gets its own endpoints, rules, and event history.

Your first endpoint takes 30 seconds

Sign up, create an endpoint, paste the URL into Stripe. That is it. No credit card required.