Server API
The Server API is the server-side surface for your domain. Its primary endpoint is the History API, the authoritative, pull-based way to read a Risk Score and the signals behind it when you cannot risk a dropped webhook. The same surface also lets you read your profile and balance and set your webhook callback URL. This API is keyed by your Secret Key and must only be called from your backend. Never call it from the browser.Base URL and authentication
Every Server API call lives under one base path that carries the credentials in the URL:
The credentials are validated against the domain’s Secret Key and its enabled status. Wrong credentials, an unknown domain, or a disabled domain return
401.
Endpoints at a glance
| Method | Path | Purpose | Cost |
|---|---|---|---|
GET | /{domain}:{secret}/history/{type}/{value}?limit=N | Read scored results by identifier (the History API) | 1 request per returned row (minimum 1) |
GET | /{domain}:{secret}/profile | Read domain config, balance, masked keys | Free (0 requests) |
POST | /{domain}:{secret}/callback | Set the webhook callback URL | Free (0 requests) |
There is no synchronous “identify” or “score” endpoint here. The score is produced asynchronously: the JS snippet posts signals to
rest.shieldlabs.ai, ShieldLabs scores them in about a second, and the result is delivered by webhook and stored for the History API. The Identification Flow walks through that asynchronous path end to end.GET /profile
Returns your domain’s configuration and current balance. The keys are masked to their last four characters. This call is free: it does not consume requests.Response
The registered domain this profile belongs to.
Your remaining balance, measured in requests. One identification consumes 1 request, and the History API consumes 1 request per returned row. When this reaches 0, scoring and History calls return
402, as the Billing page details.The webhook URL ShieldLabs posts scored results to. Empty if no callback is set. Update it with
POST /callback.Your Public Key, masked to the last four characters. The browser-safe credential that goes in the snippet URL. Read the full value from the dashboard.
Your Secret Key, masked to the last four characters. Used for this API and webhook signature verification. The full value is shown only at creation in the dashboard.
ISO 8601 UTC timestamp of when the domain was created.
POST /callback
Sets (or replaces) the webhook callback URL for the domain. The request body is the URL itself, as plain text (not JSON). This call is free.The raw HTTPS URL ShieldLabs should POST scored results to. Sent as the plain-text request body, not wrapped in a JSON object. Use a publicly reachable HTTPS endpoint.
initial webhook and, when a follow-up network check completes, an optional update webhook. Webhook delivery is at-most-once with no retries, so verify the signature, make your handler idempotent on RequestID, and fall back to the History API for anything that must not be missed.
You can also set and manage the callback from the dashboard. The dashboard and this endpoint write the same field. Either is fine.
GET /history/{type}/{value}
Searches the snapshots ShieldLabs has stored for your domain. Returns an array of Snapshot objects, newest first. This is the guaranteed read path for any scored result, the right choice when a webhook may have been missed.
Path parameters
The field to search on. One of:
ip: client IP address (IPv4 validated)user_hid: the hashed user id you passed via the snippet (free-form string)visitor_id: a VisitorID (UUID validated)request_id: a single identification’s RequestID (UUID validated)device_id: a DeviceID (UUID validated)
404. A value in the wrong format (for example a non-UUID for device_id) returns 400.The value to match for the chosen
type. UUID types are UUID validated, ip is IPv4 validated, user_hid is a free string.Query parameters
Maximum number of rows to return. Capped at 100: a higher value is clamped to 100. Rows are ordered newest first.
Common search patterns
Billing
The History API bills 1 request per returned row. An empty result still bills 1 request (the lookup itself). So a search returning 20 snapshots costs 20 requests, and a search returning 0 costs 1. If your balance is insufficient for the result, the call returns402. Webhooks, dashboard views, and exports are free, with the full cost breakdown on the Billing page.
The 1-request lookup charge is taken before the lookup is validated, so a
400 (malformed value) or 404 (unsupported {type}) still bills 1 request. Only 401 (bad credentials) and 402 (out of requests) cost 0. Send a well-formed {type} and {value} to avoid paying for a rejected call.The Snapshot object
A snapshot is a single scored identification. The History array returns a superset of the webhook body: the same identity and score fields, plus connection and network detail captured during scoring.RequestID, SessionID, CookieID, DeviceID, VisitorID, UserHID, IP, OS, Country, Score, Details, LastRequestTime) behave exactly as in the WebhookBody schema. The fields a snapshot adds on top, captured during scoring and useful for forensics and your own correlation logic:
Detected browser name, e.g.
Chrome, Safari.Form factor:
desktop, mobile, or tablet.The classified connection type for the IP, one of seven values:
direct, mobile, vpn, proxy, tor, privacy_relay, or unknown.A snapshot is a point-in-time record of one identification. The score on a snapshot is the score as computed at that time. If a later
update webhook changed the result (after a follow-up network check completes), the stored snapshot reflects the recomputed value.Reading the score
ShieldLabs scores. Your application decides. The Risk Score is a 0 to 100 number that falls into four Risk Score bands, and your code is the actor for allow, challenge, review, or block. Decide on Score + Details + action context, never the number alone: a legitimate user can score high behind a corporate proxy, a VPN, or a privacy browser. Tune your thresholds gradually, working from the per-band playbook and its worked examples.Errors
Error bodies on this surface are not uniform, so branch on the HTTP status code, not on a body field.401 and 402 return an empty body. 400 and 404 return a bare JSON string. The 429 and 503 statuses exist only on the REST ingest and WebRTC gateways, not on the Server API.
| Status | Meaning | What to do |
|---|---|---|
200 | Success | Parse the response. A History search with a valid {type} that matches nothing returns 200 with [] and still bills 1 request. |
400 | Bad parameters | A malformed value, e.g. a non-UUID where a UUID is required. Fix the request. |
401 | Bad credentials or disabled domain | Check {domain}:{secret} and that the domain is enabled. |
402 | Out of requests | Balance exhausted (History needs 1 request per returned row). Top up from the Billing page. |
404 | Unsupported history type | {type} must be one of ip, user_hid, visitor_id, request_id, device_id. |
500 | Internal error | Transient. Retry with backoff. |
Next steps
Data Models
The full Snapshot, webhook body, and Score Detail schemas in one place.
Webhooks
The push delivery path: payload,
Assing signature verification, and phases.Identification Flow
How signals become a score and how the webhook and History API fit together.
Keys
Public Key vs Secret Key, where each one belongs, and how to rotate.