Authentication
Authenticate every request with a supplier-scoped bearer token. One
authentication scheme covers everything — send an Authorization header:
curl "https://sandbox-pay.mmokick.com/api/v1/whoami" \
-H "Authorization: Bearer $CK_TEST_TOKEN" \
-H "Accept: application/json"
Expected 200 response:
{
"token": {
"id": "01JZV9AB2CD4EF6GH8JK0MN2PQ",
"name": "repricer-bot",
"mode": "test",
"scopes": ["offers:read", "offers:write", "pricing:read"],
"created_at": "2026-06-02T09:14:00Z",
"last_used_at": "2026-07-11T13:59:41Z"
},
"supplier": {
"id": "01JZV8K2E4Q6S8A0C2E4G6J8KM",
"name": "Keyforge Ltd",
"status": "active"
},
"environment": "sandbox",
"rate_limits": { "reads": 600, "writes": 120, "sync": 300, "bulk": 12, "simulate": 120, "test": 6 }
}
GET /whoami is your integration smoke test: it confirms the token is valid, tells
you which scopes it carries, and reports the environment it belongs to. Use it first
in any new integration.
Get a token
Create tokens yourself in the supplier portal, under Settings → API tokens → Create
(route supplier.developers.tokens). Two-factor authentication is required to create a
token. A token is shown once at creation and hashed at rest; if you lose it, revoke it
and create another.
- Sandbox access is instant and auto-approved: submitting the supplier application in the
portal approves your supplier into the sandbox on the spot, so you can create a
ck_test_token in the portal (env toggle = Sandbox) — or use the published seeded token — and call the sandbox base URL within minutes. One portal manages both your Live and Sandbox tokens, so the same Settings → API tokens flow works for either. See Environments. - You may hold up to 25 tokens per environment. Tokens stay valid until you revoke
them, and you can revoke any token instantly in the portal.
last_used_atis tracked and displayed so you can spot and retire stale tokens.
Export your token once and reuse it across every example in these guides:
export CK_TEST_TOKEN="ck_test_..."
The header
Authorization: Bearer <token>
Tokens carry a prefix that names the environment:
| Prefix | Environment | Base URL |
|---|---|---|
ck_test_ |
Sandbox | https://sandbox-pay.mmokick.com/api/v1 |
ck_live_ |
Production | https://pay.mmokick.com/api/v1 |
A token is the prefix plus 40 random base62 characters, for example
ck_live_1u2P9zXqK7mA4dT8rW3yB6nC0eF5gH2jL9sV4xQ7. Use tokens for
server-to-server calls: the API sends no CORS headers, so browser use is
unsupported by design. Keep tokens out of client-side code, URLs, and logs.
Match the token prefix to the host. Using a ck_test_ token against production (or a
ck_live_ token against sandbox) returns 401 with code wrong_environment — the
request always fails loudly rather than falling back silently.
Scopes
Scopes are assigned at token creation; the default is all scopes. A token missing the
scope an endpoint requires gets 403 with code insufficient_scope.
| Scope | Grants |
|---|---|
catalog:read |
Products, categories |
pricing:read |
Fee schedule, pricing simulation |
offers:read / offers:write |
Offers read / create, update, activate, price, stock |
inventory:read / inventory:write |
Inventory list / upload, invalidate |
orders:read |
Orders read model |
balance:read |
Balance and ledger |
webhooks:manage |
Webhook endpoints, deliveries log, test-fire, resend |
Create a token with only the scopes an integration needs. A repricer bot, for example,
needs offers:write and pricing:read and nothing else.
Failure responses
Every authentication and authorization failure is an RFC 9457 problem+json body with a
stable machine code you switch on. Codes stay stable; title and detail text may change.
401 — the token is the problem. You are not (yet) authenticated:
{
"type": "https://pay.mmokick.com/developers/errors#invalid_token",
"title": "Invalid token",
"status": 401,
"code": "invalid_token",
"detail": "The bearer token is unknown.",
"trace_id": "req_9f3b2c61a8d44e0f"
}
The 401 codes and what to do:
code |
Meaning | What to do |
|---|---|---|
unauthenticated |
The Authorization header is missing or malformed |
Send Authorization: Bearer <token> |
invalid_token |
The token is unknown | Check the token; create a new one in the portal |
token_revoked |
The token was revoked in the portal | Issue a new token |
wrong_environment |
A ck_test_ token was used on production, or ck_live_ on sandbox |
Use the host that matches the prefix |
403 — the token is valid, but not allowed here. Either it lacks a scope or the
supplier account is suspended:
{
"type": "https://pay.mmokick.com/developers/errors#insufficient_scope",
"title": "Insufficient scope",
"status": 403,
"code": "insufficient_scope",
"detail": "This token is missing the required scope: offers:write.",
"trace_id": "req_1a2b3c4d5e6f7081"
}
code |
Meaning | What to do |
|---|---|---|
insufficient_scope |
The token lacks a required scope | Issue a token that carries the scope |
supplier_suspended |
The supplier account is suspended by staff | Contact support; GET /whoami still works |
A request for another supplier's resource returns 404 with code not_found (rather
than 403), keeping the existence of resources you cannot access private.
Token hygiene
- Rotate by creating a new token and revoking the old one — create-then-revoke is the rotation for API tokens.
- Revoke immediately if a token is exposed. Revocation takes effect at once; the
next call with a revoked token gets
401/token_revoked. - Tokens stay out of webhook payloads and every response body. If you see a token in a payload, it did not come from us.
- Quote the
X-Request-Idheader (echoed in error bodies astrace_id) in any support request — it lets us find the exact call in our logs.
Next steps
- Environments — base URLs, the sandbox, and the magic test values.
- Your first API call in 5 minutes — from token to a live response.
- Errors — the full machine error-code catalog.