Reference

API reference

Two endpoints: one public-key identify call for clients, one secret-key events call for server-side verification. All requests and responses are JSON. Local dev base URL: http://localhost:8080.

Authentication

EndpointKey typeHeader
POST /v1/identifyPublic (vp_pk_...), safe in browsersx-api-key: vp_pk_...
GET /v1/events/:requestIdSecret (vp_sk_...), server-side onlyx-api-secret: vp_sk_... or Authorization: Bearer vp_sk_...

Key types are enforced: a secret key on /v1/identify or a public key on /v1/events both return 401.

POST /v1/identify

Identifies the device behind a request. The browser SDK calls this for you; you can also call it directly from any HTTP client.

Request body

FieldTypeDescription
signalsobject, requiredThe device signal vector: timezone, platform, hardware, fonts, canvas hashes, and so on. See the signal catalog for every field and its weight.
anchorsobject, optionalPreviously issued visitor IDs read back from client storage: cookieId, localStorageId, cacheId. Any valid anchor short-circuits fingerprint matching.
clientBotobject, optionalClient-side automation pre-checks (webdriver flags, headless markers) collected by the SDK. Merged into the server-side bot verdict.
incognitoHintboolean, optionalClient-side private-browsing detection result, used as one input to the incognito verdict.
urlstring, optionalPage URL where identification ran; shown in the dashboard event stream.
sdkVersionstring, optionalSDK version string for debugging and compatibility tracking.

Response: 200

FieldTypeDescription
visitorIdstringStable visitor identifier, vp_.... The same device resolves to the same ID across visits, subject to the confidence score.
requestIdstringOne-time ID for this identification event, vpr_.... Use it with /v1/events to verify server-side.
confidencenumberMatch confidence, 0 to 1, computed per request from anchor agreement and signal similarity.
confidenceLevel"high" | "medium" | "low"Banded version of confidence for simple threshold logic.
ipstringRequesting IP address as seen by the API.
geoobjectIP-derived location and network data. See the geo table below.
incognitobooleanWhether the session appears to be private browsing.
botobjectBot detection verdict. See the bot table below.
vpnLikelybooleanWhether the traffic pattern and network data suggest a VPN.
firstSeenAtstring (ISO 8601)When this visitor was first identified. Preserved when visitor records are re-linked.
lastSeenAtstring (ISO 8601)Timestamp of the previous identification of this visitor.
visitCountnumberTotal identifications recorded for this visitor.
matchedViastring[]How the visitor was recognized on this request: any of cookie, localStorage, cache, fingerprint, or new for a first sighting.

geo object

FieldTypeDescription
countrystringCountry name.
countryCodestringISO 3166-1 alpha-2 code, e.g. DE.
regionstringSubdivision / state.
citystringCity name.
latitudenumberApproximate latitude of the IP, not the device.
longitudenumberApproximate longitude of the IP, not the device.
asnnumberAutonomous system number.
asnOrgstringOrganization operating the ASN.
isDatacenterbooleanIP belongs to a hosting / datacenter range.
isTorbooleanIP is a known Tor exit node.

bot object

FieldTypeDescription
result"notDetected" | "automationTool" | "searchEngine" | "unknown"Overall verdict. searchEngine covers verified crawlers you usually want to allow.
typestring | nullSpecific tool or crawler when identifiable (e.g. a headless browser or known crawler).
scorenumberBot likelihood, 0 to 1.
reasonsstring[]Machine-readable reasons behind the verdict, for logging and appeals.

Example

terminal
curl -X POST http://localhost:8080/v1/identify \
  -H "x-api-key: vp_pk_demo_public_key" \
  -H "content-type: application/json" \
  -d '{"signals":{"timezone":"Europe/Berlin","platform":"MacIntel","hardwareConcurrency":10},"anchors":{}}'

GET /v1/events/:requestId

Returns the full identification record for a requestId, exactly as the API computed it. This is the trust boundary: the browser can lie about its own response, but it cannot forge what this endpoint returns.

terminal
curl http://localhost:8080/v1/events/vpr_01j8x2m9k4 \
  -H "x-api-secret: vp_sk_demo_secret_key"

Response: 200

FieldTypeDescription
requestIdstringThe requested event ID.
identificationobjectThe complete identify response for that request, the same shape as POST /v1/identify above.
Verification pattern
Have the client forward only the requestId to your backend, fetch the record here, and act on identification.visitorId, bot, and confidence from this response. Treat a mismatch between the claimed and verified visitor ID as a fraud signal in its own right.

Errors

StatusBodyWhen
401{ "error", "message" }Missing key, unknown key, or wrong key type for the endpoint (secret key on identify, public key on events).
404{ "error", "message" }/v1/events only: the requestId is unknown.
429{ "error": "rate_limited", "message", "limit" }The per-key rate limit was exceeded. The body includes your current limit.

Rate limits

Limits are enforced per API key. When you exceed yours, requests return 429 with the limit echoed in the body. Back off and retry after a short delay. On self-hosted deployments the ceiling is set with the RATE_LIMIT_MAX environment variable; see Self-hosting.

rate-limited.json
{
  "error": "rate_limited",
  "message": "Rate limit exceeded for this API key.",
  "limit": 120
}