Skip to main content
Place a new order.
TL;DRPOST /orders submits a new order. The body carries the usual economic fields (symbol, side, type, amount, price) plus the cryptographic backing that makes the order private and self-custodial: the collateral-note commitment, a zero-knowledge input proof, a note opening, a signed contributory viewing key, the current boot session, and a trading-key signature over the canonical order intent. The opening is pinned indirectly through the signed note commitment. The SDK builds and signs all of this from your keys and a deposited note.
Auth: Authorization: Bearer <token> and a trading-key signature in the body.

How a Darknyx order differs

On a transparent venue, placing an order is just sending its economic fields. On Darknyx an order is fully collateralized by a specific note you already deposited, and it is private, so the request also carries:
  • the commitment of the collateral note, and a secret opening of that note the in-enclave prover needs;
  • a zero-knowledge input proof that the note exists in the on-chain tree and is yours to spend;
  • a signed X25519 viewing key for private recovery data;
  • the current 32-byte boot session id, so a signed order cannot be replayed into a restarted engine;
  • an Ed25519 signature from your trading key over the canonical body, so the engine can attribute, and ultimately settle, the order to you without any per-order on-chain transaction;
  • deterministic partial-fill continuation: the settlement circuit derives each change inner from the consumed input inner, so no pre-supplied pool is needed.
You do not assemble these by hand. The SDK takes your keys and a spendable note and produces a ready-to-sign request. The full field reference is here so the wire contract is unambiguous.

Request body

Economic fields

Collateral, opening, and proof

Recovery and replay binding

Signature

Example

Success response

Returned with 202 Accepted.
Accepted is not filledA 202 means the order passed signature and collateral verification and entered the book, not that it has filled. Track fills via GET /orders/{order_id} or the Orders Channel.

Order status lifecycle

A market or fill-or-kill order that cannot execute in its arrival batch leaves the book immediately rather than resting.

Idempotency

order_id is your idempotency key. A retry that re-sends the byte-identical signed order returns the original acceptance (202, same order_id) instead of a conflict, so a network blip is safe to retry. Reusing an order_id for a different order (any economic field changed) is a real conflict and returns 409 (code 1201). Because order ids are client-chosen, pick a fresh one per distinct order.

Verification at intake

Every order is verified before it enters the book. A non-202 response carries a structured error code; the conditions: Because the opening is checked against the signed commitment, the secret opening fields are cryptographically pinned to your signature without being part of the signed canonical body.
Rate limits are weightedOrder management is rate-limited per account with a token bucket; cancels are cheap, place and modify cost more. A 429 includes a Retry-After header. For high-frequency management prefer the shared /v1/stream session.

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.

Body

application/json

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.

symbol
string
required
side
enum<string>
required

bid = buy base; ask = sell base.

Available options:
bid,
ask
order_type
enum<string>
required
Available options:
limit,
ioc,
fok
amount
integer<uint64>
required

Order size in base units.

price_limit
integer<uint64>
required

Worst acceptable price, in quote units per base. Required for a bid (must be > 0); an ask may use 0 to accept any clearing price. Every non-zero value must be an integer multiple of the instrument's tick_size.

expiry_slot
integer<uint64>
required

Future Solana slot past which this order auto-expires. It must leave the matcher settlement buffer and is bounded by the protocol maximum (currently 4,500 slots) to prevent an unbounded collateral-lock window. Zero is not a GTC sentinel.

order_id
string
required

16-byte client-chosen id, hex. Must be unique + non-zero.

note_commitment
string
required

32-byte hex — Poseidon6 commitment to the collateral note this order is backed by. The opening and VALID_INPUT proof are checked at intake on a settlement-enabled venue. The commitment can reserve at most one live or settlement-pending order in this venue; the on-chain lock remains the final authority at settlement.

arrival_nonce
integer<uint64>
required

Nonce bound into the signed canonical body. After exact-body idempotency handling, it must be strictly greater than every prior accepted nonce for the same trading key.

trading_key
string
required

32-byte hex — the Ed25519 public key that owns this order.

trading_key_signature
string
required

64-byte hex — Ed25519 signature over sha256(canonical body) from the trading key. Lets the TEE attribute the order to a specific key without a per-order on-chain tx.

owner_commitment
string
required

32-byte hex — the collateral note's owner commitment Poseidon2(DOMAIN_OWNER_V2=32, spending_key). Part of the input-note opening the in-TEE VALID_MATCH_BATCH prover needs (the circuit re-derives note_commitment from the opening). This is the only NOTE-BOUND owner identity an order carries, and the one settlement derives output notes back to. Verified against the signed note_commitment at intake. Held in enclave memory only.

note_inner_hash
string
required

32-byte hex — the collateral note's amount-independent inner_hash, which anchors both its commitment and unlinkable note-use tag.

merkle_root
string
required

32-byte hex — the merkle root the valid_input_proof was generated against. A settlement-enabled venue checks its recent-root mirror before accepting the order; lock_note checks the authoritative on-chain window again at settlement.

valid_input_proof
string
required

256-byte hex (pi_a ‖ pi_b ‖ pi_c) — the per-note VALID_INPUT Groth16 proof that gates lock_note. The TEE cannot generate it (needs the spending key + merkle witness), so the client supplies it. A settlement-enabled venue verifies it at intake against (merkle_root, note_use_tag, collateral mint), deriving the tag from the supplied commitment + private inner hash; on-chain lock_note verifies it again. Enqueue-only simulator / load-test deployments do not settle and may deliberately accept stub proofs.

viewing_pubkey
string
required

Required 32-byte contributory X25519 viewing-encryption public key, hex (deriveViewingEncKeypair().publicKey). The TEE encrypts each fill's (trade, change) output amounts to it and writes the ciphertext on-chain, so exact and partial output notes remain recoverable after a CVM redeploy. It is signed; low-order encodings that yield an all-zero shared secret are rejected.

session_id
string
required

Required 32-byte boot session id from GET /info, hex, bound into the signature. A stale session is rejected even when every other field and signature is valid. Programmatic clients confirm that the value matches the boot session bound by /transport-attestation; a substituted value causes rejection rather than stale-session acceptance.

Pattern: ^[0-9a-fA-F]{64}$
min_fill_size
integer<uint64>

Optional (default 0). Reject fills smaller than this; set equal to amount for resting all-or-none.

collateral_amount
integer<uint64>

Optional over-collateralization: the actual value the collateral note carries when it exceeds the order's nominal cost. Lets a large note back a small order; the surplus returns as a change note. Omit for exact collateral.

tree_id
integer<uint8>
default:0

Merkle-tree shard containing the collateral note. Intake rejects an out-of-range shard and checks the proof root against this shard's recent-root window before booking.

Response

Order accepted into the matching queue.

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