Skip to main content
Every error response has the same shape:
Most rejections happen before the order reaches the book, so a 400 means nothing was placed.
markets-service verifies your signature at submission — see Authentication and signing. An order whose signature does not authorize its action is rejected here rather than failing later onchain.

Signature

400
The signature did not recover to signer_address, and the signer is not a contract whose isValidSignature accepted it.The digest is over the Action struct exactly as described in Authentication and signing — domain Matching version 1.0, bound to the chain and the Matching contract. A mismatch in any signed field produces a different digest and so a different recovered address. Check that action_json is byte-for-byte what you signed, and that signer_address is the key that signed it rather than the account that owns it.
A signature that cannot be checked — for example an RPC failure while resolving a contract signer — is not a rejection. The order is accepted and the failure is logged, so a transient outage never blocks a valid order.

Missing fields

Every one of these is required on POST /v1/orders.

Action payload shape

These come from decoding action_json.data, the ABI-encoded TradeData tuple.
400
data is not exactly seven 32-byte words. After the 0x prefix it must be 448 hex characters. See Encoding data.
400
data is the right length but not valid hex.
400
A wrapper around the field-level failures below. The suffix names the specific problem.

Field consistency

The flat order fields and the signed action_json describe the same order, so they must agree. Rebuild both from one set of values rather than editing one of them.

Scaling

These are the most common rejections, and they almost always mean the body was sent in wei.
400
data.limitPrice must be a positive whole multiple of the body’s limit_price after tick normalization. The body takes human decimals; only data carries wei.
400
Same rule for size, normalized against the instrument’s minimum size.
400
limitPrice is a signed int256 but zero and negative values are rejected.
400
Same for desiredAmount.
400
desired_amount is smaller than the instrument’s minimum size, so it normalizes to nothing.
400
desired_amount is not a whole multiple of the instrument’s minimum size.
If a price or amount error appears and the numbers look correct, check the scale first. See Price and amount use two different scales.

Amounts and expiry

Instrument

400
The (asset_address, sub_id) pair is not an enabled market. Read GET /v1/markets — both values must come from the same entry.
400
The symbol or asset_address + sub_id on a read endpoint did not resolve.
400
These two fields apply to the spot market only. Omit them on futures orders.

Spot order translation

These apply to USDCcNGN-SPOT only. Both fields are optional — omit them and your raw engine values are used as sent. Send either one and the rules below apply. See the Spot market guide for the units involved.
400
You sent ui_intent, or an order_entry_spec with a different value. The spec string must be exactly usdc_cngn_spot_v1.
400
The two fields travel together. Send both, or neither.
400
You sent both side and ui_intent, and they disagree. Engine side is the inverse of ui_intent.side. Omit side to let the service derive it.
400
You sent both limit_price and ui_intent, and they disagree. The engine price is 1 / ui_intent.price. Omit limit_price to let the service derive it.
400
You sent both desired_amount and ui_intent, and they disagree. The engine amount is ui_intent.size * ui_intent.price. Omit desired_amount to let the service derive it.

Duplicate orders

409
order_id has already been submitted. Generate a fresh one; do not retry with the same id.
Treat order_id as an idempotency key you control. A 409 means the first submission was accepted, so check its status with GET /v1/orders/{order_id} rather than resubmitting.

Cancelling

Read endpoints

unknown market applies to GET /v1/book, GET /v1/trades, and GET /v1/candles alike.

Authentication and signing

Most rejections trace back to how the action payload was built.