Authentication

Every /v1 call names the persona it acts on with X-Persona-Id. What differs is who is asking: a browser on your site — the Live Persona (3D) and Chat Persona one-liners, or your own browser code — sends the Persona ID alone; your server adds the account key.

Persona IDX-Persona-Id· Every /v1 call

The public identifier of the persona a call acts on — the ?k= value in the widget snippet. Designed to live in your page: it identifies the persona but grants no account access. Sent alone, the call is an embed: restricted to the persona's allowed domains, anonymous-visitor rules, rate-limited.

Account keyX-Api-Key· Server-side only

One key per account (ak_…), minted on your profile. Added to a /v1 call it lifts the origin guard and unlocks the server surface — knowledge sync and chat from your own backend. The persona named in X-Persona-Id must belong to the account, else 404. Never ship it to a browser.

Identity Secretserver-side· Server-side only

One per account, beside the account key on your profile. Signs the end-user JWTs that recognize a logged-in visitor (below), for every persona. Handed to a connected site's plugin on connect. The secret itself never reaches the browser; only the short-lived JWT it signs does.

CallerHeadersRules
Embed — a browser on your siteX-Persona-IdOrigin-guarded against the persona's allowed domains; anonymous end-user identity rules apply.
Account — your own serverX-Persona-Id + X-Api-Key: ak_…No origin guard. The persona must belong to the key's account, else 404. On /v1/knowledge the key acts on the whole account, naming sources and brands explicitly.

Building your own UI on the server? See the Chat and Knowledge references — both take the account key.

Recognize a logged-in user

Without a token, each browser is an anonymous visitor (history is keyed to a random per-browser id). To make a signed-in user's history follow them across devices, your server signs a short-lived JWT with your account's Identity Secret (on your profile beside the account key, and handed to your site's plugin when it connects) and the page passes it to the widget as identityToken. The widget sends it as X-End-User-Token; the backend trusts its sub claim.

1 · Sign on your server

// Server-side only — sign a short-lived token for your logged-in user.
import jwt from "jsonwebtoken";

const token = jwt.sign(
  { sub: user.id },                    // your account id for this visitor
  process.env.PERSONAIZER_IDENTITY_SECRET, // your account's, from Profile → Identity Secret
  { algorithm: "HS256", expiresIn: "1h" },
);
// → hand 'token' to the page (never the secret)

2 · Pass it to the widget

<!-- In the page: pass the signed token to the widget -->
<script>
  window.PersonAIzerConfig = {
    identityToken: "<jwt-from-your-server>",
    // or refresh it on demand:
    // identityTokenProvider: async () => fetch("/personaizer-token").then(r => r.text()),
  };
</script>
<script src="https://cdn.personaizer.com/live.js?k=YOUR_PERSONA_ID" async></script>

Rotating the Identity Secret (on your profile) invalidates tokens signed with the old one for every persona — update your server to sign with the new secret, or logged-in visitors fall back to anonymous. Never put it in a page; only the JWT it signs.