identify — who they are
email, name, company and phone are encrypted at rest. The email is
additionally indexed by a keyed hash, so contact lookup and email search keep
working without decrypting anything.
plan is the user’s plan in your product, as a display name. It is stored
plaintext because it is not personal data — and it has no effect on your Peeve
entitlements, which come from your own subscription.
createdAt is worth setting. It is how Peeve distinguishes a genuine new signup
from an existing customer browsing logged out, so a returning user is not
miscounted as a visitor-to-user conversion.
Identity is never trusted for authentication. Anything the browser sends
in
contact is enrichment only — it cannot resolve a workspace, grant access,
or read another person’s data. The workspace always comes from the validated
key.setContext — what you know about them
The server-side equivalent
Both have a server-side counterpart onPOST /v1/users, so you can establish a complete
contact before the person ever opens a browser:
identify; the attributes object is
setContext. A later browser identify with the same external_user_id merges
into the same record.
Identity is keyed on your id, not on the key
A contact is identified by(workspace, external_user_id). It is deliberately
not keyed on the API key — if it were, every user would be orphaned the day you
rotated a key, and their history would vanish.
So: use a stable id. Your internal user id is right. An email address is
usable but changes; a session id is not an identity at all.
Anonymous visitors
Before someone signs in, Peeve still tracks them, using a persistent browser visitor id. When you later callidentify, the pre-login history links to the
now-known user.
This is why calling identify at the right moment matters: it is what joins
“someone browsed pricing three times” to “Dana signed up”.
On logout
Vendor tokens
POST /v1/users accepts a vendor_token — a token your backend issues for a
user, so a Custom API connector can call your API as them.
Rotating a token supersedes the previous one in the token history, which stores
a fingerprint only — never the recoverable secret. A freshly pushed token is
marked valid but unverified, so it is re-checked against your API on the next
agent request. That is what stops a token you have already revoked staying
valid inside Peeve.
A token authenticates; it does not authorize. Possession of one is full
account authority, so the capability allowlist you configure — not the token —
is what stands between a leaked token and real damage.