TracePass
Reference

Authentication

Two auth methods — API key (Bearer) and OAuth 2.0 with PKCE — plus Idempotency-Key for safe retries and per-plan rate limits on the v1 surface.

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:

bash
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.

ScopeGrants
passports:readView products and digital product passports
passports:writeCreate, update, and publish passports
documents:readRead uploaded documents and extractions
documents:writeUpload documents and run AI extractions
suppliers:readView supplier requests
suppliers:writeCreate and manage supplier requests
offline_accessIssue 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.

bash
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.

PlanWrites / dayPassport reads / day
Free100100
Basic200200
StarterUnlimitedUnlimited
GrowthUnlimitedUnlimited
ScaleUnlimitedUnlimited
ProUnlimitedUnlimited
EnterpriseUnlimitedUnlimited

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.