Skip to main content
Modify an open order — atomic cancel + replace.
TL;DRPUT /orders/{order_id} modifies a resting order as an atomic cancel + replace. The body carries a signed cancel of the old order plus a full, independently-signed replacement order. The swap happens under one lock with both preconditions checked first, so there is never a moment where you hold neither order.
Auth: Authorization: Bearer <token> and two signatures (a cancel of the old order and a full new order), both from the same trading key.

Why modify instead of cancel-then-place

Cancelling and re-placing as two separate calls leaves a gap: between the cancel landing and the new order arriving, you have no order resting, and a batch may clear in that gap. PUT /orders/{order_id} closes the gap. It verifies both sides, then applies the cancel and the replacement atomically: either the swap happens whole, or nothing changes.

Path parameters

Request body

The trading key that signs the cancel must be the key that signs the replacement. The replacement may reuse the old order’s note and proof while that proof’s root is still in the on-chain root window, or it may point at a different note; it is a normal place-order body either way. Its session_id also scopes the embedded cancel signature to the current boot. The replacement must keep the original order’s symbol. Atomic modify is an operation inside one isolated market book; it cannot move intent between pairs. To change markets, cancel the old order and place a fresh signed order.

Reprice in place

If the replacement’s order_id equals the path order_id, the modify is a “reprice in place”: the cancel frees the id and the replacement reclaims it, so the logical order keeps its identity. If the replacement uses a new order_id, the old id is retired and a cancelled event is emitted for it on the orders stream.

Example

Success response

Atomicity guarantees

Both preconditions are checked before anything mutates:
  1. The old order exists and is owned by the signing trading key.
  2. The replacement’s order_id is not already booked (unless it equals the old id, the reprice-in-place case).
If either fails, the call returns an error and neither order is touched. Only when both hold does the engine cancel the old order and book the replacement under the same lock; no batch can clear between the two.

Errors

Authorizations

Authorization
string
header
required

Short-lived (≤ 1h) bearer token from POST /auth/token.

Expiry is EXACT — there is no grace period past expires_in, on REST or on the streaming transport. Refresh on a margin.

A structurally valid, unexpired token is still refused when it has been revoked (401), when the operator has invalidated the tokens the account was holding (401), or when the account is suspended (403). Suspension also blocks issuing a new one, so re-authenticating does not clear it.

Path Parameters

order_id
string
required

The OLD order's id (hex) to replace.

Body

application/json
cancel_signature
string
required

64-byte signature over the old order's canonical cancel body.

cancel_nonce
string
required

Canonical decimal u64 string.

Pattern: ^(0|[1-9][0-9]*)$
replacement
object
required

The canonical-order wire schema (darknyx-order-v5 signature domain). All 32/64/16-byte fields are hex-encoded strings; all numeric fields are JSON integers (u64). The trading-key signature covers the canonical encoding of the economic fields, viewing_pubkey, session_id, and arrival_nonce; the opening fields (owner_commitment, note_inner_hash) are pinned indirectly because the matcher re-derives note_commitment from them and rejects a mismatch.

Response

Modified — old order cancelled, replacement resting.

old_order_id
string
required
order_id
string
required

Replacement id; may equal old_order_id for reprice-in-place.

status
enum<string>
required
Available options:
modified
arrival_slot
integer<uint64>
required