Skip to Content
Automation APIAuthentication

Authentication

Every /v1 route takes one of two credentials, and which one you hold decides what you may call.

CredentialWho sends itLooks like
API keyn8n, your backend, CIAuthorization: Bearer pm_live_…
Session JWTThe editor and the dashboardAuthorization: Bearer eyJhbGci…

Both resolve to the same account. Neither is interchangeable with the other for every route — see Scopes.

Sending an API key

The canonical header is Authorization:

Authorization: Bearer pm_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

X-API-Key is accepted as an alias, carrying the bare key with no Bearer prefix. It exists because it is the default header of n8n’s generic credential type:

X-API-Key: pm_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Send one or the other, not both. Missing either answers 401.

Key format

PropertyValue
Prefixpm_live_
Body24 random bytes, base64url
Stored asHMAC-SHA256 under a server-side pepper — never the secret itself
Displayed after creationThe first 14 characters only (pm_live_ab12cd)

Because only the hash is stored, a lost secret is unrecoverable. Revoke and mint a new one.

Scopes

A key carries a list of scopes. The route you call determines the scope required, and a key without it gets 403 insufficient_scope.

ScopeGranted by defaultLets a key
renders:readList, poll and download renders
renders:writeCreate and cancel render jobs, and upload assets
templates:readList and read templates
templates:writeImport a project, publish and delete templates
usage:readRead /v1/usage

Creating a key with no scopes field grants the four defaults.

templates:write is the one you have to ask for, and importing a .motion needs it. A key without it gets 403 insufficient_scope from POST /v1/templates/import. If your workflow only renders from templates that already exist, leave it off.

Why uploads ride on renders:write

POST /v1/assets does not have a scope of its own. A new assets:write would be the tidier taxonomy and the worse migration: scopes are stored per key, so it would be absent from every key already issued, and the first thing anyone tried after upgrading would be a 403 on a route that had just been announced.

The privilege is honest, too — a temporary asset exists only to feed a render, is unreadable without its unguessable URL, and expires in 24 hours. A key that can create renders can already spend the quota that matters.

Key management is session-only. /v1/keys — list, create, revoke — rejects pm_live_ keys with 403 session_required, whatever their scopes. A leaked key therefore cannot mint more keys, revoke the ones you have, or hide its own tracks.

Deny-by-default

Scope mapping is a deny-list, not an allow-list. A /v1 route added without an explicit scope mapping is treated as session-only until somebody decides which scope covers it. New endpoints are never silently reachable by every key that already exists.

Expiry

expiresAt is an optional ISO timestamp, and it must be in the future. The editor’s key dialog offers never, 30 days, 90 days and 1 year. An expired key answers 401 exactly like an invalid one.

{ "name": "CI — nightly reels", "expiresAt": "2027-08-27T00:00:00.000Z" }

Revocation

DELETE /v1/keys/{id} Authorization: Bearer <session JWT>

Revocation takes effect on the very next request — the guard reads revokedAt on every call, so there is no cache to wait out. Revoking twice is not an error.

What is tracked

Each key records lastUsedAt and a requestCount, both visible in the key list. If you are wondering whether an old key is still wired into something, that is where to look before you revoke it.

Rotating a key

Plans allow more than one active key precisely so you can rotate without downtime: mint the new key, deploy it, confirm lastUsedAt on the old key stops moving, then revoke the old one. Doing it in the other order takes your workflow down for the length of the deploy.

Errors

StatusCodeCause
401No credential, unknown key, revoked key, expired key, bad JWT
403session_requiredAn API key called a session-only route
403insufficient_scopeThe key lacks the scope this route requires
403upgrade_requiredThe plan does not include API access
403key_limit_reachedAlready at the plan’s active-key cap

The insufficient_scope body names what was missing, so you can fix it without guessing:

{ "code": "insufficient_scope", "required": "renders:write", "message": "This API key does not have the renders:write scope." }

See Errors for the full envelope.

Last updated on