--- title: Rate Limits | API Docs description: Understanding and handling API rate limits. --- The Linq API enforces rate limits to protect Apple’s ecosystem and prevent automated feedback loops between bots. ## Recommended daily volume We recommend limiting message volume to a combined total of up to **7,000 inbound and outbound messages per day per line**. Volume north of the recommended range has the potential to degrade performance. There are no hard caps on daily volume (excluding [sandbox accounts](https://dashboard.linqapp.com/sandbox-signup/)). These recommendations are meant to optimize the performance of your lines. We recommend you control volume via onboarding flows you build on your end. ## Per-phone-pair rate limit The API enforces a rate limit of **30 messages per 60-second window** for each unique sender–recipient pair. This is designed to prevent automated feedback loops where two numbers (i.e. bots) rapidly exchange messages. When exceeded, the API returns **HTTP `429`** with a `Retry-After` header (seconds until reset) and [error code `1007`](/error/codes/1xxx/1007/index.md). The same value is also available as `retry_after` in the error body. Hitting this limit almost always means a bug — check for retry loops, duplicate sends, or webhook handlers that inadvertently reply to themselves. ## Sandbox limits [Sandbox accounts](https://dashboard.linqapp.com/sandbox-signup/) are the exception to the “no hard caps” rule: - **100 messages per day** — Resets at midnight UTC ## Capability check rate limit [Capability check](/guides/chats/capability-checks/index.md) endpoints (`/v3/capability/check_imessage` and `/v3/capability/check_rcs`) are also rate-limited to prevent abuse (e.g. using them to enumerate which numbers are on iMessage). Excessive calls return the same **HTTP `429`** with `Retry-After` and [error code `1007`](/error/codes/1xxx/1007/index.md). Cache results briefly (minutes, not days) rather than re-checking the same address on every send — capability is stable over short windows and the cache reduces your risk of hitting this limit. ## Rate limit response When you hit a rate limit, the API returns HTTP `429 Too Many Requests` with a `Retry-After` header and this body: ``` { "success": false, "error": { "status": 429, "code": 1007, "message": "Rate limited. Try again in 45 seconds.", "retry_after": 45 }, "trace_id": "trace_abc123def456" } ``` The `retry_after` field mirrors the `Retry-After` header and is only present on `429` responses. See [Error Codes](/error/index.md) for the full envelope shape used by all error responses. ## Handling rate limits Prefer the `Retry-After` header when present; fall back to exponential backoff otherwise: ``` async function sendWithRetry( client: LinqAPIV3, chatId: string, message: MessageParams, maxRetries = 3, ) { for (let attempt = 0; attempt <= maxRetries; attempt++) { try { return await client.chats.messages.send(chatId, message); } catch (error) { if (error.status === 429 && attempt < maxRetries) { const retryAfter = Number(error.headers?.['retry-after']); const delayMs = Number.isFinite(retryAfter) ? retryAfter * 1000 : Math.pow(2, attempt) * 1000; // 1s, 2s, 4s fallback await new Promise(resolve => setTimeout(resolve, delayMs)); continue; } throw error; } } } ``` ``` import time def send_with_retry(client, chat_id, message, max_retries=3): for attempt in range(max_retries + 1): try: return client.chats.messages.send(chat_id, **message) except Exception as e: if getattr(e, "status_code", None) == 429 and attempt < max_retries: retry_after = getattr(e, "response", None) and e.response.headers.get("retry-after") delay = int(retry_after) if retry_after else (2 ** attempt) # 1s, 2s, 4s fallback time.sleep(delay) continue raise ``` > **Tip:** The official [SDKs](/getting-started/sdks/index.md) handle retries automatically with exponential backoff. You only need custom retry logic if you’re using the API directly. ## Best practices - **Queue messages** — Use a message queue to control send rate rather than sending as fast as possible - **Monitor usage** — Track your daily message count to avoid hitting limits unexpectedly - **Batch wisely** — Space out bulk sends rather than sending all at once - **Use idempotency keys** — Include an `idempotency_key` field in the message body on retries to prevent duplicates (see [Sending Messages](/guides/messaging/sending-messages#idempotency/index.md)) ## Other error codes Rate limits aren’t the only reason requests can fail. See [Error Codes](/error/index.md) for the complete reference, including infrastructure errors (3xxx) that may also require retry logic. See the [Send Message](/api/resources/chats/subresources/messages/methods/send/index.md) and [Create Chat](/api/resources/chats/methods/create/index.md) API references for endpoint details.