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

# Rate limit

> Limite de requisições da API da Zapster (3 req/s por token), headers RateLimit-Limit, RateLimit-Remaining e RateLimit-Reset, resposta 429 rate_limited e como tratar com backoff e fila.

O **rate limit** (limite de requisições) controla quantas chamadas você pode fazer à API da Zapster em um intervalo de tempo. Quando você passa desse limite, a API responde com o status `429 Too Many Requests` em vez de processar a requisição.

## Por que o rate limit existe

O limite protege duas coisas ao mesmo tempo:

* **A plataforma**, mantendo a API estável e justa para todos os clientes, sem que um único integrador consiga sobrecarregar o serviço.
* **O seu número de WhatsApp**, evitando rajadas de envio que o WhatsApp interpreta como comportamento de spam. Enviar devagar e de forma constante é mais seguro para a saúde do seu número do que disparar tudo de uma vez.

## Limite padrão

O limite padrão é de **3 requisições por segundo**, contadas por token de acesso (ou seja, por conta). Como toda chamada à API é autenticada, a cota é sempre atrelada ao seu token.

<Note>
  O limite é aplicado a **todas** as rotas da API, não só ao envio de mensagens. As chamadas de listagem, consulta de destinatário e gestão de instância também consomem a mesma cota.
</Note>

### Flexibilidade por plano

O limite padrão atende à maioria das integrações. Se o seu volume exige mais, a cota da sua conta pode ser ampliada de acordo com o seu plano ou mediante contratação. [Fale com o suporte](https://wa.me/5587999079455?text=Olá,%20preciso%20aumentar%20o%20rate%20limit%20da%20minha%20conta) para avaliarmos o limite ideal e a melhor condição para o seu caso.

<Warning>
  Antes de pedir um limite maior, trate o rate limit no seu lado. O jeito mais robusto de integrar é **nunca depender do 429**: controle o ritmo de envio no seu código (fila e throttling) para se manter dentro do limite. Um limite maior ajuda em picos, mas não substitui o controle de ritmo no cliente.
</Warning>

## Headers de rate limit

Toda resposta da API traz headers de rate limit que informam o estado atual da sua cota. Eles seguem o padrão de cabeçalhos [RateLimit para HTTP](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/) proposto pela IETF.

| Header                | Descrição                                                                                          |
| --------------------- | -------------------------------------------------------------------------------------------------- |
| `RateLimit-Limit`     | Número máximo de requisições permitidas na janela atual (ex.: `3`).                                |
| `RateLimit-Remaining` | Quantas requisições ainda restam na janela atual.                                                  |
| `RateLimit-Reset`     | Quantos **segundos** faltam até a janela reiniciar (é um tempo relativo, não um timestamp).        |
| `RateLimit-Policy`    | A política aplicada, no formato `limite;w=janela` (ex.: `3;w=1` = 3 requisições a cada 1 segundo). |
| `Retry-After`         | Presente **apenas na resposta 429**. Quantos **segundos** esperar antes de tentar de novo.         |

### Exemplo de resposta 200

Uma requisição bem-sucedida, ainda dentro da cota:

```http theme={null}
HTTP/1.1 200 OK
Content-Type: application/json
RateLimit-Policy: 3;w=1
RateLimit-Limit: 3
RateLimit-Remaining: 2
RateLimit-Reset: 1
```

### Exemplo de resposta 429

Quando você passa do limite, a API responde:

```http theme={null}
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
RateLimit-Policy: 3;w=1
RateLimit-Limit: 3
RateLimit-Remaining: 0
RateLimit-Reset: 1
Retry-After: 1

{
  "errors": [
    {
      "code": "rate_limited",
      "messages": "You can only make 3 requests every 1 seconds."
    }
  ]
}
```

O campo `code` é sempre `rate_limited`, e o texto de `messages` reflete o limite atual da sua conta e o tamanho da janela.

## Como tratar o rate limit

A estratégia recomendada tem duas camadas.

**1. Controle o ritmo antes de enviar (preferencial).** Para integrações de alto volume (disparos em lote, filas de mensagens), limite o seu próprio ritmo de saída para nunca ultrapassar o limite. Use uma fila com throttling (por exemplo, `bottleneck` ou `p-queue` no Node.js, ou `rate.Limiter` em Go) configurada para o mesmo teto da sua conta. Assim você não depende de receber um 429.

**2. Trate o 429 quando ele acontecer (rede de segurança).** Mesmo com throttling, mantenha um retry:

* Ao receber `429`, espere o número de segundos indicado em `Retry-After` (ou, na falta dele, em `RateLimit-Reset`) e tente de novo.
* Se não houver header, use um **backoff exponencial** com jitter (espere 1s, depois 2s, 4s, e assim por diante, com um teto).
* Antes de enviar, você também pode olhar `RateLimit-Remaining`: se estiver perto de zero, aguarde `RateLimit-Reset` segundos antes da próxima chamada.

## Exemplos de código

Os exemplos abaixo enviam uma mensagem e tratam o `429` respeitando os headers. Troque `YOUR_API_TOKEN` pelo seu token e `YOUR_INSTANCE_ID` pelo ID da instância.

<CodeGroup>
  ```javascript Node.js (cliente, fetch + backoff) theme={null}
  // Cliente resiliente: respeita Retry-After/RateLimit-Reset e faz backoff.
  async function sendWithRetry(payload, { maxRetries = 5 } = {}) {
    for (let attempt = 0; attempt <= maxRetries; attempt++) {
      const res = await fetch('https://api.zapsterapi.com/v1/wa/messages', {
        body: JSON.stringify(payload),
        headers: {
          Authorization: 'Bearer YOUR_API_TOKEN',
          'Content-Type': 'application/json',
          'X-Instance-ID': 'YOUR_INSTANCE_ID',
        },
        method: 'POST',
      })

      if (res.status !== 429) return res

      // Retry-After e RateLimit-Reset vêm em segundos.
      const hint =
        Number(res.headers.get('retry-after')) ||
        Number(res.headers.get('ratelimit-reset')) ||
        0
      // Se o servidor não mandar dica, usa backoff exponencial (teto de 30s).
      const backoff = Math.min(2 ** attempt, 30)
      const delayMs = (Math.max(hint, backoff) + Math.random() * 0.25) * 1000
      await new Promise((resolve) => setTimeout(resolve, delayMs))
    }

    throw new Error('Rate limit: tentativas esgotadas')
  }

  const res = await sendWithRetry({
    recipient: '5511999999999',
    text: 'Olá! Seu pedido foi confirmado.',
  })
  console.log((await res.json()).message_id)
  ```

  ```javascript Node.js (servidor, fila com throttling) theme={null}
  // Para disparos em lote: limite a saída a 3 req/s com bottleneck,
  // assim você nunca chega no 429.
  const Bottleneck = require('bottleneck')

  const limiter = new Bottleneck({
    maxConcurrent: 3,
    minTime: 334, // ~1 requisição a cada 334ms = 3 por segundo
    reservoir: 3,
    reservoirRefreshAmount: 3,
    reservoirRefreshInterval: 1000,
  })

  async function sendMessage(payload) {
    const res = await fetch('https://api.zapsterapi.com/v1/wa/messages', {
      body: JSON.stringify(payload),
      headers: {
        Authorization: 'Bearer YOUR_API_TOKEN',
        'Content-Type': 'application/json',
        'X-Instance-ID': 'YOUR_INSTANCE_ID',
      },
      method: 'POST',
    })
    if (!res.ok) throw new Error(`HTTP ${res.status}`)
    return res.json()
  }

  // Toda chamada passa pela fila, respeitando o teto de 3 req/s.
  const send = limiter.wrap(sendMessage)

  const recipients = ['5511999999999', '5511888888888', '5511777777777']
  await Promise.all(recipients.map((r) => send({ recipient: r, text: 'Olá!' })))
  ```

  ```python Python (requests + backoff) theme={null}
  import random
  import time

  import requests

  URL = "https://api.zapsterapi.com/v1/wa/messages"
  HEADERS = {
      "Authorization": "Bearer YOUR_API_TOKEN",
      "X-Instance-ID": "YOUR_INSTANCE_ID",
  }


  def send_with_retry(payload, max_retries=5):
      delay = 1.0  # backoff usado só se o servidor não mandar dica
      for _ in range(max_retries + 1):
          res = requests.post(URL, headers=HEADERS, json=payload, timeout=30)
          if res.status_code != 429:
              res.raise_for_status()
              return res.json()

          # Retry-After e RateLimit-Reset vêm em segundos.
          hint = res.headers.get("Retry-After") or res.headers.get("RateLimit-Reset")
          sleep_for = float(hint) if hint else delay
          time.sleep(sleep_for + random.uniform(0, 0.25))
          delay = min(delay * 2, 30)

      raise RuntimeError("Rate limit: tentativas esgotadas")


  print(send_with_retry({"recipient": "5511999999999", "text": "Olá!"}))
  ```

  ```go Go (rate.Limiter + backoff) theme={null}
  package main

  import (
  	"bytes"
  	"context"
  	"fmt"
  	"net/http"
  	"strconv"
  	"time"

  	"golang.org/x/time/rate"
  )

  // 3 requisições por segundo, igual ao limite padrão da conta.
  var limiter = rate.NewLimiter(rate.Every(time.Second/3), 3)

  func send(ctx context.Context, payload []byte) (*http.Response, error) {
  	const maxRetries = 5
  	for attempt := 0; attempt <= maxRetries; attempt++ {
  		// Segura o ritmo antes de sair: mantém 3 req/s.
  		if err := limiter.Wait(ctx); err != nil {
  			return nil, err
  		}

  		req, _ := http.NewRequestWithContext(ctx, http.MethodPost,
  			"https://api.zapsterapi.com/v1/wa/messages", bytes.NewReader(payload))
  		req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
  		req.Header.Set("X-Instance-ID", "YOUR_INSTANCE_ID")
  		req.Header.Set("Content-Type", "application/json")

  		res, err := http.DefaultClient.Do(req)
  		if err != nil {
  			return nil, err
  		}
  		if res.StatusCode != http.StatusTooManyRequests {
  			return res, nil
  		}
  		res.Body.Close()

  		// Retry-After e RateLimit-Reset vêm em segundos.
  		wait := time.Second
  		if v := res.Header.Get("Retry-After"); v != "" {
  			if s, convErr := strconv.Atoi(v); convErr == nil {
  				wait = time.Duration(s) * time.Second
  			}
  		}
  		select {
  		case <-time.After(wait):
  		case <-ctx.Done():
  			return nil, ctx.Err()
  		}
  	}
  	return nil, fmt.Errorf("rate limited: tentativas esgotadas")
  }

  func main() {
  	payload := []byte(`{"recipient":"5511999999999","text":"Olá!"}`)
  	res, err := send(context.Background(), payload)
  	if err != nil {
  		panic(err)
  	}
  	defer res.Body.Close()
  	fmt.Println(res.Status)
  }
  ```

  ```bash cURL / bash theme={null}
  # Opção A: curl repete sozinho e respeita o Retry-After do 429.
  curl --retry 5 --retry-all-errors --retry-delay 1 \
    -X POST https://api.zapsterapi.com/v1/wa/messages \
    -H "Authorization: Bearer YOUR_API_TOKEN" \
    -H "X-Instance-ID: YOUR_INSTANCE_ID" \
    -H "Content-Type: application/json" \
    -d '{"recipient":"5511999999999","text":"Olá!"}'

  # Opção B: controle manual lendo os headers e dormindo até a janela reiniciar.
  url="https://api.zapsterapi.com/v1/wa/messages"
  for attempt in $(seq 1 5); do
    # -D salva os headers; -w retorna o status HTTP.
    status=$(curl -sS -o response.json -D headers.txt -w '%{http_code}' \
      -X POST "$url" \
      -H "Authorization: Bearer YOUR_API_TOKEN" \
      -H "X-Instance-ID: YOUR_INSTANCE_ID" \
      -H "Content-Type: application/json" \
      -d '{"recipient":"5511999999999","text":"Olá!"}')

    if [ "$status" != "429" ]; then
      cat response.json
      break
    fi

    # RateLimit-Reset é o número de segundos até a janela reiniciar.
    reset=$(grep -i '^ratelimit-reset:' headers.txt | tr -d '\r' | awk '{print $2}')
    echo "Rate limited. Aguardando ${reset:-1}s..."
    sleep "${reset:-1}"
  done
  ```
</CodeGroup>

## Em resumo

* O padrão é **3 requisições por segundo** por token de acesso, válido para toda a API.
* Toda resposta traz `RateLimit-Limit`, `RateLimit-Remaining` e `RateLimit-Reset`; o 429 traz também `Retry-After`. `RateLimit-Reset` e `Retry-After` são contados em segundos.
* O 429 devolve `{ "errors": [{ "code": "rate_limited", ... }] }`.
* Controle o ritmo no seu código (fila e throttling) para não depender do 429, e mantenha um retry com backoff como rede de segurança.
* Precisa de mais volume? [Fale com o suporte](https://wa.me/5587999079455?text=Olá,%20preciso%20aumentar%20o%20rate%20limit%20da%20minha%20conta) para avaliar um limite maior.
