Documentation
Authentication
Every request carries the API key in the Authorization header as a bearer token. Keys start with zp_ and are 256 bits of entropy; we store only their SHA-256 hash, so a leaked database does not leak keys.
Authorization: Bearer zp_...
- A missing, unknown or revoked key answers 401 with the same body: the API does not confirm which keys exist.
- An account with no active subscription answers 402 with code subscription_required. There is no free trial: an account subscribes at least one number to open the console. Numbers stay connected; subscribing restores access on the next call.
- Revoking a key in the console takes effect on the next request. Keys have no scopes: one key opens the whole account, so keep one per environment and rotate by creating a new one first.
Errors
Every non-2xx response is an object with an error field carrying a stable code, an English message and, when useful, details. The code is what your code should branch on.
{
"error": {
"code": "validation_failed",
"message": "The request body does not match the schema.",
"details": { "path": "message.text", "expected": "string", "got": "undefined" },
"docs": "https://zaiped.com/developers/docs"
}
}- 400: invalid JSON, a body that does not match the route schema (validation_failed, with the path), or a rule the API enforces before Meta (for example recipient_invalid, meta_window_closed).
- 401 and 402: authentication and entitlement, as above.
- 404: the route does not exist, or the id belongs to another account (we never distinguish the two).
- 429: a Zaiped budget or a Meta rate limit. Read Retry-After and wait.
- 502 and 500: Meta refused in a way we could not translate, or we failed. Retry with backoff.
Rate limits
Per account: 600 requests per minute, plus a sending budget of 1,000 messages per hour and 5,000 per day. Meta applies its own limits per number on top; those come back as 429 with a meta_ code.