# The Async Model


Creating an audience or an activation does **not** finish the work in the
request. The Intuizi API uses a **create-then-poll** model: the write endpoint validates your
input, persists the resource, and hands the heavy processing to a background
worker. You get an immediate response with an id, then you poll the resource by
id until its lifecycle status says it is done.

## Why async

Resolving an audience's filters into a population, counting devices, and
streaming an activation to a partner all take longer than a single HTTP request
should hold open. So the create call returns fast, and the actual work happens
out of band.

## The pattern

```
1. POST .../create          -> 201, returns the new resource id + initial status
2. GET  .../{id}            -> read the lifecycle status
3. repeat step 2            -> until status is 104 Completed
4. act on the result
```

A `201 Created` on the create, or a `200 OK` on the read, only means "the
request succeeded". It does **not** mean the audience or activation is ready. Always check the lifecycle
status id inside `data` - see [Status Codes](/concepts/status-codes).

## Lifecycle status ids

The lifecycle status is a separate field from the HTTP code (these ids come from
the platform's `ActivationDefines`):

| Status id | Name | Meaning |
| --- | --- | --- |
| `100` | Initiating | Just created and queued for processing. |
| `101` | Processing | The worker is resolving the definition. |
| `102` | Analyzing | Counting / shaping the population. |
| `103` | Decryption Requested | Awaiting a decryption step. |
| `104` | Completed | Done. Audience is ready / activation finished. |
| `105` | DataStreaming | Activation is delivering results to the destination. |
| `106` | Expired | The resource has aged out. |
| `107` | Additional Info | The worker stopped the build and said why, for example a date range outside the data loaded for the dataset. Terminal - nothing follows it. The reason shows in Audience Manager, and the API read carries only the id and name. |
| `108` | Modeling | A Lookalike Model run is training. Non-terminal - keep polling. |
| `109` | Visualizing data streams | An audience is drawing the [data stream visualizations](/api/v2/audiences#datastream-visualizations) it opted into, before `105` and `104`. Non-terminal - keep polling. |
| `4xx` | Error states | Something failed, or a Lookalike Model run you cancelled stopped (`400`). Stop polling and inspect the resource. |

### Terminal states

- **Audience:** poll until `104` Completed before activating it.
- **Activation:** poll until `104` Completed, then read
  `datastreams[].results.uri`. `105` DataStreaming happens **before** `104`
  (the ids are not sequential - the delivery step was added later and took the
  next free id). At `105` results are still being delivered.
- **Failure:** `104` Completed is the only success. A build that stops at
  `107` Additional Info or at a `4xx` error state has failed and never changes
  again, and neither does a resource at `106` Expired.

## Push instead of poll

Polling is the fallback, not the recommended integration for long-running
work. Register a [webhook](/concepts/webhooks) in the console
(**My Organization > Webhooks**) and Intuizi POSTs a signed notification to
your server the moment an audience, activation or cohort completes or
fails - carrying the same object the `GET` read returns, so no follow-up call
is needed. This removes the wasted request budget and the discovery latency
of polling, and it matters most for the slow builds (lookalike models, large
activations).

The lifecycle is unchanged: webhooks fire on `104` Completed and on the
failures, `107` Additional Info and the `4xx` error states (the `400` a
cancelled Lookalike Model ends at included), and on a cohort's `4` Completed
and `5` Not Available. `105` DataStreaming still happens before `104` - there
is no webhook for it, exactly as you would keep polling through it. Keep a
low-frequency poll or an on-demand `GET` as the fallback for a delivery that
exhausts its retries: the resource read is always the source of truth.

## Polling guidance

- Poll on an interval (for example every few seconds), not in a tight loop.
- Treat `100`-`103`, `105`, `108` (Modeling), and `109` (Visualizing data
  streams) as "keep waiting".
- Treat `107` (Additional Info) as a stopped build and stop polling. It does
  not resume. Read the reason in Audience Manager, change the request (for
  example, a date range the dataset has data for), and create it again.
- Treat `106` (Expired) as final: the resource has aged out.
- Treat any `4xx` lifecycle id as an error state and stop polling.
- Build a sensible timeout into your client.

{{< callout type="warning" >}}
Do not act on an audience or activation until it reaches `104` Completed. A
`200 OK` read of a still-`Processing` resource is normal and expected - it just
means the work is not finished yet.
{{< /callout >}}

See [Audiences vs Activations](/concepts/audiences-vs-activations) for how the two
resources chain together.
