Handle HTTP 429 rate-limit responses from the IllyVoIP API

Handle IllyVoIP HTTP 429 responses with Retry-After, bounded scheduling and shared-worker coordination without confusing throttling with SMS daily limits.

An HTTP429 response means your application must slow down or inspect the reported rate-limit condition. Repeating the same request immediately usually makes recovery harder. Read the response, pause the relevant work and preserve the identity of any operation you may retry.

This guide is for API developers running one or more workers. It covers request throttling, not a request to increase the account's daily SMS allowance. Those are different limits with different remedies.

1. Save enough information to identify the limit

Record the HTTP status, endpoint, timestamp, structured error and Retry-After header without logging the API key or full customer payload. Note which workers share the credential and whether the failed request was a read or a paid action.

The current IllyVoIP API response layer provides a 60-second fallback header for HTTP429. Read the actual response rather than embedding that value as a permanent promise about all endpoints. The authentication limiter also has a distinct storage-unavailable error path; that message should not be misreported as proof that the customer exhausted a quota.

Respond to a rate limit. Original explanatory diagram, not a product screen or evidence of a completed transaction.
Respond to a rate limit. Original explanatory diagram, not a product screen or evidence of a completed transaction. Open the image for a larger view.

2. Distinguish request rate from message allowance

SituationWhat to investigate
HTTP429 request throttlingRequest frequency, shared workers and response retry guidance.
Daily SMS allowance or an administrative restrictionThe account's displayed SMS limit/review workflow and exact API error.
Validation or authentication failureCorrect the request or credential; waiting alone does not fix it.
Timeout without a reliable responseSubmission uncertainty, not an assumed429 or rejection.

A request can contain more than one recipient, so request count and message count are not interchangeable. Raising the daily SMS allowance does not establish a higher API request rate. Rotating keys is not a remedy for throttling.

3. Coordinate the workers that share access

If several workers use the same account credential, local delays inside one process may be insufficient. Use a shared queue or scheduling record so new work observes the same pause. Bound concurrency and avoid having every delayed job wake at exactly the same instant.

Keep read polling efficient: retain returned IDs, use the documented pagination, and use delivery webhooks where appropriate instead of repeatedly asking for unchanged status. Do not respond by launching more workers or changing the key.

4. Calculate a delay without retrying early

This JavaScript helper accepts either a numeric Retry-After value or an HTTP date. It adds bounded backoff and jitter while respecting a longer service delay. A missing/malformed header uses an explicit conservative application fallback. The helper does not send a request.

// Call only after classifying the response as an eligible retry.
export function retryDelayMs(header, attempt, random = Math.random, now = Date.now()) {
  if (!Number.isInteger(attempt) || attempt < 0) throw new Error('Invalid attempt');
  const text = typeof header === 'string' ? header.trim() : '';
  let serverDelay;
  if (/^[0-9]+$/.test(text)) {
    serverDelay = Number(text) * 1000;
    if (!Number.isFinite(serverDelay)) return null;
  }
  else {
    const httpDate = /^[A-Z][a-z]{2}, [0-9]{2} [A-Z][a-z]{2} [0-9]{4} [0-9]{2}:[0-9]{2}:[0-9]{2} GMT$/.test(text);
    const date = httpDate ? Date.parse(text) : NaN;
    serverDelay = Number.isFinite(date) ? Math.max(0, date - now) : NaN;
  }
  if (!Number.isFinite(serverDelay)) serverDelay = 60000;
  // A long service delay is an operator/deferred-job decision, not an early retry.
  if (serverDelay > 24 * 60 * 60 * 1000) return null;
  const backoff = Math.min(15 * 60 * 1000, 1000 * 2 ** Math.min(attempt, 10));
  const jitter = Math.floor(Math.max(0, Math.min(1, random())) * 1000);
  return Math.max(serverDelay, backoff) + jitter;
}

A null result means defer for operator review or long-term scheduling; it does not mean retry immediately. Limit the total attempts and elapsed time separately, and stop when the job is cancelled. Persist next_attempt_at in the queue instead of keeping an HTTP request open while sleeping.

5. Recheck the operation before retrying

Read-only operations and paid submissions need different handling. For SMS, retain the exact saved JSON and idempotency key for an eligible identical retry. If some recipients were already accepted, preserve their IDs and do not create a new whole-batch send to recover the rest.

For an earlier timeout or ambiguous server result, first reconcile the existing operation using its known references and the endpoint's documented rules. A later429 response does not erase uncertainty from an earlier attempt. Do not assume every Voice, DID or other API action has the same idempotency contract as SMS.

Before resuming, check that the business event still needs the action. A notification that was cancelled while waiting should not be sent just because the timer expired.

6. Exercise the failure path without real traffic

Use a local fake response to test valid seconds, a future HTTP date, malformed headers, an unusually long delay and several workers seeing the same throttle. Confirm that no attempt starts before the scheduled time and that the saved operation identity survives a restart.

The Sandbox guide includes an explicit rate-limited scenario for a supported country-list request. Use only the scenarios advertised by the selected endpoint in the current Sandbox reference. Sandbox is a simulation, not a load-testing target or a way to discover Production capacity.

When to contact Support

If throttling continues despite respecting the response and reducing concurrency, share the endpoint, timestamps/timezone, sanitized error, observed request pattern and affected operation references. If the message identifies rate-limit storage unavailability, include that exact wording rather than requesting a daily SMS increase.

Do not publish a universal requests-per-minute value based on a single response. Use current account/service guidance for your integration, and keep the retry policy bounded even after normal traffic resumes.

Related guides and references

Reviewed 9 October 2026 against current IllyVoIP source and the linked documentation. Use the settings available to your account and installed version. These instructions are not a claim of a completed physical-device or live-service test.