Order lifecycle & signing
Placing an intent returns an intentId. What happens
next depends on who holds the signing key, and that determines whether your
integration is done or has one more step.
Two dispatch paths
Section titled “Two dispatch paths”| Your credential | What happens after compose |
|---|---|
| Has a platform-held venue agent | The platform signs and dispatches. The intent moves on by itself; you watch /ws/risk or poll. |
| Holds its own signing key (SDK / MCP server) | The intent stops at intent_pending and waits for you to sign it and return the signature. |
The second case is the one that strands integrations: you get an intentId
back, nothing else happens, and there is no error to react to. The intent is
waiting.
The states
Section titled “The states”intent_pending → signed_pending_dispatch → dispatched → filledintent_pending means composed, risk-checked, not yet signed. Everything
downstream is the platform’s job.
Poll one intent
Section titled “Poll one intent”curl -s https://api.troncharts.xyz/api/v1/oms/intents/$INTENT_ID \ -H "authorization: Bearer $TOKEN" \ -H "x-tenant-slug: $TC_TENANT_SLUG"Scoped to (accountId, apiClientId) — you see the intents your credential
composed, not every intent on the account. An intent belonging to another
credential answers 404, not 403, so this can’t be used to probe.
List your recent intents
Section titled “List your recent intents”curl -s https://api.troncharts.xyz/api/v1/oms/intents \ -H "authorization: Bearer $TOKEN" \ -H "x-tenant-slug: $TC_TENANT_SLUG"Most recent first, capped at 50. Same credential scoping.
Finish a pending intent
Section titled “Finish a pending intent”When you hold the key, sign the payload and return the signature:
curl -s https://api.troncharts.xyz/api/v1/oms/intents/$INTENT_ID/sign-result \ -H "authorization: Bearer $TOKEN" \ -H "x-tenant-slug: $TC_TENANT_SLUG" \ -H 'content-type: application/json' \ -d '{ "signedPayload": { … } }'# → { "ok": true, "intentId": "…", "venueOrderId": "…", "resting": true }A success may also carry inlineFill when the venue filled it immediately.
The failures worth handling
Section titled “The failures worth handling”| Error | Status | Means |
|---|---|---|
bearer_required |
401 | Called with a cookie session. |
intent_not_found |
404 | No such intent. |
forbidden |
403 | The intent belongs to another account, or was composed under a different credential. |
invalid_state |
409 | Already signed, dispatched or dead. Only intent_pending can be sign-result’d — treat as someone else finished it, not as a retry. |
batch_predecessor_pending |
409 | An earlier leg of a flatten or reverse batch hasn’t dispatched. The intent stays pending — retry after the earlier leg lands. |
That last one is the one to get right. A flatten or reverse composes several intents in order (cancels → close → open), and signing a later leg before an earlier one dispatches would put the position through an intermediate state nobody asked for. The 409 is the platform refusing to let that happen; back off and retry rather than treating it as failure.
If dispatch itself fails, you get 400 with ok: false and an error /
detail from the venue — the signature was accepted, the venue rejected the
order.
When the credential can’t sign at all
Section titled “When the credential can’t sign at all”A credential whose agent link is missing or dead is rejected at compose
with 403. No intent is created, so you never reach the sign step above:
credential_missing_agent_wallet— the credential has no agent linked.agent_authorization_revoked/agent_authorization_expired— it had one and it is no longer valid.
agent_not_dispatchable is the other shape, and it comes back from cancel
and modify as a 409: the intent composed, but nothing could sign it, so it
was never dispatched. The agent needs re-approving.
These are provisioning problems, not order problems. Fix the credential; the order path is fine.
Which pattern should you build?
Section titled “Which pattern should you build?”If your credential is platform-signed, ignore this page: place the intent and take the outcome from the risk channel.
If you hold your own key, the loop is: compose → read intentId → sign →
sign-result → confirm from the response or the socket. Poll GET /intents/{id}
only as a reconciliation backstop, not as your primary path — the socket is
faster and cheaper.