Identification Flow
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. TheRequestID 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
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.Server scores asynchronously (~1s)
The server enriches the signals (IP intelligence, network fingerprint, real-IP discovery) and computes the Risk Score with an explainable
Details array.Score is delivered (webhook + History API)
The server pushes the score to your callback URL as an initial webhook, and may push an update webhook after the real-IP check completes. 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 theRequestID lifecycle.
{requestID}is a client-generated UUID, unique per identify call. It is the join key across snapshot → webhook → history.publicKeyis 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.
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.
In the browser, the snippet surfaces the same acknowledgment and the requestID through its optional callback, so you can correlate client and server records:
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 fingerprint
A TCP/network fingerprint is fetched and compared against what the browser claims (this is what powers OS-mismatch and the VPN corroboration rule).
Real-IP (STUN) check
The snippet runs a WebRTC real-IP discovery against
webrtc.shieldlabs.ai and stun:ice.shieldlabs.ai:3478. The result arrives shortly after the initial POST.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 serverPOSTs the score to your configured callback URL. It arrives in two possible phases, both joined by RequestID:
| Phase | Timing | Details content |
|---|---|---|
initial | ~1s after ingest, before the real-IP result | The full list of signals that fired |
update | After the WebRTC real-IP check (optional) | Only the delta signals, suppressed if more than ~10s elapsed |
Assing is the literal field name in the JSON envelope. It is the HMAC-SHA256 signature of the Data object, keyed with your Secret Key. Verify every webhook before trusting it. A cleaner field name is planned, but Assing is the current reality.RequestID 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 anyRequestID from the Management API. This is the authoritative, pull-based path and the right choice when you cannot risk a dropped webhook.
request_id, visitor_id, device_id, user_hid, or ip. Each returned row bills 1 request. See Management API for the full schema and billing rules.
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
RequestID in the Data body. Both the initial and update phases carry the same RequestID.History
Queryable as the
request_id search type to read the stored snapshot any time.- Capture
requestIDfrom the snippet callback and persist it with the user action you are protecting. - When the
initialwebhook arrives, recordScoreandDetailsagainst thatRequestID. Treat the handler as idempotent. - If an
updatewebhook arrives, apply its deltaDetailsand recompute your decision. - If you never receive a webhook (at-most-once delivery), fall back to
GET /history/request_id/{requestID}.
What you do with the score
ShieldLabs scores. Your code decides. The Risk Score lands in the 0–100 range with band labels you can act on:| Band | Range | Recommended action (a guide, not a rule) |
|---|---|---|
| Clean | 0–9 | Pass through, no friction |
| Low | 10–29 | Allow, worth logging |
| Medium | 30–59 | Step-up challenge, second look, or review |
| High | 60–100 | Block, review, or require verification |
Next steps
Webhooks
Full payload,
Assing signature verification, phases, and at-most-once delivery.Management API
History search, the snapshot schema, profile, callback config, 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.