Produktly docs
REST API

Produktly API authentication

How to authenticate against the Produktly REST API and MCP server with an API key, including scopes, rate limits, and error codes.

The Produktly REST API and the MCP server authenticate the same way: an API key sent as a Bearer token. One key works for both.

Get an API key

  1. Sign in to Produktly and open Settings → API keys.
  2. Give the key a name (for example Production, MCP, or CI) and select Generate new private key.
  3. Copy the key. It is shown in full in the list, so you can come back for it, but treat it like a password.

Keys belong to a company, not to a user, so a key keeps working after the person who created it leaves.

Send the key

Put the key in an Authorization: Bearer header on every request:

curl https://api.produktly.com/api/v1/changelogs \
  -H "Authorization: Bearer <your-api-key>"

The one exception is GET /api/v1/openapi.json, which is public and needs no header.

An MCP client sends the same header, set in its server config:

"headers": {
  "Authorization": "Bearer <your-api-key>"
}

The MCP server docs have the full config for Claude Code, Cursor, Windsurf, and VS Code.

Which key is which

Produktly has three different tokens and they are easy to mix up:

TokenWhere it livesSecret?Used for
API key (private key)Settings → API keysYes, server-side onlyREST API, MCP server, signing identity verification hashes
Client Auth TokenYour install snippetNo, public by designIdentifying your account to the widget script in the browser
Identity verification hashGenerated per user on your backendDerived from an API keyProving a identifyUser call is genuine — see Identity verification

Only the first one authenticates API and MCP requests. Never ship an API key to the browser: anyone holding it can read and write all of your Produktly data.

Scopes

Every key carries a set of scopes:

ScopeGrants
readAll GET requests
writeEverything else — create, update, delete
publishPublishing a widget, and editing one that is already live

Requests are checked against the scopes on the key: GET needs read, any other method needs write, and publish is enforced inside the individual endpoints.

Keys generated in the dashboard today carry all three scopes. Scoped-down keys can be created through the dashboard API by passing a scopes array, which is what an agent integration would use to get a key that can draft widgets but not publish them.

Errors

Authentication and quota problems come back in the standard error envelope:

{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid Authorization header"
  }
}
StatusCodeMeaning
401unauthorizedNo Authorization: Bearer header, or the key is invalid or has been deleted
403insufficient_scopeValid key, but it lacks the scope the endpoint needs
409widget_is_liveThe widget is published and the key has no publish scope. Unpublish it in the dashboard, or use a key that can publish
429rate_limit_exceededOver the rate limit — see below

MCP clients get the same failures as JSON-RPC errors rather than this envelope.

Rate limits

Limits are per API key, not per IP:

  • 60 requests per minute for most endpoints
  • 300 requests per minute for /users, which has its own bucket so backend user syncs do not starve everything else

Every response carries the current state:

  • X-RateLimit-Limit — requests allowed in the window
  • X-RateLimit-Remaining — requests left
  • X-RateLimit-Reset — Unix seconds when the bucket refills

A 429 also sets Retry-After in seconds. Back off for that long and retry.

Rotating and revoking

Delete a key from Settings → API keys to revoke it immediately. There is no grace period, so generate the replacement and roll it out before deleting the old one.

If a key leaks, delete it first and investigate second. A leaked key can read and modify every widget, response, and identified user in the account.

On this page