Rate limits and errors
Handle Problem Details, request limits, monthly quotas, and safe retries.
Use the error response's code to decide what to do. HTTP status alone is not enough: 429 RATE_LIMITED is a short request-rate limit, while quota errors require available monthly allowance.
Problem Details
API errors use Content-Type: application/problem+json. For example:
{
"type": "https://docs.watification.com/errors/rate-limited",
"title": "Developer request failed",
"status": 429,
"code": "RATE_LIMITED",
"detail": "The developer request could not be completed.",
"instance": "/api/v1/otp/messages",
"correlationId": "99999999-9999-4999-8999-999999999999"
}| Field | Use |
|---|---|
type | Explanation URL: code lowercased, with underscores replaced by dashes. |
title | Short error title. |
status | HTTP status. |
code | Stable code for programmatic handling. |
detail | Safe description; not a list of field-level validation errors. |
instance | Request route template, which may contain a path placeholder. |
correlationId | Include this when reporting a failed request. |
Do not depend on the wording of title or detail. Open the error reference for causes, fixes, and retry guidance.
Request rate limit
Each API key is limited to 20 requests per second in a fixed one-second window. OTP and COD requests, including GET status reads and idempotent repeats, share this limit.
Exceeding it returns 429 RATE_LIMITED with Retry-After: 1 (seconds). Wait at least that long, add jitter, and retry. Prefer webhooks to frequent status polling.
Monthly quotas
| Allowance | Consumed by | Exhausted or zero allowance |
|---|---|---|
| API OTP messages | One accepted OTP send. | 429 OTP_QUOTA_EXCEEDED |
| COD confirmations | One accepted confirmation create. | 429 COD_QUOTA_EXCEEDED |
| COD refusal checks | One accepted refusal check; separate from confirmations. | 429 COD_QUOTA_EXCEEDED |
Quotas use calendar-month periods and are workspace-wide. Amounts depend on your plan; unlimited allowances are supported. View your current limits under Developers > Overview and Sales > COD confirmation > Overview.
Idempotent repeats do not consume additional quota. Later send failures are not refunded. COD reminders, follow-up questions, and closing messages do not consume more COD quota units. Do not treat a quota error as a request-rate error or retry it every second.
Idempotency
All three public POST operations accept an optional Idempotency-Key string of at most 128 characters. Persist a unique, non-empty key per logical operation and reuse it with the same request after an uncertain result. Without a key, a repeated request can create another message or confirmation.
- OTP compares normalized recipient, sender, template name/language, and reference. The code is excluded: changing it with the same key does not replace the original code.
- COD compares all request values, including parameters. Named object key order does not affect the comparison. Confirmation create and refusal check have separate key namespaces in the workspace.
- A completed repeat returns the original
202acceptance body, even after status advances. GET returns the current state. - A changed fingerprint returns
409 IDEMPOTENCY_KEY_REUSED. Correct the request or use a new key only when you intend a new operation.
Retry guidance
| Result | Action |
|---|---|
202 | Save the returned ID. Track the outcome with GET or a webhook. |
401 | Fix or replace the key before retrying. |
404 | Check the ID, template language, sender, and workspace. |
409 | Resolve configuration, eligibility, or idempotency conflicts first. |
422 | Correct input, parameters, or the blocked-recipient condition. |
429 RATE_LIMITED | Wait for Retry-After, then retry with jitter. |
Quota 429 | Wait for available allowance or change the plan allowance. |
Network timeout or 5xx | Retry a bounded number of times with exponential backoff and jitter. Reuse the POST idempotency key and body. |
Choose a maximum retry count and delay cap for your integration. For transient failures, one possible client policy is a random delay between zero and min(cap, base * 2^attempt); honor Retry-After as a minimum when present. These values are your client's policy, not an API SLA. An accepted request can fail later; do not blindly resubmit a webhook-reported failure without deciding whether a new send is appropriate.
Error code catalog
The first table covers the public API-key routes. The second covers dashboard setup and management errors you may encounter while preparing an integration.
Public REST API
| Code | HTTP | Meaning |
|---|---|---|
| API_KEY_INVALID | 401 | Authorization missing, malformed, unknown, incorrect, or revoked. |
| RATE_LIMITED | 429 | Per-key request rate exceeded; Retry-After: 1. |
| DEVELOPER_INVALID_INPUT | 422 | Invalid request fields, phone, UUID, query, or idempotency header. |
| IDEMPOTENCY_KEY_REUSED | 409 | Same key with a different request fingerprint. |
| RECIPIENT_BLOCKED | 422 | The recipient is blocked for sending. |
| NOT_FOUND | 404 | OTP message not found in this workspace. |
| OTP_SENDER_NOT_FOUND | 404 | OTP sender not found in this workspace. |
| OTP_SENDER_UNAVAILABLE | 409 | OTP sender cannot send. |
| OTP_TEMPLATE_NOT_FOUND | 404 | OTP template name/language not found for sender. |
| OTP_TEMPLATE_NOT_USABLE | 409 | Template is not a usable approved authentication template. |
| OTP_QUOTA_EXCEEDED | 429 | Monthly API OTP allowance zero or exhausted. |
| COD_NOT_CONFIGURED | 409 | COD delivery time zone is missing. |
| COD_LANGUAGE_NOT_CONFIGURED | 409 | Follow-up texts missing for template language. |
| COD_SENDER_NOT_FOUND | 404 | COD sender not found in this workspace. |
| COD_SENDER_UNAVAILABLE | 409 | COD sender cannot send. |
| COD_TEMPLATE_NOT_FOUND | 404 | COD template name/language not found for sender. |
| COD_TEMPLATE_NOT_USABLE | 409 | Template does not meet the selected check's requirements. |
| COD_TEMPLATE_PARAMETERS_INVALID | 422 | Header/body values do not match template requirements. |
| COD_QUOTA_EXCEEDED | 429 | Selected monthly COD allowance zero or exhausted. |
| COD_CONFIRMATION_NOT_FOUND | 404 | Confirmation not found in this workspace. |
| COD_CONFIRMATION_NOT_ELIGIBLE | 409 | Confirmation accepted, failed, or missing a conversation. |
| COD_REFUSAL_CHECK_EXISTS | 409 | Confirmation already has a refusal check. |
Dashboard setup and management
| Code | HTTP | Meaning |
|---|---|---|
API_KEY_LIMIT_REACHED | 409 | Already 10 active workspace API keys. |
API_KEY_NOT_FOUND | 404 | API key not found. |
WEBHOOK_ENDPOINT_LIMIT_REACHED | 409 | Already 5 endpoints, including disabled endpoints. |
WEBHOOK_URL_INVALID | 422 | URL violates webhook URL rules. |
WEBHOOK_ENDPOINT_NOT_FOUND | 404 | Webhook endpoint not found. |
WEBHOOK_DELIVERY_NOT_FOUND | 404 | Delivery unavailable or no longer retained. |
SALES_INVALID_INPUT | 422 | Invalid COD settings or dashboard input. |
SALES_FORBIDDEN | 403 | Signed-in user lacks required Sales access. |