> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Test webhooks with the Webhook Tester

> Fire a test event at your endpoint from the dashboard, inspect the status code, headers, and body your server returns, and pre-diagnose signature failures before you register a real subscription.

# Test webhooks with the Webhook Tester

The Webhook Tester sends a synthetic event to any HTTPS URL you control and shows you exactly what came back — the status code, response headers, response body, and round-trip time for each attempt. Use it when you're building a new receiver and want to iterate on payload shape and response handling before you register a real endpoint.

Two facts to know up front:

* The tester delivers through Orbit's dispatcher, so the HTTP POST reaching your server is real — your URL must be publicly reachable over HTTPS.
* Test sends are **unsigned**. Registered endpoints get full `X-Orbit-Signature` HMAC headers; the tester has no endpoint secret, so it cannot sign. If your receiver rejects unsigned requests, the tester will return a 401/403 — see the signature checklist below.

## Open the tester

In the dashboard, go to **Developer → Webhook Tester**.

The page header carries a "Test mode — signatures not computed" badge. That badge is the reminder that everything you fire from this page is unsigned.

## Pick an event type

The event dropdown lists the supported event types, grouped by category:

| Category | Event types                                           |
| -------- | ----------------------------------------------------- |
| Messages | `message.sent`, `message.delivered`, `message.failed` |
| Voice    | `call.initiated`, `call.completed`                    |
| Other    | `agent.response`, `contact.created`                   |

Selecting a type pre-fills the payload editor with that event's example payload — the same envelope shape the dispatcher emits in production, with `id`, `type`, `created_at`, and a `data` object specific to the event. The pre-fill is a starting point: edit any field before you send. Switching event type replaces the editor contents with the new example unless you've already edited the payload.

For the full envelope schema and every header a registered delivery carries, see [Event payloads](/webhooks/event-payloads). For every `type` value you can subscribe to, see the [events catalog](/webhooks/events).

## Send a test and read the result

1. Paste your endpoint URL into the URL field. It must be HTTPS and publicly reachable — URLs that resolve to private or internal addresses are rejected.
2. Pick the event type and edit the payload if needed.
3. Click **Send**.

Each attempt lands in the history panel on the right, newest first. For every send you see:

* **Status** — the HTTP status code your endpoint returned (`200`, `401`, `404`, …). A transport failure (unreachable host, timeout, TLS error) shows as an error instead of a status.
* **Response time** — round-trip milliseconds.
* **Response headers** — every header your server returned.
* **Response body** — the raw body, pretty-printed when it's JSON.

The history keeps your last 10 attempts in the browser, so you can refresh or close the tab without losing results. Use **Clear** to reset the list.

Read the failures by status:

* **2xx** — your endpoint accepted the event. Green light.
* **404** — your server answered but no route matched the path. The URL path is wrong — check exactly which path your receiver listens on. A 404 is never a signature problem.
* **401 / 403** — your endpoint rejected the request. The common cause: your receiver verifies the signature and the tester's send is unsigned. Work through the checklist below.
* **Other non-2xx** — your handler rejected or errored on the payload. The response body in the history panel usually says why.

## Signature-verification checklist

If your receiver already verifies signatures, an unsigned test send will fail verification by design. Run this checklist before assuming the tool — or your endpoint — is broken:

1. **Expect the tester to fail signature checks.** No endpoint secret exists for an ad-hoc URL, so no `X-Orbit-Signature` header is attached. A verification-first receiver correctly returns 401/403.
2. **To test the signature path itself, use the signed Test action on a registered endpoint.** Register the URL under **Settings → Webhooks**, copy the cleartext `whsec_...` secret shown once at registration, then use that endpoint's Test action — registered deliveries are signed with your secret and exercise your full verification logic.
3. **Verify against the raw body.** The HMAC is computed over the exact bytes received. A JSON middleware that parses the body before verification changes the bytes and fails the check.
4. **Check the timestamp window.** Reject signatures older than 5 minutes — but verify your server's clock is sane first; a skewed clock rejects every delivery.
5. **Compare timing-safe.** Use your language's constant-time comparison (`crypto.timingSafeEqual`, `hmac.compare_digest`) so a signature mismatch is never distinguishable by response time.

The full signature format, verifiers in seven languages, and the rotation grace header are on [Webhook security](/webhooks/security).

## Worked example — send `message.delivered` and parse the response

You have a receiver that returns a JSON ack. Here's a complete pass through the tester:

1. Open **Developer → Webhook Tester**.
2. Enter your URL: `https://yourapp.com/webhooks/orbit`.
3. Select **message.delivered**. The editor pre-fills:

```json theme={null}
{
  "id": "evt_d4e5f6g7h8",
  "type": "message.delivered",
  "created_at": "2026-03-08T14:30:05Z",
  "data": {
    "message_id": "msg_abc123",
    "channel": "sms",
    "to": "+14155552671",
    "status": "delivered",
    "delivered_at": "2026-03-08T14:30:05Z"
  }
}
```

4. Click **Send**.
5. Your endpoint acked, so the history shows a new entry with status `200` and a response time — for example 187 ms.
6. Expand the entry. The response panel shows your server's actual reply:

```json theme={null}
{
  "received": true
}
```

If your handler had instead replied `{"error": "Missing event id"}` with a 400, you'd see status `400` and that body in the same panel — which tells you the handler ran but decided the payload was malformed. Compare the `data` object you sent against your handler's expectations; in this example a receiver that requires `data.message_id` accepts the pre-fill as-is.

Change a field, send again, and the new result stacks above the old one — the history panel is your before/after record for the iteration.

<Tip>
  New to Orbit webhooks entirely? [Build your first webhook receiver](/webhooks/first-receiver) walks through signature verification, deduplication, and retry handling end to end — come back here to test what you build.
</Tip>

## Live event stream

Below the tester, the **Live Event Stream** connects to your organization's real delivery stream over SSE and prints events as they arrive. This is the other half of debugging: the tester shows what your endpoint *returns*; the stream shows what Orbit actually *sent*. Click **Connect** to attach — leave the API key field blank to use your session, or paste a key for a narrower credential. Click **Disconnect** to close the stream.

## See also

* [Build your first webhook receiver](/webhooks/first-receiver) — verified receiver, dedup, and retry handling end to end
* [Webhooks overview](/webhooks/overview) — delivery guarantees and endpoint management
* [Webhook security](/webhooks/security) — canonical HMAC reference and secret rotation
* [Event payloads](/webhooks/event-payloads) — envelope schema and request headers
* [Troubleshooting signature failures](/webhooks/troubleshooting-signature-failures) — when verification fails in production
