Skip to main content
A ShieldLabs identification is asynchronous by design. The browser snippet collects signals and posts them. The server computes the Risk Score (0–100) a moment later and delivers it two ways: a webhook push and a History API read. There is no synchronous score endpoint: the POST that ingests signals returns an acknowledgment, not the score. The RequestID is the join key that ties the three steps together.
You normally do not call rest.shieldlabs.ai yourself. The JS snippet posts to it automatically. Your server-side work is to receive the webhook and, when you need a guaranteed read, query the History API.

The three steps

1

Snippet posts signals (browser → rest.shieldlabs.ai)

The snippet generates a per-call RequestID (a client UUID) and posts the collected fingerprint to rest.shieldlabs.ai/snapshot/{requestID}?publicKey=…. The response is an acknowledgment (the client IP as a JSON string), not the score.
2

Server scores asynchronously (~1s)

The server enriches the signals (IP intelligence and network analysis) and computes the Risk Score with an explainable Details array.
3

Score is delivered (webhook + History API)

The server pushes one final webhook per check (within up to 60 seconds, after optional follow-up network checks). You can also read the result any time from the History API by request_id.

Step 1: The snapshot POST (acknowledgment, not a score)

The snippet calls this for you. It is documented here so you understand the contract and the RequestID lifecycle.
  • {requestID} is a client-generated UUID, unique per identify call. It is the join key across snapshot → webhook → history.
  • publicKey is your per-domain Public Key. It is safe to expose in the browser.
  • The body is the fingerprint payload. The snippet may send it plain or AES-256-GCM encrypted. Both are accepted.
The response is an acknowledgment, not the result:
The body is the client IP as a JSON string (HTTP 200). It confirms the signals were received and billed. It does not contain the VisitorID, DeviceID, or Risk Score. Those are computed server-side and delivered in Step 3.
This response is a receipt, not the score; read the result from the webhook or History API.
In the browser, the snippet surfaces the same acknowledgment and the requestID through its optional callback, so you can correlate client and server records:
The snippet install guide has the full method list and framework examples.

Step 2: Why scoring is asynchronous

The Risk Score is not available the instant the POST lands because the strongest signals need a round of server-side enrichment. This takes roughly one second:

IP intelligence

The server looks up reputation and connection type for the client IP (VPN, proxy, datacenter, privacy relay).

Network analysis

Network-level attributes are analyzed and compared against what the browser claims (this is what powers OS-mismatch and VPN corroboration).

Follow-up network check

A follow-up network check completes shortly after the initial POST and can refine the score.
Because these run concurrently and follow-up checks resolve slightly later, ShieldLabs waits for the optional follow-up network-check evidence, then delivers one final webhook per check (within 60 seconds). The VPN corroboration behind a VPN signal depends on these enrichment steps agreeing, which is part of why the score is computed off the request path.

Step 3: Receiving the score

You get the score two ways. Use both: the webhook for low latency, the History API as the guaranteed-read fallback.

Webhook (push)

The server POSTs the score to each enabled webhook endpoint once per check, joined by request_id: The webhook body is a signed snake_case envelope. The signature travels in the X-Shield-Signature header:
Full field schema: WebhookEvent.
Verify X-Shield-Signature on the raw request body, keyed with that endpoint’s whsec_… signing secret (not the domain Secret Key). See the verification recipe.
Webhook delivery is at-most-once with no retries (a ~1 second timeout, no backoff, no dead-letter queue). Make your handler idempotent on request_id and use the History API for anything that must not be missed. Full payload, signature verification in Node/Go/Python, and delivery guarantees are in Webhooks.

History API (read)

You can read the scored result for any RequestID from the History API. This is the authoritative, pull-based path and the right choice when you cannot risk a dropped webhook.
The response is a { data, total } envelope with snapshots (newest first). You can search by request_id, visitor_id, device_id, user_hid, ip, session_id, or cookie_id. History reads through account.shieldlabs.ai do not bill per row. The full schema and alternate Management API path are in the Server API reference.

The RequestID lifecycle

RequestID is the single value that lets you stitch the asynchronous pieces together:

Snapshot

Minted client-side as a UUID and sent in the POST path: /snapshot/{requestID}. Returned to your page in the snippet callback.

Webhook

Echoed back as request_id. One scored POST per check.

History

Queryable as the request_id search type to read the stored snapshot any time.
Persist the requestID early, record score and signals idempotently when the webhook arrives, and fall back to GET /api/v1/history/request_id/{requestID} on account.shieldlabs.ai if it never does (allow up to ~60s). The full reliability pattern, with signature verification, is in Webhooks.

What you do with the score

ShieldLabs scores. Your code decides. The Risk Score lands in the 0–100 range and falls into four Risk Score bands you can act on, with your application the actor for allow, challenge, review, or block. Decide on Score + Details + action context, never the number alone: a legitimate user can score high (corporate proxy, VPN, privacy browser). The per-band playbook gives threshold guidance and worked examples.

Next steps

Webhooks

Full payload, X-Shield-Signature verification, and at-most-once delivery.

Server API

History search, the snapshot schema, profile, and billing.

Risk Score

How the 0–100 explainable score and the Clean / Low / Medium / High bands work.

Identifiers

RequestID, SessionID, CookieID, DeviceID, VisitorID, and UserHID mechanics.