Skip to main content

Signed actions

Every state change — orders, cancels, withdrawals, transfers, triggers, session management — is an Action: a protobuf message, signed, submitted to a single endpoint. If you use the TypeScript SDK this is handled for you; this page is what you need to implement it elsewhere.

The schema is served by the exchange

curl -sO https://api-mainnet.n1.xyz/schema.proto

Generate bindings from that file rather than from a vendored copy, so your client matches the deployment's version. Check the version you are talking to with GET /info and the Changelog.

Submitting

POST /action
Content-Type: application/octet-stream

The body is the length-delimited protobuf encoding of the Action, immediately followed by the signature over those encoded bytes:

body = size_delimited(Action) || signature

The response is a length-delimited Receipt. A receipt whose kind is err carries an Error enum value — an HTTP 200 with an error receipt is a rejected action, not a success, so decode the receipt before treating a submission as executed.

The encoded action, including the signature, must be 1024 bytes or less. Batch with care: an atomic action containing many subactions can exceed the limit.

Required fields

Every Action carries:

FieldValue
currentTimestampServer time from GET /timestamp, not local clock time
nonceMonotonic per signer; replayed or stale nonces are rejected
kindThe specific action (place order, cancel, withdraw, …)

Recover state after a restart with GET /event/last-acked-nonce for your signer and GET /action/last-executed-id. Using the client clock instead of /timestamp is the most common cause of otherwise-valid actions being rejected.

Signing

Actions are signed either by the wallet key or by a session key authorized by that wallet. Sessions exist so a trading process never holds the wallet key — see Accounts and sessions. Session-signed actions carry the sessionId inside the action kind.

Session creation supports two signature framings, hex and solanaTransaction, the latter for wallets that will only sign a Solana transaction rather than an arbitrary message.

Units

All prices, sizes, and amounts in actions are scaled integers, using the market's priceDecimals / sizeDecimals or the token's decimals from GET /info. Quote notional amounts scale by priceDecimals + sizeDecimals. u128 values are carried as hi / lo pairs. Sending a human-readable decimal where an integer is expected is silently a very different order.

Checklist

  1. Fetch /info once; cache market and token IDs and decimals.
  2. Fetch /timestamp before signing.
  3. Track your nonce.
  4. Encode length-delimited, sign, append the signature.
  5. POST /action as application/octet-stream.
  6. Decode the Receipt, and check for err.

These materials are provided for informational purposes only and do not constitute financial, investment, legal, or tax advice, or an offer or solicitation to buy or sell any asset. Trading digital assets and derivatives involves substantial risk, including the possible loss of some or all capital. Products may not be available in all jurisdictions. Users are responsible for evaluating suitability and complying with applicable laws.