Verify the browser that followed a link
const url = 'https://api.ebitex.io/audience/delivery/v1/sign-in/handoff';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"code":"example","visitor":"example","consent":{"cmp":"example","gpc":true,"dnt":true,"cmpString":"example"}}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.ebitex.io/audience/delivery/v1/sign-in/handoff \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "code": "example", "visitor": "example", "consent": { "cmp": "example", "gpc": true, "dnt": true, "cmpString": "example" } }'A verification link opened on another device (a phone, from a mail) proves the device that asked. When that link had a returnUrl, the page it opens offers a “Continue” link that carries a one-time code in its URL fragment, #ebitex-verify=<code>. Call this from the page it leads to, with the code and this device’s visitor token, and this device is proved for the same person and address as if it had followed the link, so the next resolve for it includes the audience as verified. @ebitex/content-sdk does it for you when the client has an audience option: it reads the fragment, removes it from the address bar, calls this and resolves again (audience: { handoff: false } turns that off).
The code is issued only when the person presses the button on the verification page (opening the link, as a mail scanner does, issues none), works once, and expires after 10 minutes. visitor is the device’s visitor token (either kind) and consent is as for resolve: the proof is remembered for 30 days when the device has granted recognition, otherwise for the session (at most 4 hours).
The answer never depends on the code. It is always 202 with the same body, whether the code was valid, used, expired or never issued, and whether the device was revoked, so the route cannot be used to find out anything. The response is private, no-store.
Key: audience.delivery.read
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”object
Examplegenerated
{ "code": "example", "visitor": "example", "consent": { "cmp": "example", "gpc": true, "dnt": true, "cmpString": "example" }}Responses
Section titled “ Responses ”202 with { "message": "…" }, always the same text.
invalid_api_key: the key is missing, revoked, expired or not an Audience delivery key.
missing_api_key or invalid_api_key: no key was sent, or it is unknown, revoked or expired.
origin_denied or ip_denied: the key’s restriction does not admit this request. app_not_available.
scope_denied: the key lacks this route’s scope. origin_denied or ip_denied: a browser-safe key was used from an origin or address outside its restrictions. app_not_available: Content is not enabled for the organization.
rate_limited: the key’s per-minute budget is spent; Retry-After says when it resets.
Quota exceeded; Retry-After says how long to wait. too_many_failed_authentications: too many bad keys from this address.