Skip to main content

Rate Limiting

Zavu implements rate limiting to ensure fair usage and protect the platform from abuse. All API requests to /v1/* endpoints are subject to rate limiting.

Rate Limit Tiers

Your rate limit depends on your project’s verification status:
TierLimitEligibility
Default600 requests/minAll new projects
Compliance Verified1,200 requests/minProjects with verified business compliance
10DLC Verified2,400 requests/minProjects with approved 10DLC campaign
Rate limits are applied per project. If you have multiple projects, each has its own independent rate limit.

How to Increase Your Limit

1

Complete Compliance Verification

Submit your business information and use case in the dashboard under Settings > Compliance. Once verified, your limit automatically increases to 1,200 requests/min (2x).
2

Register for 10DLC (US Numbers)

If you’re sending SMS to US recipients, register your brand and campaign for 10DLC compliance. Approved campaigns receive 2,400 requests/min (4x).
Verification is automatic - once approved, your rate limit increases immediately with no code changes needed.

Rate Limit Headers

Every API response includes headers to help you track your rate limit usage:
HeaderDescriptionExample
X-RateLimit-LimitMaximum requests per minute600
X-RateLimit-RemainingRequests remaining in current window542
X-RateLimit-ResetUnix timestamp (ms) when window resets1701234600000
Retry-AfterSeconds until reset (only on 429)45

Checking Rate Limits with the SDK

Use .withResponse() to access the rate limit headers:
import Zavudev from '@zavudev/sdk';

const zavu = new Zavudev({
  apiKey: process.env['ZAVUDEV_API_KEY'],
});

// Use .withResponse() to get the full HTTP response
const { response, result } = await zavu.messages.send.withResponse({
  to: "+14155551234",
  text: "Hello from Zavu!",
});

// Access rate limit headers
const limit = response.headers.get("X-RateLimit-Limit");
const remaining = response.headers.get("X-RateLimit-Remaining");
const reset = response.headers.get("X-RateLimit-Reset");

console.log(`Rate limit: ${remaining}/${limit} requests remaining`);
console.log(`Window resets at: ${new Date(Number(reset)).toISOString()}`);

// Access the message result as usual
console.log("Message ID:", result.message.id);

Rate Limit Exceeded (429)

When you exceed the rate limit, the API returns a 429 Too Many Requests response:
{
  "code": "rate_limited",
  "message": "Rate limit exceeded. Retry after 2024-01-15T12:30:00.000Z",
  "details": {
    "retryAfter": 1705322400000
  }
}

Handling Rate Limits

Here’s how to properly handle rate limiting in your application:
import { Zavu } from "@zavudev/sdk";
import * as errors from "@zavudev/sdk/models/errors";

const zavu = new Zavu({
  bearerAuth: process.env.ZAVU_API_KEY,
});

async function sendWithRateLimitHandling(to: string, text: string) {
  try {
    const { response, result } = await zavu.messages.send.withResponse({
      to, text,
    });

    // Check remaining quota
    const remaining = Number(response.headers.get("X-RateLimit-Remaining"));
    if (remaining < 10) {
      console.warn(`Low rate limit: ${remaining} requests remaining`);
    }

    return result;
  } catch (error) {
    if (error instanceof errors.SDKError && error.statusCode === 429) {
      // Get retry time from error or headers
      const retryAfter = error.body?.details?.retryAfter;
      const waitMs = retryAfter ? retryAfter - Date.now() : 60000;

      console.log(`Rate limited. Waiting ${waitMs}ms before retry...`);
      await new Promise(resolve => setTimeout(resolve, waitMs));

      // Retry the request
      return sendWithRateLimitHandling(to, text);
    }
    throw error;
  }
}

How It Works

Zavu uses a fixed window algorithm for rate limiting:
Window: 12:00:00 - 12:00:59
├── Request 1: OK (remaining: 599)
├── Request 2: OK (remaining: 598)
├── ...
├── Request 600: OK (remaining: 0)
└── Request 601: 429 Rate Limited

Window: 12:01:00 - 12:01:59
└── Request 1: OK (remaining: 599) ← Counter resets!
The counter resets at the start of each minute (e.g., 12:00:00, 12:01:00, 12:02:00).

Best Practices

Monitor Headers

Always check X-RateLimit-Remaining to avoid hitting limits unexpectedly.

Implement Backoff

Use the Retry-After header or retryAfter field to wait the correct amount of time.

Use Broadcasts

For bulk sending, use our Broadcasts API instead of individual requests.

Use Idempotency Keys

Include idempotencyKey in requests to safely retry without duplicates.

Bulk Sending Example

For sending many messages, implement a simple rate limiter:
import Zavudev from '@zavudev/sdk';

const zavu = new Zavudev({
  apiKey: process.env['ZAVUDEV_API_KEY'],
});

async function sendBulkMessages(messages: { to: string; text: string }[]) {
  const results = [];
  let remaining = 600;

  for (const msg of messages) {
    // If running low, wait for next window
    if (remaining < 10) {
      console.log("Approaching rate limit, waiting for next window...");
      await new Promise(resolve => setTimeout(resolve, 60000));
      remaining = 600;
    }

    const { response, result } = await zavu.messages.send.withResponse(msg);

    remaining = Number(response.headers.get("X-RateLimit-Remaining"));
    results.push(result);
  }

  return results;
}
For sending to more than 100 recipients, we strongly recommend using the Broadcasts API instead. Broadcasts handle rate limiting, retries, and progress tracking automatically.

Summary

TierLimitHow to Get
Default600/minAutomatic for all projects
Compliance Verified1,200/minComplete business verification
10DLC Verified2,400/minRegister 10DLC brand & campaign

Next Steps