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 PKCEis 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 Authorizationheader; every write also accepts an Idempotency-Keyfor safe retries. Available on every plan including Free. Daily call caps apply only to Free (100/day) and Basic (200/day); 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:writestill 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, update, and publish passports |
| documents:read | Read uploaded documents and extractions |
| documents:write | Upload documents and run AI extractions |
| suppliers:read | View supplier requests |
| suppliers:write | Create and manage supplier requests |
| offline_access | Issue a refresh token (stay connected) |
Idempotency-Key
Every POST, PATCH, and DELETE on the v1 surface accepts an Idempotency-Keyheader. Send a UUID v4 (or any opaque string ≤ 255 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 returns422 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, per workspace:
1. v1 write budget — `maxV1WritesPerDay`
Counts every POST / PATCH / DELETEon the v1 surface. Reads aren't budgeted on this counter.
2. v1 passport-read budget — `maxV1PassportsPerDay`
Counts every GETon the passport endpoints (single read + paginated list). 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 quota — maxDpps — caps total active DPPs in your workspace and is enforced via a 402 response with an overage_required body when the plan supports per-passport overage. See the Create a passport endpoint for the overage flow.
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.