Logo

Link

Rate limits

Generous quotas. Predictable headers.

Per-tier request budgets, the X-RateLimit-* response headers Link AI returns on every request, and the recommended back-off + retry strategy for staying under quota.

Link AI rate-limits every workspace independently. Limits are generous on purpose — most integrations never see a 429. When you do, the response is deterministic and easy to recover from.

Per-plan budgets

Two distinct budgets apply: request rate (per minute, against the REST API) and concurrent voice calls (the cap on outbound calls in flight at any one moment).

PlanRequests / minuteConcurrent voice calls
Starter1205
Growth60025
Scale3,000100
EnterpriseCustomCustom

Mailer endpoints additionally inherit campaign-level send budgets (per the configured throttle), but those caps live on the campaign object — not the API surface — so they do not return 429.

Response headers

Every response carries three headers describing the current bucket state. Read them before you start tuning — they are cheaper than trial-and-error.

HeaderMeaning
X-RateLimit-LimitTotal requests allowed in the current 60-second window.
X-RateLimit-RemainingRequests left in the current window.
X-RateLimit-ResetUnix timestamp (seconds) when the window resets.
Retry-AfterOnly on 429. Seconds the client should wait before the next attempt.
example headers
HTTP/1.1 200 OK
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 587
X-RateLimit-Reset: 1747823640
Content-Type: application/json

When you hit a 429

A 429 Too Many Requests response means the workspace has spent its budget for the current window. The body always carries a structured error and the headers always include Retry-After.

429 response
{
  "error": {
    "code": "rate_limited",
    "message": "Workspace exceeded 600 requests/minute. Retry after 38s.",
    "retry_after_seconds": 38,
    "request_id": "req_01HFE9X..."
  }
}

Recommended back-off

TypeScript
async function fetchWithBackoff(
  url: string,
  init: RequestInit,
  maxAttempts = 5,
): Promise<Response> {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    const res = await fetch(url, init);
    if (res.status !== 429) return res;

    // Honour the server's hint when present, otherwise exponential.
    const hint = Number(res.headers.get("retry-after") ?? "0");
    const backoffMs = hint > 0
      ? hint * 1000
      : Math.min(30_000, 500 * 2 ** (attempt - 1));

    await new Promise((r) => setTimeout(r, backoffMs));
  }
  throw new Error("Exceeded retry budget");
}

Best practices

  • Batch list reads. Use limit=100 instead of polling one-by-one. Pagination is free of the rate counter beyond the single request that yields each page.
  • Coalesce webhook side effects. If a webhook triggers a bulk fan-out against the API, queue the work locally — never spawn 1,000 parallel requests from a single delivery.
  • Use idempotency keys. A safe retry costs nothing; an accidental duplicate call costs minutes and reputation. See API conventions.
  • Monitor the headers. Alarm on X-RateLimit-Remaining dropping below 10% of X-RateLimit-Limit for more than a minute. That is the early signal of an integration that is about to start failing.
Rate limits — Link AI API · Link AI