Meetso API

Rate limits

Two windows, per-key buckets, and a recommended retry strategy.

The public API uses two parallel rate-limit windows per API key. The strictest one wins.

WindowLimitPurpose
Burst10 requests / secondCatches accidental loops + thundering herds.
Sustained60 requests / minuteFair-use ceiling for long-running ingests.

Limits are tracked per key, not per IP. Multiple integrations behind the same NAT or load balancer don't share buckets, and a single integration distributed across multiple servers doesn't get N× the limit by accident.

When you hit a limit

You get an HTTP 429 with the standard error envelope:

{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded. Try again later.",
    "request_id": "req_…"
  }
}

Retry strategy

For burst hits (you sent 11 requests in a second), waiting one second is enough. For sustained hits, the bucket replenishes over the next minute.

Recommended: exponential backoff with jitter, max 3 retries.

async function call<T>(url: string, apiKey: string): Promise<T> {
  for (let attempt = 0; attempt < 3; attempt++) {
    const res = await fetch(url, {
      headers: { Authorization: `Bearer ${apiKey}` },
    });
    if (res.status !== 429) {
      if (!res.ok) {
        const { error } = await res.json();
        throw new Error(`${error.code}: ${error.message}`);
      }
      return res.json();
    }
    // Backoff: 1s, 2s, 4s with ±25% jitter
    const base = 2 ** attempt * 1000;
    const jitter = base * (Math.random() * 0.5 - 0.25);
    await new Promise((r) => setTimeout(r, base + jitter));
  }
  throw new Error('Rate limit retries exhausted');
}

Tips for staying under the limit

  • Paginate, don't poll. Use cursor pagination to walk a list once, rather than re-requesting page 1 repeatedly.
  • Cache aggressively. The reference data (meeting metadata, transcripts) is immutable once a transcript is COMPLETED. Cache in your own store; only refetch when polling for status transitions.
  • Use one key per integration. Each integration has its own bucket. Splitting across keys means a heavy CRM sync won't starve a real-time Slack bot.
  • Pull at off-peak hours. Bulk backfills tolerate latency better than user-triggered requests; schedule them overnight in your time zone.

Custom limits

If your integration has a legitimate reason to need higher limits (large org, real-time-ish needs), reach out via support with your expected QPS and use case. We'll adjust your key's bucket without a contract amendment for reasonable asks.

On this page