> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tawked.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Reliability and limits

> Idempotency keys, rate limits, per-destination caps, and the protection guard.

## Idempotency

Send an `Idempotency-Key` header on `start` (and on WhatsApp sends) to make retries safe. The key is 1 to 128 printable ASCII characters that you generate, scoped to your API key. Replaying it returns the original `201` unchanged, with the response header `Idempotent-Replayed: true`; nothing is sent or charged again. A send that fails releases the key so a retry can go through.

```bash theme={null}
curl -X POST https://tawked.com/v1/verify/start \
  -H "Authorization: Bearer tk_live_xxxxxxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: signup-8f1c2-attempt" \
  -H "Content-Type: application/json" \
  -d '{ "to": "0551234567", "reference": "signup-8f1c2" }'
```

<Tip>
  Use one key per business event, and retry a `502` or a network error with the same key.
</Tip>

## Your own reference

`reference` (up to 64 printable characters) is echoed on `start` and on `GET /v1/verify/{id}`, and is searchable in the dashboard's verifications list. Put your order id or session id there.

## Rate limits

| Limit                    | Value                                                                       | Error                      |
| ------------------------ | --------------------------------------------------------------------------- | -------------------------- |
| Requests per key         | 120 per minute, fixed 60-second window                                      | `429 too_many_requests`    |
| Sends per destination    | 5 per hour by default, per account, across applications, channels and modes | `429 rate_limited`         |
| Resends per verification | 3                                                                           | `429 resend_limit_reached` |

The two `429` codes share a status and differ in the `error` string. The per-key limit fails open if the limiter itself is unavailable.

## The protection guard

Three per-application settings stop a runaway integration or an attacker from spending your balance. All are evaluated on `start` and `resend`, and skipped in the sandbox.

* **Daily spend cap** (`daily_spend_cap_halalas`, off by default): today's charges plus this send would pass the cap, so the send answers `429 spend_cap_reached`. Days are Riyadh calendar days.
* **Per-IP cap** (`max_per_ip_per_hour`, default 20): only checked when you pass `client_ip` on `start`. The address is never inferred from the request. Over the cap answers `429 ip_rate_limited`.
* **New-destination pumping** (`max_new_destinations_per_hour`, default 300): crossing it auto-pauses the application. Every call then answers `403 application_paused` until the owner resumes it from the dashboard. The pause is audit-logged and the owner is notified.

<Note>
  Pass `client_ip` whenever the verification is started on behalf of an end user's request. It is the one signal that lets Tawked tell many users apart from one abuser.
</Note>

## Verification lifecycle

```
start ──▶ pending ──▶ verified
             │
             ├──▶ failed        (attempts exhausted, or the send failed)
             ├──▶ expired       (the code lifetime passed)
             └──▶ canceled      (you called cancel)
```

`resend` keeps the id and issues a new code: the old code stops working, attempts and expiry reset, and the send is charged and rate-limited like any other. A new `start` never invalidates an earlier code. Read the current state at any time with `GET /v1/verify/{id}` without consuming an attempt.
