API credentials
Personal tokens vs machine keys, scopes, number restrictions, step-up and what revokes a credential.
The SUZKO API takes exactly one kind of authentication: a bearer
credential in the Authorization header.
curl https://www.suzko.com/api/v1/numbers \
-H "Authorization: Bearer szk_mk_YOUR_MACHINE_KEY"
Cookies, app sign-ins and anything else are ignored. A bad credential
is 401 unauthorized even if you're signed in to the dashboard in the
same browser.
Credentials are managed in the developer console at /dashboard/developers. The Profile → Developers tab shows a summary (what's expiring, what's due for rotation) and links there. The console always works on the account you're currently in.
Two kinds of credential
| Personal token | Machine key | |
|---|---|---|
| Looks like | szk_pat_ + 43 letters and digits | szk_mk_ + 43 letters and digits |
| Belongs to | You, on one account | A service account: the account's machine identity |
| Who can create one | The owner, or a team member with the permissions its scopes need | The account owner only |
| Expires | Always. 30 days by default, 90 at most | Never. Due for rotation after 90 days |
| Survives you leaving the account | No | Yes |
| Use it for | Your own scripts, one-off jobs, trying the API | Servers, integrations, webhooks |
Use a machine key for anything that runs unattended. A personal token stops working when it expires, when you change your password, or when your access to the account changes, and every webhook endpoint it created pauses with it. A machine key keeps working through all of that.
Every credential is shown once, when you create it. SUZKO stores only a SHA-256 hash of it plus its first 12 characters (the prefix you see in the console, e.g.
szk_mk_4Fq9z). Lost it? Revoke it and make a new one. Keep credentials on your server: never in a mobile app, a browser, or a repository.
Personal tokens
- Pick an expiry when you create it. The API accepts 1–90 days and defaults to 30; the console offers 7, 30, 60 or 90.
- SUZKO emails you and the account owner 14 days and 3 days before it expires.
- Each scope must be within your current permissions on the
account, and that's re-checked on every request. If the owner takes a
permission away from you, requests that need it fail at once with
403 scope_not_permitted. The owner is checked the same way: owning the account doesn't widen a token past its scopes. - The owner sees every personal token on the account (with who made it) and can revoke any of them. A team member sees only their own.
Service accounts and machine keys
A service account holds the scopes and number restrictions; its keys are the secrets you deploy.
- At most 2 live keys per service account: keys that aren't
revoked or expired. An expired key stops working and frees its slot.
A third live key is
409 key_limit. - Keys don't expire. Each one is due for rotation 90 days after it's created: the console flags it, and it keeps working.
- To rotate without downtime: create the second key, deploy it, then revoke the old one.
- A service account can be suspended (its keys stop working until the owner re-enables it) or disabled (permanent: its keys are revoked).
- Only the account owner can see or manage service accounts.
Scopes
Give each credential only what it uses. There is no "full access" scope.
| Scope | Allows | Permission a personal token's holder needs | Needs a SUZKO Phone plan |
|---|---|---|---|
messages:send | POST /messages, POST /messages/batch | Make calls + send SMS (voip.use) | Yes |
messages:read | GET /messages, GET /messages/{id} | View phone system (voip.view) | Yes |
numbers:read | GET /numbers | View phone system (voip.view) | Yes |
usage:read | GET /usage | View phone system (voip.view) | Yes |
webhooks:manage | Everything under /webhooks | Buy + configure numbers (voip.numbers) | Only to create an endpoint |
- A credential without the scope a request needs gets
403 forbidden_scope. - A personal token whose holder lost the permission gets
403 scope_not_permitted. - Scopes that need a plan answer
403 plan_requiredon every request, reads included, while the account has no active SUZKO Phone plan. - Webhook endpoints only receive message and opt-out events when their
creator's credential also has
messages:read. See Webhooks.
Restricting a credential to some numbers
Each credential covers either all numbers on the account or an
explicit list of up to 100 numbers, picked by their pn_… id.
With a list:
- it can only send from those numbers (
from, and the default sender); GET /messages,GET /messages/{id}andGET /numbersonly show those numbers and their messages;- its webhook endpoints only get message events for those numbers. Opt-out events are account-wide and still arrive.
Anything outside the list behaves as if it didn't exist: a from
outside it is 422 invalid_request ("That number isn't on your
account"), and a message outside it is 404 not_found. GET /usage
is account-wide either way.
Confirming it's you (step-up)
Creating, revoking or changing anything in the developer console (tokens, service accounts, keys, webhooks) needs a fresh confirmation:
- Two-factor authentication must be on. Without it you get
403 mfa_enrollment_required. The console offers to set it up right there; confirming your new authenticator's code also counts as the confirmation, so you carry straight on. - The console asks for a 6-digit code from your authenticator app. Backup codes and your password are not accepted here.
- One confirmation covers 5 minutes of changes. After that the
console asks again (
401 step_up_required). - Code attempts are limited (5 per 15 minutes per person, 20 per 15 minutes per address).
- Staff signed in as you from SUZKO support can't pass step-up.
The console's own endpoints only accept a signed-in browser session, never a bearer credential: an API credential can't create, list or revoke credentials.
What revokes or suspends credentials
| Event | Personal tokens | Machine keys |
|---|---|---|
| You change your password | All of yours, on every account, revoked | Unchanged |
| You change your email (or SUZKO support does) | All of yours revoked | Unchanged |
| You turn off two-factor authentication | All of yours revoked | Unchanged |
| You reset your password through account recovery | All of yours revoked | The service accounts on your own account suspended |
| The owner removes you from their account | Yours on that account revoked | — |
| The owner changes your permissions | Not revoked; scopes you no longer qualify for fail with 403 scope_not_permitted | — |
| SUZKO closes an account | That person's tokens revoked on every account; any other token used on the closed account gets 403 account_suspended | The closed account's service accounts suspended |
| You revoke it, or it expires | That token stops at once | That key stops at once |
A revoked, expired or suspended credential gets the same
401 unauthorized as an unknown one. Texts it already queued still
go out. A suspended service account comes back when the owner
re-enables it in the console (with step-up).
Webhook endpoints follow their creator: when a credential loses its authority, the endpoints it created pause. See pause rules.
Next
- Errors and limits: the response envelope, every error code, rate limits, pagination.
- Messaging API overview: the texting endpoints.
Want a complete example client and webhook receiver? Ask SUZKO support; examples are available on request.