Preview: SendMock has no stable release yet. These docs follow develop.
SendMock
Webhooks

Webhooks

How SendMock talks back to your app. The six parts of a webhook, how they fit, and the Webhooks overview screen.

Try it in the demo.

Real services call your app back: Postmark posts inbound email, Twilio posts delivery receipts and incoming SMS, SendGrid posts bounces, Stripe posts payment events. Locally they cannot reach you without a tunnel, and you cannot make them send what you need when you need it. SendMock sends those requests itself, shaped like the provider's and signed the way it signs them.

The Webhooks overview with deliveries over time

What it solves

  • Testing webhook handlers without a public URL or tunnel, and without waiting for the provider.
  • Your production handler, unchanged: the request has the provider's fields, content type and signature.
  • Failures you can fix and replay: every request and your app's answer are logged; replay after the fix. See Recipe: replay a failed webhook.
  • Signature checks: each endpoint has its own secret, which you can rotate to test your verification.
  • Team alerts: send events to Slack, Discord or Teams.

The six parts

PartIsPage
Eventsomething that happened: email.received, sms.status, payment.succeeded, ...Events below
Rule"send these events, when they match this filter, to this endpoint"Rules
Endpointwhere to send (URL, method), how to shape it (template), how to sign it (secret), and retriesEndpoints
Templatethe request's shape: the provider's fields, headers and signatureTemplates
Variablea value a template reads: an auth token, a tenant id, a random idVariables
Deliveryone request SendMock sent, with your app's answer, retries and replayDeliveries
event ──► rule (filter) ──► endpoint ──► template + variables + secret ──► request ──► your app
                                                                               │
                                                             delivery log ◄────┘ (answer, retries, replay)

Some deliveries skip the rule, because the real provider would send them anyway: an SMS's status callback, a number's reply webhook (Numbers), an incoming email's inbound route, and a gateway's payment notification (Gateways). They all land in the same delivery log.

You can also send by hand: Send to webhook on any email, SMS or captured request, or the Composer.

How it connects

Gets fromSends to
events from Mail, SMS, Verify, HTTP Catcher and Paymentsrequests to your app
simulations: Simulate, Reply as recipient, Verify force, payment SimulateDeliveries, the Overview and the bell

Use it

  1. In Endpoints, press Add endpoint, name it, set the URL of your app's handler (for example http://localhost:8000/webhooks/mail), and in the Request tab pick the template your app expects.
  2. Press Send test on the endpoint to check your app answers 2xx.
  3. In Rules, press Add rule, pick the endpoint and the events, and save.
  4. Make the event happen (send an email, an SMS, a payment). The request shows in Deliveries with your app's answer.

Events

EventFires when
email.receivedyour app sent an email to SendMock
email.inboundan incoming email arrived (a simulated reply or forward, or mail to an inbound domain)
email.openedan email was opened in the UI, or an open was simulated
email.clickeda link of an email was clicked in the preview, or a click was simulated
email.delivered, email.deferred, email.bounced, email.complained, email.unsubscribeda delivery outcome was simulated (Outcomes)
email.releasedan email was released to a real SMTP relay
sms.sentyour app sent an SMS or WhatsApp message
sms.statusa message's status changed
sms.openedan SMS was viewed in the UI, or a read was simulated
sms.inboundthe contact replied
verify.started, verify.checked, verify.expiredTwilio Verify activity
push.sent, push.failedyour app sent a push notification through FCM, Expo or OneSignal, or the provider refused it (Push)
http.capturedthe HTTP Catcher recorded a request
payment.*, checkout.*payments were created, succeeded, failed, refunded, disputed; checkouts completed or expired
webhook.faileda delivery used up its retries (useful for alerts)
test.pingSend test on an endpoint

Everything on this screen

The Webhooks overview screen

The first Webhooks screen shows how deliveries are going, live.

  • Range: 24 hours (hourly) or 7 days (daily), and All endpoints or one endpoint. Both are kept in the URL.
  • Stat tiles: deliveries, success rate, p50 and p95 latency, retries and render failures.
  • Deliveries over time: stacked columns for succeeded, retrying and failed, with a tooltip (hover or arrow keys) that adds p50 and p95 latency, and Show as table.
  • By endpoint: deliveries, success-rate meter, latency, retries and top failure codes per endpoint; click a row to narrow the screen to it.
  • Top failure codes: each code or error with its count and share, linking to the failed deliveries.
  • Recent failures: each linking to its delivery.

Signing

SendMock's own JSON follows Standard Webhooks: webhook-id, webhook-timestamp and webhook-signature headers with the endpoint's whsec_ secret, so the official libraries verify it. Runnable examples for the Node, Python, PHP and Go libraries are in examples/webhooks. Provider templates sign the provider's way (X-Twilio-Signature, Mailgun's signature field, Stripe-Signature, ...).

Every control and text, one by one: Webhooks overview in depth.

Customize

From your code

Wait for the delivery an email triggers and check your handler accepted it.

The examples call SendMock's REST API with each language's usual HTTP client and test framework. JavaScript, Go, Java, Rust, Ruby and C# use the small call helper shown under Test helper on their page in Connect your app.

# In your app: email the order confirmation

delivery=$(sendmock webhook deliveries wait --event email.received --timeout 10s --json)

jq -e '.status == "succeeded"' <<<"$delivery" >/dev/null

From the CLI, API and AI

On this page