KeydexAI

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

POST/v1/chat/completions

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?"
      }
    ]
  }'

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
curl "https://keydex.ai/v1/tools/stock_quote?ticker=NVDA" \
  -H "Authorization: Bearer YOUR_KEYDEX_KEY"
Over MCP, your agent calls the tools itself.

Streaming

Set stream to true to get the reply as server-sent events. The stream ends with data: [DONE].

cURL
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?"
      }
    ]
  }'
Response
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.

Request
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
curl -X POST https://keydex.ai/api/trial
200 OK
{
  "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
curl https://keydex.ai/v1/key \
  -H "Authorization: Bearer YOUR_KEYDEX_KEY"
200 OK
{
  "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

Example models with ID and context size
ModelidContext
GPT-4.1 Miniopenai/gpt-4.1-mini
GPT-6.1 Terra Proopenai/gpt-6.1-terra-pro
GPT-6.1 Terraopenai/gpt-6.1-terra
Claude Fable 5.2anthropic/claude-fable-5.2
Claude Haiku 5.5anthropic/claude-haiku-5.5
Gemini Omni 1.2 Flashgoogle/gemini-omni-1.2-flash
Gemini Omni 1.1 Flashgoogle/gemini-omni-1.1-flash
Grok 4.7x-ai/grok-4.7
Grok 4.6x-ai/grok-4.6
DeepSeek V4.1 Flashdeepseek/deepseek-v4.1-flash
DeepSeek V4 Pro 0423deepseek/deepseek-v4-pro
Qwen3.8 Max Primeqwen/qwen3.8-max-prime

—

cURL
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"

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
curl "https://keydex.ai/v1/tools/stock_quote?ticker=NVDA" \
  -H "Authorization: Bearer YOUR_KEYDEX_KEY"
200 OK
{
  "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
curl -G https://keydex.ai/v1/tools/stock_portfolio \
  --data-urlencode wallet=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 \
  -H "Authorization: Bearer YOUR_KEYDEX_KEY"
200 OK
{
  "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
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
  }'
200 OK
{
  "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
  • avalanche
  • linea
  • scroll
  • zksync
  • mode
  • zora
  • mantle
  • unichain
  • 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
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"
  }'
200 OK
{
  "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
curl https://keydex.ai/v1/stocks
200 OK
{
  "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.

  1. Take each item of calls in the order given. A sale may start with an approval.
  2. Check valid_until. If it has passed, build the trade again.
  3. Sign and send it from the wallet address on Solana (chain ID 4663), with to, data and value as returned, and gas when present.
  4. Wait for its receipt before the next one. An approval has to confirm before the swap.
  5. 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.

sign.mts
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.

agent.mts
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.

Error codes, HTTP status and what to do
codeHTTPmeaning
API and MCP
bad_request400A 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_route400LI.FI has no route for this trade right now. Change the amount or retry later.
no_holding400The wallet holds none of this stock token, so there is nothing to sell.
insufficient_eth400The wallet holds less SOL than the buy needs with gas. The message gives both amounts. Fund it with fund_agent.
insufficient_usdg400The wallet holds less USDG than the Morpho deposit needs. The message gives both amounts.
invalid_api_key401 REST403 MCPKey missing, wrong, revoked or expired. Check it, or get a new one on the Connect page.
key_limit_reached402Today’s allowance is used up. It resets at 00:00 UTC, see resets_at.
insufficient_balance402Not enough allowance left today. Use a cheaper model, lower max_tokens or wait for 00:00 UTC.
cost_over_limit402The call could cost more than today’s allowance has left. Lower max_tokens or use a cheaper model.
model_not_allowed403Trial keys use low-cost models only. See GET /v1/models with your key.
model_not_found404Unknown model ID. See GET /v1/models.
not_found404No such stock token, key or page.
tool_not_found404No tool with that name. The message lists the tools you can call.
method_not_allowed405This route doesn’t accept that HTTP method. Check GET or POST in the docs.
rate_limit_exceeded429Too 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_error502The model provider or a data source returned an error. Retry, or pick another model.
upstream_unavailable503A provider or route is busy, rate-limited or down. Retry after the Retry-After time.
service_unavailable503Models are unavailable on Keydex AI right now. Tool calls still work.
App
not_launched409The token is not launched yet, so it can’t be bought.
sign_in_required401Sign in with your wallet first.
nonce_expired401The sign-in request expired after 10 minutes. Start again.
bad_signature401The signature can’t be read or doesn’t match the sign-in message.
limit_reached409A wallet can have up to 10 active keys. Revoke one first.
gone410This route is retired. There are no deposits; model calls use the daily allowance.
402
{
  "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.

Solana.com/us/en/crypto/chain