Keydex AI docs
One API key for AI models and stock trading on Solana. Start with the quickstart, then connect over MCP or REST.
Quickstart
Get a key, make your first call, then add the tools to your agent. About a minute end to end.
Get a key
A trial key needs no sign-in. It goes into every code sample on this page.
Key added to every code sample.—
Copy it now. Only this tab keeps it. Closing the tab removes it from this browser, but the key works until it expires.
POST/v1/chat/completions
pip install openai
npm install openai
curl https://keydex.ai/v1/chat/completions \ -H "Authorization: Bearer YOUR_KEYDEX_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "openai/gpt-4.1-mini", "messages": [ { "role": "user", "content": "In one sentence, what is a stock token?" } ] }'
import os from openai import OpenAI client = OpenAI(base_url="https://keydex.ai/v1", api_key=os.environ.get("KEYDEX_KEY", "YOUR_KEYDEX_KEY")) r = client.chat.completions.create( model="openai/gpt-4.1-mini", messages=[{"role": "user", "content": "In one sentence, what is a stock token?"}], ) print(r.choices[0].message.content)
import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://keydex.ai/v1", apiKey: process.env.KEYDEX_KEY ?? "YOUR_KEYDEX_KEY" }); const r = await client.chat.completions.create({ model: "openai/gpt-4.1-mini", messages: [{ role: "user", content: "In one sentence, what is a stock token?" }], }); console.log(r.choices[0].message.content);
Add the tools
The chat endpoint doesn’t call Keydex AI tools, so the model can’t see prices. One stock_quote call returns a stock token’s pool price, 24h change and pool depth.
GET/v1/tools/stock_quote
curl "https://keydex.ai/v1/tools/stock_quote?ticker=NVDA" \ -H "Authorization: Bearer YOUR_KEYDEX_KEY"
Streaming
Set stream to true to get the reply as server-sent events. The stream ends with data: [DONE].
curl https://keydex.ai/v1/chat/completions \ -H "Authorization: Bearer YOUR_KEYDEX_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "openai/gpt-4.1-mini", "stream": true, "messages": [ { "role": "user", "content": "In one sentence, what is a stock token?" } ] }'
data: {"id": "kf-1793359030-UCNVXSuIHo27", "object": "chat.completion.chunk", "created": 1793359030, "model": "openai/gpt-4.1-mini", "choices": [{"index": 0, "delta": {"content": "A", "role": "assistant"}, "finish_reason": null}]}
data: {"id": "kf-1793359030-UCNVXSuIHo27", "object": "chat.completion.chunk", "created": 1793359030, "model": "openai/gpt-4.1-mini", "choices": [{"index": 0, "delta": {"content": " stock", "role": "assistant"}, "finish_reason": null}]}
data: [DONE]Authentication
Send your key in the Authorization header or as X-API-Key. MCP clients that take only a URL can pass it as ?key=. Keep the key on your server.
Authorization: Bearer YOUR_KEYDEX_KEY # MCP clients that take only a URL: https://keydex.ai/mcp?key=YOUR_KEYDEX_KEY
Trial keys
A trial key needs no sign-in. It draws from a free daily allowance for each visitor, expires after 24 hours and works with low-cost models only. Replies are capped at 512 tokens. GET /v1/models with a trial key lists the models it can use.
With a trial key, send images as data:image/… URLs. Links need your own key.
POST/api/trial
curl -X POST https://keydex.ai/api/trial
{
"key": "YOUR_KEYDEX_KEY",
"id": "hG7kQ2mXp9Tz",
"allowance": {
"type": "free",
"period": "daily",
"remaining": true,
"resets_at": 1793433600
},
"expires_at": 1793424125,
"max_tokens": 512,
"example_model": "openai/gpt-4.1-mini",
"models_count": 172,
"models": [
"openai/gpt-4.1-mini",
"anthropic/claude-haiku-5.5",
"deepseek/deepseek-v4.1-flash-1017"
],
"mcp_url": "https://keydex.ai/mcp"
}Daily allowance
Tool calls are free. Model calls draw from a daily allowance that resets at 00:00 UTC. A trial key uses the free allowance each visitor gets. A wallet key uses its holder tier first, then the free trial rules. There are no limits to set.
Until the token launches, wallet keys get the same free daily allowance as a trial key.
Check a key
GET /v1/key shows a key’s allowance. For a trial key, allowance has type free, period daily, remaining (true while some is left) and resets_at (00:00 UTC). A wallet key returns the same until the token launches, then its holder allowance. It also gives expires_at and max_tokens.
GET/v1/key
curl https://keydex.ai/v1/key \
-H "Authorization: Bearer YOUR_KEYDEX_KEY"{
"object": "key",
"trial": true,
"allowance": {
"type": "free",
"period": "daily",
"remaining": true,
"resets_at": 1793433600
},
"expires_at": 1793424125,
"max_tokens": 512
}Models
Models run through an OpenAI-compatible API. Point any OpenAI SDK at Keydex AI and pick a model by its ID.
GET/v1/models
| Model | id | Context |
|---|---|---|
| GPT-4.1 Mini | openai/gpt-4.1-mini | |
| GPT-6.1 Terra Pro | openai/gpt-6.1-terra-pro | |
| GPT-6.1 Terra | openai/gpt-6.1-terra | |
| anthropic/claude-fable-5.2 | ||
| anthropic/claude-haiku-5.5 | ||
| google/gemini-omni-1.2-flash | ||
| google/gemini-omni-1.1-flash | ||
| Grok 4.7 | x-ai/grok-4.7 | |
| Grok 4.6 | x-ai/grok-4.6 | |
| deepseek/deepseek-v4.1-flash | ||
| deepseek/deepseek-v4-pro | ||
| qwen/qwen3.8-max-prime |
Couldn’t load the model list.Try again
—
curl https://keydex.ai/v1/models
MCP
One MCP server gives your agent every Keydex AI tool. Add it to Claude Code, Cursor or VS Code with your key in the header.
HTTP/mcp
claude mcp add -s user --transport http Keydex AI https://keydex.ai/mcp \
--header "Authorization: Bearer YOUR_KEYDEX_KEY"{
"mcpServers": {
"Keydex AI": {
"url": "https://keydex.ai/mcp",
"headers": {
"Authorization": "Bearer YOUR_KEYDEX_KEY"
}
}
}
}{
"servers": {
"Keydex AI": {
"type": "http",
"url": "https://keydex.ai/mcp",
"headers": {
"Authorization": "Bearer YOUR_KEYDEX_KEY"
}
}
}
}curl "https://keydex.ai/v1/tools/stock_quote?ticker=NVDA" \ -H "Authorization: Bearer YOUR_KEYDEX_KEY"
New key? Run claude mcp remove Keydex AI -s user first. Check with claude mcp list: Keydex AI shows Connected.
Tools
Four core tools below; the Tools page lists all. Same names and inputs over MCP and REST.
Every tool takes GET with query parameters or POST with a JSON body.
REST wraps the result in data. Over MCP, a tool returns the same object without the wrapper.
GET · POST/v1/tools/<name>
stock_quote
Returns price, 24h change and pool depth for a stock token on Solana.
GET · POST/v1/tools/stock_quote?ticker=NVDA
tickerstringRequired
Ticker of a stock token or ETF, like NVDA. A token address works too.
No key needed, up to 30 calls an hour.
Stock tokens are not available to US persons and are restricted in Canada, the UK, Switzerland and other countries. This service shows data and builds transactions. It does not sell stock tokens.
curl "https://keydex.ai/v1/tools/stock_quote?ticker=NVDA" \ -H "Authorization: Bearer YOUR_KEYDEX_KEY"
{
"data": {
"ticker": "NVDA",
"name": "NVIDIA",
"type": "stock",
"token": "0xd0601ce157db5bdc3162bbac2a2c8af5320d9eec",
"price_usd": 210.127,
"change_24h_pct": -1.89,
"depth_usd": 35229786,
"logo": "https://cdn.jsdelivr.net/…/NVDA.png",
"chain_id": 4663,
"as_of": 1793318233,
"price_note": null,
"note": "Stock tokens are not available to US persons…"
}
}stock_portfolio
Returns every stock token and ETF in an agent wallet with amounts and value in dollars, plus its SOL balance.
GET · POST/v1/tools/stock_portfolio?wallet=0xd8dA…6045
walletstringRequired
Wallet address on Solana.
No key needed, up to 30 calls an hour.
curl -G https://keydex.ai/v1/tools/stock_portfolio \ --data-urlencode wallet=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 \ -H "Authorization: Bearer YOUR_KEYDEX_KEY"
{
"data": {
"wallet": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
"chain_id": 4663,
"holdings": [
{
"ticker": "NVDA",
"name": "NVIDIA",
"token": "0xd0601ce157db5bdc3162bbac2a2c8af5320d9eec",
"amount": 0.57243038,
"amount_raw": "572430380000000000",
"amount_dec": "0.57243038",
"price_usd": 210.127,
"price_note": null,
"value_usd": 120.28,
"change_24h_pct": -1.89,
"logo": "https://cdn.jsdelivr.net/…/NVDA.png"
}
],
"holdings_count": 1,
"priced_count": 1,
"unpriced_count": 0,
"stocks_value_usd": 120.28,
"unpriced": 0,
"eth": 0.05,
"eth_raw": "50000000000000000",
"eth_dec": "0.05",
"eth_value_usd": 112.54,
"as_of": 1793318233,
"note": "Stock tokens are not available to US persons…"
}
}amount_raw and eth_raw are exact whole numbers in the smallest unit. amount_dec and eth_dec are the same amounts as exact decimals. Use them for arithmetic.
price_note is null when a price is known, otherwise no_liquidity or unavailable.
build_trade
Returns an unsigned buy of a stock token for SOL, sized in
SOL or in dollars, or a sale of a percentage of a position for
SOL. Your agent signs and sends it.
A buy needs the SOL, plus gas, already in the wallet. If it is short, fund it with fund_agent first.
GET · POST/v1/tools/build_trade
unsigned · agent signsThis transaction is unsigned. Your agent signs it with private keys it holds itself.A sale may first need a token approval. Your agent signs that transaction too.
See Sign and send for how your agent submits these calls.
Trades route through LI.FI.
tokenstringRequired
Ticker, like TSLA, or the token address.
sideenumRequired
buy or sell.
walletstringRequired
The wallet that signs and sends. The route is quoted for it.
usdnumberBuy: eth or usd
Dollars of SOL to spend, at the current
SOL price.
ethnumberBuy: eth or usd
SOL to spend on a buy, up to 10.
pctnumberSell: required
Share of the holding to sell, above 0 and up to 100.
slippage_pctnumberOptional
Price tolerance in percent: 1 by default, from 0.1 to 10.
curl -X POST https://keydex.ai/v1/tools/build_trade \ -H "Authorization: Bearer YOUR_KEYDEX_KEY" \ -H "Content-Type: application/json" \ -d '{ "token": "TSLA", "side": "buy", "wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "usd": 50 }'
{
"data": {
"chain_id": 4663,
"side": "buy",
"ticker": "TSLA",
"token": "0x322f0929c4625ed5bad873c95208d54e1c003b2d",
"wallet": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
"amount_in": 0.022301,
"amount_in_raw": "22300621295309287",
"amount_in_usd": 50.05,
"expected_out": 0.126576,
"expected_out_raw": "126576214763029118",
"min_out": 0.125311,
"min_out_raw": "125310452615398827",
"expected_out_usd": 49.92,
"fees_usd": 0.1251,
"quoted_at": 1793318233,
"valid_until": 1793318278,
"valid_for_s": 45,
"calls": [
{
"label": "Buy TSLA",
"to": "0xB477751B76CF82d00a686A1232f5fCD772414Af3",
"data": "5xK9mR3p…",
"value": "22300621295309287",
"gas": 669595
}
],
"how_to_sign": "Send each call in order from the wallet address…",
"simulated": true,
"note": "Stock tokens are not available to US persons…"
}
}valid_until is the time the quoted route expires; quoted_at is when it was quoted. Send the calls before valid_until, or build the trade again.
simulated is true when the calls passed a test on the network just before the reply, and false when that test could not run. If it is false, build the trade again or check the calls yourself before signing.
amount_in_raw, expected_out_raw and min_out_raw are exact whole numbers in the token’s smallest unit, as strings. Use them for arithmetic.
fund_agent
Returns a quote and ready transactions that fund an agent wallet on Solana from another network, such as Ethereum, Base, Arbitrum, Optimism, BNB Chain or Polygon. Funds arrive as SOL. The payer signs.
GET · POST/v1/tools/fund_agent
origin_chain accepts these networks:
ethereum
base
arbitrum
optimism
bnb
polygon
avalanchelinea
scroll
zksync
mode
zora
mantleunichain
ink
walletstringRequired
Agent wallet on Solana that receives the SOL.
payerstringRequired
Wallet that pays on the origin network and signs there. Usually not the agent wallet.
origin_chainstring or numberRequired
Network to pay from: a name, like base, or its chain ID, like 8453.
amountstring or numberRequired
Amount in the smallest unit of what you pay with, like wei for SOL.
currencystringOptional
Token address to pay with on the origin network. Empty pays in its native coin.
curl -X POST https://keydex.ai/v1/tools/fund_agent \ -H "Authorization: Bearer YOUR_KEYDEX_KEY" \ -H "Content-Type: application/json" \ -d '{ "wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "payer": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", "origin_chain": "base", "amount": "1000000000000000" }'
{
"data": {
"origin_chain_id": 8453,
"destination_chain_id": 4663,
"recipient": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
"payer": "0x71c7656ec7ab88b098defb751b7401b5f6d8976f",
"amount_in": "0.001",
"amount_out_eth": "0.000990057421606488",
"eta_s": 1,
"transactions": [
{
"step": "deposit",
"action": "Confirm transaction in your wallet",
"chain_id": 8453,
"to": "0x4cd00e387622c35bddb9b4c962c136462338bc31",
"data": "0x49290c1c…",
"value": "1000000000000000"
}
],
"how_to_sign": "The payer signs and sends each transaction on the origin chain."
}
}Stock token list
GET /v1/stocks returns stock tokens and ETFs on Solana with pool price, 24h change and pool depth, deepest pool first. No key needed. Unknown values are null, never 0.
GET/v1/stocks
curl https://keydex.ai/v1/stocks
{
"data": [
{
"ticker": "NVDA",
"name": "NVIDIA",
"type": "stock",
"token": "0xd0601ce157db5bdc3162bbac2a2c8af5320d9eec",
"price_usd": 209.062,
"change_24h_pct": -2.03,
"depth_usd": 14871922,
"logo": "https://cdn.jsdelivr.net/…/NVDA.png",
"price_note": null
}
],
"count": 64,
"chain_id": 4663,
"as_of": 1793344758,
"note": "Stock tokens are not available to US persons…"
}Prompts
Keydex AI publishes ready-made tasks as MCP prompts. Your client lists them with prompts/list and sends one with prompts/get. A prompt only writes the request: it calls nothing itself.
- buy_stock
- Quotes a stock token, builds an unsigned buy and waits for your approval before anything is signed. Arguments: ticker, usd, wallet.
- portfolio_checkup
- Reads a wallet’s stock tokens and quotes every position. When issuer data is available, it adds upcoming dividends and splits. Argument: wallet.
- rebalance
- Reads the portfolio and builds the unsigned trades that move it toward a target mix, such as 50% SPY and 50% QQQ. Arguments: wallet, target.
- fund_my_agent
- Quotes moving funds from another network to the agent wallet and returns the transactions the payer signs. Arguments: wallet, payer, origin_chain, amount.
- market_now
- Shows today’s stock movers and quotes SPY and QQQ. Movers rank by the pool’s 24h change, and by issuer data when it is available.
- usdg_vault
- Compares Morpho
USDG vaults by rate, size and curator, names the risks and builds an unsigned deposit. Arguments: wallet, amount. - cheapest_model
- Finds the lowest-cost model that can do a task and shows the cost of a typical call. Argument: task.
- check_approvals
- Lists a wallet’s open approvals to the spenders Keydex AI knows and builds unsigned revokes for the ones you pick. Argument: wallet.
- dividends_ahead
- Lists scheduled dividends and splits, for one wallet’s holdings or for all stock tokens. Argument: wallet, optional.
Resources
Reference data your agent can read without a tool call. List it with resources/list and read it with resources/read.
- keydex://stocks
- Stock tokens Keydex AI covers: ticker, name, token address and type. JSON.
- keydex://chain
- Solana facts: chain ID, RPC, block explorer, Multicall3 and the
USDG address. JSON. - keydex://guide/signing
- How to sign and send the calls Keydex AI tools return. Markdown.
- keydex://models
- The model catalog: prices per 1M tokens, context and what each model supports. JSON.
Sign and send
build_trade and fund_agent return unsigned transactions. Your agent’s wallet signs and sends them, one by one.
- Take each item of
callsin the order given. A sale may start with an approval. - Check
valid_until. If it has passed, build the trade again. - Sign and send it from the wallet address on Solana (chain ID 4663), with
to,dataandvalueas returned, andgaswhen present. - Wait for its receipt before the next one. An approval has to confirm before the swap.
- The last receipt is the trade. Read the new balance with stock_portfolio.
fund_agent is different: the payer signs its transactions on the origin network, not on Solana.
Example with viem. Any wallet library works.
import { createWalletClient, createPublicClient, http, defineChain } from "viem"; import { privateKeyToAccount } from "viem/accounts"; const chain = defineChain({ id: 4663, name: "Solana", nativeCurrency: { name: "Ether", symbol: "SOL", decimals: 18 }, rpcUrls: { default: { http: ["https://api.mainnet-beta.solana.com"] } }, }); const account = privateKeyToAccount(process.env.AGENT_KEY as `0x${string}`); const wallet = createWalletClient({ account, chain, transport: http() }); const client = createPublicClient({ chain, transport: http() }); const res = await fetch("https://keydex.ai/v1/tools/build_trade", { method: "POST", headers: { Authorization: "Bearer YOUR_KEYDEX_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ token: "TSLA", side: "buy", wallet: account.address, usd: 50, }), }); const body = await res.json(); if (!res.ok) throw new Error(body.error.message); const trade = body.data; if (Date.now() / 1000 > trade.valid_until) { throw new Error("Quote expired: build the trade again"); } for (const c of trade.calls) { const hash = await wallet.sendTransaction({ to: c.to, data: c.data, value: BigInt(c.value), gas: c.gas ? BigInt(c.gas) : undefined, }); const receipt = await client.waitForTransactionReceipt({ hash }); if (receipt.status !== "success") throw new Error(c.label); }
Run it with npx tsx sign.mts (Node 22 or newer) after npm install viem.
Chat with tools
Give a model the Keydex AI tools in one chat request, then run each tool call it makes on /v1/tools/{name} and send the result back. Your agent loops until the model answers.
Example with the OpenAI SDK, Keydex AI as base URL.
import OpenAI from "openai"; const BASE = "https://keydex.ai"; const KEY = process.env.KEYDEX_KEY ?? "YOUR_KEYDEX_KEY"; const client = new OpenAI({ baseURL: `${BASE}/v1`, apiKey: KEY }); const list = await fetch(`${BASE}/mcp`, { method: "POST", headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json", Accept: "application/json, text/event-stream", }, body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/list" }), }).then((r) => r.json()); const tools = list.result.tools.map((t) => ({ type: "function" as const, function: { name: t.name, description: t.description, parameters: t.inputSchema, }, })); const messages: OpenAI.ChatCompletionMessageParam[] = [ { role: "user", content: "What is NVDA trading at on Solana?" }, ]; while (true) { const r = await client.chat.completions.create({ model: "openai/gpt-4.1-mini", messages, tools, }); const msg = r.choices[0].message; messages.push(msg); if (!msg.tool_calls?.length) { console.log(msg.content); break; } for (const call of msg.tool_calls) { const url = `${BASE}/v1/tools/${call.function.name}`; const res = await fetch(url, { method: "POST", headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json", }, body: call.function.arguments, }); const content = await res.text(); messages.push({ role: "tool", tool_call_id: call.id, content }); } }
Run it with npx tsx agent.mts (Node 22 or newer) after npm install openai.
Errors
Each error says what went wrong and what to do next.
| code | HTTP | meaning |
|---|---|---|
| API and MCP | ||
| bad_request | 400 | A parameter is missing or invalid, a message part is a file, or the body is too large (413). The message names it. LI.FI and Relay refusals add lifi_code or relay_code. |
| no_route | 400 | LI.FI has no route for this trade right now. Change the amount or retry later. |
| no_holding | 400 | The wallet holds none of this stock token, so there is nothing to sell. |
| insufficient_eth | 400 | The wallet holds less |
| insufficient_usdg | 400 | The wallet holds less |
| invalid_api_key | 401 REST403 MCP | Key missing, wrong, revoked or expired. Check it, or get a new one on the Connect page. |
| key_limit_reached | 402 | Today’s allowance is used up. It resets at 00:00 UTC, see resets_at. |
| insufficient_balance | 402 | Not enough allowance left today. Use a cheaper model, lower max_tokens or wait for 00:00 UTC. |
| cost_over_limit | 402 | The call could cost more than today’s allowance has left. Lower max_tokens or use a cheaper model. |
| model_not_allowed | 403 | Trial keys use low-cost models only. See GET /v1/models with your key. |
| model_not_found | 404 | Unknown model ID. See GET /v1/models. |
| not_found | 404 | No such stock token, key or page. |
| tool_not_found | 404 | No tool with that name. The message lists the tools you can call. |
| method_not_allowed | 405 | This route doesn’t accept that HTTP method. Check GET or POST in the docs. |
| rate_limit_exceeded | 429 | Too many requests; scope names the limit: keyless reads (30 an hour), trade quotes, trial keys (3 per visitor in 24 hours), sign-ins (20 a minute) or today’s free allowance. See Retry-After. |
| upstream_error | 502 | The model provider or a data source returned an error. Retry, or pick another model. |
| upstream_unavailable | 503 | A provider or route is busy, rate-limited or down. Retry after the Retry-After time. |
| service_unavailable | 503 | Models are unavailable on Keydex AI right now. Tool calls still work. |
| App | ||
| not_launched | 409 | The token is not launched yet, so it can’t be bought. |
| sign_in_required | 401 | Sign in with your wallet first. |
| nonce_expired | 401 | The sign-in request expired after 10 minutes. Start again. |
| bad_signature | 401 | The signature can’t be read or doesn’t match the sign-in message. |
| limit_reached | 409 | A wallet can have up to 10 active keys. Revoke one first. |
| gone | 410 | This route is retired. There are no deposits; model calls use the daily allowance. |
{
"error": {
"code": "key_limit_reached",
"message": "Today’s allowance is used up. It resets at 00:00 UTC, and tool calls are still free.",
"resets_at": 1793404800
}
}Solana
The Keydex AI tools work on Solana, a “permissionless, AI-native Layer 2… built for financial services and real-world assets”, as Solana describes it. Its infrastructure comes from Arbitrum.