PalveronPalveronDocs

Authentication

Authenticate requests to the Palveron API.

Every request to the Palveron API is authenticated with a bearer token — always the project API key.

curl -H "Authorization: Bearer pv_live_..." https://gateway.palveron.com/api/v1/verify

Key types

PrefixUsed byLifecycle
pv_live_Server-side SDKs, your own backend, and the Browser Guard extensionIssued per project, rotatable in Settings → API Keys

Agent keys (ag_)

Registering an agent also mints an ag_ agent key internally, stored hashed at rest only — it is not returned in the response and never displayed. This key is not accepted for API authentication today — it is reserved for future agent-scoped authentication and is invalidated when the agent is revoked or rejected. Every caller, including one acting for a single agent, authenticates with the project key.

Agents are attributed by their agent id instead — a plain CUID with no prefix (e.g. ckagent...): metadata.agent_id on verify requests, the X-Agent-Id header on the MCP proxy, or the X-Palveron-Agent header on the gateway LLM proxy.

Never commit keys to source control. The dashboard shows each key exactly once on creation. Store them in your secrets manager (AWS Secrets Manager, GCP Secret Manager, Vault) or in your CI/CD pipeline's secret store.

Key mode

Every project API key is a live key (prefix pv_live_); there is no separate test or sandbox key. A key's prefix does not change how a request is billed or anchored — that behaviour is a property of the project, not of the key.

For gas-free experimentation, use the dashboard Playground: Playground traces are never anchored on-chain, regardless of the project's configured network.

Error responses

Authentication and authorization errors return a structured JSON body:

{ "error": { "code": "unauthorized", "message": "Invalid API key", "request_id": "req-..." } }
StatusMeaning
401Missing/invalid Authorization header, or the key is unknown/revoked
403The key is valid but the caller cannot perform this action, or the endpoint needs a higher plan (error.code is forbidden)
429Rate limit hit — see below

Branch on error.code (for example unauthorized, forbidden, validation_error), not on the HTTP status alone. Quote the request_id in support requests; it is also in the x-request-id response header.

Rate limits

Two independent limits, both resolved from your plan configuration (null = unlimited, 0 = locked, N = limit):

  • Monthly quota — governance requests per month.
  • Requests-per-minute (RPM) — only enforced when your plan sets one.

A 429 carries a structured body and standard headers (all values below are illustrative examples — your project's real limits come from the live tier configuration):

{
  "error": "Rate limit exceeded",
  "tier": "pro",
  "limit": 20000,
  "limit_type": "monthly",
  "remaining": 0,
  "retry_after_secs": 86400,
  "action": "top_up",
  "detail": "Rate limit exceeded. Purchase additional governance traces to continue.",
  "top_up_available": true
}

Headers: Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining, X-Rate-Limit-Type (rpm / monthly), X-RateLimit-Behavior, X-TopUp-Available.

On 429 the SDK does not retry on its own. The verify() function returns the decision RATE_LIMITED with retryAfterMs; honour that value before sending again.

On this page