Voyager

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.

  1. Sign in with your wallet and create an agent.
  2. Fund the agent's wallet with only what it may trade, plus about 0.02 SOL for network fees.
  3. 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 connector
Name:  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 server
Name:            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

Terminal
claude 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/agents
import { 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.json
gemini 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/sdk
import { 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 client
curl -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_account

Returns 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_balances

Lists the tokens held by the agent's wallet with amounts and USD values.

search_tokens

Finds 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_prices

Current USD prices for up to 50 tokens, with the 24h change in percent.

(tokens)

get_quote

Quotes 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 funds

Swaps 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_trade

Returns the current status of a trade by ID, including the transaction signature and explorer link once it lands.

(tradeId)

list_trades

Lists the agent's most recent trades, newest first, including rejected and pending ones.

(limit)

create_limit_ordermoves funds when the order fires

Places 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_orders

Lists the agent's limit orders, optionally filtered by status (open, filled, cancelled, expired, failed).

(status)

cancel_limit_order

Cancels 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/accountWallet address, spending policy and remaining budget
GET/api/v1/balancesWallet balances with USD values
GET/api/v1/tokens/search?q=Look up tokens by symbol, name or mint
GET/api/v1/prices?tokens=SOL,JUPUSD prices for up to 50 tokens
POST/api/v1/quoteQuote a swap and get the policy verdict, without executing
POST/api/v1/swapsExecute a swap (supports an Idempotency-Key header)
GET/api/v1/tradesRecent trades, newest first
GET/api/v1/trades/:idOne trade
POST/api/v1/limit-ordersCreate a price-triggered order
GET/api/v1/limit-orders?status=openList limit orders
DELETE/api/v1/limit-orders/:idCancel an open limit order
POST/api/mcpMCP 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

  • confirmed Landed on-chain.
  • failed Did not land.
  • rejected Blocked by the policy before anything was signed.
  • awaiting_approval Over the owner's approval threshold; becomes confirmed, rejected or expired.
  • submitted Sent, 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.