Authentication

How GigaQR API keys work — secret vs publishable, scopes, origin allowlists, rotation.

Every request to the REST API carries a bearer token in the Authorization header:

Authorization: Bearer sk_live_...

Two kinds of keys

Key typePrefixWhere it runsPlan
Secretsk_live_Server-only. Never ship to a browser or mobile client.Pro and above
Publishablepk_live_Browser, via the @gigaqr/embed widget. Restricted to specific origins.Free and above

Publishable keys can only hit the widget endpoint /api/v1/widget/qr. Secret keys hit the full REST API. Mixing them up (e.g. a pk_live_ in a server request) is rejected with 401.

Scopes

Secret keys carry scopes that narrow what they can do. Grant the minimum a given integration needs. Common scopes:

  • qr:read — list and fetch QRs and scan events.
  • qr:write — create, update, and delete QRs.
  • bulk:write — submit bulk jobs.
  • scans:export — export raw scan events.

A request that exceeds the key's scope returns 403 with code: "forbidden".

Origin allowlist (publishable keys)

When you create a publishable key, list the origins your widget will run on (e.g. https://acme.com). Requests from other origins are rejected with 403. Add http://localhost:3000 during local development.

Rotating a key

  1. Create a new secret key with the same scopes.
  2. Roll it out in your secret manager (Vercel, Doppler, AWS Secrets Manager).
  3. Wait 24 hours — the Developer page shows Last used for every key.
  4. Revoke the old key. The audit log records every revoke.

When a key is compromised

Revoke it immediately in the dashboard. A revoked key fails with 401 on the very next request — there is no propagation delay. Rotate into a fresh key and then review Dashboard → Audit log for anything you didn't initiate.

Error shape

{
  "error": "Origin not allowed",
  "code": "forbidden"
}

Every error response has this shape. code is machine-readable and stable; error is human-readable and may change over time.