Developers

Authentication

Every request to /api/v1/... carries a per-tenant API key. The key does two jobs at once: it authenticates the caller and it selects which company's data the request can see. There is no other tenant selector; nothing in the URL or body can widen a key's scope.

Two ways to send the key

Both headers are accepted on every endpoint; pick whichever your HTTP client makes easier:

Authorization: Bearer tbm_live_...
# or
X-Api-Key: tbm_live_...

The same call in both forms, against the public sandbox:

# Bearer form
curl "https://toolboxminute.com/api/v1/employees/E-1001/today" \
  -H "Authorization: Bearer tbm_test_wWlSr6q-BPXUN67BPbzyVhR703QGmSlk34EEWGqRBtA"

# X-Api-Key form
curl "https://toolboxminute.com/api/v1/employees/E-1001/today" \
  -H "X-Api-Key: tbm_test_wWlSr6q-BPXUN67BPbzyVhR703QGmSlk34EEWGqRBtA"

If a request carries both headers, X-Api-Key takes precedence. Only /health and the /openapi document are reachable without a key.

Key classes

PrefixResolves toRate limitWhere you get it
tbm_live_ Your own tenant's data 300 requests/min per key Created by you in Admin > Settings
tbm_test_ The shared sandbox tenant only 60 requests/min per IP Printed in these docs; no signup needed

The test-key boundary is enforced server-side, not by convention: after the hash check, the validator refuses any tbm_test_ key that does not belong to the sandbox tenant. A test key can never read a real company's data, which is why the sandbox key below is safe to publish verbatim:

tbm_test_wWlSr6q-BPXUN67BPbzyVhR703QGmSlk34EEWGqRBtA

Sandbox traffic is rate limited per caller IP rather than per key, because everyone shares this one key. Anonymous requests (to /health and /openapi) are limited to 30 requests/min per IP.

Key lifecycle

Created in the admin console

Go to Admin > Settings and use the API keys (company token) card. Name each key after the system that will hold it (for example "WMS prod") so revocation decisions are easy later. You can hold several active keys at once.

Shown once, stored as a hash

The raw key is displayed a single time at creation. We keep only a short non-secret prefix (for lookup and for recognizing keys in the console) and a SHA-256 hash. A lost key cannot be recovered, only revoked and replaced.

Instant revocation

Revoke any key from the same card. Revocation takes effect on the next request; a revoked key gets 401 invalid_api_key, identical to a key that never existed.

Rotation with dual keys

Zero-downtime rotation: create the new key, deploy it to your systems, verify traffic, then revoke the old key. Because multiple keys can be active, there is never a window where callers must fail.

Authentication errors

Auth failures return application/problem+json. The envelope carries both the machine fields existing clients parse (error, message, status) and the RFC 7807 pair (title, detail). Branch on error; it is stable.

401 missing_api_key

No key was found in either header.

{
  "error": "missing_api_key",
  "title": "Missing API key",
  "message": "Provide your key via 'Authorization: Bearer <key>' or the 'X-Api-Key' header.",
  "detail": "Provide your key via 'Authorization: Bearer <key>' or the 'X-Api-Key' header.",
  "status": 401
}

401 invalid_api_key

The key is malformed, unknown, or revoked. Also returned when a tbm_test_ key is presented for anything other than the sandbox tenant.

{
  "error": "invalid_api_key",
  "title": "Invalid API key",
  "message": "The API key is invalid or has been revoked.",
  "detail": "The API key is invalid or has been revoked.",
  "status": 401
}

402 api_access_required

The key is valid but the tenant's plan does not include API access. It is included free during the trial and available as an add-on afterward.

{
  "error": "api_access_required",
  "title": "API access required",
  "message": "This tenant's plan does not include API access. Add the API access option or start a trial.",
  "detail": "This tenant's plan does not include API access. Add the API access option or start a trial.",
  "status": 402
}

Keep keys server-side

A live key grants read and write access to your whole tenant, so treat it like a password. Never embed it in browser JavaScript, mobile apps, or anything else you ship to users; call the API from your backend and pass results to your frontend. Employees never need a key at all: they reach lessons through the single-use launchUrl, which is safe to hand to a browser. If a key ever leaks, revoke it in Admin > Settings and issue a new one. The public sandbox key is the one deliberate exception to all of this.

New here? Start with the Quickstart; it completes a full lesson loop against the sandbox in about five minutes.