Authentication
Authentication
Every request to the Zingasuite API is authenticated with an API key sent as a
bearer token. The key identifies which entity you are acting on and which
operations you are allowed to perform — there is no entity id in the URL.
API keys
Keys are created in the console (Settings → API Keys). A key
looks like this:
zk_live_xxxxxxxxxxxxxxxxxxxxxxxx # production
zk_test_xxxxxxxxxxxxxxxxxxxxxxxx # sandbox / testing
The full key is shown once, at creation time. Store it securely — only a
short prefix (for example zk_live_abc1…) is retained for display afterwards,
and a lost key cannot be recovered (create a new one and revoke the old).
Sending the key
Send the key in the Authorization header on every request:
curl https://api-v1.zingasuite.com/papi/v1/products \
-H "Authorization: Bearer zk_live_xxxxxxxxxxxxxxxxxxxxxxxx"
If the header is missing or malformed you receive 401 with
{"detail": "missing_bearer_token"} or {"detail": "invalid_token"}. An
unknown, revoked or expired key returns 401 invalid_or_revoked_key.
Scopes
Each key carries a set of scopes that limit what it can do. Grant the
minimum a key needs.
| Scope | Grants |
|---|---|
data:read |
Read any object your role can read |
data:write:* |
Create/update/delete any object your role can write |
billing:read |
Read billing information |
messaging:read |
Read messaging channels and message status (ZingaConnect) |
messaging:send |
Send messages (ZingaConnect) |
messaging:webhooks |
Manage delivery/inbound webhooks (ZingaConnect) |
These are the only scopes you can attach to a key; any other value is rejected
at creation with 400 scope_not_allowed:<scope>.
Notes:
- Writes are all-or-nothing at the key level.
data:write:*lets a key
write any object type — there is no per-object write scope you attach to the
key. To limit a key to, say, only products, create it under a user whose
role is restricted to products (see below); the key can never exceed that
role. - Messaging scopes are separate from data scopes on purpose:
data:write:*
does not grant the ability to send messages, and a messaging key needs no
data access. - Internally the API checks a granular scope per object type (for example it
requiresdata:write:productsto write a product);data:write:*satisfies
all of them. A request that lacks the required access returns403with
{"detail": "insufficient_scope:<scope>"}, e.g.
insufficient_scope:data:write:products.
Keys never exceed your permissions
A key's effective permissions are the intersection of the scopes you grant
it and the permissions of the user who created it:
effective permissions = (creator's role permissions) ∩ (key scopes)
A key can never do more than its creator's role allows. If your role loses
access to an object type — or your membership in the entity is revoked — keys
you created lose that access too (a revoked membership returns
403 membership_revoked). Beyond the scope check, each write is also validated
against the creator's object-level permissions and may return
403 permission_denied:<operation>:<model>.
Test vs live keys
Use zk_test_ keys while developing and zk_live_ keys in production. Both
authenticate the same way; keep them in separate configuration so test traffic
never touches live data.