> For the complete documentation index, see [llms.txt](https://docs.native.org/native-dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.native.org/native-dev/build-with-native/native-core/guides/trade-over-rest.md).

# Trade over REST

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](/native-dev/build-with-native/native-core/reference/api-access.md#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](/native-dev/build-with-native/native-core/reference/api-access.md#access-model-api-wallets):

1. Generate an agent keypair locally; its 20-byte address is the `agent`.
2. Deposit the quote asset you'll trade from your main wallet — your account is created on the first deposit.
3. Approve the agent: your main wallet signs one `approveAgent` (EIP-712). The [**Native web app**](https://app.native.org/markets/ETH-USDT?agentWallets=agents) 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](/native-dev/build-with-native/native-core/concepts/account-types.md) 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.

```bash
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:

```bash
curl -sS -X POST "$API_URL/info" -H 'content-type: application/json' \
  -d '{"type":"userAgents","user":"<accountAddress>"}'
```

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**](/native-dev/build-with-native/native-core/python-sdk.md) — signs, manages nonces, and reconciles for you. Recommended.
* **By hand** — the full byte layout and a TypeScript signer are in [Transaction Signing](/native-dev/build-with-native/native-core/reference/transaction-signing.md).

The assembled request:

```bash
curl -sS -X POST "$API_URL/trade" -H 'content-type: application/json' \
  -d '{
    "action": {
      "type": "order", "market_id": "2",
      "side": "bid", "order_type": "limit", "tif": "gtc",
      "price": "3500.00", "quantity": "1.0000",
      "cloid": "0x11111111111111111111111111111111"
    },
    "nonce": "1760000000000",
    "agent_epoch": "3",
    "signature": "0x…"
  }'
```

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.

```json
{
  "submission_status": "accepted",
  "tx_hash": "0x…",
  "response": {
    "type": "order",
    "status": {
      "open": { "oid": 1964626153570560, "cloid": "0x11111111111111111111111111111111" }
    }
  }
}
```

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:

{% content-ref url="/pages/ZLzO3CMBhAhcbAQVVZXB" %}
[Handle outcomes & timeouts](/native-dev/build-with-native/native-core/guides/handle-timeouts.md)
{% endcontent-ref %}

That is a full round trip. The order is working — list it with [`openOrders`](/native-dev/build-with-native/native-core/reference/post-info.md#openorders), and cancel with a [`cancel`](/native-dev/build-with-native/native-core/reference/post-trade.md#cancel) action.

Streaming its lifecycle instead of polling? [Stream over WebSocket](/native-dev/build-with-native/native-core/guides/stream-over-websocket.md).

## Next steps

* [POST /trade](/native-dev/build-with-native/native-core/reference/post-trade.md) — every action and envelope field
* [POST /info](/native-dev/build-with-native/native-core/reference/post-info.md) — every read
* [Transaction Signing](/native-dev/build-with-native/native-core/reference/transaction-signing.md) — sign it yourself
* [Error responses](/native-dev/build-with-native/native-core/reference/error-responses.md) — every code and what to do about it
