Signed JWT
The recommended way to identify visitors — a short-lived HS256 token signed with your shared secret
A host-signed JWT is the recommended way to identify visitors. You mint a short-lived token on your server, hand it to the widget, and the backend verifies it against your integration's shared secret.
Token format
| Field | Requirement | Value |
|---|---|---|
| Algorithm | required | HS256 |
| Secret | required | Your integration's shared secret — server-side only |
sub | required | A stable, opaque visitor id (your user's id) |
iat | required | Issued-at, Unix seconds |
exp | required | Expiry, Unix seconds — recommend 1–24 hours |
email | optional | Visitor email |
name | optional | Display name |
phone | optional | Phone |
fields | optional | A trusted profile map written to the contact (see below) |
Sign it on your server
import jwt from "jsonwebtoken";
const token = jwt.sign(
{
sub: user.id,
email: user.email,
name: user.name,
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + 3600, // 1 hour
},
process.env.WEXIO_INTEGRATION_SECRET,
{ algorithm: "HS256" },
);Hand it to the widget
// React
<WexioWidget
publicKey="pk_live_..."
user={{ jwt: serverSignedJwt, name: "Ada Lovelace", email: "ada@example.com" }}
/>// Web Component
document.querySelector("wexio-widget").identify({ jwt: serverSignedJwt, name: "Ada" });
// Script loader
window.Wexio("identify", { jwt: serverSignedJwt, name: "Ada" });The backend verifies HS256 and exp, extracts sub as the user id, and establishes a verified session. A leaked token self-revokes at exp.
Trusted profile fields
Because the whole token is signature-verified, a fields claim writes the contact's profile server-side — no prechat form needed:
const token = jwt.sign(
{
sub: user.id,
email: user.email,
name: user.name,
fields: {
company: "Acme", // system field
lead_status: "QUALIFIED", // system select — must be a valid option
plan_tier: "enterprise", // custom field by key
mrr: 4200,
},
iat: now,
exp: now + 3600,
},
process.env.WEXIO_INTEGRATION_SECRET,
{ algorithm: "HS256" },
);Rules:
namesplits intofirst_name+last_nameat the first space;email/phonemap to the email/phone fields. Explicitfields.first_nameetc. override the split.- Other keys write people-field values by key — but only fields that exist for your org and are writable.
- Unknown keys, read-only/derived fields (
*_at,total_*,flow_*, …), and protected keys (trust flags, channel ids) are skipped silently. Invalid values are skipped, never thrown.
Protected keys — web_verified, is_blocked, chat_status, priority, channel ids like telegram_id, and wexio_id — can never be set through the JWT. web_verified in particular is set by the backend only on a real verification, so flows and the AI assistant can trust it.
Rotating identity
Pass a new token to log in as a different user; clear it to log out:
<WexioWidget user={{ jwt: newJwt, name: "Grace" }} /> // switch user
<WexioWidget user={undefined} /> // log outSee Sessions for renewal and shutdown semantics.