Conventions
Envelope
Success:
json
{ "success": true, "data": { }, "pagination": { "limit": 50, "has_more": true, "next_before": 1760000000000 }, "request_id": "..." }Error:
json
{ "success": false, "error": { "code": "VALIDATION_ERROR", "message": "Invalid body parameters", "details": [{ "path": "body.text", "message": "At most 10000 characters" }] }, "request_id": "..." }Every response has an X-Request-Id header: include it when you report a problem.
Error codes
| HTTP | code | Meaning |
|---|---|---|
| 400 | VALIDATION_ERROR, INVALID_JSON | Invalid parameters |
| 401 | UNAUTHORIZED | Key missing/invalid/revoked/expired |
| 403 | FORBIDDEN_SCOPE, FORBIDDEN_ACCOUNT, FORBIDDEN_IP, FORBIDDEN_ERP | Insufficient permissions |
| 404 | NOT_FOUND | No such endpoint or data |
| 409 | ACCOUNT_OFFLINE, CONFLICT | Account not connected / conflict |
| 413 | PAYLOAD_TOO_LARGE | Body/file too large |
| 422 | CHANNEL_UNSUPPORTED | The channel does not support this operation |
| 429 | RATE_LIMITED, AUTH_BLOCKED | Exceeded the limit you set / IP temporarily blocked |
| 502 | UPSTREAM_ERROR | Zalo/Facebook/Telegram returned an error |
| 503 | API_DISABLED, WORKSPACE_UNAVAILABLE | API turned off / the machine has an employee workspace open |
| 504 | TIMEOUT | Processing took too long |
Pagination
- Regular lists:
?limit=50&offset=0, readpagination.next_offset. - Messages: newest → oldest,
?limit=50&before=<epoch ms>; for the next page usepagination.next_before. Messages sharing the same timestamp may repeat at the page boundary → deduplicate bymsg_id.
Data
- Times: epoch milliseconds.
- Field names:
snake_case, following the DB columns. JSON columns (attachments, reactions, quote) are already parsed. - Cookies, sessions, passwords and local file paths are never returned.
- Account ID =
accounts.zalo_id(Facebook: the Facebook ID; Telegram: the Telegram account ID).
Idempotency
For POST requests, send the header Idempotency-Key: <unique string>. Repeating a call with the same key within 24 hours returns the original result unchanged (header Idempotent-Replayed: true) instead of sending the message a second time. Temporary errors (409, 429, 5xx) are not stored, so you can retry.
Limits
- JSON body up to 10 MB, file uploads up to 100 MB (change these in Settings, Cài đặt).
- By default there is no rate limit. You can set a limit per key or a global default.
- Calls are queued with at most N jobs running concurrently (default 4) so the app stays responsive; requests are never rejected because of the queue.
- Outgoing messages go through the same per-account send queue as the app, so Zalo accounts don't get locked for sending in bursts.
Didn't find your answer?
Message us on Telegram