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

# Machine Markets: Orders & payments

> Order lifecycle, payment intent, escrow, execute, confirm, dispute on the peaqOS Machine Markets API.

A <Tooltip tip={G.machineAgent.def}>Machine Agent</Tooltip> buys a service through an order. The orchestrator owns the full lifecycle: order create, payment intent, proof or <Tooltip tip={G.escrow.def}>escrow</Tooltip> lock, execute, confirm, dispute, release, refund. Server-side enforcement covers identity proofs, agent <Tooltip tip={G.pairing.def}>pairing</Tooltip>, <Tooltip tip={G.delegationPolicy.def}>delegation policy</Tooltip>, per-transaction and daily spend limits, quote freshness, and rail compatibility.

See the [Machine Markets overview](/peaqos/api-reference/machine-markets-overview) for base path, auth model, and common envelopes.

## Order state machine

```text theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
created -> payment_pending -> ready -> executing -> delivered -> confirmed
                                                              \-> handoff
                                                              \-> disputed
                                                              \-> failed
                                                              \-> cancelled
```

## Payment state machine

```text theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
intent_created -> held -> release_pending -> released
not_required                              \-> refunded
                                          \-> frozen   (on dispute)
```

## Types

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
type MarketOrderStatus =
  | "created" | "payment_pending" | "ready" | "executing"
  | "delivered" | "confirmed" | "disputed" | "cancelled"
  | "failed" | "handoff";

type MarketPaymentStatus =
  | "not_required" | "intent_created" | "held" | "release_pending"
  | "released" | "frozen" | "refunded";

type MarketPaymentRailType =
  | "not-required" | "wallet" | "x402" | "xvv42"
  | "vault-stripe" | "wdk-usdt-transfer" | "escrow"
  | "offchain-record" | "external" | "onchain-escrow";

type MarketOrderRecord = {
  id: string;
  machineId: string;
  agentPairingId: string;
  searchId: string | null;
  quoteId: string | null;
  serviceId: string;
  skillKey: string;
  providerKey: string;
  serviceType: ServiceType;
  operation: string;
  executionMode: ExecutionMode;
  integrationStatus: IntegrationStatus;
  status: MarketOrderStatus;
  input: Record<string, unknown>;
  budget?: { amount?: number | null; currency?: string | null } | null;
  payment: MarketPaymentRailRecommendation;
  serviceSnapshot: Record<string, unknown>;
  taskId: string | null;
  routeId: string | null;
  runId: string | null;
  outcomeId: string | null;
  handoff: ExternalHandoff | null;
  errorMessage: string | null;
  createdAt: string;
  updatedAt: string;
};

type MarketPaymentRailRecommendation = {
  defaultRail: MarketPaymentRailType;
  supportedRails: MarketPaymentRailType[];
  required: boolean;
  provider?: string | null;
  chain?: string | null;
  token?: string | null;
  walletAddress?: string | null;
  externalUrl?: string | null;
  notes: string[];
};

type MarketPaymentRecord = {
  id: string;
  orderId: string;
  machineId: string;
  status: MarketPaymentStatus;
  rail: {
    type: MarketPaymentRailType;
    chain?: string | null;
    token?: string | null;
    escrowAddress?: string | null;
    externalUrl?: string | null;
    provider?: string | null;
    accountId?: string | null;
    walletAddress?: string | null;
    payerAddress?: string | null;
    payeeAddress?: string | null;
    tokenAddress?: string | null;
    transactionHash?: string | null;
    paymentIntentId?: string | null;
    metadata?: Record<string, unknown>;
  };
  amount?: number | null;
  currency?: string | null;
  proof?: {
    transactionHash: string;
    verificationMode: "recorded" | "rpc";
    status: "recorded" | "verified";
    chain?: string | null;
    token?: string | null;
    tokenAddress?: string | null;
    payerAddress?: string | null;
    payeeAddress?: string | null;
    amount?: string | null;
    rawAmount?: string | null;
    blockNumber?: number | null;
    verifiedAt: string;
    metadata?: Record<string, unknown>;
  } | null;
  notes: string[];
  createdAt: string;
  updatedAt: string;
};

type ExternalHandoff = {
  label: string;
  url: string;
  notes: string[];
};

type MarketDisputeRecord = {
  id: string;
  orderId: string;
  machineId: string;
  status: "open" | "resolved";
  reason: string;
  evidence: Record<string, unknown>;
  createdAt: string;
  updatedAt: string;
};
```

## Orders

### `GET /market/orders?machineId={id}`

Lists orders for a machine.

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
type ListMarketOrdersQuery = { machineId: string };
type ListMarketOrdersResponse = ListResponse<MarketOrderRecord>;
```

Errors: `VALIDATION_ERROR`, `NOT_FOUND`, `MACHINE_NOT_ACTIVE`, `MACHINE_NOT_ACTIVATED`.

### `POST /market/orders`

Locks a service from the catalogue into an order. Status starts at `created`. The recommended payment rail is copied from the service into `order.payment`.

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
type CreateOrderRequest = {
  machineId: string;
  agentPairingId: string;
  serviceId: string;
  searchId?: string;        // required when PEAQOS_REQUIRE_MARKET_QUOTES=true
  quoteId?: string;         // required when PEAQOS_REQUIRE_MARKET_QUOTES=true
  operation?: string;
  input?: Record<string, unknown>;
  budget?: { amount?: number; max?: number; currency?: string };
  operatorCredentials?: {
    providers?: Record<string, { env?: Record<string, string> } & Record<string, string>>;
  };
};

type CreateOrderResponse = ItemResponse<MarketOrderRecord>;
```

Errors: `VALIDATION_ERROR`, `QUOTE_EXPIRED`, `AGENT_PAIRING_REQUIRED`, `AGENT_PAIRING_INACTIVE`, `AGENT_POLICY_DENIED`, `AGENT_SPEND_LIMIT_EXCEEDED`, `AGENT_DAILY_LIMIT_EXCEEDED`, `MACHINE_NOT_ACTIVE`, `MACHINE_NOT_ACTIVATED`, `NOT_FOUND`.

### `GET /market/orders/:orderId`

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
type GetMarketOrderResponse = ItemResponse<MarketOrderRecord>;
```

## Payment

### `POST /market/orders/:orderId/payment-intent`

Creates or returns the payment record. Idempotent: returns the existing payment if one already exists. For `not-required` rails the order moves straight to `ready`.

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
type CreatePaymentIntentRequest = {
  amount?: number;
  currency?: string;
  rail?: {
    type?: MarketPaymentRailType;
    chain?: string;
    token?: string;
    tokenAddress?: string;
    tokenMint?: string;        // alias for tokenAddress on Solana
    escrowAddress?: string;
    externalUrl?: string;
    provider?: string;
    accountId?: string;
    walletAddress?: string;
    payerAddress?: string;
    payeeAddress?: string;
    transactionHash?: string;
    paymentIntentId?: string;
    metadata?: Record<string, unknown>;
  };
  payerAddress?: string;
  payeeAddress?: string;
  tokenAddress?: string;
  tokenMint?: string;
  transactionHash?: string;
  txHash?: string;
};

type CreatePaymentIntentResponse = ItemResponse<MarketPaymentRecord>;
```

Errors: `NOT_FOUND`, `VALIDATION_ERROR` (unsupported rail, invalid address, rail not in service `supportedRails` when `PEAQOS_ENFORCE_SERVICE_PAYMENT_RAILS=true`).

### `POST /market/orders/:orderId/payment-proof`

Records a payment proof. `recorded` mode stores operator attestation. `rpc` mode queries an EVM RPC for the <Tooltip tip={G.transaction.def}>transaction</Tooltip> receipt and validates the ERC-20 Transfer log against expected token, sender, recipient, and raw amount. Solana proofs are always `recorded`.

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
type RecordPaymentProofRequest = {
  transactionHash: string;  // EVM 0x… 64 hex, or Solana base58 64–100. Aliases: txHash, transactionSignature, signature.
  chain?: string;            // default "peaq"
  token?: string;            // default "USDT"
  payerAddress?: string;
  payeeAddress?: string;
  tokenAddress?: string;     // aliases: tokenMint, usdtContract; falls back to PEAQOS_USDT_CONTRACT
  amount?: string;
  rawAmount?: string;        // integer in token base units
  tokenDecimals?: number;    // 0..36, default 6
  verificationMode?: "recorded" | "rpc";  // default rpc when RPC URL set
  rpcUrl?: string;
  metadata?: Record<string, unknown>;
};

type RecordPaymentProofResponse = ItemResponse<MarketPaymentRecord>;
```

Errors: `NOT_FOUND`, `ORDER_CLOSED`, `VALIDATION_ERROR`, `PAYMENT_RPC_REQUIRED` (rpc mode with no RPC URL), `PAYMENT_RPC_ERROR` (502), `PAYMENT_NOT_MINED` (409, receipt null), `PAYMENT_TX_FAILED` (402, receipt status not `0x1`), `PAYMENT_TRANSFER_NOT_FOUND` (400, no matching Transfer log).

On successful verification the <Tooltip tip={G.paymentRail.def}>rail</Tooltip> type upgrades from `wallet` to `wdk-usdt-transfer`. Payment status moves to `held`; order moves `created`/`payment_pending` → `ready`.

### `GET /market/orders/:orderId/payment`

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
type GetMarketPaymentResponse = ItemResponse<MarketPaymentRecord>;
```

### `POST /market/orders/:orderId/payment/escrow-lock`

Records an on-chain escrow lock. Payment → `held`. Order → `ready`. Idempotent for `held`.

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
type EscrowLockRequest = {
  transactionHash: string;
  chain: string;
  escrowAddress: string;
};

type EscrowLockResponse = ItemResponse<MarketPaymentRecord>;
```

Errors: `NOT_FOUND`, `ORDER_CLOSED`, `VALIDATION_ERROR`.

### `POST /market/orders/:orderId/payment/release`

Releases held funds after `confirm`. Payment must be `release_pending`, order must be `confirmed`. Status → `released`.

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
type ReleasePaymentRequest = {
  transactionHash?: string;
  notes?: string;
};

type ReleasePaymentResponse = ItemResponse<MarketPaymentRecord>;
```

Errors: `NOT_FOUND`, `ORDER_CLOSED`, `ORDER_NOT_DELIVERED`. Idempotent for `released` and `not_required`.

### `POST /market/orders/:orderId/payment/refund`

Refunds payment. Status → `refunded`. Open orders move to `cancelled`.

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
type RefundPaymentRequest = {
  transactionHash?: string;
  reason?: string;
};

type RefundPaymentResponse = ItemResponse<MarketPaymentRecord>;
```

Errors: `NOT_FOUND`, `ORDER_CLOSED`. Idempotent for `refunded` and `not_required`.

## Execute, confirm, dispute

### `POST /market/orders/:orderId/execute`

Materialises the order as a task plus route, runs the skill runtime, writes a `Run` and an `Outcome`. Order status moves `executing` → `delivered` (outcome `completed`) / `handoff` (outcome `external`) / `failed`. The HTTP status code is propagated from the inner execution result.

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
type ExecuteOrderRequest = Record<string, unknown> & {
  operatorCredentials?: {
    providers?: Record<string, { env?: Record<string, string> } & Record<string, string>>;
  };
};

type ExecuteOrderResponse = {
  order: MarketOrderRecord;
  execution: {
    statusCode: number;
    outcome: OutcomeRecord;
    run: RunRecord;
    resolution: TaskResolution;
  };
};
```

Errors: `ORDER_CLOSED` (order in `confirmed` / `disputed` / `cancelled`), `PAYMENT_REQUIRED` (when `PEAQOS_REQUIRE_PAYMENT_BEFORE_EXECUTE=true`, the production default, and payment is not in `not_required` / `held` / `release_pending` / `released` — except `intent_created` is allowed for `external` / `vault-stripe` rails). All downstream skill-runtime errors are surfaced as well.

x402-rail services (Agentic Market, most pay.sh) execute through the `paidHttp` adapter. The execute call replays the original 402-challenged request with the operator-supplied payment headers (`x-payment`, `payment-signature`, `authorization`, `sign-in-with-x`). The payment intent response now preserves the full x402 `accepts[]` entries including `extra` (EIP-712 signing metadata: `{ name: "USD Coin", version: "2" }`-style) and `outputSchema`. Operators that build their own paid-HTTP adapters should pass headers under `operatorCredentials.providers[providerKey]`; raw headers are stripped from request bodies before forwarding and never persisted.

### `POST /market/orders/:orderId/confirm`

Buyer confirms delivery. Order `delivered` / `handoff` → `confirmed`. Payment `held` → `release_pending`.

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
type ConfirmOrderResponse = {
  order: MarketOrderRecord;
  payment: MarketPaymentRecord | null;
};
```

Errors: `ORDER_NOT_DELIVERED`.

### `POST /market/orders/:orderId/dispute`

Opens a dispute record. Order → `disputed`. Payment → `frozen`. Returns 201.

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark"}}
type DisputeOrderRequest = {
  reason: string;
  evidence?: Record<string, unknown>;
};

type DisputeOrderResponse = {
  order: MarketOrderRecord;
  payment: MarketPaymentRecord | null;
  dispute: MarketDisputeRecord;
};
```

Errors: `VALIDATION_ERROR` (missing reason).

## Related

* [Machine Markets overview](/peaqos/api-reference/machine-markets-overview)
* [Machine Markets: Pairings](/peaqos/api-reference/machine-markets-pairings)
* [Machine Markets: Skills, services, search](/peaqos/api-reference/machine-markets-discovery)
* [Machine Markets: Orchestration](/peaqos/api-reference/machine-markets-orchestration)
* [Machine Markets concept](/peaqos/concepts/machine-markets)
* [Scale function](/peaqos/functions/scale)
