Skip to main content

Personal data is encrypted per workspace

Identity fields — email, name, company, phone, and any vendor token — are encrypted at rest under a key belonging to your workspace alone. That key is itself stored wrapped by a master key held only in the application environment, so a dump of the key table is inert on its own. The workspace key is minted on first use. Concurrent first writes re-read rather than overwrite, because replacing a key would make everything already encrypted under it permanently unreadable.

Encrypted, but still searchable

Encrypted fields cannot be searched directly — the same address encrypts to different bytes each time. Email is therefore also stored as a keyed hash, which is what contact lookup and email search actually query. This has a consequence worth knowing: when a visitor gives an address that already belongs to a known contact, they are matched through that index rather than recorded as a new lead. An existing customer arriving anonymously is not a fresh prospect.

What is plaintext, and why

Because setContext is plaintext, do not put personal data in it. Identity belongs in identify or the top-level fields of /v1/users, which are encrypted.

What is never stored

  • Raw IP addresses. IPs are used to bucket rate limits and to mint a visitor contact for sites with no login. They are hashed first; the raw address is not kept.
  • Recoverable secret keys. Only a hash.
  • Recoverable vendor tokens in history. The live token is stored encrypted; token history keeps a fingerprint and a status only.
  • MCP tool arguments. The audit trail records which capability was called, by what method, with what outcome — never the arguments.

What is never logged

/v1/users logs nothing from its payload — not the token, not the hash, not the email. On failure it logs the error shape only, because database error messages can echo the offending row, which for that table means ciphertext at best and the plaintext body at worst. Billing webhook payloads are likewise never logged, since they carry billing detail.

Identity is never an authorization key

Anything the browser asserts about who the user is — contact, externalUserId — is enrichment only. It cannot resolve a workspace, grant access, or read another person’s data. The clearest example is the widget’s session-history command: identity is anchored server-side from the session id or the unguessable visitor id, and the client-asserted externalUserId is deliberately not trusted as an authorization key, so a page cannot read someone else’s history by asserting their id. The workspace always comes from the validated key, never from the request body. That is the tenant boundary.

Vendor tokens never reach the browser

A vendor token is pushed server-to-server through /v1/users, stored encrypted, and used server-side. There is no browser-side equivalent: anything in the DOM is reachable by any script on the page, including a prompt-injection payload. A freshly pushed token is marked valid but unverified, so it is re-checked against your API on the next agent request — which is what stops a token you have already revoked staying valid inside Peeve.

Grounding is data, not instructions

The agent receives several kinds of external content each turn: your product map, retrieved knowledge, customer context from connectors, and the names and descriptions of any MCP tools you have connected. All of it is treated as reference data, never as instructions. Text embedded in a page, a tool description or a connector result cannot direct the agent’s behaviour. In particular, no instruction from any of those sources can waive the confirm-before-write rule — that is enforced in code, on the server, after the model has produced its plan. On any conflict between retrieved knowledge and what the live page shows, the page wins.

Attachments

Files sent in chat go to private storage, scoped by workspace and session. They are served through short-lived signed URLs valid for one hour, minted per request — so a cross-site <img> can display a private image without any storage credential reaching the browser. Limits: 10 MB, images and common document types only.

Transcript retention

Each workspace has a transcript policy governing when a session transcript is kept and attached to a hand-off — on request (the default), always, or never. Set it in Settings → Transcripts & data, alongside the retention window.