Messaging API overview
Get a credential, make your first call, and see every texting endpoint.
The SUZKO Phone Messaging API lets your own software send texts from your business numbers, read them back, and get events when they're delivered or answered. API texts go through the same path as texts you send from the dashboard: same included texts, same spend limit, same texting registration, same opt-out list.
- Sending, reading, usage and pricing: Sending texts
- Events to your server: Webhooks
- Credentials and scopes: API credentials
- Envelope, error codes, rate limits: Errors and limits
1. Get a credential
Open the developer console at /dashboard/developers, also reachable from Profile → Developers. API tokens, machine keys and webhooks all live there. You'll need two-factor authentication on, and the console asks for a code from your authenticator app before it creates anything.
- For a server, an integration or webhooks: a machine key
(
szk_mk_…). Create a service account under Machine keys, give it the scopes it needs, then create its key. Owner only. Machine keys don't expire. - For your own scripts: a personal token (
szk_pat_…). Create one under Personal tokens. It expires in 30 days by default (90 at most) and stops working if your access to the account changes.
The full secret is shown once. Copy it straight into your server's secret store. The differences, scopes and revocation rules are in API credentials.
Keep credentials on your server. Never put one in a mobile app, a browser, or a public repository: anyone holding it can text as your business and spend against your account.
2. Make a call
Base URL:
https://www.suzko.com/api/v1
Use www.suzko.com. The bare suzko.com redirects there, and most
HTTP clients drop the Authorization header (and turn a POST into
a GET) when they follow a redirect.
Send the credential as a bearer token. List your numbers first (scope
numbers:read):
curl https://www.suzko.com/api/v1/numbers \
-H "Authorization: Bearer szk_mk_YOUR_MACHINE_KEY"
{
"success": true,
"data": [
{
"object": "phone_number",
"id": "pn_Ht6Wq2Kz9LmB",
"number": "+13175550100",
"type": "local",
"displayName": "Front desk",
"canText": true,
"reason": null
}
],
"meta": { "nextCursor": null }
}
Then send a text (scope messages:send):
curl https://www.suzko.com/api/v1/messages \
-H "Authorization: Bearer szk_mk_YOUR_MACHINE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f1c2e0a-order-1042" \
-d '{"to": "+13175550123", "from": "pn_Ht6Wq2Kz9LmB", "body": "Your order #1042 is ready for pickup."}'
A 202 with "status": "queued" means it's accepted and on its way.
Real texts cost real money: test against your own phone first.
The console's Quick start has a ready-to-run send command with your number filled in.
Endpoints
Every request and response body is JSON. Send
Content-Type: application/json on requests with a body.
| Method | Path | Scope | What it does |
|---|---|---|---|
POST | /messages | messages:send | Send one text |
POST | /messages/batch | messages:send | Send up to 1,000 texts |
GET | /messages | messages:read | List messages, newest first |
GET | /messages/{id} | messages:read | One message |
GET | /numbers | numbers:read | Your numbers and whether each can text |
GET | /usage | usage:read | This month's texting usage |
GET | /webhooks | webhooks:manage | The endpoints this credential created |
POST | /webhooks | webhooks:manage | Add an endpoint |
GET | /webhooks/{id} | webhooks:manage | One endpoint and its newest 50 deliveries |
DELETE | /webhooks/{id} | webhooks:manage | Remove an endpoint |
POST | /webhooks/{id}/verify | webhooks:manage | Send the verification challenge again |
POST | /webhooks/{id}/rotate-secret | webhooks:manage | New signing secret, 24-hour overlap |
POST | /webhooks/{id}/test | webhooks:manage | Queue a test event |
POST | /webhooks/{id}/deliveries/{deliveryId}/replay | webhooks:manage | Deliver a finished delivery again |
Every texting scope needs an active SUZKO Phone plan on the account:
without one, those routes answer 403 plan_required. If the plan is
active but Business Phone was never set up, sends and /usage answer
404 not_found and lists come back empty.
Responses in short
{ "success": true, "data": { } }
{
"success": false,
"error": "This recipient has opted out of texts from your business.",
"code": "opted_out",
"requestId": "req_7Hq2Lm9Xc4Vb8Nz1Kd5Rt3Wy"
}
- Branch on
code, not onerror. - Every response carries
X-Request-Id. Quote it to support. - Lists return
data: [...]andmeta.nextCursor; 25 per page by default, 100 at most. - Timestamps are RFC 3339 UTC. Money is
{ "amount": "50.00", "currency": "USD" }.
The full code table, rate limits and headers are in Errors and limits.