For the complete documentation index, see llms.txt. This page is also available as Markdown.

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

A trigger order created with onFillOco that completes carries a childOrderId pointing at the bracket order it created. Poll the bracket from that point.

Slice Orders

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.

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.

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=…

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.

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.

Last updated