> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kairos.trade/llms.txt
> Use this file to discover all available pages before exploring further.

# Best price across venues

> One routedOrder action buys at the best all-in price across every venue a market is listed on. The wallet signs one order per venue, cheapest first.

> [!NOTE]
>
> **Preview.** Routed orders are live on staging. On production the action answers `403 routed orders are not enabled here` until routed execution is switched on there.

When the same question is listed on Polymarket, Predict.fun and Hyperliquid, one `routedOrder` action buys it at the best combined price. Kairos reads each venue's live book and fees, splits your size across them, and asks the wallet to sign one ordinary order per venue, cheapest first.

Use it for buys you want filled at the best price now. To pick one venue yourself, or to sell, place an [`order`](https://docs.kairos.trade/wallets/trade) per venue instead ([choosing a venue](https://docs.kairos.trade/wallets/routing.md)).

## What you need

* A market that is **linked** to the same question on another venue. Check with `GET https://data.kairos.trade/market-links/lookup?markets=<provider>:<marketId>` (public). A market with no link is refused with `422`.
* A wallet that has completed [setup](https://docs.kairos.trade/wallets/setup.md) on at least one of the linked venues. Venues it isn't set up on are left out of the plan.
* The `X-Kairos-Wallet-Api: 2` header, as on every multi-venue call.

## Place a routed order

```bash HTTP theme={null}
curl -X POST "$BASE/v3/actions" -H "X-Kairos-Partner-Id: $PARTNER" -H "X-Kairos-Wallet-Api: 2" -H "Content-Type: application/json" \
  -d '{"wallet":"0xUSER","action":{"type":"routedOrder",
       "market":"polymarket:0x0e9d7335ee3eb0add746b555b39a8dd45533f628d607a4b927955ef51a9488b2",
       "outcome":"Yes","size":"50","maxPrice":"0.35","clientOrderId":"acme-route-41"}}'
# {"id":"…","type":"routed_order","status":"needs_signature","venue":"predictfun","chainId":"0x38",
#  "leg":{"index":1,"of":2},"route":{…the plan…},"request":{…}}
# Sign each step's request and post {"signature":"0x…"} to /v3/actions/{id}, until "done".
```

```python Python theme={null}
from kairos_wallet import run  # the client from /wallets/http

result = run({
    "type": "routedOrder",
    "market": "polymarket:0x0e9d7335ee3eb0add746b555b39a8dd45533f628d607a4b927955ef51a9488b2",
    "outcome": "Yes", "size": "50", "maxPrice": "0.35", "clientOrderId": "acme-route-41",
})
for leg in result["legs"]:
    print(leg["venue"], leg["status"], leg.get("orderId"), leg.get("error"))
```

```js JavaScript (SDK) theme={null}
// wallet.run signs every step, switching chains as each venue needs.
const result = await kairos.wallet.run(wallet, {
  type: 'routedOrder',
  market: 'polymarket:0x0e9d7335ee3eb0add746b555b39a8dd45533f628d607a4b927955ef51a9488b2',
  outcome: 'Yes',
  size: '50',          // shares to receive, across all venues
  maxPrice: '0.35',    // optional: highest price per share, venue fees included
  clientOrderId: 'acme-route-41',
})
// result.legs: [{ venue: 'predictfun', status: 'placed', orderId: '…' }, { venue: 'polymarket', … }]
```

### Request

| Field | Required | Means |
| - | - | - |
| `type` | Yes | `routedOrder` |
| `market` | Yes | Any linked venue's market, as in an `order`: `polymarket:0x…`, `predictfun:<id>` or `hyperliquid:<id>` |
| `outcome` | Yes | `Yes` or `No`, or any linked venue's own name for that side (for example a team name) |
| `size` | Yes | Shares to receive in total, as a string |
| `maxPrice` | No | Highest price per share any planned share may cost, **venue fees included** (0–1, string) |
| `slippageCents` | No | Plan only book levels within this many cents (fees included) of the best price. 1–99 |
| `timeInForce` | No | `FAK` (default) or `IOC`, for every venue order. Each venue order fills what it can at its price and cancels the rest |
| `clientOrderId` | No | Your id for the whole routed order, up to 100 characters. See [retries](#retries) |

Buys only. `side`, `price` and `postOnly` aren't taken: each venue order's price comes from the plan.

## What the wallet is asked

The first response already holds the whole plan in `route`, so you can show it before the first signature:

```json theme={null}
{
  "linkTitle": "Buccaneers vs. Bears",
  "requested": "50",
  "planned": "50",
  "unfilled": "0",
  "blendedEffective": "0.3121",
  "stop": "filled",
  "legs": [
    { "venue": "predictfun", "market": "predictfun:3481439", "outcome": "Buccaneers", "price": "0.3", "size": "30.6", "delivered": "30", "estCost": "9.18", "estFee": "0.18", "effectiveLimit": "0.306", "timeInForce": "FAK", "clientOrderId": "acme-route-41:predictfun" },
    { "venue": "polymarket", "market": "polymarket:0x0e9d…88b2", "outcome": "Yes", "price": "0.31", "size": "20", "delivered": "20", "estCost": "6.37", "estFee": "0.17", "effectiveLimit": "0.3185", "timeInForce": "FAK", "clientOrderId": "acme-route-41:polymarket" }
  ],
  "notes": ["hyperliquid: wallet not set up — run setup to route here", "kalshi: not on the wallet API — leg excluded"]
}
```

* `blendedEffective` is the planned cost per share received, venue fees included. `stop` says why planning ended: `filled`, `exhausted` (books or balances ran out), `effective_cap` (`maxPrice` or `slippageCents` reached) or `below_minimum`.
* Each leg is one order on one venue, at `price`: the worst book price planned on that venue. No leg pays more than the plan shows. `delivered` is less than `size` where a venue takes its fee in shares (Predict.fun).
* The wallet signs one leg at a time, cheapest first. Every step carries `venue`, `chainId` and `leg: { index, of }`, and is that venue's ordinary order signature ([what the wallet signs](https://docs.kairos.trade/wallets/signing.md)). Each signed leg is sent to its venue at once, before the next is asked.
* Only venues where the wallet is set up are planned, and each leg is sized so what that venue holds for the order (price × size, plus fees it holds in cash) fits the wallet's balance there. `notes` says why any venue was left out.

## Read the result

The action is `done` when at least one leg was placed. `result` is the plan plus each leg's outcome:

```json theme={null}
{
  "routed": true,
  "placed": 1,
  "unknown": 0,
  "failed": 1,
  "requested": "50",
  "legs": [
    { "venue": "predictfun", "status": "placed", "orderId": "…", "orderStatus": "live", "venueOrderId": "…", "order": { "…": "the venue's order result" }, "stepId": "…" },
    { "venue": "polymarket", "status": "failed", "error": "No fill: the venue matched none of this order", "errorCode": "NO_MATCH", "stepId": "…" }
  ]
}
```

| Leg `status` | Means | Do |
| - | - | - |
| `placed` | The venue took the order. `order` has its fill, as in an [order result](https://docs.kairos.trade/wallets/reference.md#order) | Follow it in [orders](https://docs.kairos.trade/wallets/portfolio.md) like any order |
| `failed` | Nothing was placed on that venue. `error` and `errorCode` say why | Place the rest elsewhere if you want, with a new `clientOrderId` |
| `unknown` | The venue didn't answer clearly (`ORDER_OUTCOME_UNKNOWN`). The order **may be live** | Read the wallet's orders on that venue before buying again |
| `skipped` | The routed order ended before this leg, for example because a signing window closed or the action's 15 minutes ran out. Nothing was placed | Place it again if you still want it |

A failed leg doesn't stop the others. The action is `failed` only when no leg was placed; `result.legs` still lists every leg and why. `errorCode` is then `ORDER_OUTCOME_UNKNOWN` if any leg may be live, otherwise the first leg's code.

The plan is fixed when the action starts. A book can move while the user signs: a leg then fills what it can at its price, or ends `NO_MATCH`. It never pays more than its planned price.

## When nothing can be routed

The action is refused before anything is signed:

| Status | Body | Means |
| - | - | - |
| `422` | `this market is not linked to another venue; place a single-venue order` | No approved cross-venue link holds this market |
| `422` | `errorCode: "ROUTE_UNAVAILABLE"`, with `route` | The link exists, but no venue can take a leg for this wallet right now. `route.notes` says why for each venue |
| `400` | `outcome matches neither side of this market` | Use `Yes`, `No`, or one of the linked venues' outcome names |
| `400` | `timeInForce on a routed order must be FAK or IOC`, `maxPrice must be a decimal in (0, 1]`, `slippageCents must be 1 to 99` | Fix the field |
| `400` | `routedOrder needs the multi-venue API (x-kairos-wallet-api: 2)` | Send the version header |
| `403` | `routed orders are not enabled here` | Routed execution is switched off on this deployment |

What `route.notes` can say about a venue:

| Note | Do |
| - | - |
| `<venue>: wallet not set up — run setup to route here` | Run [setup](https://docs.kairos.trade/wallets/setup.md) on that venue |
| `<venue>: wallet status could not be read — leg excluded` | Retry shortly |
| `<venue>: not available right now — leg excluded` | The venue isn't offered to you now ([availability](https://docs.kairos.trade/wallets/venues.md#availability)) |
| `<venue>: no book — skipped` | That venue has no live book for this market |
| `<venue>: planned … is under the … minimum order — leg excluded` | Its share was below the venue's minimum. Buy more, or place a single-venue order |
| `kalshi: not on the wallet API — leg excluded` | Kalshi isn't traded through the Partner API |

## Retries

`clientOrderId` holds one routed order per wallet for 7 days:

| You send the same `clientOrderId` | You get |
| - | - |
| While the first action still exists (15 minutes, plus 10 to read it) | The same action, as it is now. Nothing is planned or signed again |
| After that | `409 this clientOrderId already ran a routed order`. Read the wallet's orders, or use a new id |
| After a refusal before anything was signed (`422`, `400`) | A new attempt. A refusal frees the id |

Each leg is sent with its own id: `<clientOrderId>:polymarket`, `<clientOrderId>:predictfun`, and on Hyperliquid `0x` plus the first 16 bytes, in hex, of keccak256 of `<clientOrderId>:hyperliquid`. Each leg's id is in `route.legs[].clientOrderId`.

Without a `clientOrderId`, every request plans and places a new routed order.

## Checklist for agents

**1. Find a linked market**

`GET https://data.kairos.trade/market-links/lookup?markets=polymarket:<conditionId>`. Any `venues[]` entry with provider `polymarket`, `predictfun` or `hyperliquid` can be the `market`.

**2. Check the wallet**

`GET /v3/wallets/{address}`. At least one linked venue must be `ready` and funded.

**3. Start the action**

`POST /v3/actions` with `type: "routedOrder"`, a `clientOrderId`, and a `maxPrice` if you have a limit. Show `route` to the user.

**4. Sign each leg**

For every `needs_signature` step, switch to `chainId`, sign `request`, post the signature. Poll `GET /v3/actions/{id}` while `working`.

**5. Act on each leg**

At `done` (or `failed`), read `result.legs`. Never buy again for an `unknown` leg before reading the wallet's orders.

The schemas are `WalletRoutedOrderAction`, `WalletRoute` and `WalletRoutedOrderResult` in the [OpenAPI spec](https://docs.kairos.trade/openapi/wallet-api.json) and the **Endpoints** group of this tab. Field-by-field rules for every action are in the [reference](https://docs.kairos.trade/wallets/reference.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.