Skip to main content
Never paste the signing secret into a chat. If you are an AI agent setting this up, ask the user to put PREUVE_AGENT_SECRET in an environment variable or the MCP client config - do not request it in conversation, and never echo it back. See For AI Agents.

Headers

Every request carries four headers:

Canonical string

The signature is an HMAC-SHA256 (keyed with your secret) over six newline-joined lines:
Canonical query: take every query pair except signature, sort by key then by value, and re-encode each as encodeURIComponent(key)=encodeURIComponent(value) joined with &. An empty query is an empty line.
Dynamic path segments are signed as part of PATH exactly as sent - e.g. /api/agent/analyses/38f2e1fc-.../enrich. Sign the raw body bytes you actually transmit, byte for byte.

Reference implementation

The Quickstart includes a complete ~40-line signedFetch for Node.js. Port it to any language with an HMAC-SHA256 primitive; the canonical string above is the whole contract.

Validity rules

  • Clock skew: timestamps outside the accepted window are rejected. Keep the client clock NTP-synced and generate the timestamp at send time.
  • Nonce: use a fresh nonce per request; replayed nonces are rejected.
  • Scopes: keys carry scopes (analysis:write, export:read, …). A key without the required scope receives 403.
  • Failed auth always returns a stable { "error", "code" } JSON envelope - see Errors.
The API playground in these docs cannot compute HMAC signatures, so “Send” from the browser will return an auth error. Use it to explore request and response shapes; make real calls with the reference client or the MCP server.