Orders
Submit Order
Rest a signed limit order, match it, and stage the settlement
POST
/
orderbooks
/
external-securities
/
api
/
orders
curl -X POST "https://api.trusset.org/orderbooks/external-securities/api/orders" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: extsec-order-0001" \
-d '{
"orderBookId": "clx_ob_extsec_001",
"userAddress": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3",
"side": "BUY",
"price": "104200000",
"quantity": "10000000",
"expiry": 1750593600,
"nonce": "0",
"salt": "0x7c1d0a5f3b8e29406d1af7c58b2e0349d6a1f80b3c5e97246fa0d81b5e37c204",
"signature": "0x9b1e...1c",
"timeInForce": "GTC"
}'
const res = await fetch(
'https://api.trusset.org/orderbooks/external-securities/api/orders',
{
method: 'POST',
headers: {
'X-API-Key': 'trusset_your_key_here',
'Content-Type': 'application/json',
'Idempotency-Key': prep.data.orderHash
},
body: JSON.stringify({
orderBookId,
userAddress: order.trader,
side: 'BUY',
price: '104200000',
quantity: '10000000',
expiry: Number(order.expiry),
nonce: order.nonce,
salt: order.salt,
signature
})
}
);
const { data } = await res.json();
if (data.settlement?.transaction) {
const tx = await operator.sendTransaction(data.settlement.transaction);
await tx.wait();
// then POST /settlements/{settlementId}/confirm { txHash: tx.hash }
}
{
"success": true,
"data": {
"order": {
"orderId": "c81f4a9e-2d70-4bb3-9f16-08a5c7d1e320",
"orderBookId": "clx_ob_extsec_001",
"userAddress": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3",
"side": "BUY",
"orderType": "LIMIT",
"price": "104200000",
"quantity": "10000000",
"filledQuantity": "10000000",
"remainingQuantity": "0",
"status": "FILLED",
"timeInForce": "GTC",
"expiresAt": "2025-06-22T12:00:00.000Z",
"createdAt": "2025-06-15T12:00:00.000Z"
},
"trades": [
{
"tradeId": "5b3c19e0-7a42-4d86-91f5-2c0e8d47b613",
"price": "104200000",
"quantity": "10000000",
"makerAddress": "0x9f8c1d4b2e7a3056c1b8f4d29e0a7c3518b6d24f",
"takerAddress": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3",
"side": "BUY",
"settlementStatus": "AWAITING_SIGNATURE"
}
],
"filledQuantity": "10000000",
"remainingQuantity": "0",
"status": "FILLED",
"stpTriggered": false,
"cancelReason": null,
"stpCancelledMakerIds": [],
"orderHash": "0x2f9d41c8b7a05e3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b",
"signedOrder": {
"trader": "0xABC7f1093D5e26b804a1C3f78dE025916B47c0d3",
"token": "0x51F2B9d0E77c4a1B83Ce6d4A9271E5f3a0C8b912",
"quote": "0x98aD0ca091552e23C564B41C74282e5343D03E8a",
"isBuy": true,
"quantity": "10000000000000000000",
"price": "104200000",
"expiry": "1750593600",
"nonce": "0",
"salt": "0x7c1d0a5f3b8e29406d1af7c58b2e0349d6a1f80b3c5e97246fa0d81b5e37c204"
},
"settlement": {
"settlementId": "0f7c2a19-64b8-4d02-9e51-73ab0c5d6f18",
"status": "AWAITING_SIGNATURE",
"tradeCount": 1,
"skipped": [],
"settlementOperator": "0x5ad87a0621175206b72d10e4b8577b192e7f40ab",
"confirmWith": { "endpoint": "POST /settlements/:settlementId/confirm", "field": "txHash" },
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x489aee4ae9546081d55848f157e03192e826988c",
"data": "0x..."
},
"functionName": "settleTrade",
"description": "Settle trade 0x8a1c... between 0xABC7... and 0x9F8c...",
"expectedSigner": "0x5ad87a0621175206b72d10e4b8577b192e7f40ab",
"tradeRef": "0x8a1c3f70d24e5b8916af02c5d7e34b18906fa2c1d5083e7649bb102f37cd5a44"
}
}
}
{
"success": true,
"data": {
"order": {
"orderId": "c81f4a9e-2d70-4bb3-9f16-08a5c7d1e320",
"status": "OPEN",
"filledQuantity": "0",
"remainingQuantity": "10000000",
"expiresAt": "2025-06-22T12:00:00.000Z"
},
"trades": [],
"filledQuantity": "0",
"remainingQuantity": "10000000",
"status": "OPEN",
"stpTriggered": false,
"cancelReason": null,
"stpCancelledMakerIds": [],
"orderHash": "0x2f9d41c8b7a05e3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b",
"settlement": null
}
}
{
"success": false,
"data": null,
"error": {
"code": "DUPLICATE_ORDER",
"message": "This signed order is already resting on the book. Sign a new order (a fresh salt) instead of resubmitting this signature.",
"orderId": "c81f4a9e-2d70-4bb3-9f16-08a5c7d1e320",
"orderHash": "0x2f9d41c8b7a05e3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b"
}
}
{
"success": false,
"data": null,
"error": {
"code": "DELIVERY_NOT_ALLOWED",
"message": "Seller does not hold enough unfrozen tokens",
"deliveryCode": 10
}
}
Submits a signed order. The signature is verified against the custody contract’s domain, the order is checked for liveness on chain, the trader’s balance is reserved off-chain, and the order is matched against the book.
If it fills, a settlement is staged in the same call and its calldata comes back in the response, ready for the venue operator to sign. If it rests,
settlement is null.
Send the same expiry, nonce and salt that Prepare Order returned. All three are part of the signed struct, so any difference changes the hash and the signature is rejected.
Idempotency
Accepts an optionalIdempotency-Key header. Sending one is strongly recommended: a retry after a network timeout would otherwise be refused as a DUPLICATE_ORDER rather than returning the original result.
Body Parameters
string
required
Target book. Must be
ACTIVE and reachable from your instance.string
required
The trader’s wallet. Must be the address that produced the signature.
string
required
BUY or SELL.string
required
Limit price in order book units. Must be a multiple of the book’s
tickSize.string
required
Base quantity in order book units. Must sit between the book’s
minOrderSize and maxOrderSize.integer
required
Unix seconds from the prepared order.
string
required
Nonce from the prepared order.
string
required
32-byte hex salt from the prepared order.
string
required
The trader’s EIP-712 signature over the prepared order. An EOA signature or an EIP-1271 smart contract wallet signature is accepted.
string
default:"LIMIT"
Only
LIMIT is accepted. Anything else returns MARKET_ORDER_NOT_SUPPORTED, because a market order carries no price for a signature to bind.string
default:"GTC"
GTC rests until filled, cancelled or expired. IOC fills what it can and cancels the rest. FOK must fill entirely. Use a limit price with IOC to sweep the book.boolean
default:"false"
Reject the order rather than let it take. Checked against the whole eligible peer set.
string
default:"NONE"
NONE, CANCEL_TAKER, CANCEL_MAKER or CANCEL_BOTH. An unrecognised value falls back to NONE.What runs before the order rests
The checks run in a fixed order, so the first refusal names the earliest condition that failed.1
Field shape
The order struct is rebuilt from your fields. Quantity and price must convert to whole token units, and
expiry, nonce and salt must be in range.2
Signature
The order hash is derived from that struct, and the signature must recover to
userAddress or validate through the wallet’s own EIP-1271 check.3
Book rules
Size against
minOrderSize and maxOrderSize, price against tickSize, the reference price band where one is configured, any account restriction on which books may be traded, and the post-only check against the eligible peer set.4
Liveness
The signature must not already be cancelled, nonce-invalidated or filled on chain, and must not already be resting on the book. See Signed order liveness.
5
Balance
The tradable balance, net of the trader’s existing reservations, must cover the order.
6
Delivery
On a sell, the token’s own compliance layer must permit the delivery. See Delivery checks.
7
Stale depth
Resting orders the incoming order could reach are re-read on chain, and any the chain has retired are cancelled before a trade can be booked against them.
Response Fields
Returns201.
object
Show child attributes
Show child attributes
object
The order record, including
orderId, status, filledQuantity, remainingQuantity and expiresAt.array
Trades produced by this submission.
string
Quantity filled, in order book units.
string
Quantity still resting.
string
OPEN, PARTIALLY_FILLED, FILLED or CANCELLED.boolean
Whether self-trade prevention acted.
string
Why the order closed, or
null.array
Resting orders self-trade prevention cancelled.
string
The EIP-712 hash of the submitted order.
object
The struct as it was signed, echoed back.
object
null when nothing filled.Show child attributes
Show child attributes
string
Settlement to confirm once broadcast.
string
AWAITING_SIGNATURE.integer
Fills in this settlement.
array
Trades excluded from the transaction, each with
tradeId and reason.string
Wallet that must sign.
object
The endpoint and field to confirm with.
string
SIGN_TRANSACTION.object
to and data for the settlement transaction.string
settleTrade for one fill, batchSettleTrades for several.string
The operator the transaction was simulated as.
string
On a single fill, the trade reference the contract records.
string
On a batch, the batch reference.
boolean
Present and
true when the book belongs to another instance. No calldata is returned; the owner’s operator settles it.object
Present when staging failed, carrying
code, message, and unwound: true if the fill was reversed.A settlement whose revert is permanent is diagnosed at staging and unwound immediately: the trade is reversed, both reservations are released, and
settlement.error.unwound is true. The order in the response is re-read after the unwind, so it reflects the reversal rather than the fill that was rolled back.curl -X POST "https://api.trusset.org/orderbooks/external-securities/api/orders" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: extsec-order-0001" \
-d '{
"orderBookId": "clx_ob_extsec_001",
"userAddress": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3",
"side": "BUY",
"price": "104200000",
"quantity": "10000000",
"expiry": 1750593600,
"nonce": "0",
"salt": "0x7c1d0a5f3b8e29406d1af7c58b2e0349d6a1f80b3c5e97246fa0d81b5e37c204",
"signature": "0x9b1e...1c",
"timeInForce": "GTC"
}'
const res = await fetch(
'https://api.trusset.org/orderbooks/external-securities/api/orders',
{
method: 'POST',
headers: {
'X-API-Key': 'trusset_your_key_here',
'Content-Type': 'application/json',
'Idempotency-Key': prep.data.orderHash
},
body: JSON.stringify({
orderBookId,
userAddress: order.trader,
side: 'BUY',
price: '104200000',
quantity: '10000000',
expiry: Number(order.expiry),
nonce: order.nonce,
salt: order.salt,
signature
})
}
);
const { data } = await res.json();
if (data.settlement?.transaction) {
const tx = await operator.sendTransaction(data.settlement.transaction);
await tx.wait();
// then POST /settlements/{settlementId}/confirm { txHash: tx.hash }
}
{
"success": true,
"data": {
"order": {
"orderId": "c81f4a9e-2d70-4bb3-9f16-08a5c7d1e320",
"orderBookId": "clx_ob_extsec_001",
"userAddress": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3",
"side": "BUY",
"orderType": "LIMIT",
"price": "104200000",
"quantity": "10000000",
"filledQuantity": "10000000",
"remainingQuantity": "0",
"status": "FILLED",
"timeInForce": "GTC",
"expiresAt": "2025-06-22T12:00:00.000Z",
"createdAt": "2025-06-15T12:00:00.000Z"
},
"trades": [
{
"tradeId": "5b3c19e0-7a42-4d86-91f5-2c0e8d47b613",
"price": "104200000",
"quantity": "10000000",
"makerAddress": "0x9f8c1d4b2e7a3056c1b8f4d29e0a7c3518b6d24f",
"takerAddress": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3",
"side": "BUY",
"settlementStatus": "AWAITING_SIGNATURE"
}
],
"filledQuantity": "10000000",
"remainingQuantity": "0",
"status": "FILLED",
"stpTriggered": false,
"cancelReason": null,
"stpCancelledMakerIds": [],
"orderHash": "0x2f9d41c8b7a05e3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b",
"signedOrder": {
"trader": "0xABC7f1093D5e26b804a1C3f78dE025916B47c0d3",
"token": "0x51F2B9d0E77c4a1B83Ce6d4A9271E5f3a0C8b912",
"quote": "0x98aD0ca091552e23C564B41C74282e5343D03E8a",
"isBuy": true,
"quantity": "10000000000000000000",
"price": "104200000",
"expiry": "1750593600",
"nonce": "0",
"salt": "0x7c1d0a5f3b8e29406d1af7c58b2e0349d6a1f80b3c5e97246fa0d81b5e37c204"
},
"settlement": {
"settlementId": "0f7c2a19-64b8-4d02-9e51-73ab0c5d6f18",
"status": "AWAITING_SIGNATURE",
"tradeCount": 1,
"skipped": [],
"settlementOperator": "0x5ad87a0621175206b72d10e4b8577b192e7f40ab",
"confirmWith": { "endpoint": "POST /settlements/:settlementId/confirm", "field": "txHash" },
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x489aee4ae9546081d55848f157e03192e826988c",
"data": "0x..."
},
"functionName": "settleTrade",
"description": "Settle trade 0x8a1c... between 0xABC7... and 0x9F8c...",
"expectedSigner": "0x5ad87a0621175206b72d10e4b8577b192e7f40ab",
"tradeRef": "0x8a1c3f70d24e5b8916af02c5d7e34b18906fa2c1d5083e7649bb102f37cd5a44"
}
}
}
{
"success": true,
"data": {
"order": {
"orderId": "c81f4a9e-2d70-4bb3-9f16-08a5c7d1e320",
"status": "OPEN",
"filledQuantity": "0",
"remainingQuantity": "10000000",
"expiresAt": "2025-06-22T12:00:00.000Z"
},
"trades": [],
"filledQuantity": "0",
"remainingQuantity": "10000000",
"status": "OPEN",
"stpTriggered": false,
"cancelReason": null,
"stpCancelledMakerIds": [],
"orderHash": "0x2f9d41c8b7a05e3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b",
"settlement": null
}
}
{
"success": false,
"data": null,
"error": {
"code": "DUPLICATE_ORDER",
"message": "This signed order is already resting on the book. Sign a new order (a fresh salt) instead of resubmitting this signature.",
"orderId": "c81f4a9e-2d70-4bb3-9f16-08a5c7d1e320",
"orderHash": "0x2f9d41c8b7a05e3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b"
}
}
{
"success": false,
"data": null,
"error": {
"code": "DELIVERY_NOT_ALLOWED",
"message": "Seller does not hold enough unfrozen tokens",
"deliveryCode": 10
}
}
Error Codes
| Code | HTTP | Cause |
|---|---|---|
VALIDATION_ERROR | 400 | A field failed schema validation |
SIGNATURE_REQUIRED | 400 | signature is missing or not hex |
MARKET_ORDER_NOT_SUPPORTED | 400 | orderType is anything other than LIMIT |
INVALID_SIGNATURE | 401 | The signature does not recover to the trading wallet |
ORDER_TOO_SMALL | 400 | quantity is below the book’s minOrderSize |
ORDER_TOO_LARGE | 400 | quantity is above the book’s maxOrderSize |
INVALID_PRICE | 400 | The price is not a multiple of tickSize, or does not convert cleanly |
INVALID_QUANTITY | 400 | The quantity does not convert to a whole number of token units |
PRICE_OUTSIDE_BAND | 400 | The price falls outside the reference band. Carries referencePrice, lowerBound, upperBound and spreadBps |
INSUFFICIENT_CUSTODY_BALANCE | 400 | The tradable balance, net of reservations, does not cover the order. Carries required, available and tokenAddress |
ORDER_BOOK_INACTIVE | 400 | The book is PAUSED or CLOSED |
WRONG_SETTLEMENT_MODE | 400 | The book does not settle on chain |
ORDER_NOT_LIVE | 409 | The signature was cancelled, nonce-invalidated, or already filled on chain. Carries reason and sometimes remainingBase |
DUPLICATE_ORDER | 409 | The same signature is already resting. Carries orderId and orderHash |
POST_ONLY_WOULD_CROSS | 409 | A post-only order would have taken liquidity |
DELIVERY_NOT_ALLOWED | 409 | The token’s compliance layer refuses the delivery. Carries deliveryCode, and tokenRestrictionCode where the token reports its own |
MM_CONFIG_VIOLATION | 403 | The account is restricted to a set of books that excludes this one |
ORDER_BOOK_NOT_FOUND | 404 | The book does not exist, or is not reachable from your instance |
SETTLEMENT_NOT_BUILDABLE | 409 | The fill could not be turned into a settlement transaction |
SETTLEMENT_REJECTED | 409 | The settlement simulation reverted. Carries reason |
SETTLEMENT_OPERATOR_UNAUTHORIZED | 409 | The book’s settlement operator is not authorized on this security |
PRICE_REF_STALE | 503 | The reference price is stale and the book halts on stale references |
PRICE_REF_UNAVAILABLE | 503 | No reference price could be obtained and the book halts without one |
CHAIN_UNAVAILABLE | 502 | A required chain read did not answer |
IDEMPOTENCY_MISMATCH | 409 | The key was used before with a different body |
SERVICE_NOT_ENABLED | 403 | The Trading service is not enabled on this instance |
⌘I
curl -X POST "https://api.trusset.org/orderbooks/external-securities/api/orders" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: extsec-order-0001" \
-d '{
"orderBookId": "clx_ob_extsec_001",
"userAddress": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3",
"side": "BUY",
"price": "104200000",
"quantity": "10000000",
"expiry": 1750593600,
"nonce": "0",
"salt": "0x7c1d0a5f3b8e29406d1af7c58b2e0349d6a1f80b3c5e97246fa0d81b5e37c204",
"signature": "0x9b1e...1c",
"timeInForce": "GTC"
}'
const res = await fetch(
'https://api.trusset.org/orderbooks/external-securities/api/orders',
{
method: 'POST',
headers: {
'X-API-Key': 'trusset_your_key_here',
'Content-Type': 'application/json',
'Idempotency-Key': prep.data.orderHash
},
body: JSON.stringify({
orderBookId,
userAddress: order.trader,
side: 'BUY',
price: '104200000',
quantity: '10000000',
expiry: Number(order.expiry),
nonce: order.nonce,
salt: order.salt,
signature
})
}
);
const { data } = await res.json();
if (data.settlement?.transaction) {
const tx = await operator.sendTransaction(data.settlement.transaction);
await tx.wait();
// then POST /settlements/{settlementId}/confirm { txHash: tx.hash }
}
{
"success": true,
"data": {
"order": {
"orderId": "c81f4a9e-2d70-4bb3-9f16-08a5c7d1e320",
"orderBookId": "clx_ob_extsec_001",
"userAddress": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3",
"side": "BUY",
"orderType": "LIMIT",
"price": "104200000",
"quantity": "10000000",
"filledQuantity": "10000000",
"remainingQuantity": "0",
"status": "FILLED",
"timeInForce": "GTC",
"expiresAt": "2025-06-22T12:00:00.000Z",
"createdAt": "2025-06-15T12:00:00.000Z"
},
"trades": [
{
"tradeId": "5b3c19e0-7a42-4d86-91f5-2c0e8d47b613",
"price": "104200000",
"quantity": "10000000",
"makerAddress": "0x9f8c1d4b2e7a3056c1b8f4d29e0a7c3518b6d24f",
"takerAddress": "0xabc7f1093d5e26b804a1c3f78de025916b47c0d3",
"side": "BUY",
"settlementStatus": "AWAITING_SIGNATURE"
}
],
"filledQuantity": "10000000",
"remainingQuantity": "0",
"status": "FILLED",
"stpTriggered": false,
"cancelReason": null,
"stpCancelledMakerIds": [],
"orderHash": "0x2f9d41c8b7a05e3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b",
"signedOrder": {
"trader": "0xABC7f1093D5e26b804a1C3f78dE025916B47c0d3",
"token": "0x51F2B9d0E77c4a1B83Ce6d4A9271E5f3a0C8b912",
"quote": "0x98aD0ca091552e23C564B41C74282e5343D03E8a",
"isBuy": true,
"quantity": "10000000000000000000",
"price": "104200000",
"expiry": "1750593600",
"nonce": "0",
"salt": "0x7c1d0a5f3b8e29406d1af7c58b2e0349d6a1f80b3c5e97246fa0d81b5e37c204"
},
"settlement": {
"settlementId": "0f7c2a19-64b8-4d02-9e51-73ab0c5d6f18",
"status": "AWAITING_SIGNATURE",
"tradeCount": 1,
"skipped": [],
"settlementOperator": "0x5ad87a0621175206b72d10e4b8577b192e7f40ab",
"confirmWith": { "endpoint": "POST /settlements/:settlementId/confirm", "field": "txHash" },
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x489aee4ae9546081d55848f157e03192e826988c",
"data": "0x..."
},
"functionName": "settleTrade",
"description": "Settle trade 0x8a1c... between 0xABC7... and 0x9F8c...",
"expectedSigner": "0x5ad87a0621175206b72d10e4b8577b192e7f40ab",
"tradeRef": "0x8a1c3f70d24e5b8916af02c5d7e34b18906fa2c1d5083e7649bb102f37cd5a44"
}
}
}
{
"success": true,
"data": {
"order": {
"orderId": "c81f4a9e-2d70-4bb3-9f16-08a5c7d1e320",
"status": "OPEN",
"filledQuantity": "0",
"remainingQuantity": "10000000",
"expiresAt": "2025-06-22T12:00:00.000Z"
},
"trades": [],
"filledQuantity": "0",
"remainingQuantity": "10000000",
"status": "OPEN",
"stpTriggered": false,
"cancelReason": null,
"stpCancelledMakerIds": [],
"orderHash": "0x2f9d41c8b7a05e3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b",
"settlement": null
}
}
{
"success": false,
"data": null,
"error": {
"code": "DUPLICATE_ORDER",
"message": "This signed order is already resting on the book. Sign a new order (a fresh salt) instead of resubmitting this signature.",
"orderId": "c81f4a9e-2d70-4bb3-9f16-08a5c7d1e320",
"orderHash": "0x2f9d41c8b7a05e3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b"
}
}
{
"success": false,
"data": null,
"error": {
"code": "DELIVERY_NOT_ALLOWED",
"message": "Seller does not hold enough unfrozen tokens",
"deliveryCode": 10
}
}
