Rate Limits

API rate limiting information


SuperSend API uses two layers of rate limiting:

  • Infrastructure — Applies to all requests (V1 and V2). Enforced at the load balancer per IP. Exceed it → 503, no body.

  • Per-endpoint — Only on some V1 endpoints (e.g. guess-email, verify-email). Enforced by the API. Exceed it → 429 with a JSON error.
  • The sections below give the numbers and how to handle each.


    Infrastructure rate limits (V1 and V2)

    All API traffic—both V1 and V2—to api.supersend.io, track.supersend.io, and io.supersend.io is subject to the following limits per client IP address:

    LimitValueDescription
    Requests per second50Max 50 requests per second per IP
    Concurrent connections20Max 20 simultaneous connections per IP
    Requests per minute3,000Max 3,000 requests per minute per IP


    These limits are enforced at the load balancer before traffic reaches the application. If you exceed them, you will receive 503 Service Temporarily Unavailable. Clients behind a shared IP (e.g. NAT, corporate proxy) share the same limits.


    Endpoint-specific rate limits

    V1 API

    The V1 API applies additional rate limiting on specific endpoints only:

    EndpointAuthenticatedUnauthenticated
    /v1/guess-email10,000/min3/min
    /v1/verify-email100/sec (paid)10/sec (free)
    /v1/generate-summary10 per 2 secondsN/A


    Note: Most V1 endpoints (contact CRUD, campaigns, teams, etc.) do not have rate limiting applied.

    V2 API

    The V2 API does not apply endpoint-specific rate limits (unlike the V1 endpoints in the table above). V2 traffic is still subject to the infrastructure rate limits (50 req/s, 20 connections, 3,000 req/min per IP). We recommend reasonable request patterns and exponential backoff on 503 to stay within those limits.


    Best Practices

    To stay within rate limits and keep your integration reliable:

    1. Use Bulk Endpoints

    Instead of creating contacts one by one, use bulk creation:

    javascript
    // Less efficient - multiple requests
    for (const contact of contacts) {
    await createContact(contact)
    }

    // More efficient - single request
    await fetch('https://api.supersend.io/v1/bulk-contacts', {
    method: 'POST',
    headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
    },
    body: JSON.stringify({
    contacts: contacts,
    TeamId: 'your-team-id',
    CampaignId: 'your-campaign-id'
    })
    })

    2. Implement Exponential Backoff

    For any errors, implement exponential backoff:

    javascript
    async function apiRequestWithRetry(url, options, maxRetries = 3) {
    for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
    const response = await fetch(url, options)
    if (response.ok) return response

    // For server errors, retry with backoff
    if (response.status >= 500) {
    const delay = Math.min(1000 * Math.pow(2, attempt), 30000)
    await new Promise(r => setTimeout(r, delay))
    continue
    }

    return response // Client errors shouldn't be retried
    } catch (err) {
    if (attempt === maxRetries - 1) throw err
    const delay = Math.min(1000 * Math.pow(2, attempt), 30000)
    await new Promise(r => setTimeout(r, delay))
    }
    }
    }

    3. Cache Responses

    Don't fetch the same data repeatedly:

    javascript
    const cache = new Map()

    async function getCampaign(id) {
    if (cache.has(id)) {
    return cache.get(id)
    }

    const response = await fetch(https://api.supersend.io/v2/campaigns/${id}, {
    headers: { 'Authorization': 'Bearer YOUR_API_KEY' }
    })
    const campaign = await response.json()

    cache.set(id, campaign.data)

    // Clear cache after 5 minutes
    setTimeout(() => cache.delete(id), 5 60 1000)

    return campaign.data
    }

    4. Use Pagination Efficiently

    When fetching large datasets, use appropriate page sizes:

    javascript
    async function getAllContacts(teamId, campaignId) {
    const allContacts = []
    let offset = 0
    const limit = 100

    while (true) {
    const response = await fetch(
    https://api.supersend.io/v2/contacts?TeamId=${teamId}&CampaignId=${campaignId}&limit=${limit}&offset=${offset},
    { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }
    )
    const data = await response.json()

    allContacts.push(...data.data)

    if (!data.pagination.has_more) break
    offset += limit
    }

    return allContacts
    }


    When you hit a rate limit

    Limit typeHTTP statusResponse bodyWhat to do
    Infrastructure (too many requests/sec, too many connections, or too many requests/min for your IP)503NoneBack off and retry with exponential backoff. Reduce concurrency or request rate.
    Endpoint (e.g. guess-email, verify-email over their per-endpoint cap)429JSON with rate_limit_error or rate_limit_exceededWait for the limit window to reset, then retry.


    503 from infrastructure: The load balancer returns 503 before your request reaches the API. There is no JSON body—only the status code. Use exponential backoff and avoid retrying immediately.

    429 from endpoint limits: The API returns a normal error payload. Example (V2 format):

    json
    {
    "error": {
    "type": "rate_limit_error",
    "code": "rate_limit_exceeded",
    "message": "Too many requests. Please retry after the limit window resets.",
    "doc_url": "https://docs.supersend.io/docs/rate-limits"
    },
    "request_id": "req_a1b2c3d4e5f6789012345678"
    }

    For full error shapes and codes, see Error Handling.


    Need Higher Throughput?

    For enterprise customers with specific throughput requirements, contact support@supersend.io to discuss your use case.