identify

Link accounts to channels

Tell Datalenk who a visitor became. From your backend, connect the anonymous visitor id captured at signup to the account's email, and we permanently record which channel brought that customer. Every future payment, even years later and without any cookie, is then attributed to the right channel.

Authentication

Bearer token in the Authorization header, your workspace API token (the same one used for the MCP and the rest of the v1 API). These are server-to-server calls: never expose the token in the browser.

Identify a single account

POST/api/v1/identify
Link one visitor to one account, and optionally enrich it.
ParamTypeDescription
anonymous_idreqstringThe visitor id captured at signup: window.datalenk.ref on your site. Used to resolve the acquisition channel of that session.
emailreqstringThe account email. It is the durable join key. Hashed on our server (see below); the raw value is never stored.
user_idstringYour internal user id, for enrichment.
planstringCurrent plan (also accepted inside traits).
companystringB2B account key: groups customers into accounts, retroactively.
mrrnumberAccount MRR, for enrichment.
traitsobjectAny extra key/values to attach to the profile.
curl -X POST https://datalenk.com/api/v1/identify \
  -H "Authorization: Bearer dlk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "anonymous_id": "dl_a1b2c3",
    "email": "jane@acme.com",
    "user_id": "usr_123",
    "company": "Acme",
    "plan": "pro"
  }'
node
await fetch("https://datalenk.com/api/v1/identify", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.DATALENK_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    anonymous_id: cookies.get("dl_ref"), // window.datalenk.ref captured at signup
    email: user.email,
    user_id: user.id,
  }),
});
response
{ "ok": true, "linked": true, "channel": "Organic Search" }

linked: false means we had no anonymous session to tie to that visitor id yet (the traits are still saved, with enriched: true). A missing email or anonymous_id returns a 400.

Backfill in bulk

POST/api/v1/identify/bulk
Enrich your existing base, up to 1000 users per call.
ParamTypeDescription
usersreqobject[]Array of { email, user_id?, plan?, company?, mrr?, traits? }. Max 1000 per call: send in batches. Rows without a valid email are skipped.
curl -X POST https://datalenk.com/api/v1/identify/bulk \
  -H "Authorization: Bearer dlk_live_…" -H "Content-Type: application/json" \
  -d '{ "users": [
    { "email": "jane@acme.com", "company": "Acme", "plan": "pro", "mrr": 99 },
    { "email": "bob@globex.com", "company": "Globex" }
  ] }'
response
{ "ok": true, "imported": 2, "skipped": 0 }

What we do, and what we do not

The email is hashed on our server (keyed HMAC) the moment it arrives; the raw address is never stored. You keep the legal basis for your own user data: we never pull your database, you push the accounts you choose.

Bulk is enrichment, not retroactive attribution. It attaches traits to a profile so your accounts and B2B groupings fill in; it does not invent an acquisition channel for a visit we never observed. Channel attribution comes from a real anonymous session, which is why the single identify call needs the anonymous_id.