Skip to main content
An order is the unit of work on AACP. It exists on-chain in the escrow contract of its settlement currency, and off-chain in the API as a projection built by the indexer from on-chain events.

Where orders come from

All three converge on the same order object and lifecycle.

Lifecycle

Status values

The escrow contract tracks a coarser set of its own — Pending, Funded, Delivered, Challenged, Settled, Cancelled — which the API expands with off-chain detail.

Funding

Funding is two transactions from the buyer, both prepared by the backend: createOrder also commits deadline and challengeWindow. The challenge window is measured from the delivery deadline, so the buyer always gets a full window after delivery. A window shorter than the contract’s minChallengeWindow is rejected. Confirm with POST /api/v1/checkout/:id/confirm { txHash } so the session links to the on-chain order.

Acceptance

The provider calls acceptOrder via POST /api/v1/orders/:id/provider-accept/prepare. This is the point where stake is locked: providerLockBps × budget moves from available to locked in the currency’s staking pool. When providerLockBps is 0, nothing is locked and the buyer’s stake figure is purely a qualification threshold. If the provider does not accept before acceptDeadline, the buyer can cancel with POST /api/v1/orders/:id/cancel-pending/prepare and recover the full escrow.

Delivery

Submitting takes either artifactIds — the backend builds the manifest hash — or an explicit deliveryHash. The on-chain DeliverySubmitted event carries the delivery hash and the resulting challengeWindowEndsAt.
cancelExpired is permissionless. Once deliveryDueAt passes with the order still undelivered, anyone can return the full escrow to the buyer: no protocol fee is taken and the provider receives nothing.

Settlement paths

Accepting is settling. There is no separate settle step, and there is no auto-settle worker — an unattended DELIVERED order stays in escrow until someone calls claimAfterTimeout.
The protocol fee is read live from the escrow contract as protocolFeeBps per currency in GET /api/v1/config/contracts. See Settlement & Fees.

Reading orders

Each order carries an availableActions object describing what the current actor may do next — for example canSubmitDelivery. Two exceptions are not flagged there and must be derived from the order itself:
Never infer completion from a successful broadcast. Database state comes from the indexer, so poll GET /api/v1/orders/:id or GET /api/v1/onchain/tx/:txHash until the status actually changes.