# Polling & Rate Limits


Most write operations on the Intuizi API are asynchronous, so a well-behaved
client spends most of its time doing two things: polling a resource until it is
ready, and staying inside the rate limits while it does. This guide covers both,
plus how to retry safely. It applies equally whether you are writing an
integration by hand or driving the API from an AI agent - the same intervals,
limits, and retry rules keep an autonomous loop from hammering the API or
double-creating resources.

## The two rate buckets

Limits are enforced **per token** (an agent's MCP token counts the same as an
API bearer token):

| Bucket | Limit | Applies to |
| --- | --- | --- |
| Read | 120 requests/min | Every `GET` (reads, reference lookups, polling) |
| Write | 30 requests/min | Every create and delete (`POST`) |

Polling counts against the **read** bucket, so a tight poll loop can exhaust
120 reads/min on its own. Space your polls out (below) and you will stay well
under it.

## The build budget

Rate buckets are per token and per minute. Separately, every **create that
starts a worker job** (an audience, an estimate, a Lookalike Model, a cohort, an
activation) counts against your organization's **build budget**: 60 per rolling
hour and 300 per rolling day by default, shared across every token, MCP and the
console. Over the budget you get the same `429` + `Retry-After` as a rate
bucket, and nothing is created. `GET /api/v2/usage` reports the budget and your
live counts under `build_budget` - check it before a batch and pace the batch to
it instead of retrying on `429`. Scheduled replays never count.

## How to poll

Creating an audience, activation, cohort, or Lookalike Model returns immediately
with an id; the work finishes in the background (see
[The Async Model](/concepts/async-model)). Poll the matching `GET .../{id}`
endpoint and read the lifecycle status inside `data`:

- **`100`-`103`, `108` (Modeling), and `109` (Visualizing data streams)** -
  still working. Keep polling.
- **`105` (DataStreaming)** - an activation is delivering to the destination;
  keep polling. Note `105` happens **before** `104`.
- **`104` (Completed)** - the only terminal success state; stop polling and act
  on the result.
- **`107` (Additional Info)** - the build or export stopped and will not
  continue. Stop polling. Audience Manager shows the reason. Fix the request
  and create it again.
- **`4xx` lifecycle ids** - an error state. Stop polling and inspect the
  resource.

Recommended approach:

- Poll on an interval of a few seconds to start, and **back off** as the wait
  grows (for example 5s, then 10s, then 30s). Do not poll in a tight loop.
- Build a sensible overall **timeout** into your client so a stuck job does not
  poll forever.
- Only the lifecycle status tells you the work is done - a `200 OK` on the read
  just means "here is the current state". See
  [Status Codes](/concepts/status-codes).

## Handling a 429

If you exceed a bucket you get `429 Too Many Requests`. The response carries a
**`Retry-After`** value (seconds to wait); the same value also appears in the
error text. Do not retry immediately.

1. Read `Retry-After` from the `429` response.
2. Wait that many seconds.
3. Retry the request.

A backoff-and-retry-on-`429` wrapper around your HTTP client is the simplest way
to stay compliant without hand-tuning every call. See
[Errors](/concepts/errors) for the `429` envelope.

## Retrying a create safely

A `429` or a `5xx` on a **create** is the risky case: you do not know whether the
resource was made. Make creates idempotent so a retry can never double-create:

- Generate an `Idempotency-Key` (a UUID) before the first attempt.
- On any retry of that same create, **resend the same key**. If the original
  request had actually succeeded, you get its response back
  (`Idempotency-Replayed: true`) instead of a duplicate; if it never ran, the
  retry executes cleanly.

Full semantics - including which eight endpoints honor the header - are on
[Idempotency](/concepts/idempotency).

## Notes for AI agents

- Tool calls over [MCP](/mcp) consume the **same** per-token buckets as direct
  API calls (120 reads/min, 30 writes/min, plus 120 MCP requests/min). A polling
  loop is read traffic.
- On a `429`, the tool error text includes the `Retry-After` seconds - wait,
  then retry, rather than looping immediately.
- The create tools accept an `idempotency_key` argument - set it once per logical
  create and reuse it across retries so an interrupted run never doubles up.
- The full agent journey, from connecting a client to a delivered audience, is
  [Automate with an AI Agent](/guides/automate-with-an-ai-agent).

## Reference

- [The Async Model](/concepts/async-model)
- [Status Codes](/concepts/status-codes)
- [Idempotency](/concepts/idempotency)
- [Errors](/concepts/errors)
