TracePass v1 supports two auth methods. An API key (a static Bearer token) is the simplest — best for server-to-server and ERP integrations. OAuth 2.0 with PKCE is for third-party apps and AI assistants that act on a user's behalf with scoped, revocable access. Both arrive as a Bearer token in the standard Authorization header; most write routes also accept an Idempotency-Key for safe retries. Available on every plan including Free. Daily caps apply only to Free (100 writes + 100 passport reads per API key) and Basic (200 + 200); Starter and above are unlimited.
API keys
Mint keys at Developer → API keys in the dashboard. Keys are workspace-scoped: every key is tied to one workspace and inherits its plan, limits, and audit log. Keys carry the tp_ prefix followed by an opaque random suffix — there's no separate live / test prefix, and no env-namespaced sandbox. Test against your Free or Basic workspace if you need a non-production environment.
Pass the key as a Bearer token on every request:
curl -sS https://app.tracepass.eu/api/v1/products \
-H "Authorization: Bearer tp_REDACTED_xxxxxxxxxxxx"OAuth 2.0 (user-authorized apps)
When you're building an app that other TracePass users connect — or an AI assistant a user authorizes — use OAuth 2.0 instead of asking them to paste an API key. The user approves specific scopes on a consent screen; the access token they generate is limited to the intersection of their dashboard role and the scopes granted. Register your app at Developer → OAuth Apps (or programmatically via Dynamic Client Registration at /api/oauth/register). We support the authorization-code flow with PKCE — public clients (SPA / mobile / MCP) need no secret; confidential server-side clients get one.
The flow
Discovery metadata lives at /.well-known/oauth-authorization-server (RFC 8414). The short version: (1) send the user to /api/oauth/authorize with your client_id, redirect_uri, requested scope, state, and a PKCE code_challenge (S256); (2) they approve, and we redirect back with a single-use code; (3) exchange it at /api/oauth/token with your code_verifier for a 15-minute access token (plus a refresh token if offline_access was granted). Refresh tokens rotate on every use; revoke at /api/oauth/revoke (RFC 7009).
Scopes
Request only what your app needs — the consent screen shows the user exactly these. A write scope additionally requires the authorizing user to have a write-capable dashboard role, so a viewer who grants passports:write still can't write. API keys, by contrast, are all-or-nothing and ignore scopes.
| Scope | Grants |
|---|---|
| passports:read | View products and digital product passports |
| passports:write | Create and update passports (publishing stays in the dashboard) |
| regulatory:read | Check DPP scope applicability (scope-check and DPP assistant tools) |
| documents:read | Reserved — no v1 endpoints yet |
| documents:write | Reserved — no v1 endpoints yet |
| suppliers:read | Reserved — no v1 endpoints yet |
| suppliers:write | Reserved — no v1 endpoints yet |
| offline_access | Issue a refresh token (stay connected) |
Idempotency-Key
Selected v1 write routes accept an Idempotency-Key header — products (create, batch, update, delete, archive), passports (create, batch, update, archive, suspend, field update, party update, condition flags, measurement capture), EPCIS capture, and scope catalogue runs. Send a UUID v4 (or any opaque string ≤ 64 chars) per logical operation; the platform stores the first response for 24 hours and replays it if the same key + same workspace shows up again. Network retries become safe — you won't double-create a passport because your HTTP client retried on a transient 5xx.
curl -sS https://app.tracepass.eu/api/v1/passports \
-H "Authorization: Bearer tp_REDACTED_xxxxxxxxxxxx" \
-H "Idempotency-Key: 7b4f1e2c-9a3d-4e5b-8c1a-2d3e4f5a6b7c" \
-H "Content-Type: application/json" \
-d '{ "productId": "...", "gs1": { "gtin": "...", "serialNumber": "..." } }'Reusing the same key with a different request body returns 422 Unprocessable Entity with error: "Idempotency-Key has already been used with a different request body. Use a new key for the new request, or reuse the original body." — the platform doesn't silently overwrite, because that's almost always a client bug. Generate a fresh key for genuinely new operations.
Rate limits
Two ceilings apply per UTC day, counted per API key (an OAuth app keeps its own count):
1. v1 write budget — `maxV1WritesPerDay`
Counts every POST / PATCH / DELETE on the v1 surface. Reads aren't budgeted on this counter.
2. v1 passport-read budget — `maxV1PassportsPerDay`
Counts passports read: a list call counts its page size (limit, default 20), even when the last page returns fewer; every other read counts 1 (a single passport, its QR code, snapshots, EPCIS document, compliance check and registry readiness, plus EPCIS query, an EPCIS capture job and the scope catalogue). Separate from the write budget so an ERP pushing updates doesn't starve your read quota and vice versa.
| Plan | Writes / day | Passport reads / day |
|---|---|---|
| Free | 100 | 100 |
| Basic | 200 | 200 |
| Starter | Unlimited | Unlimited |
| Growth | Unlimited | Unlimited |
| Scale | Unlimited | Unlimited |
| Pro | Unlimited | Unlimited |
| Enterprise | Unlimited | Unlimited |
When you hit either ceiling the response is 429 Too Many Requests with a body like { "error": "API rate limit: 200 writes/day via /api/v1. Currently 200 today; requested 1. Retry tomorrow (UTC) or upgrade your plan." }. The window resets at 00:00 UTC; we don't support rolling windows because they make the limit harder to reason about downstream.
A separate limit — maxDpps — caps the published passports in your workspace. A passport created through the API is a draft and takes no slot, so create never returns an overage error. The limit applies when you publish in the dashboard. Past the cap, the dashboard asks you to confirm the per-passport overage charge, or refuses if your plan has no overage rate; then upgrade or archive passports. See the Create a passport endpoint.
What we don't support (yet)
The OAuth client-credentials grant (machine identity with no user) and IP allow-listing are on the roadmap but not shipped. For pure server-to-server access today, use an API key — mint one per integration so you can revoke at the integration level.