The River
  • Home
  • Stocks
  • Strategies
  • Earn
  • Activity
The River

The River API

Read prices, buy and sell at market, place limit orders, run recurring buys and read a wallet's holdings, history and P&L over plain HTTP and JSON. No key and no sign-up. The River never holds your keys: every write returns unsigned transactions, and your own wallet signs and sends them.

Basics

  • Base URL: https://theriver.markets
  • Chains: Base (chainId 8453, settles in USDC) and Robinhood Chain (4663, settles in USDG). One side of every order is the chain's settlement token.
  • Amounts are exact base units as strings (1 USDC = "1000000", 1 wtNVDA = "1000000000000000000"). Prices are plain decimals ("182.5").
  • Limit: 60 requests a minute per IP per endpoint. Over it you get 429.
  • Errors come back as { error, message } with a 4xx/5xx status, and nothing is built.
  • Placing and cancelling orders and plans through The River has no fee; you pay network gas. A market trade may carry The River's fee of at most 0.10%, inside the quoted amounts and named in its quote.fee.

Worked example: place, check and cancel a limit order

We ran exactly these calls on production on 2 Nov 2026 from our own test wallet on Base: a limit buy of 0.01 wtNVDA at 100 USDC (well below the market, so it would not fill), then cancelled it and got the 1 USDC back. The onchain transactions:

  • Approve 1 USDC: 0x9194bdfa…2486
  • Place order: 0x2cbaf151…7988
  • Cancel and withdraw: 0xdf90fa56…183a

1. Build the order

amount is how much of the stock token to buy (0.01 wtNVDA); price is USDC per wtNVDA. To sell, swap sellToken and buyToken.

curl -X POST https://theriver.markets/api/v1/limit-orders/build-place \
  -H 'content-type: application/json' \
  -d '{
    "chainId": 8453,
    "owner": "0x944F1dafb62F6886336660B31b87f9f7613496de",
    "sellToken": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "buyToken": "0xFb5B41acdbA20a3230F84BE995173CFb98b8D6E7",
    "amount": "10000000000000000",
    "price": "100"
  }'

Response (shortened):

{
  "txs": [
    { "to": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "data": "0x095ea7b3…", "value": "0", "chainId": 8453,
      "description": "Approve the Raindex orderbook 0xe522…7C9D on Base to move exactly 1 USDC (1000000 base units) from your wallet (not unlimited; current allowance 0). No fee." },
    { "to": "0xe522cB4a5fCb2eb31a52Ff41a4653d85A4fd7C9D", "data": "0xac9650d8…", "value": "0", "chainId": 8453,
      "description": "Place a limit order on the Raindex orderbook …: deposit 1 USDC into your own vault and buy 0.01 wtNVDA at 100 USDC per wtNVDA or better. …" }
  ],
  "order": {
    "side": "buy", "chainId": 8453,
    "asset": { "address": "0xFb5B41acdbA20a3230F84BE995173CFb98b8D6E7", "symbol": "wtNVDA", "decimals": 18 },
    "settlement": { "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "symbol": "USDC", "decimals": 6 },
    "quantity": "10000000000000000", "price": "100", "ioRatio": "0.01",
    "deposit": { "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "amount": "1000000" },
    "rainlang": "/* 0. calculate-io */ …"
  }
}

2. Sign and send the transactions

Send each entry of txs in order from the owner wallet and wait for each receipt. Read the description first: it says exactly what the transaction does. The approval is for the exact deposit, never unlimited.

// Send each tx in order from the owner's wallet (viem shown; any wallet works).
for (const tx of res.txs) {
  const hash = await wallet.sendTransaction({ to: tx.to, data: tx.data, value: BigInt(tx.value) });
  await publicClient.waitForTransactionReceipt({ hash });
}

3. List your orders

Status is open, partially_filled, filled or cancelled. Up to 50 orders, newest first.

curl 'https://theriver.markets/api/v1/limit-orders?chainId=8453&owner=0x944F1dafb62F6886336660B31b87f9f7613496de'
{
  "orders": [
    {
      "orderHash": "0x28da5d1df10b1a5b99d1a24016590775e8a4824c535c0b72fedb09230a8fd32d",
      "chainId": 8453,
      "status": "open",
      "sell": { "symbol": "USDC", "filled": "0", "remaining": "1000000", ... },
      "buy":  { "symbol": "wtNVDA", "received": "0", "inVault": "0", ... },
      "tradesCount": 0
    }
  ]
}

4. Cancel

One transaction removes the order and withdraws what is left in its vaults to your wallet.

curl -X POST https://theriver.markets/api/v1/limit-orders/build-cancel \
  -H 'content-type: application/json' \
  -d '{
    "chainId": 8453,
    "owner": "0x944F1dafb62F6886336660B31b87f9f7613496de",
    "orderHash": "0x28da5d1df10b1a5b99d1a24016590775e8a4824c535c0b72fedb09230a8fd32d"
  }'
{
  "txs": [
    { "to": "0xe522cB4a5fCb2eb31a52Ff41a4653d85A4fd7C9D", "data": "0x…", "value": "0", "chainId": 8453,
      "description": "Cancel order 0x28da…d32d on the Raindex orderbook … in one transaction: withdraw 1 USDC (1000000 base units) …" }
  ],
  "withdrawals": [
    { "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "vaultId": "0xd6a3…4be4", "amount": "1000000" }
  ]
}

Sign and send it as in step 2. Listing again shows the order as cancelled with "remaining": "0".

Buy or sell at market

The same best-execution route as the trade ticket on the site: KyberSwap across DEX pools, or the stock's listed pool when that is what fills. A buy says what it spends (spend, base units of USDC or USDG); a sell says what it sells (quantity, base units of the token). slippageBps is optional (default 100 = 1%, at most 500).

curl -X POST https://theriver.markets/api/v1/trades/build \
  -H 'content-type: application/json' \
  -d '{
    "chainId": 8453,
    "owner": "0x944F1dafb62F6886336660B31b87f9f7613496de",
    "side": "buy",
    "token": "0xFb5B41acdbA20a3230F84BE995173CFb98b8D6E7",
    "spend": "25000000",
    "slippageBps": 100
  }'

Response (shortened; the quote is the live route on production on 2 Nov 2026, the transactions were built, not sent):

{
  "txs": [
    { "to": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "data": "0x095ea7b3…", "value": "0", "chainId": 8453,
      "description": "Approve the Aerodrome router 0x698Cb2b6dd822994581fEa6eA4Fc755d1363A92F on Base to move exactly 25 USDC (25000000 base units) from your wallet (not unlimited; current allowance 0). No fee." },
    { "to": "0x698Cb2b6dd822994581fEa6eA4Fc755d1363A92F", "data": "0xa026383e…", "value": "0", "chainId": 8453,
      "description": "Buy wtNVDA at market through the Aerodrome router … (Aerodrome) on Base: pay exactly 25 USDC (25000000 base units) and get about 0.117452496946883071 wtNVDA …, at least 0.11627797197741424 wtNVDA … or the swap reverts (slippage limit 1.00%). Price about 212.85201 USDC per wtNVDA, worst 215.00203. No River fee on this route. …" }
  ],
  "quote": {
    "side": "buy", "chainId": 8453, "route": "pool", "venue": "Aerodrome",
    "spender": "0x698Cb2b6dd822994581fEa6eA4Fc755d1363A92F",
    "tokenIn":  { "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "symbol": "USDC", "decimals": 6 },
    "tokenOut": { "address": "0xFb5B41acdbA20a3230F84BE995173CFb98b8D6E7", "symbol": "wtNVDA", "decimals": 18 },
    "amountIn": "25000000",
    "amountOut": "117452496946883071",
    "minAmountOut": "116277971977414240",
    "slippageBps": 100,
    "price": "212.85201", "worstPrice": "215.00203",
    "fee": null, "gasUsd": 0.01
  }
}

The approval is for exactly amountIn, to the router the swap goes to, and only when your allowance is short. The swap reverts if it would pay less than minAmountOut. Prices move: send within a few minutes, or build again. To sell:

{ "chainId": 8453, "owner": "0x…", "side": "sell", "token": "0xFb5B41acdbA20a3230F84BE995173CFb98b8D6E7", "quantity": "117452496946883071" }

Recurring buys

Spread a budget over days (1 to 365) or hours (2 to 72). The whole budget is deposited into your own vault now and spent in buys of at least $25 each. Each buy is an auction that starts near the order-book price and never pays more than maxPrice (settlement per 1 token).

curl -X POST https://theriver.markets/api/v1/recurring/build-create \
  -H 'content-type: application/json' \
  -d '{
    "chainId": 8453,
    "owner": "0x944F1dafb62F6886336660B31b87f9f7613496de",
    "token": "0xFb5B41acdbA20a3230F84BE995173CFb98b8D6E7",
    "budget": "100000000",
    "days": 28,
    "maxPrice": "220"
  }'

Response shape (shortened; illustrative numbers for a $100 plan, not sent):

{
  "txs": [
    { "to": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "data": "0x095ea7b3…", "value": "0", "chainId": 8453,
      "description": "Approve the Raindex orderbook 0xe522…7C9D on Base to move exactly 100 USDC (100000000 base units) …" },
    { "to": "0xe522cB4a5fCb2eb31a52Ff41a4653d85A4fd7C9D", "data": "0xac9650d8…", "value": "0", "chainId": 8453,
      "description": "Start a recurring buy of wtNVDA …: deposit 100 USDC … spent over 28 days in 4 buys of 25 USDC … Each buy is an auction that starts near 207.52 USDC per wtNVDA and never pays more than 220 USDC per wtNVDA …" }
  ],
  "plan": {
    "chainId": 8453, "orderbook": "0xe522cB4a5fCb2eb31a52Ff41a4653d85A4fd7C9D",
    "budget": "100000000", "period": { "days": 28 },
    "clip": "25000000", "buys": 4,
    "startPrice": "207.52", "maxPrice": "220", "marketPrice": 207.52,
    "firstBuyAt": 1794240000,
    "deposit": { "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "amount": "100000000" },
    "rainlang": "…"
  }
}

Stop a plan with its order hash. One transaction gives back what it has not spent and what it bought, then removes it.

curl -X POST https://theriver.markets/api/v1/recurring/build-stop \
  -H 'content-type: application/json' \
  -d '{ "chainId": 8453, "owner": "0x…", "planId": "0x…" }'

Holdings, history and P&L

Any wallet's public onchain data; the same numbers the site shows. Run on production on 2 Nov 2026 for our test wallet (shortened).

Holdings

Stock tokens and cash on Base and Robinhood Chain, or one chain with chainId. balance is exact base units; usd is a guide at the last US price, null when there is none.

curl 'https://theriver.markets/api/v1/holdings?owner=0x944F1dafb62F6886336660B31b87f9f7613496de&chainId=8453'
{
  "owner": "0x944F1dafb62F6886336660B31b87f9f7613496de",
  "holdings": [
    { "chainId": 8453, "token": "0xfb5b41acdba20a3230f84be995173cfb98b8d6e7",
      "symbol": "wtNVDA", "name": "Wrapped NVIDIA Corporation ST0x", "decimals": 18,
      "balance": "937690529190392684", "amount": "0.937690529190392684",
      "otherIssuer": false, "usd": 193.71 },
    { "chainId": 8453, "token": "0xB200000000000000000000Ab99cFa739E253872B",
      "symbol": "MSFTc", "name": "Microsoft (Coinbase)", "decimals": 8,
      "balance": "1885319", "amount": "0.01885319",
      "otherIssuer": true, "usd": 9.80 },
    …
  ],
  "totalUsd": …, "unvalued": 0
}

History

Buys, sells and transfers of stock tokens since 1 Oct 2026, newest first. cash is dollars in base units (6 decimals); transfers have no price. A wallet seen for the first time answers 202 with "status": "scanning" while it is read; ask again in a minute.

curl 'https://theriver.markets/api/v1/history?owner=0x944F1dafb62F6886336660B31b87f9f7613496de'
{
  "owner": "0x944F1dafb62F6886336660B31b87f9f7613496de",
  "status": "done", "since": "2026-10-01", "chains": ["Base", "Robinhood Chain"],
  "trades": [
    { "chainId": 8453, "tx": "0xce3f…4c14", "time": 1793160945,
      "token": "0x78c31580c97101694c70022c83d570150c11e935", "symbol": "wtSGOV", "decimals": 18,
      "type": "received", "amount": "19457979454022527", "cash": null, "price": null },
    { "chainId": 8453, "tx": "0xcca9…12fc", "time": 1792945463,
      "token": "0x78c31580c97101694c70022c83d570150c11e935", "symbol": "wtSGOV", "decimals": 18,
      "type": "buy", "amount": "9769636640872985", "cash": "1000000", "price": "102.357952" },
    { "chainId": 8453, "tx": "0xd06d…ffc", "time": 1792780953,
      "token": "0xfb5b41acdba20a3230f84be995173cfb98b8d6e7", "symbol": "wtNVDA", "decimals": 18,
      "type": "buy", "amount": "15000000000000000", "cash": "3150000", "price": "210" },
    …
  ],
  "notes": [ … ]
}

P&L

Average cost from the wallet's own trades; transfers are never priced. Unrealised uses the last US price: a guide, not a sell price. Also 202 while scanning.

curl 'https://theriver.markets/api/v1/pnl?owner=0x944F1dafb62F6886336660B31b87f9f7613496de'
{
  "owner": "0x944F1dafb62F6886336660B31b87f9f7613496de",
  "status": "done", "since": "2026-10-01", "chains": ["Base", "Robinhood Chain"],
  "asOfBlock": 53426471,
  "realisedUsd": -0.324361, "unrealisedUsd": -2.400262,
  "tokens": [
    { "token": "0xfb5b41acdba20a3230f84be995173cfb98b8d6e7", "symbol": "wtNVDA",
      "held": "0.937690529190392684", "heldWithKnownCost": "0.017855220386212667",
      "costUsd": 3.786663, "realisedUsd": -0.323171, "unrealisedUsd": -0.098169,
      "markUsdPerToken": 206.57793278678812,
      "transfersWithoutPrice": 5, "soldWithoutKnownCost": "0" },
    …
  ],
  "notes": [ … ]
}

All endpoints

GET /api/public/prices
Order-book midpoint, bid and ask for every listed token, by chain ID and token address (in the settlement token, per token). source is live, cached (last price kept while the market is shut) or unavailable.
curl https://theriver.markets/api/public/prices
{
  "success": true,
  "prices": {
    "8453": {
      "0xfb5b41acdba20a3230f84be995173cfb98b8d6e7": {
        "price": 207.52, "bid": 206.75, "ask": 208.29,
        "source": "live", "asOf": 1793635200000,
        "change24hPercent": 0.97
      },
      ...
    },
    "4663": { ... }
  }
}
GET /api/v1/limit-orders?chainId=&owner=
A wallet's limit orders with fill status (step 3).
POST /api/v1/limit-orders/build-place
Body { chainId, owner, sellToken, buyToken, amount, price }. Returns txs plus the order's terms and its Rainlang (step 1).
POST /api/v1/limit-orders/build-cancel
Body { chainId, owner, orderHash }. Returns txs and what will be withdrawn (step 4).
POST /api/v1/vaults/build-withdraw
Body { chainId, owner, token, vaultId, amount } (base units) or "max": true. Withdraws filled tokens or leftovers from one of your vaults.
curl -X POST https://theriver.markets/api/v1/vaults/build-withdraw \
  -H 'content-type: application/json' \
  -d '{ "chainId": 8453, "owner": "0x…", "token": "0x…", "vaultId": "0x…", "max": true }'
POST /api/v1/trades/build
Body { chainId, owner, side, token, spend | quantity, slippageBps? }. Returns txs and the quote: price, minimum out, fee, venue.
POST /api/v1/recurring/build-create
Body { chainId, owner, token, budget, days | hours, maxPrice }. Returns txs and the plan.
POST /api/v1/recurring/build-stop
Body { chainId, owner, planId }. One transaction.
GET /api/v1/holdings?owner=&chainId=
Balances in base units, with a dollar guide.
GET /api/v1/history?owner=
Stock-token trades and transfers since 1 Oct 2026.
GET /api/v1/pnl?owner=
Realised and unrealised P&L per token.

An error looks like this:

{ "error": "bad_request", "message": "price must be a plain decimal above 0 with at most 18 decimals, e.g. \"182.5\"." }

For AI agents

The same tools are available as an MCP server at https://theriver.markets/mcp. See Use The River with your own AI, llms.txt and the manifest.

Home Stocks Strategies Earn Activity