# BStocks: full API reference > Self-custodial interface for Coinbase Tokenized Stocks (B20) on Base, and a public API for the data behind it and the calls to trade it. ## Conventions - Base URL: https://basestocks.finance/api/v1 · JSON · Base mainnet (8453) - Keys: none · no account and no sign-up · the paid endpoints take an x402 payment instead of a key - CORS: open to every origin, GET and POST · a browser on any site may call it - Envelope: { data, meta } · meta.cacheSeconds says how long the body stays valid, and the CDN honours the same number - Errors: { error: { code, message, hint? } } with a 4xx or 5xx status · 402 carries the x402 payment requirements · 451 means the eligibility answer is missing - Amounts: integer strings in the smallest unit: USDC has 6 decimals, ETH 18; a stock token carries a multiplier, so read shares from the API rather than dividing yourself - Identity: a stock is its contract address; tickers and symbols are accepted and resolved to it - Signing: never on the server · /api/v1/trade returns calls for the user's own wallet, which signs and sends them - Eligibility: from a restricted country, /api/v1/trade answers 451 until the visitor confirms they are not a US person; a site that asks in its own UI sends x-bstocks-eligibility: confirmed, never on the visitor's behalf ## Read this before using the data - **One token is not one share.** Every stock carries a multiplier that moves on splits and dividends. Share-equivalents are rawBalance × multiplier ÷ 1e18. The portfolio endpoint returns both so no conversion is guessed. - **The Chainlink reference is a total-return value.** Coinbase's feeds report total return, not the raw equity price. It is returned as reference.totalReturnUsd, deliberately not named a price: comparing it with dexPriceUsd and calling the gap an arbitrage is a mistake. - **Feeds run 24/5 and then hold.** Outside US trading hours, and during a corporate action, a feed stops updating and keeps its last value while staying callable. Read reference.updatedAt and reference.isStale before relying on it. - **Not every stock has a reference.** A newer stock may have no Chainlink feed yet. Its reference is null, displaySource is "market" and displayUsd is the pool price with nothing to check it against. Read liquidityUsd and status before relying on it: a pool of a few thousand dollars moves with a single trade. - **A pool is not automatically a price.** dexPriceUsd is read only from a pool quoted in USDC or ETH, and only counts as displayUsd when it is within 20% of a live reference. A pool prices a token against whatever is on its other side, so a pair quoted in a long-tail token reports that token's valuation: one such pair had a stock reading 49x its reference. When the check refuses the market price, displaySource is "reference" even though dexPriceUsd is present. - **Identity is the address.** Names and symbols are mutable onchain metadata. Symbols are accepted for convenience, but store the address. ## Quick start: a trade ```js // 1. Ask for the calls. amount is what is sold, in its smallest unit: 10 USDC = 10000000. const res = await fetch("https://basestocks.finance/api/v1/trade", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ stock: "NVDA", side: "buy", amount: "10000000", account, builderCode: "bc_yourcode" }), }); const { data, error } = await res.json(); if (error) throw new Error(error.message); // 2. The user's wallet sends them in order: the approval first, when there is one. // A quote lives for data.expiresAt; ask again if the approval took longer. for (const call of data.calls) { const hash = await walletClient.sendTransaction({ account, to: call.to, data: call.data, value: BigInt(call.value) }); await publicClient.waitForTransactionReceipt({ hash }); } ``` ## Market data Prices, references, liquidity, headlines, yield venues and platform totals. Free, cached at the edge, open to every origin. ### GET /api/v1/stocks Every tokenized stock that can be traded right now (supply, a pool and a quote in both directions): DEX price, Chainlink reference where one exists, liquidity, 24h volume, multiplier and trading status. (free · cached 30s) Returns: data = { count, stocks: Stock[] } ```sh curl -s 'https://basestocks.finance/api/v1/stocks' ``` ### GET /api/v1/stocks/{symbol} One stock by ticker, token symbol or contract address, with the pools that trade it. Answers for any verified stock, including one that is not in the list above because it has no market yet. (free · cached 30s) Parameters: - `symbol` (path, string, required): Ticker ("NVDA"), token symbol ("NVDAc") or 0x address. Returns: data = { stock: Stock, pools: { address, name, dex, liquidityUsd, volume24hUsd, isPrimary, url }[] } Errors: 404 UNKNOWN_STOCK ```sh curl -s 'https://basestocks.finance/api/v1/stocks/NVDA' ``` ### GET /api/v1/news Headlines: one stock's wire, the market desks, or the Base and Coinbase tokenized-stock feed. Titles and links only. (free · cached 300s) Parameters: - `scope` (query, enum one of ecosystem | market, optional) (default ecosystem): Which feed. Ignored when symbol is given. - `symbol` (query, string, optional): Ticker, for that stock's own headlines. - `limit` (query, integer 1..30, optional) (default 10): Headlines to return. Returns: data = { scope, symbol, count, items: { title, url, source, publishedAt, symbol, mentions }[] } Errors: 400 BAD_SCOPE, 404 UNKNOWN_STOCK ```sh curl -s 'https://basestocks.finance/api/v1/news?scope=ecosystem&limit=5' ``` ### GET /api/v1/earn Where idle USDC can earn on Base: venue, variable APY, TVL and risk notes, discovered live from the protocols. (free · cached 120s) Returns: data = { asset, count, opportunities: Opportunity[], unavailableProviders } ```sh curl -s 'https://basestocks.finance/api/v1/earn' ``` ### GET /api/v1/stats What has been done through the app, counted from records verified against a receipt on Base. (free · cached 300s) Returns: data = { generatedAt, windows, trading, strategies, gifts, earn } ```sh curl -s 'https://basestocks.finance/api/v1/stats' ``` ## Wallets Any wallet's tokenized-stock position, read from the chain. ### GET /api/v1/portfolio/{address} Any wallet's tokenized-stock position, read from the chain — raw balances and share-equivalents side by side. (free · cached 15s · 60/min per caller) Parameters: - `address` (path, address, required): 0x-prefixed wallet address. Returns: data = { owner, totalValueUsd, change24hPct, usdc, earnValueUsd, liquidityValueUsd, holdings: Holding[], readAt } Errors: 400 BAD_ADDRESS, 429 RATE_LIMITED ```sh curl -s 'https://basestocks.finance/api/v1/portfolio/0xEAa823AB4C4eE00283d8ed7be713ddf8A5ba0Fac' ``` ## Trading The calls to buy or sell a stock, built by the same router the app trades with. Nothing is signed or sent: the user's own wallet does that. ### POST /api/v1/trade The calls to buy or sell one stock, for the account that will send them: an approval of exactly the amount sold when the allowance is short, then the swap, from the router the app trades with. Nothing is signed or sent. (free · not cached · 30/min per caller · eligibility rule applies) Parameters: - `stock` (body, string, required): Ticker ("NVDA"), token symbol ("NVDAc") or 0x address. - `side` (body, enum one of buy | sell, required): buy spends USDC (or ETH), sell spends the stock for USDC. - `amount` (body, uint, required): What is sold, in its smallest unit: USDC has 6 decimals, ETH 18, a stock its own. - `account` (body, address, required): The wallet that sends the calls and pays. - `recipient` (body, address, optional): Who receives a buy. Defaults to account; a sale always pays the account. - `payWith` (body, enum one of USDC | ETH, optional) (default USDC): What a buy is paid with. - `slippageBps` (body, integer 10..500, optional) (default 100): How far below the quote the output may land, in basis points. - `provider` (body, enum one of zeroX | kyber | okx | uniswap | velora | aerodrome, optional): Try this route first; the others still cover a failure. - `builderCode` (body, string, optional): Your ERC-8021 builder code. It goes on every call beside the app's, so the trade is attributed to both. Returns: data = { stock, side, account, recipient, provider, quote, approval, calls: { to, data, value, description }[], quoteId, expiresAt } Errors: 400 BAD_BODY, 404 UNKNOWN_STOCK, 409 NO_ROUTE, 429 RATE_LIMITED, 451 REGION_RESTRICTED, 4xx from the pre-trade checks, 502 TRADE_FAILED ```sh curl -s -X POST 'https://basestocks.finance/api/v1/trade' \ -H 'content-type: application/json' \ -d '{"stock":"NVDA","side":"buy","amount":"10000000","account":"0xEAa823AB4C4eE00283d8ed7be713ddf8A5ba0Fac"}' ``` ## Paid Two endpoints with a cost a cache cannot remove, priced at $0.10 in USDC per call over x402. ### GET /api/v1/pro/report The written market brief with the prices behind it. $0.10 in USDC per call — it is backed by a model, so every call has a cost a cache cannot remove. (paid: $0.10 USDC per call over x402 · cached 900s) Returns: data = { report: { headline, summary, mood, marketOpen, perStock, ecosystem, themes, generatedAt }, stocks, disclaimer } Errors: 402 PAYMENT_REQUIRED, 503 REPORT_UNAVAILABLE ```sh curl -s 'https://basestocks.finance/api/v1/pro/report' ``` ### GET /api/v1/pro/history/{symbol} Full candle history for one stock, labelled with its source. $0.10 in USDC per call. (paid: $0.10 USDC per call over x402 · cached 300s) Parameters: - `symbol` (path, string, required): Ticker or 0x address. - `timeframe` (query, enum one of 1D | 1W | 1M | 3M | 1Y, optional) (default 1M): The span of the series. Returns: data = { symbol, address, timeframe, source, multiplier, count, candles } Errors: 400 BAD_TIMEFRAME, 402 PAYMENT_REQUIRED, 404 UNKNOWN_STOCK ```sh curl -s 'https://basestocks.finance/api/v1/pro/history/NVDA?timeframe=1M' ``` ## Listed stocks Identity is the contract address; tickers are accepted for convenience. The registry below also holds stocks without a market yet; /api/v1/stocks returns the ones that can be traded right now. - AAPL: 0xb200000000000000000000C2e324d24d7eEcd1fb - AMZN: 0xb200000000000000000000d9192b6B456483C2E8 - COIN: 0xb200000000000000000000c85a31389D71F3ecfb - CRCL: 0xB20000000000000000000019f6E7C675b73C2e4D - GOOGL: 0xb2000000000000000000002D0BA3164cc74f58B7 - INTC: 0xB2000000000000000000004AFF16039bA04bdFBc - META: 0xb2000000000000000000008bC8786B856E61707C - MSFT: 0xB200000000000000000000Ab99cFa739E253872B - MSTR: 0xb2000000000000000000004884b426556b92883d - NVDA: 0xb20000000000000000000078ee7ce2fE4908108C - SNDK: 0xb200000000000000000000397293Cb8cda9a10c5 - SPCX: 0xb2000000000000000000007b9fcbd005511aCBd5 - TSLA: 0xb2000000000000000000001e800a7f5189430cD0 - WRD: 0xb200000000000000000000e88efe88d8ade3f0da - ARM: 0xb20000000000000000000026215d755356e5043f - SAN: 0xb20000000000000000000017bb66e9301e913a99 - NOK: 0xb2000000000000000000005ac674f707e357409c - HSAI: 0xb200000000000000000000f3049f4aa834b23b64 - UL: 0xb200000000000000000000349ef3aa93a0897476 - INFY: 0xb200000000000000000000f6b0417af5f52341fc - BILI: 0xb200000000000000000000ca7c6d1438e7245eb6 - LI: 0xb200000000000000000000d61efd9f54a23ef9eb - VALE: 0xb20000000000000000000063376b142c0764b489 - SONY: 0xb200000000000000000000a26326a922ffa87f6c - SAP: 0xb200000000000000000000da6f64c306234127e0 - NIO: 0xb2000000000000000000002d2b5dc53c61f1ba06 - SE: 0xb2000000000000000000003088798f6d0722aaac - PDD: 0xb200000000000000000000c8a7223510467d8563 - BUD: 0xb200000000000000000000c36ce081dd09e86ca2 - SKHY: 0xb200000000000000000000187f7071d6e321a7d2 - BIDU: 0xb200000000000000000000d2b7d9aee52f6c6bef - NVO: 0xb2000000000000000000008d5328e9208773dc58 - RKLB: 0xb200000000000000000000e8e50cbbb9a3861a3c - CBRS: 0xb200000000000000000000720133eedf525f93e2 - WDC: 0xb2000000000000000000008fde21a1f5c69fec0b - CRWV: 0xb200000000000000000000f111184a74720787e6 - BMNR: 0xb200000000000000000000ea2df44a307cab279c - SOUN: 0xb2000000000000000000002137743d4a01fe4e88 - PFE: 0xb20000000000000000000018fe7ec7d6dfeeb528 - PYPL: 0xb200000000000000000000450ad3abe5d4846c6e - CAKE: 0xb200000000000000000000f215e4c890cfb7176b - DUOL: 0xb200000000000000000000a613d12deafbbb1db7 - PTON: 0xb2000000000000000000009272a491812842aa84 - NVAX: 0xb200000000000000000000c597c476fcf9aed3a8 - WEN: 0xb20000000000000000000044e3cd7a0e1028e57a - PM: 0xb2000000000000000000008fc2a8c23cf5937b66 - QUBT: 0xb200000000000000000000ca425ab42e07c35bc3 - AMD: 0xb2000000000000000000000d8ce462e99ee7a47b - MRVL: 0xb200000000000000000000ec3c4c7395cc609813 - ORCL: 0xb200000000000000000000347afba223d7b6b63c - BE: 0xb20000000000000000000016f9dfe862feba122b - RBLX: 0xb2000000000000000000005bd7ae89b9e6189bb5 - HIMS: 0xb20000000000000000000043a599976181bcf336 - MRNA: 0xb200000000000000000000e215e9b76ecba02468 - TTWO: 0xb200000000000000000000f720c26062bc3067da - ASTS: 0xb200000000000000000000b1a29cf17a1819288a - PLTR: 0xb2000000000000000000007d16372840df4dabbe - LLY: 0xb200000000000000000000f1a0f91e34892e4718 - DJT: 0xb200000000000000000000428e3a3eebbb20692b - AVGO: 0xb200000000000000000000fc737aea6196ab5a4c - GME: 0xb2000000000000000000007790ed6e48e06ed935 - RDDT: 0xb20000000000000000000066242d4067724cb7a1 - MU: 0xb200000000000000000000fd2f87532b90095211 - NFLX: 0xb20000000000000000000058b8c947e44011dfe6 - HTZ: 0xb2000000000000000000002601c5c94f435da168 Endpoints in this file: 9. OpenAPI: https://basestocks.finance/api/v1/openapi.json. Docs with runnable examples: https://basestocks.finance/developers.