🚀 GoSendAPI is in beta — Meta App Review in progress. Get on the waitlist →
GuidesRate limits

Rate limits

GoSendAPI rate-limits at multiple levels: per-API-key, per-phone-number-throughput, and per-WABA-conversations. This guide covers all three.

Per-API-key (our limit)

Each API key has a default quota across all endpoints:

PlanRequests/secRequests/day
Sandbox (gsk_test_)101,000
Standard (gsk_live_)100100,000
High Volume5001,000,000
EnterpriseCustomCustom

If you exceed your key’s RPS, we return 429:

{
  "statusCode": 429,
  "message": "Rate limit exceeded for API key",
  "retry_after_seconds": 1
}

Per-phone-number (Meta’s limit)

Each phone number has a throughput tier set by Meta:

TierLimitHow to upgrade
Standard80 msg/sDefault for new numbers
Medium200 msg/sSustained green-quality traffic
High1,000 msg/sApply via Meta, requires consistent volume
UnlimitedNo capEnterprise customers

If you exceed the throughput, we still accept your request but queue it locally and send to Meta as the bucket refills. If queue gets too deep (>10,000 messages waiting on the same phone), we start returning 429.

See Phone numbers concept for upgrading tiers.

Per-WABA (Meta conversation limit)

A WABA has a daily limit on unique conversations:

TierUnique business-initiated conversations/24h
Tier 11,000
Tier 210,000
Tier 3100,000
Tier 4Unlimited

You start at Tier 1. Meta auto-upgrades when you consistently hit the cap with quality content (low block rate, low complaint rate).

Service conversations (user-initiated) don’t count toward this limit. Only business-initiated (you sending first via template).

Response headers

Every response includes:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1716030120
HeaderMeaning
X-RateLimit-LimitYour RPS limit (requests/second)
X-RateLimit-RemainingRequests remaining in current 1s window
X-RateLimit-ResetUnix timestamp when the window resets

On 429 responses, also includes:

Retry-After: 1

The value is seconds — sleep that long before retrying.

Backoff implementation

class GoSendAPIClient {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.queue = [];
  }
 
  async send(payload) {
    return this._withBackoff(async () => {
      const res = await fetch('https://cloud.gosendapi.com/v1/messages', {
        method: 'POST',
        headers: {
          'X-API-Key': this.apiKey,
          'Content-Type': 'application/json',
          'Idempotency-Key': payload.idempotencyKey,
        },
        body: JSON.stringify(payload),
      });
 
      if (res.status === 429) {
        const retryAfter = Number(res.headers.get('Retry-After') ?? 1);
        await sleep(retryAfter * 1000);
        throw new RetryError(`Rate limited, retry after ${retryAfter}s`);
      }
 
      if (!res.ok && res.status >= 500) {
        throw new RetryError(`Server error ${res.status}`);
      }
 
      if (!res.ok) {
        throw new PermanentError(await res.text());
      }
 
      return res.json();
    });
  }
 
  async _withBackoff(fn, attempt = 1, maxAttempts = 5) {
    try {
      return await fn();
    } catch (err) {
      if (err instanceof PermanentError) throw err;
      if (attempt >= maxAttempts) throw err;
      const wait = Math.min(60_000, 1000 * Math.pow(2, attempt));
      await sleep(wait + Math.random() * 500);  // jitter
      return this._withBackoff(fn, attempt + 1, maxAttempts);
    }
  }
}
 
const sleep = ms => new Promise(r => setTimeout(r, ms));

Bulk sends (e.g. marketing campaigns)

For sending to >1000 recipients:

1. Use template + media reuse

Upload media once, get an id, reuse. See Sending messages → Media.

2. Spread over time

Don’t blast 10,000 messages in 1 second. Spread over 5-10 minutes (= ~30 msg/s). Reasons:

  • Stays under throughput cap with margin for organic traffic
  • Improves Meta delivery rate (anti-spam heuristics)
  • Lets you abort mid-campaign if quality issues surface

3. Pre-validate recipients

Before sending to 10,000 phones, run them through your own deduper:

// Check which numbers are on WhatsApp via Meta's contact validation
// (Coming soon in API. For now, send and skip the ones that fail with RECIPIENT_NOT_ON_WHATSAPP)

4. Use webhooks for status

Don’t poll GET /v1/messages/{id} for 10,000 messages. Subscribe to whatsapp.message.delivered / failed and accumulate.

Quota visibility

In the dashboard at app.gosendapi.com → Usage:

  • Today’s API requests (vs limit)
  • Today’s messages sent
  • Per-phone throughput utilization
  • Conversation tier and current consumption

Upgrading limits

Contact hello@gosendapi.com if you need:

  • Higher API RPS (>500)
  • Custom retention period for messages
  • Multi-region request routing
  • Dedicated phone-number pools

We respond within 1 business day with a custom quote.

What’s next