Skip to main content
BotShield sends a signed HTTP POST to your server when a gate request or an Agents Ask proposal reaches an outcome. You add endpoints in the BotShield Console, verify each delivery with the svix library, deduplicate, and answer with a 2xx quickly. Webhooks carry results only. No personal data about the human is included.

How a delivery works

Add an endpoint

1

Open the Webhooks tab

In the BotShield Console, go to Settings → Developer Tools → Webhooks. The tab embeds a webhooks portal for your organization. Use Open in new tab if you want more room.
2

Add your endpoint URL

Add an endpoint and enter a public https:// URL on your server, for example https://api.meridianairlines.example/webhooks/botshield.
3

Choose event types

Subscribe the endpoint to the event types you need. An endpoint with no filter receives every event type, including types added later. An endpoint with a filter receives only the types you selected, so add a new type to the filter when you want it. See Webhook events for the list.
4

Copy the signing secret

Open the endpoint and copy its signing secret (it starts with whsec_). Store it as a server-side secret. Each endpoint has its own secret.
5

Send an example event

Use the portal’s testing view to send an example of any event type to your endpoint, then check the result in the endpoint’s delivery log.
The same portal shows every delivery attempt with its request body, response code, and timing, and lets you replay a single message or recover all failed messages from a point in time.
Webhook endpoints belong to your organization, not to one environment. An endpoint receives events from both your Development and Production gates and agents. Every gate event carries a top-level environment field, "development" or "production". Branch on it before you act, so a test verification never changes production data. Agents Ask events have no environment field. Match their request_id against the records you created.

Verify the signature

Every delivery carries three headers: Verify with the svix library and your endpoint’s signing secret. Verify against the raw request body. If a framework parses the JSON and you re-serialize it, the bytes change and verification fails.
Never act on an unverified payload, and never log the signing secret. If a secret leaks, rotate it from the endpoint’s page in the portal.

Respond fast

Return any 2xx as soon as the signature checks out and the event is recorded. Do slow work (database writes beyond the dedupe record, calls to other services, email) after you respond. A response that is not 2xx, including a 3xx redirect, or that is slow to arrive counts as a failed attempt. Aim to respond within a few seconds.

Retries

A failed attempt is retried automatically, several times, with increasing delay between attempts. Retries continue for hours, not minutes, so a short outage on your side does not lose events. Every attempt, with its response code and body, is listed under the endpoint in the portal. After the last attempt the message is marked failed for that endpoint, and you can replay it from the portal at any time. An endpoint that keeps failing for days can be disabled automatically. Re-enable it in the portal once it is healthy, then replay what it missed.

Deduplicate

Retries and manual replays mean your endpoint can receive the same event more than once. Make processing idempotent by recording a key per event before you act on it. The svix-id header also works as a transport-level key: it is identical on every retry of one message.

Do not depend on webhooks alone

Webhook delivery is best-effort relative to the verification itself. BotShield never delays or fails a verification because a webhook could not be queued, so a webhook can be late or, rarely, missing. BotShield sends a gate event when something happens to a request on the phone:
  • The human confirms. gate.human_verified is sent.
  • The BotShield app reports a failure, for example the person cancels the biometric prompt, or a request that was opened fails. gate.unavailable is sent with failed_at and a reason. Webhook events lists the values.
  • The person opens the request after its five-minute window has passed. gate.unavailable is sent with expired_at.
Two paths produce no gate event at all:
  • Recent Presence fast path. When a returning human passes instantly and the widget reports via: "precheck", no gate.human_verified webhook is sent for that pass. Confirm it from your server right away with GET /verification/status, which reports status: "pass" for 60 seconds after the check.
  • Requests nobody opens. A request that the person never opens on their phone expires with no event. Closing the widget’s modal without scanning the QR code, or ignoring the push, ends this way.
So a missing webhook is itself an outcome. Do not hold a user’s flow open waiting for gate.unavailable. For any flow where the outcome matters (checkout, account changes, agent actions), also check the result from your server:
  • BotShield Gate: call GET /verification/status with the request_id. See Verify on your server.
  • Agents Ask: long-poll GET /agentlink/check-status with your request_id. See Propose an action.
Treat a gate request with no gate.human_verified, and no completed or pass status by its expires_at, as Unavailable.

Next steps

Webhook events

Payloads and field tables for every event type.

Verify on your server

Confirm a gate result without waiting for a webhook.

Proof of Resolution

Verify the signed JWT carried by resolution events.

Keys and environments

Where your keys live in the Console.