Identify a person
const url = 'https://api.ebitex.io/audience/management/v1/identify';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"identity":{"type":"example","value":"example","system":"example","verified":{"method":"example"},"mergeOnConflict":false},"visitor":"example","consent":{"cmp":"example","gpc":true,"dnt":true,"cmpString":"example"},"name":"example","attributes":{},"interaction":{"kind":"example","sourceEventId":"example","occurredAt":"2026-04-15T12:00:00Z","data":"example"},"source":{"label":"example"},"account":{"externalId":"example","name":"example","role":"example","attributes":{},"attribution":{"source":"example","medium":"example","campaign":"example","isEmpty":true}},"verification":{"audienceId":"2489E9AD-2EE2-8E00-8EC9-32D5F69181C0","returnUrl":"example","message":{"subject":"example","text":"example","html":"example"}},"attribution":{"source":"example","medium":"example","campaign":"example","isEmpty":true},"locale":"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/management/v1/identify \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "identity": { "type": "example", "value": "example", "system": "example", "verified": { "method": "example" }, "mergeOnConflict": false }, "visitor": "example", "consent": { "cmp": "example", "gpc": true, "dnt": true, "cmpString": "example" }, "name": "example", "attributes": {}, "interaction": { "kind": "example", "sourceEventId": "example", "occurredAt": "2026-04-15T12:00:00Z", "data": "example" }, "source": { "label": "example" }, "account": { "externalId": "example", "name": "example", "role": "example", "attributes": {}, "attribution": { "source": "example", "medium": "example", "campaign": "example", "isEmpty": true } }, "verification": { "audienceId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "returnUrl": "example", "message": { "subject": "example", "text": "example", "html": "example" } }, "attribution": { "source": "example", "medium": "example", "campaign": "example", "isEmpty": true }, "locale": "example" }'The one event-shaped write: tell Audience that you now know who someone is. { "identity": { "type", "value", "system", "verified": { "method" } }, "visitor", "consent": { "cmp", "gpc", "dnt", "cmpString" }, "name", "locale", "attributes", "interaction": { "kind", "sourceEventId", "occurredAt", "data" }, "source": { "label" }, "account": { "externalId", "name", "role", "attributes" }, "verification": { "audienceId", "returnUrl", "message": { "subject", "text", "html" } }, "attribution": { "source", "medium", "campaign" } }.
In one transaction it finds the person by the identity (a verified match first, then an unverified match on exactly one person; with two or more it creates a new person and says so with ambiguous), adds the identity, fills empty name, locale (a language code such as fr or en-GB, used to choose the language messages are written in) and custom fields only (an event never overwrites what a person typed), records the interaction, and, when asked, links the visitor.
A verified identity belongs to one person in an organization. Adding one that another person already holds verified is refused with 409 identity_verified_elsewhere and the holder’s id, unless the request sets mergeOnConflict: true: then the person you were writing to is merged into the holder, who survives. The merge is recorded and can be reverted by a person in the dashboard. identify always merges, because an identification event is the automatic consolidation.
Linking a visitor. visitor is the visitor token your page holds. It is linked to the person only if it reads as a valid, unrevoked recognition token and the device’s own consent signals say recognition is granted. You must forward the device’s signals in consent: the consent-management choice, the Global Privacy Control header and the Do Not Track header, exactly as the browser sent them. Sending none is treated as no consent. linked says whether it worked, and linkReason says why not: no_visitor, token_invalid, session_token, recognition_not_granted, visitor_linked_elsewhere or revoked.
Naming an account. When the organization has accounts turned on, account adds the person to an account found by its externalId and creates the account if it does not exist (name is used for a new account and defaults to the external id; attributes fill an existing account’s empty values only). role is a label you choose. Accounts are never merged or matched by anything but the external id. If the plan’s account limit is reached the person is still identified and the answer says accountSkipped: "account_quota_exceeded"; an account that already exists can still be joined.
Asking for a verification link. verification asks Audience to email the person a one-time link that proves they hold the address, as part of this identification. It needs a visitor token (the proof is for that device) and an email identity, and it sends the link only when the person is in a verified-access audience (audienceId names one; leave it out for any). It never fails the identification: verification.status says what happened (sent, replayed, no-visitor, no-email, throttled or not-a-member), and a replay of the same sourceEventId sends nothing. returnUrl is where the confirm page offers to continue (an absolute https address, treated as none when it is not acceptable), so it can be a page, a download page or a file’s own address. message is your own words for the email: subject is one line and text and the optional html must each contain {{link}}; {{returnUrl}}, {{name}} and {{audience}} are also filled in, and values are inserted escaped. Leave message out for the built-in wording.
Where the person came from. attribution is the three campaign tags of the link they followed (utm_source, utm_medium and utm_campaign, as source, medium and campaign; each at most 100 characters). Audience records it once, as the person’s first touch: a person with no Awareness pass gets one, opened with those three facts; a person whose open Awareness pass has none of the three is filled in; anyone else is left exactly as they are, and sending it again is never an error. The campaign text is matched to a campaign that already has it as an alias and never registers a new campaign, because anyone can write a link. It never fails the identification: attribution.status says recorded, filled, kept or none, and attribution.campaignResolved whether the text matched a campaign.
Key: an Audience management key with audience.management.write (write also needs read; erase needs both).
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”object
Responses
Section titled “ Responses ”{ "individual": { "id", "name" }, "created", "identityAdded", "merged": { "survivorId" }, "linked", "linkReason", "ambiguous", "account": { "id", "externalId", "created", "memberAdded" }, "accountSkipped" }. account and accountSkipped appear only when account was sent. verification appears only when verification was sent. attribution ({ "status", "campaignResolved" }) appears only when attribution was sent.
validation_failed: the identity, name, attributes, interaction or verification message is invalid. kind_not_accepted: page views are not accepted.
missing_api_key or invalid_api_key: no key was sent, or it is unknown, revoked or expired, or it was not created from the Audience settings page.
payment_required: the organization’s subscription needs attention.
quota_exceeded: the identity matched nobody and the plan’s individual limit is reached, so no person was created (an identity that matches someone is still found and linked).
scope_denied: the key lacks this route’s scope. ip_denied: the caller’s address is outside the key’s allowed ranges. app_not_available: Audience is not enabled for the organization.
not_found: no such route.
accounts_not_enabled: account was sent but the organization has not turned accounts on; nothing was written.
rate_limited: the key spent its requests-per-minute budget; Retry-After says how long to wait. too_many_failed_authentications: too many bad keys from this address.