(Webhook delivery · Nautilus)

Send Webhooks to Your Customers For SaaS products that send events to their customers' servers

Your product publishes an event with one API call. Nautilus queues it, signs it and delivers it to every endpoint subscribed to that event type. A failed delivery is retried on a fixed schedule, and every attempt appears in your dashboard with the response it got.

curl -X POST https://api.vernesoft.com/v1/relay/messages \
  -H "Authorization: Bearer vrn_relay_•••" \
  -d '{"event_type":"user.created","payload":{"id":"usr_123"}}'

(Build or Buy)

Building a Webhook System Takes a Week. Running It Takes Years.

The first version is a POST request in a retry loop. It stops being simple when a customer's server is down for a weekend, when a handler deploy goes out broken and an hour of events has to be sent again, and when one slow endpoint starts holding up everyone else's.

Building It Yourself

  • ✕ A queue and a backoff schedule you write, run and monitor: Redis, RabbitMQ, or a table with a cron job.
  • ✕ Signing you design yourself: which bytes are signed, how a secret is rotated, how a captured request is kept from being replayed.
  • ✕ No screen for support: when a customer says an event never arrived, an engineer reads logs by hand.
  • ✕ Workers to keep running and monitor, for a feature customers only notice when it breaks.

Webhook Delivery in Nautilus

  • ✓ Automatic retries on a fixed schedule — 8 attempts over about 28 hours.
  • ✓ Every message signed with HMAC SHA-256 and a secret of its own for each endpoint, checkable with the standard Svix libraries.
  • ✓ A delivery log in your dashboard with the response code and body of every attempt, and a button to resend a delivery or replay what failed.
  • ✓ Real uptime history, published on our public status page.

(Core Features)

What Happens to Each Event

(01)

Retries on a Fixed Schedule

A response other than 2xx, or a timeout, counts as a failed attempt. The message is retried at growing intervals: 8 attempts over about 28 hours, the same schedule for every endpoint. Delivery is at-least-once, so a retry can reach your customer's server more than once.

(02)

Signed Messages

Every message is signed with HMAC SHA-256, using a secret that belongs to one endpoint. Each delivery carries three headers (svix-id, svix-timestamp and svix-signature), and the signature covers the id, the timestamp and the body, so your customers can check who sent it and reject a replayed request.

(03)

Your Call Returns Early

Publishing an event returns 202 as soon as the message is queued. Delivery to your customers' servers happens afterwards, so a slow or dead endpoint does not slow the request your own code is waiting on.

(04)

One Event, Every Subscriber

Publish one event, for example user.created, and it is delivered to every endpoint subscribed to that event type. Add a channel to a message to reach only the endpoints listening on it.

(05)

Delivery Log and Replay

Every attempt is recorded with its time, the response code and the response body your server returned, so you can see why a delivery failed. On the Events tab of your dashboard you can resend one delivery, or replay everything that failed since a moment you pick, up to 14 days back.

(06)

Idempotency Keys and Message IDs

Send an idempotency_key and a repeated call returns the original message instead of creating a second one. Delivery itself is at-least-once: a retry can reach your clients again, so they should deduplicate on the svix-id header, which is the same on every attempt for a message.

(Part of Nautilus)

One Account, One Dashboard

Webhook delivery is one part of Nautilus, not a service of its own. It shares an account and a dashboard with sign-in and cron jobs. Sign-in events such as a new registration reach your backend the same way, as signed and retried webhooks.

Your applicationNautilus: signs, retries, logsYour customer's endpoint

(Developer Experience)

Publish an Event in One Call

Publish an event with a single call — through an official SDK for Node, Python, PHP or Rust, or a plain HTTP request when you would rather not add a dependency.

curl -X POST https://api.vernesoft.com/v1/relay/messages \
  -H "Authorization: Bearer $VERNE_RELAY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "subscription.renewed",
    "payload": { "user_id": "usr_987", "plan": "pro_tier" },
    "idempotency_key": "evt_5f3c9a"
  }'

(FAQ)

Frequently Asked Questions

How are webhooks signed?

Nautilus generates a unique secret for each endpoint and signs every outgoing request using HMAC SHA-256. Each delivery carries three headers: svix-id, svix-timestamp and svix-signature. The signature is computed over svix-id, svix-timestamp and the raw body, joined by dots, so the receiving party can verify authenticity and reject a replay. The official Svix libraries check all of it in one call.

What happens if the recipient server is down?

Anything other than a 2xx, and any timeout, counts as a failed attempt. The message is retried on a fixed schedule of growing intervals, 8 attempts over about 28 hours, which spares servers that are still recovering. The schedule is the same for every endpoint and cannot be changed. An endpoint that fails every attempt for five days is disabled, and nothing notifies you, so look at the Events tab now and then. Once your server is back, you can resend failed deliveries from the dashboard, or replay everything that failed since a moment you pick.

Can I use it for local development?

Yes. Expose your local endpoint with a tunnel such as ngrok or Cloudflare Tunnel and add that URL as an endpoint in the dashboard. Use a live key: events sent with a test key are accepted but not delivered. The delivery log lets you inspect every attempt while you test.

Should we just build this ourselves?

You can, and it is far more than a POST: a queue and exponential backoff, per-endpoint secrets and HMAC signing, a way to deduplicate a retried send, and a delivery log your support team can look through when a client says the event never arrived. Nautilus has that list built, and you pay per API request. What you give up is control: the retry schedule is fixed, endpoints are added from the dashboard rather than the API, and the engine underneath is Svix, which is open source if you ever need to run it yourself.

Can my customers add their own endpoints?

Not through the API today. Endpoints are created in the dashboard, so if you want your customers to paste their own URL into your product's settings, that screen is yours to build, and for now someone with dashboard access adds the URL. Publishing events and reading them back are available over the API.

(Get Started)

Send your first signed webhook from a free account

Webhook delivery is one part of Nautilus: the same account and dashboard as sign-in and cron jobs.

What building it costs

The build is not the expensive part. A queue, a retry with backoff and a signing helper is a week's work, and most teams get there without trouble. The expense starts the week after, when a customer says an event never arrived and answering that means reading logs by hand — and it does not stop, because every new customer endpoint is a new way for delivery to fail.

It also spends your attention somewhere that earns nothing. Nobody chose your product because your retries use exponential backoff. But a webhook that quietly stopped arriving is a support ticket, then a refund conversation, then sometimes a customer who leaves. High consequence, no credit — which is the shape of a thing worth buying rather than building.

If you would rather build it, build it: the design is not a secret and we would make most of the same choices. Just cost it as a service you will operate for years, not as a sprint. If you would rather not, an endpoint you already have can be taking signed, retried deliveries as soon as you have an API key and its URL is in the dashboard, and the first 3,000 requests each month are free.