Authentication
Bearer tokens for the REST API.
Every call to api/v1 carries one header —
Authorization: Bearer pkd_…. No signing, no nonces, no clock
skew to worry about. HTTPS handles the transport.
Token shape
onpack tokens begin with pkd_ followed by 32 random hex bytes.
They are opaque — don't try to parse them. Tokens are account-level:
one token authorises calls against every brand your company owns. Scope is
enforced by the :brand_slug path segment in the URL.
Sending the token
curl https://onpack.io/api/v1/brands/milka/scans \
-H "Authorization: Bearer pkd_••••••••••••••••"
require "net/http"
uri = URI("https://onpack.io/api/v1/brands/milka/scans")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{ENV['ONPACK_API_TOKEN']}"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
const res = await fetch("https://onpack.io/api/v1/brands/milka/scans", {
headers: { Authorization: `Bearer ${process.env.ONPACK_API_TOKEN}` }
});
Responses you should expect
| Status | Meaning |
|---|---|
200 OK | Request succeeded. Body is JSON. |
401 | Missing or invalid token. |
402 | Billing inactive for your company. Re-activate from the dashboard. |
404 | Resource not found or belongs to a brand outside your company. |
422 | Validation failed. Details in details. |
Rotating a token
Rotate any time from the dashboard. Clicking Regenerate invalidates the old token immediately — there is no overlap window, so plan a deploy to your services first.
Scope: what one token can reach
A token authorises calls on behalf of your company across every brand you
own. It cannot reach brands owned by anyone else. Each request includes a
:brand_slug — onpack 404s anything outside your scope.