Voyager docs
Voyager is a swap rail for AI agents. Each agent has its own Solana wallet and an API key. Every call it makes, whether through MCP, the SDK or REST, goes through the same checks against the limits its owner set, then routes through Jupiter for the best price.
- Sign in with your wallet and create an agent.
- Fund the agent's wallet with only what it may trade, plus about 0.02 SOL for network fees.
- Set its limits, create an API key, and connect your agent with one of the options below.
Before you fund an agent, read Safety and risks.
Connect
Every option sends the agent's API key as Authorization: Bearer …. Clients that can't send a header can run the local MCP server instead.
Claude
Claude Desktop or claude.ai: Customize → Connectors → Add custom connectorName: Voyager URL: https://www.runvoyager.com/api/mcp Then Connect: sign in with your wallet and choose the agent.
To use an API key instead, set Authentication to “No sign in” and add the request header Authorization: Bearer vgr_live_….
ChatGPT
chatgpt.com/plugins → + → Add custom MCP serverName: Voyager MCP server URL: https://www.runvoyager.com/api/mcp Authentication: OAuth Then sign in with your wallet, choose the agent and whether it may trade.
Custom MCP servers are added on chatgpt.com, and workspace admins may need to allow them.
Claude Code
Terminalclaude mcp add --transport http voyager https://www.runvoyager.com/api/mcp \ --header "Authorization: Bearer vgr_live_…"
Leave out --header to sign in with your wallet instead: run /mcp in Claude Code and choose Authenticate.
OpenAI API
Responses API, remote MCP tool (ChatGPT models)import OpenAI from "openai";
const openai = new OpenAI();
const response = await openai.responses.create({
model: "gpt-5",
input: "How much of my daily budget is left?",
tools: [{
type: "mcp",
server_label: "voyager",
server_url: "https://www.runvoyager.com/api/mcp",
headers: { Authorization: "Bearer vgr_live_…" },
require_approval: "never",
}],
});OpenAI Agents SDK
TypeScript, @openai/agentsimport { Agent, run, hostedMcpTool } from "@openai/agents";
const agent = new Agent({
name: "Trader",
instructions: "Trade on Solana within the owner's Voyager limits.",
tools: [hostedMcpTool({
serverLabel: "voyager",
serverUrl: "https://www.runvoyager.com/api/mcp",
headers: { Authorization: "Bearer vgr_live_…" },
requireApproval: "never",
})],
});
const result = await run(agent, "Swap $20 of USDC into SOL.");Cursor
~/.cursor/mcp.json (or .cursor/mcp.json in a project){
"mcpServers": {
"voyager": {
"url": "https://www.runvoyager.com/api/mcp",
"headers": { "Authorization": "Bearer ${env:VOYAGER_API_KEY}" }
}
}
}VS Code
.vscode/mcp.json (GitHub Copilot agent mode){
"inputs": [
{ "type": "promptString", "id": "voyager-key", "description": "Voyager API key", "password": true }
],
"servers": {
"voyager": {
"type": "http",
"url": "https://www.runvoyager.com/api/mcp",
"headers": { "Authorization": "Bearer ${input:voyager-key}" }
}
}
}Gemini CLI
Terminal, or ~/.gemini/settings.jsongemini mcp add --transport http \ --header "Authorization: Bearer vgr_live_…" \ voyager https://www.runvoyager.com/api/mcp
Codex
~/.codex/config.toml (OpenAI Codex)[mcp_servers.voyager] url = "https://www.runvoyager.com/api/mcp" bearer_token_env_var = "VOYAGER_API_KEY"
Windsurf
Cascade panel → … → Open MCP config file{
"mcpServers": {
"voyager": {
"serverUrl": "https://www.runvoyager.com/api/mcp",
"headers": { "Authorization": "Bearer ${env:VOYAGER_API_KEY}" }
}
}
}Zed
Zed settings.json{
"context_servers": {
"voyager": {
"url": "https://www.runvoyager.com/api/mcp",
"headers": { "Authorization": "Bearer vgr_live_…" }
}
}
}Cline
MCP Servers → Configure → cline_mcp_settings.json{
"mcpServers": {
"voyager": {
"type": "streamableHttp",
"url": "https://www.runvoyager.com/api/mcp",
"headers": { "Authorization": "Bearer vgr_live_…" }
}
}
}Local MCP
Any client that runs stdio servers, e.g. claude_desktop_config.json{
"mcpServers": {
"voyager": {
"command": "npx",
"args": ["-y", "@voyager/mcp"],
"env": {
"VOYAGER_API_KEY": "vgr_live_…",
"VOYAGER_BASE_URL": "https://www.runvoyager.com"
}
}
}
}TypeScript SDK
npm i @voyager/sdkimport { VoyagerClient, createVoyagerTools, toVercelAITools } from "@voyager/sdk";
const voyager = new VoyagerClient({ apiKey: process.env.VOYAGER_API_KEY!, baseUrl: "https://www.runvoyager.com" });
// Direct calls
await voyager.swap({ inputToken: "USDC", outputToken: "SOL", amountUsd: 25 });
// Or hand the tools to your framework (also: toOpenAITools, toAnthropicTools)
const tools = toVercelAITools(createVoyagerTools(voyager));REST
Any HTTP clientcurl -X POST https://www.runvoyager.com/api/v1/swaps \
-H "Authorization: Bearer vgr_live_…" \
-H "Content-Type: application/json" \
-d '{"inputToken":"USDC","outputToken":"SOL","amountUsd":25}'Tools
The same tools are served over MCP and returned by the SDK adapters.
get_accountReturns this agent's Solana wallet address, the spending policy its owner set (per-trade cap, daily and monthly caps, allowed tokens, max slippage, approval threshold) and how much budget is left. Call this before trading so you stay inside the limits.
get_balancesLists the tokens held by the agent's wallet with amounts and USD values.
search_tokensFinds Solana tokens by symbol, name or mint address. Returns mint, decimals, USD price, liquidity, and whether Jupiter has verified the token or flagged it as suspicious. Many scam tokens copy popular symbols, so use the returned mint address when trading anything outside the majors.
(query)
get_pricesCurrent USD prices for up to 50 tokens, with the 24h change in percent.
(tokens)
get_quoteQuotes a swap through Jupiter without executing it: expected output, minimum output after slippage, price impact, fees, and whether the owner's spending policy would allow it (policy.allowed, policy.requiresApproval, policy.violations). Give exactly one of amount or amountUsd.
(inputToken, outputToken, amount, amountUsd, slippageBps)
swapmoves fundsSwaps tokens from the agent's wallet through Jupiter, at the best route available, and waits for the result. The owner's spending policy is enforced: a trade over a limit is rejected with the rule it broke, and a trade over the approval threshold returns status "awaiting_approval" until the owner approves it in the dashboard. Give exactly one of amount or amountUsd. Pass an idempotencyKey if you might retry.
(inputToken, outputToken, amount, amountUsd, slippageBps, idempotencyKey)
get_tradeReturns the current status of a trade by ID, including the transaction signature and explorer link once it lands.
(tradeId)
list_tradesLists the agent's most recent trades, newest first, including rejected and pending ones.
(limit)
create_limit_ordermoves funds when the order firesPlaces a price-triggered order: when the trigger token's USD price crosses triggerPriceUsd in the given direction, Voyager swaps the input token for the output token at market. Use it for buy-the-dip ("buy SOL with 50 USDC if SOL goes below $120"), take-profit ("sell 2 SOL if SOL goes above $250") or stop-loss ("sell 2 SOL if SOL goes below $90"). Funds stay in the wallet until the order fires, and the spending policy is checked again at that moment.
(inputToken, outputToken, amount, amountUsd, condition, triggerPriceUsd, triggerToken, slippageBps, expiresInHours, idempotencyKey)
list_limit_ordersLists the agent's limit orders, optionally filtered by status (open, filled, cancelled, expired, failed).
(status)
cancel_limit_orderCancels an open limit order. Nothing moves on-chain, since funds never left the wallet.
(orderId)
REST API
Authenticate with Authorization: Bearer vgr_live_…. Bodies and responses are JSON.
| GET | /api/v1/account | Wallet address, spending policy and remaining budget |
| GET | /api/v1/balances | Wallet balances with USD values |
| GET | /api/v1/tokens/search?q= | Look up tokens by symbol, name or mint |
| GET | /api/v1/prices?tokens=SOL,JUP | USD prices for up to 50 tokens |
| POST | /api/v1/quote | Quote a swap and get the policy verdict, without executing |
| POST | /api/v1/swaps | Execute a swap (supports an Idempotency-Key header) |
| GET | /api/v1/trades | Recent trades, newest first |
| GET | /api/v1/trades/:id | One trade |
| POST | /api/v1/limit-orders | Create a price-triggered order |
| GET | /api/v1/limit-orders?status=open | List limit orders |
| DELETE | /api/v1/limit-orders/:id | Cancel an open limit order |
| POST | /api/mcp | MCP endpoint (Streamable HTTP) exposing the same operations as tools |
// POST /api/v1/swaps
{ "inputToken": "USDC", "outputToken": "SOL", "amountUsd": 25, "idempotencyKey": "rebalance-2026-10-21" }
// 200
{ "id": "trd_…", "status": "confirmed", "inAmount": "25", "outAmount": "0.2341…",
"usdValue": 25, "feeBps": 50, "signature": "5Kj…", "explorerUrl": "https://solscan.io/tx/5Kj…" }
// 403
{ "error": { "code": "policy_violation",
"message": "Trade would bring the last 24h total to $215.00, over the $200.00 daily limit ($25.00 left)",
"violations": [{ "rule": "daily_limit", "limit": 200, "attempted": 215 }] } }Errors
- policy_violation
- Blocked by the owner's limits. `violations[].rule` says which one; do not retry unchanged.
- insufficient_funds
- The wallet lacks the input token or SOL for fees.
- token_not_found / ambiguous_token
- Symbol not resolvable to one verified token. Use the mint address.
- invalid_request
- Bad input, e.g. both amount and amountUsd, or too many decimals.
- quote_failed / execution_failed
- Jupiter could not route or land the swap. Safe to retry with the same idempotency key.
- unauthorized
- Missing, invalid or revoked API key.
- rate_limited
- Over 60 requests per minute for this agent.
Policy rules
- max_per_trade
- Trade value over the per-trade cap
- daily_limit / monthly_limit
- Would exceed the rolling 24h / 30-day budget
- token_not_allowed
- A side of the trade is not on the allowlist
- unverified_token / suspicious_token
- Buying a token Jupiter has not verified, or has flagged
- slippage / price_impact
- Execution would exceed the owner's ceilings
- agent_paused
- The owner paused the agent
- limit_orders_disabled / max_open_orders
- Limit orders off, or too many open
Trade lifecycle
confirmedLanded on-chain.failedDid not land.rejectedBlocked by the policy before anything was signed.awaiting_approvalOver the owner's approval threshold; becomes confirmed, rejected or expired.submittedSent, outcome not yet known; it still counts against the budget until it settles.
Safety and risks
Voyager's checks narrow what an agent can do. They do not make trading safe.
- Limits cap exposure, not losses
- Your limits bound how much an agent can trade, not whether its trades are good. An agent can lose money on trades inside its limits.
- Not financial advice
- Voyager executes what your agent asks for. Nothing Voyager or your agent says is financial, investment or tax advice.
- Swaps are final
- Solana transactions cannot be reversed. Prices move between quote and execution, so a swap can fail or fill at a worse price within your slippage limit.
- Agent wallets are hot wallets
- Voyager creates each agent wallet and keeps its key encrypted on its servers so it can sign that agent's trades. Fund it only with what the agent may trade, and withdraw what it no longer needs.
- Guard your API keys
- Anyone with an agent's key can trade within that agent's limits. Store keys like passwords, revoke any that leak, and pause the agent if something looks wrong.
- Tokens carry their own risk
- Jupiter's token verification and Voyager's checks reduce, but do not remove, the risk of scam, illiquid or volatile tokens.
- Early software
- Voyager is new and depends on Jupiter and the Solana network. Start with small limits, review your agent's activity, and comply with the laws and tax rules that apply to you.