> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anthid.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SENT is not FILLED: the two-state order lifecycle

> Why Anthid reports how far the platform got and what the broker did as two separate fields, what goes wrong when they are collapsed into one, and which field answers which question

The single most common bug written against Anthid is a dashboard or a strategy that treats `SENT` as done. It is an easy mistake, because on most broker APIs a status is a status. On Anthid an intent reports two different answers about where things stand, and they are not interchangeable. This article explains the two, why there are two, and which one to read for each question you actually have.

## Two questions, two fields

An instruction goes through two independent things. Anthid has to carry it to the broker, and then the broker has to do something with it. Each is reported on the intent.

**Dispatch** is how far Anthid got in handing the instruction over. It is the `state` field, and it moves through four values.

| `state`      | What it means                                             |
| ------------ | --------------------------------------------------------- |
| `PENDING`    | Accepted and recorded, waiting to be picked up            |
| `PROCESSING` | Being acted on                                            |
| `SENT`       | Handed to the broker, and the broker accepted the handoff |
| `FAILED`     | Could not be handed to the broker                         |

Dispatch is terminal at `SENT` or `FAILED`. Once an intent is `SENT`, it stays `SENT` forever, including after the order fills, is cancelled, or is rejected at the venue. That is the point at which people go wrong: `SENT` is the last thing dispatch will ever say, so it looks final, and it is final, but only about the handoff.

**Outcome** is what the broker did with the order that followed. It is the `runtime_status` field, and it keeps moving after dispatch has stopped.

| `runtime_status`   | What it means                                       |
| ------------------ | --------------------------------------------------- |
| `null`             | The broker has not said anything yet                |
| `PENDING`          | The broker holds the order and has not worked it    |
| `OPEN`             | Working at the venue                                |
| `PARTIALLY_FILLED` | Some quantity has traded, the rest is still working |
| `FILLED`           | Fully executed                                      |
| `CANCELLED`        | Withdrawn                                           |
| `REJECTED`         | Refused at the venue                                |

A perfectly healthy order reads `state: SENT, runtime_status: OPEN` for as long as it rests, then `state: SENT, runtime_status: FILLED`. A rejected one reads `state: SENT, runtime_status: REJECTED`. In both cases dispatch succeeded. The handoff and the outcome are different facts.

## Why one field cannot do this job

Collapse the two into one status and something has to give.

If the single status is dispatch-shaped, it ends at `SENT` and can never say filled. If it is outcome-shaped, it cannot begin until the broker speaks, so an order the broker never acknowledged has no status at all, which is exactly the order you most need to point at. And if it tries to be both, `PENDING` becomes ambiguous: is the platform still holding the instruction, or is the broker?

That last ambiguity is why `runtime_status` is `null` rather than `PENDING` before the broker reports. A null says Anthid has heard nothing. `PENDING` is the broker saying it has the order and has not worked it. A caller that only wants one value can treat null as pending. A caller watching for a stuck order needs to tell them apart, because an intent that has been `SENT` for a minute with a null outcome is a different problem from one the broker is holding.

<Warning>
  **`SENT` does not mean filled.** A report that counts `SENT` intents as executed overstates what traded, by every order that was rejected, cancelled, or is still resting. Read `runtime_status`, or read `filled_quantity` from the resulting order.
</Warning>

## The order carries the same idea twice more

Once the broker acknowledges an order there is an [order record](/pages/concepts/orders) alongside the intent, and it makes the same distinction in two more places.

The order carries `order_status`, the precise lifecycle position in the venue's own vocabulary, and `order_state`, a coarse rollup computed from it for filtering lists and driving dashboards. Because the state is derived from the status, the two cannot disagree.

| `order_state` | Statuses that map to it                                                                   |
| ------------- | ----------------------------------------------------------------------------------------- |
| `Open`        | `PENDING_NEW`, `NEW`, `PARTIALLY_FILLED`, `PENDING_CANCEL`, `PENDING_REPLACE`, `REPLACED` |
| `Closed`      | `FILLED`, `CANCELLED`, `STOPPED`                                                          |
| `Rejected`    | `REJECTED`                                                                                |

Two consequences bite in reporting, and both are the `SENT` mistake in a different coat.

A partially filled order is `Open`, not `Closed`. It has traded, but it is still working, and closing it out in your own model on the first fill strands the remainder.

`Closed` is not a synonym for filled. A cancelled order and a fully filled order are both `Closed`, because both are finished. Which of the two it was comes from `order_status`, or from comparing `filled_quantity` against `quantity`.

<Note>
  The two fields do not share a casing. `order_state` serializes as `Open`, `Closed`, `Rejected`. `order_status` beside it serializes as `NEW`, `FILLED`, `PARTIALLY_FILLED`. A comparison against `"OPEN"` never matches, and it fails silently.
</Note>

## Which field answers which question

| You want to know                                               | Read                                                                           | Where                                            |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------ |
| Did Anthid accept and record the instruction                   | The `intent_id` in the submit response                                         | `POST /v1/intents`                               |
| Did Anthid hand it to the broker                               | `state`                                                                        | `GET /v1/intents/{intent_id}`                    |
| Is the platform still holding it, or has the broker not spoken | `state` is `PENDING` or `PROCESSING`, versus `SENT` with `runtime_status` null | `GET /v1/intents/{intent_id}`                    |
| What did the broker do with it                                 | `runtime_status`                                                               | `GET /v1/intents/{intent_id}`                    |
| Is the order still working                                     | `order_state` is `Open`                                                        | `GET /v1/orders?environment=<env>&intent_id=...` |
| How much actually traded                                       | `filled_quantity`                                                              | `GET /v1/orders?environment=<env>&intent_id=...` |
| What it traded at                                              | `average_price`                                                                | Same                                             |

`filled_quantity` is the only field that reports how much executed, and it is meaningful at every state: partial on an open order, complete on a filled one, and zero on a cancelled one that never traded. Do not infer execution from any state or status field.

## Reading it from the stream

The same facts arrive live over gRPC. A `BrokerOrder` event on the [streaming API](/api-reference/stream/overview) carries the order's status and its cumulative `filled_quantity`, and a `BrokerTrade` event carries each individual execution for the venues that report them. If you want to know how much of an order has traded, read `filled_quantity` on `BrokerOrder`; it already aggregates the trades.

Reconnecting does not replay every missed transition. Orders default to live delivery, but `ORDER_DELIVERY_PRIMED` first sends the latest retained snapshot per order and a completion marker. See [Streaming](/api-reference/stream/overview#initial-state-and-live-delivery). After a disconnect, read `GET /v1/orders?environment=<env>` for the latest known state per order rather than assuming continuity. The stream is a view over the record, not a replacement for it.

## A worked example

An intent is submitted at 09:30:00 and returns an `intent_id`. Reading it back:

```json theme={null}
{ "state": "PENDING", "runtime_status": null }
```

Anthid has recorded it and not yet picked it up. A moment later:

```json theme={null}
{ "state": "SENT", "runtime_status": null }
```

The broker accepted the handoff and has not reported. This is normal for a few hundred milliseconds. If it lasts a minute, something is wrong on the broker side, and this is the shape a stuck-order monitor should look for. Then:

```json theme={null}
{ "state": "SENT", "runtime_status": "OPEN" }
```

Working at the venue. Then:

```json theme={null}
{ "state": "SENT", "runtime_status": "PARTIALLY_FILLED" }
```

Some traded. The order is `Open`, and `filled_quantity` on the order record says how much. Finally:

```json theme={null}
{ "state": "SENT", "runtime_status": "FILLED" }
```

Dispatch never changed after the second reading. Everything you cared about happened in the other field.

<Columns cols={2}>
  <Card title="Intents" icon="route" href="/pages/concepts/intents">
    The concept page: dispatch, outcome, and the action history.
  </Card>

  <Card title="Intents API" icon="terminal" href="/api-reference/intents/overview">
    Field names, endpoints, and the `state` versus `runtime_status` contract.
  </Card>
</Columns>
