Skip to main content
Use the public History API to read an identification and the ShieldLabs SDK to verify signed webhooks. The example keeps the entity response intact and checks its availability before applying a signup policy.

Before you start

Java 11+ and Maven or Gradle. The SDK includes Jackson for JSON. Register your domain in the dashboard. The browser must send its identificationId to your backend with the protected action. For a fresh integration, start with Quick Start.

Get your credentials

Set these server environment variables:
  • SHIELDLABS_API_KEY: the domain’s Private API Key from Integration > API keys.
  • SHIELDLABS_DOMAIN_ID: the public domain UUID returned by GET /api/v1/domains with that key, or by MCP shieldlabs_list_domains. Use the UUID, not the hostname.
  • SHIELDLABS_WEBHOOK_SECRET: the endpoint signing secret from Integration > Webhooks.
Use credentials from the same domain and environment as the browser. Never expose server secrets to the browser.

Install the SDK

Save the code as QuickStart.java. Call allowSignup(id, expectedUserHid) from your application route.

Add the integration

The History request is GET /api/v1/domains/{domain_id}/history/identifications/{identification_id}. The following code uses your language’s HTTP client for that request and the published SDK’s signature helper. Entity cards are read as entity cards; do not pass them to a helper expecting a normalized webhook Identification model.
This example accepts a fresh, available identification below the Dangerous band unless Banned IP or Browser Automation is present. Adapt the decision to the action you protect. For signed-in actions, obtain the expected User HID from the authenticated account on your server and compare it before claiming the identification. Never take that expected value from an untrusted form field. Claim each accepted Identification ID atomically using a unique key on the domain and Identification ID. One identification authorizes one protected action. The demonstration store is local to one process or machine; replace it with shared durable storage and coordinate the claim with the action. If the store is unavailable, the action stays unverified.

Wait for a new result

The code performs one History read. For a new browser UUID, retry that same read within a total ten-second budget: immediately, then after 250 ms, 500 ms, 1 s, 1.5 s and every 2 s. Retry a missing card, a connection error or a 5xx only within that budget. Stop on 400, 401, 402 or 403. On 429 respect Retry-After, with no immediate retry; stop if the required wait exceeds the remaining budget. Do not create another browser identification to poll a result. A missing result, unavailable risk or unavailable signals remains unverified. Do not replace it with score zero or empty known flags. A malformed response, identity mismatch or persistent API failure must not authorize an action.

Accept webhooks

Verify X-Shield-Signature over the original raw bytes, then validate the current webhook envelope. Keep the complete verified JSON. Use event_id to deduplicate deliveries and data.identification_id to correlate scored events. Handle identification.scored and hre.multi_account.changed separately. Before acknowledging with 2xx, commit the envelope to a durable queue/outbox with a unique event key. Queue failures must return a retryable non-2xx. Signature failures return 401; an invalid known payload returns 400. A demonstration log is not durable acceptance.

Test the complete flow

  1. Use an Identification ID from a real browser check on the same domain.
  2. Confirm the card’s domain, ID, type, available Risk Score and signals.
  3. Test missing, unavailable, stale, mismatched and reused identifications; none should authorize the action.
  4. Verify a signed raw webhook body, then change one byte and confirm rejection.
  5. Deliver the same event_id twice and confirm your durable handler processes it once.

Troubleshooting

  • Missing result: keep the browser open while collectors send data and use the bounded wait for the same UUID.
  • Authentication failure: use the domain’s Private API Key, not its Public Key, Management Secret Key or OAuth token.
  • Unavailable score or signals: retain the unavailable state and use your review or retry flow.
  • Invalid signature: verify the original bytes with the full endpoint signing secret.
  • HTTP 429 rate_limited is an API rate-limit error, separate from the public Banned IP banned_ip signal.

Next steps