Skip to main content

Authentication

The SKU.io API authenticates external callers with Personal Access Tokens (PATs) — Laravel Sanctum bearer tokens with explicit scopes.

Base URL​

SKU.io is multitenant. Every tenant has its own domain, and the API is served from it:

https://{tenant}.sku.io/api

Your token belongs to your user account on your tenant. Calling another tenant's domain with it will not work.

Creating a token​

Tokens are created in the web app:

  1. Settings → Developer → Personal Access Tokens
  2. Create Token — choose a name, scopes, and (optionally) an expiry, an IP allowlist, and a per-token rate limit.
  3. Copy the plaintext token from the create dialog. It is shown once and never again — only a hash is stored.

A token looks like:

142|hZk3vX9pQ7WmT2sLxCbNvA8dRfGjK4eYuI6oP1zq

Token management is deliberately session-only: a PAT cannot be used to create, list, or revoke PATs. A leaked token can't mint more tokens. Each user can hold at most 50 active PATs.

Sending the token​

Include it as a Bearer token on every request, and ask for JSON:

curl "https://acme.sku.io/api/v2/products" \
-H "Authorization: Bearer 142|hZk3vX9pQ7WmT2sLxCbNvA8dRfGjK4eYuI6oP1zq" \
-H "Accept: application/json"

Scopes​

Tokens carry an explicit list of scopes, named {resource}:{action}:

ScopeGrants
orders:readView sales orders and order lines
orders:writeCreate, update, and cancel sales orders
products:readView products, SKUs, and variants
products:writeCreate and update products
inventory:readView stock levels, allocations, and reorder points
inventory:writeAdjust inventory, transfer stock, and reconcile counts
customers:readView customers
customers:writeCreate and update customers
suppliers:readView suppliers
suppliers:writeCreate and update suppliers
purchase-orders:readView purchase orders
purchase-orders:writeCreate, update, and approve purchase orders
warehouses:readView warehouses and locations
reports:readView reports and analytics
webhooks:manageCreate and delete webhook subscriptions

How scopes are applied:

  • Endpoints under a resource require {resource}:read for GET/HEAD requests and {resource}:write for POST/PUT/PATCH/DELETE.
  • PATs are deny-by-default. Endpoints that haven't been opened to the token scope system reject PATs outright with 403 — "This endpoint is not available to API tokens." The API reference and these guides only describe token-accessible surface; if you hit that error on an endpoint you need, contact support.
  • Scopes do not bypass user permissions. A token acts as you — if your user role can't delete products, neither can your token, even with products:write.

Missing scope response (403 Forbidden):

{
"message": "Token is missing the required scope: orders:read",
"required_scope": "orders:read"
}

What a 401 looks like​

Missing, malformed, expired, or revoked tokens all produce 401 Unauthorized:

{
"errors": {
"token": [
{
"message": "Unauthorized",
"code": "Unauthorized",
"data": []
}
]
},
"status": "failure",
"message": "Unauthorized"
}

Treat any 401 as "re-check the credential" — the API does not distinguish expired from revoked.

Token lifecycle​

  • Expiry — optional, set at creation. The create dialog suggests 90 days; a token created without an expiry never expires. Expired tokens return 401.
  • Revocation — delete the token in Settings → Developer → Personal Access Tokens. Revocation is immediate.
  • Editing — name, scopes, IP allowlist, and rate limit can be changed after creation. Adding a :write or :manage scope to an existing token requires re-entering your password (and your 2FA code, if enabled).
  • IP allowlist — optional CIDR list per token. Requests from other addresses get 403: "This token is not permitted from 203.0.113.5."
  • Per-token rate limit — optional requests-per-minute cap per token; see Rate Limits.
  • Usage log — every token-authenticated request is recorded. Open a token in Developer Settings to see its request history and usage analytics.

Headless & machine-to-machine access​

There is no OAuth or client-credentials flow — a Personal Access Token is the credential for all automation, including unattended servers, cron jobs, and agents. The only step that requires a human is minting the token; nothing in the running integration needs a person in the loop.

To run automation unattended:

  1. A user with the necessary permissions creates one dedicated token per integration, scoped to exactly the {resource}:{action} pairs it needs.
  2. Give it no expiry (or a long one you rotate on a schedule) so the integration doesn't break while unattended — the trade-off is that a long-lived token must be guarded carefully.
  3. Pin it to your egress IPs with the token's IP allowlist, so a leaked token is unusable from anywhere else.
  4. Store the plaintext in a secrets manager and inject it at runtime; never commit it.

Because a PAT cannot create, list, or revoke PATs, a compromised automation token cannot mint more tokens — but it keeps acting with its granted scopes until a human revokes it, which is why IP-pinning and rotation matter for headless use.

Security recommendations​

  • Create one token per integration, scoped to exactly what it needs.
  • Prefer read-only scopes wherever possible.
  • Set an expiry and rotate before it lapses.
  • Pin production tokens to your servers' egress IPs with the allowlist.
  • Store tokens in a secrets manager; never commit them.