waiaconnect

Documentazione / Completo

Limiti di velocità (per numero, per account, per key)

POST /v1/messages

Markdown

Programmi con l'IA? Collegala al tuo account via MCP: controlla la tua configurazione, crea webhook e modelli con la tua conferma e scrive il codice. Scopri come →

Tre limiti, e ognuno conta per conto suo. Per numero (connection), solo POST /v1/messages: il ritmo che Meta dà a quel numero — Coesistenza 20 al secondo, Cloud API 80 al secondo, con una raffica di un secondo. Un numero al massimo non frena gli altri del tuo account. Per account (account), solo POST /v1/messages, al minuto secondo il piano: prova 600, Starter 1.200, Studio 2.400, Agencia 4.800, Escala 9.600; piano su misura senza tetto; mai meno di 600 per key attiva. Per key (key): tutto il resto di /v1, 600 richieste al minuto. Un invio non consuma i 600 della key.

curl -i -X POST https://api.waiaconnect.com/v1/messages \
  -H "Authorization: Bearer wc_live_YOUR_API_KEY" \
  -H "Idempotency-Key: 7c0e…-same-on-every-retry" \
  -H "Content-Type: application/json" \
  -d '{"connectionId":"conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","to":"5493511234567","type":"text","text":{"body":"Hi"}}'
# 202 → X-RateLimit-Scope: connection  X-RateLimit-Limit: 20  X-RateLimit-Remaining: 19
# 429 → Retry-After: 1
# { "error": { "code": "RATE_LIMITED", "limit": "connection", "connectionId": "conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
#              "retryAfterSeconds": 1, "details": { "limitPerSecond": 20, "burst": 20 } } }
// One limiter PER NUMBER (Coexistence 20/s, Cloud API 80/s); retry 429 with the SAME key.
const pausedUntil = new Map(); // connectionId → ms (pause only the number that hit its limit)
async function send(msg, idempotencyKey) {
  for (;;) {
    const wait = (pausedUntil.get(msg.connectionId) || 0) - Date.now();
    if (wait > 0) await new Promise(r => setTimeout(r, wait));
    const res = await fetch("https://api.waiaconnect.com/v1/messages", {
      method: "POST",
      headers: { "Authorization": "Bearer wc_live_YOUR_API_KEY", "Idempotency-Key": idempotencyKey, "Content-Type": "application/json" },
      body: JSON.stringify(msg)
    });
    if (res.status !== 429) return res.json();
    const { error } = await res.json();
    if (error.code !== "RATE_LIMITED") return { error }; // quota: do not retry
    const until = Date.now() + Number(res.headers.get("retry-after") || error.retryAfterSeconds) * 1000;
    if (error.limit === "connection") pausedUntil.set(msg.connectionId, until);
    else await new Promise(r => setTimeout(r, until - Date.now())); // account or key: everything waits
  }
}
<?php
// Retry a 429 with the SAME Idempotency-Key, after Retry-After.
function send(array $msg, string $idemKey): array {
  for ($i = 0; $i < 5; $i++) {
    $ch = curl_init("https://api.waiaconnect.com/v1/messages");
    curl_setopt_array($ch, [
      CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HEADER => true,
      CURLOPT_HTTPHEADER => ["Authorization: Bearer wc_live_YOUR_API_KEY", "Idempotency-Key: $idemKey", "Content-Type: application/json"],
      CURLOPT_POSTFIELDS => json_encode($msg),
    ]);
    $raw = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $body = json_decode(substr($raw, curl_getinfo($ch, CURLINFO_HEADER_SIZE)), true);
    if ($status !== 429 || ($body["error"]["code"] ?? "") !== "RATE_LIMITED") return $body;
    sleep(max(1, (int)$body["error"]["retryAfterSeconds"])); // = Retry-After
  }
  return $body;
}
import time, requests
# Retry a 429 with the SAME Idempotency-Key, after Retry-After.
def send(msg, idem_key):
    for _ in range(5):
        res = requests.post("https://api.waiaconnect.com/v1/messages", json=msg, headers={
            "Authorization": "Bearer wc_live_YOUR_API_KEY", "Idempotency-Key": idem_key})
        if res.status_code != 429 or res.json()["error"]["code"] != "RATE_LIMITED":
            return res.json()
        err = res.json()["error"]  # err["limit"]: connection | account | key
        time.sleep(int(res.headers.get("Retry-After", err["retryAfterSeconds"])))
    return res.json()

Il 429: il code è quello di sempre, RATE_LIMITED. Aggiunge error.limit (connection, account o key: quale ti ha fermato), error.connectionId (solo se era quello del numero) e error.retryAfterSeconds, uguale all'header Retry-After. Per account e key la cifra è in details.limitPerMinute; per connection, in details.limitPerSecond e details.burst.

Ogni risposta di /v1 porta X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (secondi finché torna pieno) e X-RateLimit-Scope, del limite più stretto in quel momento.

Come costruire la tua coda: un limitatore per numero (fino a 20/s in Coesistenza, 80/s in Cloud API), tutti sotto la cifra al minuto del tuo account. Davanti a un 429, aspetta Retry-After e riprova con la stessa Idempotency-Key: un 429 non crea nulla, il nuovo tentativo è sicuro. Con limit: "connection" metti in pausa solo quel numero; con account o key, tutto.

Accettato non è consegnato: dopo un 202 la coda passa ogni messaggio a Meta al suo ritmo e non ne perde nessuno. GET /v1/usage/by-connection conta messaggi, non richieste: un 429 lì non compare.

Ti serve un'altra cifra di account per un caso speciale? Scrivici: si regola account per account.