Exchange fingerprint components for a device token

Called from the **browser**, cross-origin, with your **publishable** key (`pk_live_…` / `pk_test_…`) — never the secret key. In practice you do not call this yourself: `@portreeve/browser`'s `collectDeviceToken()` does, and resolves to `null` instead of throwing when collection is blocked. The raw components never leave the request — they are hashed server-side and the response is a short-lived signed token you forward to your own backend and pass through as `device_token` on the verdict call. This is the only endpoint with CORS enabled and the only one a publishable key can reach. A `device_token` that is expired, tampered with, or minted for a different tenant or mode is **silently dropped** by `POST /v1/verdict`: the verdict still returns 200, simply without device signals. A bad token never rejects or degrades a verdict call.

Authentication

AuthorizationBearer

Authorization: Bearer pk_live_… (or pk_test_…). Public by design — it is meant to appear in page source. It can mint device tokens and nothing else; it is rejected on every other endpoint.

Request

This endpoint expects an object.
componentsmap from strings to anyRequired

Component name → value. Keys up to 64 characters; values are opaque. Hashed server-side; the raw components are not stored.

Response

A signed, short-lived device token.

device_tokenstring

Forward this to your own backend and pass it through as device_token on the verdict call.

expires_atdatetime

RFC 3339 timestamp. Tokens are short-lived — collect close to the screened action, not at page load.

Errors

400
Bad Request Error
401
Unauthorized Error
429
Too Many Requests Error
500
Internal Server Error