X-Shield-Signature header, and act on the score in your own code.
This page is the how-to. The Webhooks API reference has the exact field-by-field payload schema.
Webhooks are optional. If you do not register an endpoint, checks still run and still bill, but results are only available in the dashboard or through the History API. An endpoint is what makes scores real-time.
Register an endpoint
You can configure up to 10 endpoints per domain. Each endpoint has its own name, HTTPS URL, and a unique signing secret (whsec_…). Manage them from the dashboard.
1
Open the domain
Go to app.shieldlabs.ai, open your domain, and switch to the Webhooks tab.
2
Add an endpoint
Click Add endpoint, give it a name and a public HTTPS URL on a route your backend controls, and save. ShieldLabs generates a dedicated signing secret (
whsec_…) for that endpoint.3
Verify it
Use Verify to send a signed ping. When your endpoint answers with a
2xx, its status flips to Active. You can also use Send test event to deliver a sample risk event at any time.What a delivery looks like
ShieldLabs sends aPOST with Content-Type: application/json to each enabled endpoint. The body is a signed envelope (snake_case), and the signature travels in the X-Shield-Signature header.
data.request_id. The full field list is in the Webhooks API reference.
This delivery is a masked session: data.public_ip is a US proxy exit (203.0.113.42) while data.local_ip is the visitor’s real network in Germany (198.51.100.23). The two countries disagree, so data.detection_flags.ip_mismatch is true. ShieldLabs surfaces both IPs so your code can compare them; the difference is informational and does not add to the score, which here comes from the proxy, datacenter, and abuser signals.
Branch on
data.risk_score, signal name slugs, and detection_flags.One webhook per check
Each identification produces exactly one scored webhook per enabled endpoint, joined byrequest_id.
ShieldLabs waits for follow-up network checks when they apply to the visit. The webhook is sent as soon as those checks finish, or no later than 60 seconds after the check started — whichever comes first. If a follow-up never arrives, you still get one webhook with the best score available at that point.
Typical timing:
- Simple visits (no follow-up network check): about 1 second after ingest.
- Chrome with a follow-up network check: usually within a few seconds, up to 60 seconds in slow cases.
Verify the signature
Every delivery is signed. TheX-Shield-Signature header is the hex-encoded HMAC-SHA256 of the raw request body, keyed with that endpoint’s signing secret, prefixed with sha256=:
sha256=, and compare it to the X-Shield-Signature header using a constant-time comparison. Reject the request (respond 401) on a mismatch, and do not process the body.
Delivery guarantees
Webhook delivery is at-most-once. A practical handler pattern:1
Verify
Constant-time compare the
X-Shield-Signature header. Reject with 401 on a mismatch.2
Acknowledge
Return
200 immediately once the signature is valid and the body is parsed.3
Deduplicate
Upsert on
request_id. A redelivery for the same id should be a no-op.4
Decide
Map
data.risk_score plus data.signals to allow, challenge, review, or block in your application logic.Next steps
Webhooks API reference
Field-by-field payload schema, timing, and signature details.
Acting on the Risk Score
Map scores and signals to allow, challenge, review, or block.
History API
Poll stored snapshots for guaranteed reads.
API keys
Where your public and secret keys come from.