Trade over REST
Zero to a live order over REST — the fastest path to your first Native Core trade.
One signed request per call, and the call blocks for the outcome — no socket to manage. This page takes you from nothing to a working order.
The examples below use mainnet, API_URL=https://api.native.org. To integrate against testnet, swap in https://api-test.native.org and sign with the testnet chain id — see environments.
1. Get an API wallet
An API wallet is an agent keypair you generate locally, authorized by one owner-signed approveAgent. It places and cancels orders but can never move funds. Three steps — covered in full, with the connection-bundle shape, under creating an API wallet:
Generate an agent keypair locally; its 20-byte address is the
agent.Deposit the quote asset you'll trade from your main wallet — your account is created on the first deposit.
Approve the agent: your main wallet signs one
approveAgent(EIP-712). The Native web app does all three for you and hands back the agent key.
You end up holding the agent private key (your only signing secret) and your owner accountAddress. See Account Types if you were granted a credit account.
2. Find your market
Markets and their precision are public. You need the market_id and its decimals to build an order.
curl -sS -X POST "$API_URL/info" -H 'content-type: application/json' \
-d '{"type":"markets"}'Note the market_id, price_decimals, and base_quantity_decimals for the pair you want to trade.
3. Get your agent_epoch
Every trading write signed by an API wallet must carry agent_epoch — the current generation of your wallet's approval. Read it once at startup:
Use the epoch of the slot whose agent matches your API-wallet address. Omit agent_epoch and the write is rejected with DirectSignerIsActiveAgent.
4. Sign and place an order
signature signs a canonical binary payload built from action + nonce + agent_epoch — not the JSON text. Two ways to produce it:
Python SDK — signs, manages nonces, and reconciles for you. Recommended.
By hand — the full byte layout and a TypeScript signer are in Transaction Signing.
The assembled request:
Always set a cloid — it is how you reconcile a timeout (step 5). Send price and quantity as strings at the market's precision.
5. Read the outcome
/trade is synchronous: the call blocks until the transaction executes and returns the outcome. Typical latency is a block or two; the wait budget is 3 seconds, so set your client timeout above that.
Read both fields. submission_status: "accepted" means the transaction landed; response.status is what actually happened to the order — open (rested), filled, cancelled, or {"error":"<code>"} if it failed at execution. A failed order still reports accepted, so branching on submission_status alone will read it as a success.
The other two outcomes — rejected and timeout — each need their own handling, and a timeout can double-fill you if you resubmit the wrong kind. The full decision playbook is one page:
That is a full round trip. The order is working — list it with openOrders, and cancel with a cancel action.
Streaming its lifecycle instead of polling? Stream over WebSocket.
Next steps
POST /trade — every action and envelope field
POST /info — every read
Transaction Signing — sign it yourself
Error responses — every code and what to do about it
Last updated