Skip to main content

Management API

The Management API is the server-side surface for your domain. Use it to read your profile and balance, set your webhook callback URL, and search the scored snapshots that ShieldLabs has stored. It is the authoritative, pull-based way to read a Risk Score when you cannot risk a dropped webhook. 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 Management API call lives under one base path that carries the credentials in the URL:
https://api.shieldlabs.ai/{domain}:{secret}/
PartValueNotes
{domain}Your registered domain, e.g. myshop.comThe hostname you set up in Domains
{secret}Your per-domain Secret KeyBackend only. See Keys
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.
The Secret Key authenticates this API and verifies webhook signatures. Keep it server-side. It must never appear in the browser, the JS snippet, client logs, or a public repository. If it leaks, rotate it from the dashboard. The browser-safe credential is the Public Key, which goes in the snippet, not here.

Endpoints at a glance

MethodPathPurposeCost
GET/{domain}:{secret}/profileRead domain config, balance, masked keysFree (0 requests)
POST/{domain}:{secret}/callbackSet the webhook callback URLFree (0 requests)
GET/{domain}:{secret}/history/{type}/{value}?limit=NSearch stored snapshots1 request per returned row (minimum 1)
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. See Identification Flow.

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.
curl "https://api.shieldlabs.ai/myshop.com:YOUR_SECRET/profile"

Response

{
  "Domain":     "myshop.com",
  "Weight":     148230,
  "Callback":   "https://myshop.com/webhooks/shieldlabs",
  "PublicKey":  "•••• a3f8",
  "Secret":     "•••• 9c2d",
  "CreatedAt":  "2026-01-15T09:00:00Z"
}
Domain
string
The registered domain this profile belongs to.
Weight
integer
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. See Billing.
Callback
string
The webhook URL ShieldLabs posts scored results to. Empty if no callback is set. Update it with POST /callback.
PublicKey
string
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.
Secret
string
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.
CreatedAt
string
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.
curl -X POST "https://api.shieldlabs.ai/myshop.com:YOUR_SECRET/callback" \
  -H "Content-Type: text/plain" \
  --data "https://myshop.com/webhooks/shieldlabs"
callback URL
string
required
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.
After this is set, every identification on the domain delivers an initial webhook and, when the real-IP 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.
curl "https://api.shieldlabs.ai/myshop.com:YOUR_SECRET/history/request_id/550e8400-e29b-41d4-a716-446655440000?limit=1"

Path parameters

type
string
required
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)
Any other value returns 404. A value in the wrong format (for example a non-UUID for device_id) returns 400.
value
string
required
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

limit
integer
default:"100"
Maximum number of rows to return. Capped at 100: a higher value is clamped to 100. Rows are ordered newest first.

Common search patterns

# Pull the scored result for a specific check (the guaranteed-read fallback
# when a webhook may have been dropped). Bills 1 request.
curl "https://api.shieldlabs.ai/myshop.com:YOUR_SECRET/history/request_id/550e8400-e29b-41d4-a716-446655440000?limit=1"

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 returns 402. Webhooks, dashboard views, and exports are free. See Billing.
To keep reads cheap and predictable, query by request_id with limit=1 when you only need one scored result. Reserve the wider device_id / user_hid / ip searches for investigations, and set limit to the smallest value that answers your question.

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":            "550e8400-e29b-41d4-a716-446655440000",
  "SessionID":            "7a1b2c3d-4e5f-6789-abcd-ef0123456789",
  "CookieID":             "3f2e1d0c-9b8a-7654-3210-fedcba987654",
  "DeviceID":             "6ba7b810-9dad-11d1-80b4-00c04fd430c9",
  "VisitorID":            "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "IP":                   "203.0.113.10",
  "OS":                   "Windows",
  "Browser":              "Chrome",
  "DeviceType":           "desktop",
  "Country":              "US",
  "UserHID":              "e3b0c44298fc1c149afbf4c8996fb924",
  "ConnectionType":       "vpn",
  "WebRtcConnectionType": "srflx",
  "WebRtcCountry":        "US",
  "WebRtcHIP":            "198.51.100.24",
  "TcpMss":               1460,
  "MtuValue":             1500,
  "MtuHint":              "tunneled",
  "Score":                45,
  "Details": [
    { "Value": 30, "Description": "IP Mismatch" },
    { "Value": 15, "Description": "VPN" }
  ],
  "LastRequestTime":      "2026-06-16T10:00:00Z"
}

Identity and score fields (shared with the webhook)

RequestID
string
The per-call UUID, minted client-side and used as the join key across snapshot, webhook, and history. See Identifiers.
SessionID
string
Per-visit UUID from the browser’s sessionStorage (a 10-minute visit window).
First-party cookie/localStorage UUID. Lost when the visitor clears cookies or storage.
DeviceID
string
Server-derived UUID from dozens of stable browser-fingerprint components. Durable: survives cookie-clear, incognito, and IP rotation within the same browser. Browser-bound (a different browser is a different DeviceID; no cross-browser recognition today).
VisitorID
string
Server-derived UUID from DeviceID + CookieID. Changes when the cookie is cleared. Multiple VisitorIDs can map to one DeviceID.
UserHID
string
The hashed/pseudonymous user id you passed via the snippet. Never a raw email or login.
IP
string
The client’s public IP at the time of the check.
OS
string
Operating system, e.g. Windows, Mac OS X, iOS.
Country
string
Two-letter ISO country derived from the IP.
Score
integer
The Risk Score, 0 to 100 (hard-capped at 100). Higher means more anonymous, masked, or spoofed. Read it with the band guide below.
Details
array
The explainable breakdown of the score. Each entry is { "Value": <int>, "Description": "<signal>" }: the signal that fired and the points it contributed. See Signals for the full reference.
LastRequestTime
string
ISO 8601 UTC timestamp of the most recent request for this identity.

Connection and network fields (History only)

These fields are not in the webhook body. They describe the connection and network fingerprint observed during scoring. They are useful for forensics and your own correlation logic.
Browser
string
Detected browser name, e.g. Chrome, Safari.
DeviceType
string
Form factor: desktop, mobile, or tablet.
ConnectionType
string
The classified connection type for the IP: direct, privacy_relay, vpn, proxy, or tor.
WebRtcHIP
string
The IP discovered through the WebRTC real-IP (STUN) check, used to corroborate or contradict the public IP. Compare it against IP to reason about masking.
WebRtcCountry
string
Two-letter ISO country derived from the WebRTC-discovered IP.
WebRtcConnectionType
string
The WebRTC ICE candidate type observed, e.g. host, srflx, relay.
TcpMss
integer
TCP Maximum Segment Size from the network fingerprint. A low-level input that helps distinguish direct connections from tunneled ones.
MtuValue
integer
Detected MTU value from the network fingerprint.
MtuHint
string
A coarse label derived from the MTU/network fingerprint that hints at the connection’s shape.
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 the real-IP check), the stored snapshot reflects the recomputed value.

Reading the score

ShieldLabs scores. Your application decides. The Risk Score is a 0 to 100 number with four bands you can act on:
BandRangeRecommended action (a guide, not a rule)
Clean0–9Pass through, no friction
Low10–29Allow, worth logging
Medium30–59Step-up challenge, second look, or review
High60–100Block, review, or require verification
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. For worked examples, see Acting on the Risk Score.

Errors

All errors return JSON of the form { "error": "..." }.
StatusMeaningWhat to do
200SuccessParse the response.
400Bad parametersA malformed value, e.g. a non-UUID where a UUID is required. Fix the request.
401Bad credentials or disabled domainCheck {domain}:{secret} and that the domain is enabled.
402Out of requestsBalance exhausted (History needs 1 request per returned row). Top up. See Billing.
404Unsupported history type or not found{type} must be one of ip, user_hid, visitor_id, request_id, device_id.
429Rate-limitedYou hit an infra rate limit. Back off and retry. See Rate limits.
500Internal errorTransient. Retry with backoff.
503Server busyA concurrency cap was hit. Retry with backoff.
429 is an infrastructure rate limit, not a Risk Score. It protects the gateway and never feeds the score. See Rate limits. The Score field is always 0 to 100.
For the full error reference across every surface, see Errors.

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.