The Tanvik API uses conventional HTTP status codes and a consistent JSON error body so failures are easy to handle programmatically.
Error response shape
{
"error": {
"code": "invalid_request",
"message": "to is required",
"status": 400
}
}
HTTP status codes
| Status | Meaning |
|---|
200 | Request succeeded |
400 | Malformed request — check required fields and formats |
401 | Missing, invalid, or revoked API key |
403 | Key is valid but the account’s plan doesn’t include this feature |
404 | Resource (message, template, webhook) not found |
422 | Request understood but rejected downstream (WhatsApp, OTP logic) |
429 | Rate limit exceeded — 120 requests/minute per key |
500 | Something went wrong on our end |
Error codes
| Code | Status | Cause |
|---|
missing_api_key | 401 | No Authorization header sent |
invalid_api_key | 401 | Key is malformed, doesn’t match any account, or was revoked |
feature_not_enabled | 403 | Your plan doesn’t include API access |
rate_limited | 429 | More than 120 requests/minute on this key — see Retry-After header |
invalid_request | 400 | A required field is missing or malformed |
no_default_otp_template | 422 | No approved authentication-category template exists; create one or pass template explicitly |
otp_send_failed | varies | WhatsApp/OTP send failed downstream — message has the underlying reason |
otp_expired | 422 | The OTP code has passed its validity window |
otp_max_attempts | 422 | Too many incorrect verification attempts for this otp_id |
otp_not_found | 404 | No pending OTP matches the given otp_id |
otp_verify_failed | varies | Unexpected failure verifying the code |
template_create_failed | varies | Template submission was rejected — message includes the reason |
template_not_found | 404 | No template with that id on this account |
send_failed | varies | Message send failed — check message for the specific reason (e.g. closed session window, insufficient wallet balance) |
too_many_recipients | 400 | More than 100 recipients in one /v1/messages call |
message_not_found | 404 | No message with that id on this account |
webhook_not_found | 404 | No webhook with that id on this account |
not_found | 404 | No matching route for this method/path |
internal_error | 500 | Unexpected server-side failure |
Handling 429s
Rate-limited responses include a Retry-After header (seconds). Back off and retry rather than looping immediately.
otp_send_failed, template_create_failed, and send_failed wrap the real downstream error text in message — read it, since the specific reason (e.g. “Session window closed. Use a template.”) is usually more actionable than the generic code.