> For the complete documentation index, see [llms.txt](https://titan-exchange.gitbook.io/titan/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://titan-exchange.gitbook.io/titan/developer-doc/special-order-types/guides/lifecycle.md).

# Lifecycle & Polling

Order statuses, the withdrawal lifecycle, and how to keep your UI in sync by polling.

An order moves through a fixed set of statuses from creation to a terminal state. Titan doesn't push those changes — there are no webhooks today — so you poll the read endpoints while a user is looking at their orders.

## The status enum

Every order carries a `status` from the same enum, whatever its type:

`pending | active | executing | pending_modification | paused | completed | cancelled | failed | expired`

DCA orders use all of it. `pending` is narrower than it looks: an order only rests there when you set a future `config.startAt`, so most DCA orders go straight to `active` at confirm. Trigger orders use a subset — always `active` after confirm, never `pending` or `pending_modification`, and they can't be retried out of `failed`. Slice Orders use a smaller subset still: `active` after confirm, `executing` for the whole run, then `completed` or `failed`.

### DCA

```
intent ──confirm──▶ active ──cycle..N──▶ completed
                      │
                      ├─ pending  ── (only with a future config.startAt;
                      │               becomes active at that time)
                      │
                      ├─ pause/resume ↔  paused
                      │
                      ├─ executing  ── (during a cycle)
                      │
                      ├─ pending_modification  ── (during modify signing)
                      │
                      ├─ failed  ── (retry budget exhausted) ── unspent input auto-returned
                      │              (retry ──▶ active only in the brief pre-return window)
                      │
                      ├─ cancelled  ── (user cancel)
                      │
                      └─ expired   ── (config.expiresAt reached)
```

### Trigger orders

```
intent ──confirm──▶ active ──trigger crossed──▶ executing ──▶ completed
                      │
                      ├─ pause/resume ↔ paused          (price not watched while paused)
                      │
                      ├─ cancelled  ── (user cancel)
                      │
                      ├─ failed   ── deposit auto-returned within ~1 minute
                      │
                      └─ expired  ── (config.expiresAt reached) ── deposit auto-returned
```

A trigger order created with [`onFillOco`](/titan/developer-doc/special-order-types/order-types/otoco.md) that completes carries a `childOrderId` pointing at the bracket order it created. Poll the bracket from that point.

### Slice Orders

```
intent ──confirm──▶ active ──picked up──▶ executing ──all slices confirmed──▶ completed
                                              │
                                              └─ failed  ── partial or zero fill ── unspent input auto-returned
```

Slice Orders cannot be paused, cancelled, modified or retried. An order can remain `executing` for several minutes after its last slice while the recovery sweep verifies an unresolved slice — continue polling rather than treating it as an error. See [Slice Orders](/titan/developer-doc/special-order-types/order-types/slice.md#lifecycle).

`executing` and `pending_modification` are transient states an order passes through during a cycle or a modify-signing window. The order's `previousStatus` holds the resting state it'll return to, so you can keep rendering "active" or "paused" instead of flickering.

## Automatic input return

When an order permanently **fails** — including a partially filled Slice Order — or a **trigger order expires**, Titan returns its remaining unspent input to the user's external wallet on its own. No partner action, no user signature. Funds reserved for the user's other active orders are untouched.

This is why those orders' `withdrawalStatus` transitions to `completed` without you doing anything. Don't build a manual "withdraw failed order" step — surface the return via `withdrawalStatus` and `withdrawalTxHash` instead.

{% hint style="warning" %}
The one gap: an **`expired` DCA order is not auto-returned.** Expiry only triggers the automatic return for trigger orders. For an expired DCA order you still call [order-level withdraw](/titan/developer-doc/special-order-types/guides/withdrawals.md#order-level-withdrawals) to get the unspent input back.
{% endhint %}

`withdrawalStatus` tracks the return of an order's funds: `none → pending → completed` (or back to `none` via abandon). It advances automatically in the cases above, and on demand when you call order-level withdraw for a `completed` or `cancelled` order. `withdrawalTxHash` holds the on-chain signature of the return — a real signature, or `null` when no transfer was needed.

A `completed` trigger order or Slice Order has nothing to return: the fills consumed the whole deposit and the output went to `outputRecipientAddress` at execution time.

## What to poll

| Surface                                    | Endpoint                                                                                       |
| ------------------------------------------ | ---------------------------------------------------------------------------------------------- |
| Active-orders list (the user's dashboard)  | `GET /me/orders/active`                                                                        |
| DCA order detail (user has it open)        | `GET /dca/{orderId}`                                                                           |
| Armed trigger order (user has it open)     | `GET /stop-loss/{orderId}` · `/take-profit/{orderId}` · `/oco/{orderId}`                       |
| Slice Order in progress (user has it open) | `GET /slice/{orderId}` every 2–3 seconds — progress is `chunks.length / order.executionsTotal` |
| Execution history (during/after a fill)    | `GET /orders/{orderId}/executions`                                                             |
| Back-office reconciliation                 | `GET /partners/me/executions?createdAtGte=…`                                                   |

{% hint style="info" %}
Each order type wants a different cadence. A DCA order tells you when its next cycle lands via `nextExecutionAt`, so you can poll lazily and time it. A trigger order has no schedule — it can fire at **any moment** — so an armed order on screen needs a steadier cadence. A Slice Order completes within seconds to minutes, so poll it every 2–3 seconds while it runs.
{% endhint %}

A few rules that keep polling cheap and correct:

**Don't poll during the two-step flows.** Between `intent` → user signs → `confirm`, just wait for the signature and call `confirm`. Pending-order transitions are deterministic once `confirm` returns.

**Back off on `EXECUTION_IN_FLIGHT`.** A `409` from cancel or withdraw means a swap is still being reconciled. Retry every few seconds; the server-side recovery loop settles it within a small bounded window.

**Don't double-poll the same user.** If your UI has both a list and a detail view open, share state in your frontend rather than polling both endpoints for the same data.

## Related pages

* [Managing Orders](/titan/developer-doc/special-order-types/guides/managing-orders.md) — the state transitions you trigger
* [Withdrawals](/titan/developer-doc/special-order-types/guides/withdrawals.md) — how `withdrawalStatus` advances
* [Order & Execution Schema](/titan/developer-doc/special-order-types/reference/schema.md) — every status-related field
