# Jupiter CLI Source: https://dev.jup.ag/docs/ai/cli Trade on Jupiter from your terminal, Telegram, or through AI agents. The Jupiter CLI (`jup`) lets you interact with Jupiter's products from the command line. Trade spot, open perps positions, earn yield, and more. The CLI is pre-v1 (early alpha) and should be considered unstable. Breaking changes may be introduced without warning. ## Install ```bash theme={null} npm i -g @jup-ag/cli ``` For other install methods (install script, standalone binary), see the [CLI repository](https://github.com/jup-ag/cli). ## Usage The CLI covers Jupiter products like Spot (swaps, portfolio, transfers), Perps (leveraged longs/shorts), and Lend (earn yield on deposits). For the full command reference, key management, configuration, and examples, see the full [CLI documentation](https://github.com/jup-ag/cli/tree/main/docs) in the public CLI repository. ## Ways to Use ### Terminal The most direct way. Install, add a key, and start trading: ```bash theme={null} jup keys add mykey jup spot swap --from SOL --to USDC --amount 1 ``` ### Telegram Use the CLI through [OpenClaw](https://openclaw.ai), an open-source AI assistant that runs locally and connects to Telegram and other chat apps (WhatsApp, Discord, Slack, Signal). 1. Install OpenClaw: ```bash theme={null} curl -fsSL https://openclaw.ai/install.sh | bash ``` 2. Connect your Telegram account by following the [OpenClaw setup guide](https://openclaw.ai) 3. Install the Jupiter CLI: ```bash theme={null} npm i -g @jup-ag/cli ``` 4. Add a key: ```bash theme={null} jup keys add mykey ``` 5. Message your OpenClaw bot on Telegram: > "Swap 1 SOL to USDC" OpenClaw executes the CLI command on your behalf and returns the result in chat. For a more lightweight starting point, check out [miniclaw](https://github.com/yoeven/miniclaw), a minimal open-source personal AI assistant you can run locally with Telegram. ### AI Agents The CLI is designed to be LLM-friendly. All commands are non-interactive and support JSON output for structured, parseable responses. ```bash theme={null} jup spot swap --from SOL --to USDC --amount 1 -f json ``` AI agents (Claude Code, Cursor, Codex, etc.) can invoke CLI commands directly through shell access. Point your agent at the [CLI documentation on GitHub](https://github.com/jup-ag/cli/tree/main/docs) for complete command references and JSON response schemas. Set an API key from [Portal](https://developers.jup.ag/portal) for higher rate limits when running automated workflows: ```bash theme={null} jup config set --api-key ``` ## Resources Full command reference, key management, configuration, and examples. Get an API key for higher rate limits. # AI Source: https://dev.jup.ag/docs/ai/index Connect your AI agent to Jupiter's APIs and docs Jupiter's APIs are AI-native: no RPC, clean JSON, simple REST. Whether your agent is running locally or on a hosted platform, there's a way to connect it to Jupiter. ## Pick the Right Tool Which tools to use depends on where your agent runs and what it needs to do: | Goal | Local (Claude Code, Cursor, Codex) | Hosted (ChatGPT, Claude.ai) | | ---------------------- | ---------------------------------- | --------------------------- | | **Read the docs** | Skills + llms.txt | Docs MCP + llms.txt | | **Execute operations** | CLI | Jupiter MCP | **Local agents** have shell access, can install packages and run commands. The CLI + Skills combination integrates naturally into these environments. **Hosted agents** cannot install tools or execute shell commands. MCP exposes Jupiter's capabilities as a network service that any agent can discover and call without prior setup. ## Read the Docs For agents that need to discover and understand Jupiter's APIs before writing code or taking action. LLM-optimised documentation index. Works everywhere, no setup required. Pre-built context files that give coding agents structured integration guidance for Jupiter's APIs. Search and query Jupiter docs via Model Context Protocol. For agents without filesystem access. ## Execute Operations For agents that interact with Jupiter directly - swap tokens, check prices, place orders. Trade from your terminal, Telegram, or through AI agents. Non-interactive, JSON-native, designed for both humans and LLMs. Execute Jupiter operations via MCP from any hosted platform. Coming soon. # llms.txt Source: https://dev.jup.ag/docs/ai/llms-txt Structured documentation index optimised for LLM and AI agent consumption. Jupiter provides structured documentation files purpose-built for LLMs and AI agents, following the [llmstxt.org](https://llmstxt.org) standard. Jupiter's `llms.txt` is auto-generated from the documentation structure. Every page includes an `llmsDescription` field in its frontmatter, a description specifically optimised for LLM consumption, separate from the human-readable description. This ensures AI tools get the most relevant context for each page. ## llms.txt A plain Markdown file containing a structured index of all Jupiter documentation with titles and descriptions for each page: * **Site title** as an H1 heading * **Sections** for each major area (Docs, API References, Guides, Tool Kits, etc) * **Links with descriptions** for every page Open the llms.txt for Jupiter docs ```mdx theme={null} # Jupiter ## Docs - [Build with Jupiter](https://developers.jup.ag/docs/index.md) - [Get Started](https://developers.jup.ag/docs/get-started/index.md): Welcome to Jupiter's Developer Docs... - [Overview](https://developers.jup.ag/docs/swap/index.md): One API for all swap use cases on Jupiter. - [API Reference](https://developers.jup.ag/docs/api-reference/index.md): Overview of Jupiter API Reference ``` This is the perfect entrypoint for LLMs and AI agents to get started. It allows them to efficiently locate relevant content at a high level without processing the entire documentation. ## llms-full.txt Open the llms-full.txt for Jupiter docs While `llms.txt` provides a concise index, `llms-full.txt` contains the **entire documentation site** as context, including every description, code example, and parameter detail. Use `llms-full.txt` when: * Your AI tool needs **complete, granular context** for deep indexing * You're building **custom RAG pipelines** over Jupiter docs * You want **every code example** available for reference ## Markdown Export Any documentation page can be accessed as raw markdown, making it easy for AI agents to consume individual pages programmatically. **Method 1: Append `.md` to the URL** ```bash theme={null} curl https://developers.jup.ag/docs/swap.md curl https://developers.jup.ag/docs/swap/order-and-execute.md ``` **Method 2: Use the `Accept` header** ```bash theme={null} curl -H "Accept: text/markdown" https://developers.jup.ag/docs/swap ``` Both methods return the page content as `text/markdown`. # Documentation MCP Source: https://dev.jup.ag/docs/ai/mcp Search and query Jupiter docs and APIs from your AI editor via Model Context Protocol. Jupiter supports the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) through Mintlify's native integration. This lets AI tools search and query Jupiter's documentation and API specifications directly from your editor. ## What is MCP? MCP is an open protocol that connects AI assistants to external data sources and tools. With Jupiter's MCP server, your AI editor can: * **Search documentation**: find relevant API endpoints, guides, and references * **Read OpenAPI specs**: access full request/response schemas * **Understand API contracts**: look up parameters, response fields, and error codes This is a read-only documentation server. It helps your AI assistant understand Jupiter's APIs, but does not execute API calls. For trading via AI tools, see [Jupiter CLI](/docs/ai/cli). ## Mintlify Native MCP Every Mintlify documentation site includes a built-in MCP server. Jupiter's is available at: ``` https://developers.jup.ag/docs/mcp ``` This server exposes all Jupiter documentation and OpenAPI specifications through the MCP protocol, with no additional setup required. ## What You Get Once connected, your AI assistant can search and read: | Resource | Description | | :------------------------- | :----------------------------------------------------- | | **Documentation pages** | All guides, tutorials, and reference docs | | **OpenAPI specifications** | Complete API schemas for Swap, Tokens, Price, and more | | **Error references** | Common error codes and troubleshooting guides | Combine MCP with [llms.txt](/docs/ai/llms-txt) for the best results: use MCP for in-editor queries and llms.txt for batch processing or RAG pipelines. ## Setup **How to enable Jupiter MCP in Claude Code:** 1. Open your terminal. 2. Add Jupiter's MCP server by running: ```bash theme={null} claude mcp add --scope user --transport http jupiter https://developers.jup.ag/docs/mcp ``` 3. Launch Claude Code and start chatting with Jupiter. **Or add to your project’s `.mcp.json`:** ```json theme={null} { "mcpServers": { "jupiter": { "url": "https://developers.jup.ag/docs/mcp" } } } ``` **Verify with:** ```bash theme={null} claude mcp list ``` **Setup Jupiter MCP in Claude:** 1. Go to [**Connectors**](https://claude.ai/settings/connectors) in your Claude settings. 2. Select **Add custom connector**. 3. Set the name to **Jupiter** and the URL to **[https://developers.jup.ag/docs/mcp](https://developers.jup.ag/docs/mcp)**. 4. When chatting, click the attachments button (plus icon) and select the Jupiter connector. **Setup Jupiter MCP in Cursor:** 1. Open the command palette with `Cmd + Shift + P` (or `Ctrl + Shift + P` on Windows). 2. Search for **Open MCP settings**. 3. Add the following to your `mcp.json` file: ```json theme={null} { "mcpServers": { "jupiter": { "url": "https://developers.jup.ag/docs/mcp" } } } ``` 4. Save and reload Cursor. **Using Jupiter MCP in Windsurf:** 1. Open the command palette with `Cmd + Shift + P` (or `Ctrl + Shift + P` on Windows). 2. Search for **Windsurf: Configure MCP Servers**. 3. Add the following to your `mcp_config.json` file: ```json theme={null} { "mcpServers": { "jupiter": { "serverUrl": "https://developers.jup.ag/docs/mcp" } } } ``` 4. Save and restart Windsurf. ### Other MCP-Compatible Tools Any tool that supports the MCP protocol can connect to `https://developers.jup.ag/docs/mcp` using HTTP transport. # Skills Source: https://dev.jup.ag/docs/ai/skills Pre-built agent skills for integrating Jupiter APIs into AI coding agents. Jupiter's [agent skills repository](https://github.com/jup-ag/agent-skills) provides structured context that AI coding agents use when building with Jupiter APIs. Each skill is a `SKILL.md` file containing integration guidance, API playbooks, code examples, and best practices that your AI agent consumes as reference material. ## Available Skills ### integrating-jupiter Comprehensive integration guidance for all Jupiter APIs. This is the starting point for any Jupiter integration. | Category | Description | | :----------------- | :-------------------------------------------------------------------------------------------------------------------- | | Swap | Flagship swap API with managed execution (`/order` + `/execute`), custom transactions (`/build`), and gasless support | | Lend | Deposit and withdraw assets to earn yield | | Perps | Perpetual futures trading | | Trigger | Limit orders with price conditions | | Recurring | Dollar-cost averaging (DCA) strategies | | Token | Token metadata, search, and organic scoring | | Price | Real-time and historical pricing | | Portfolio | DeFi wallet positions across protocols | | Prediction Markets | Binary outcome markets with JupUSD | | Send | Token transfers via invite links | | Studio | Token creation with Dynamic Bonding Curves | | Lock | Token vesting and lock | | Routing | DEX aggregation, RFQ integration, and market listing | The skill includes an intent router that maps developer goals to the right API, complete endpoint references, error handling patterns, and production hardening recommendations. **Install:** ```bash theme={null} npx skills add jup-ag/agent-skills --skill "integrating-jupiter" ``` ### jupiter-lend Deep-dive integration guidance for Jupiter Lend (powered by Fluid Protocol). Use this when building lending and borrowing features. | Category | Description | | :----------------- | :------------------------------------------------------------------------------------ | | Key Concepts | Protocol architecture, jlTokens, exchange prices, collateral factors, sentinel values | | Liquidity | Querying liquidity pool data, interest rates, and supply/borrow positions | | Lending (jlTokens) | Depositing and withdrawing assets to earn yield via `@jup-ag/lend` | | Vaults | Collateral deposits, borrowing, repaying, and position management | | Flashloans | Uncollateralised loans for atomic operations | | Build Kit | UI components, utilities, and documentation index for frontend integration | The skill covers both the read SDK (`@jup-ag/lend-read`) for querying data and the write SDK (`@jup-ag/lend`) for building transactions, with complete working examples. **Install:** ```bash theme={null} npx skills add jup-ag/agent-skills --skill "jupiter-lend" ``` ## How Skills Work Skills follow the [Agent Skills](https://agentskills.io) specification. Each skill is a `SKILL.md` file with structured frontmatter (name, description, tags) and Markdown content that AI agents consume as context. When you install a skill, it's added to your project so your AI coding agent (Claude Code, Cursor, Codex, etc.) can reference it when writing code. The agent uses the skill's guidance to choose the right API, construct correct requests, handle errors, and follow best practices. ```bash theme={null} # Install all Jupiter skills (requires Node.js) npx skills add jup-ag/agent-skills # Install a specific skill npx skills add jup-ag/agent-skills --skill "integrating-jupiter" ``` ## skill.md Jupiter's documentation also exposes a machine-readable skill file at [`developers.jup.ag/docs/skill.md`](https://developers.jup.ag/docs/skill.md). This is a high-level navigator that points AI agents to the available skills and their capabilities, following the [Mintlify skill.md](https://mintlify.com/docs/ai/skillmd) specification. ## Contributing The skills repository is open source. You can contribute new skills, improve existing ones, or adapt them for your use case. Source code, skill definitions, and contribution guidelines. # Deposit Source: https://dev.jup.ag/docs/api-reference/lend/earn/deposit /openapi-spec/lend/lend.yaml post /earn/deposit Request for a base64-encoded unsigned earn deposit transaction to deposit assets # Deposit Instructions Source: https://dev.jup.ag/docs/api-reference/lend/earn/deposit-instructions /openapi-spec/lend/lend.yaml post /earn/deposit-instructions Request for the instruction of an earn deposit transaction to deposit assets # Earnings Source: https://dev.jup.ag/docs/api-reference/lend/earn/earnings /openapi-spec/lend/lend.yaml get /earn/earnings Request for the earnings of one or multiple positions of a user # Mint Source: https://dev.jup.ag/docs/api-reference/lend/earn/mint /openapi-spec/lend/lend.yaml post /earn/mint Request for a base64-encoded unsigned earn mint transaction to mint shares # Mint Instructions Source: https://dev.jup.ag/docs/api-reference/lend/earn/mint-instructions /openapi-spec/lend/lend.yaml post /earn/mint-instructions Request for the instruction of an earn mint transaction to mint shares # Positions Source: https://dev.jup.ag/docs/api-reference/lend/earn/positions /openapi-spec/lend/lend.yaml get /earn/positions Request for the position data of one or multiple users # Redeem Source: https://dev.jup.ag/docs/api-reference/lend/earn/redeem /openapi-spec/lend/lend.yaml post /earn/redeem Request for a base64-encoded unsigned earn redeem transaction to redeem shares # Redeem Instructions Source: https://dev.jup.ag/docs/api-reference/lend/earn/redeem-instructions /openapi-spec/lend/lend.yaml post /earn/redeem-instructions Request for the instruction of an earn redeem transaction to redeem shares # Tokens Source: https://dev.jup.ag/docs/api-reference/lend/earn/tokens /openapi-spec/lend/lend.yaml get /earn/tokens Request for the tokens available to be deposited and their information # Withdraw Source: https://dev.jup.ag/docs/api-reference/lend/earn/withdraw /openapi-spec/lend/lend.yaml post /earn/withdraw Request for a base64-encoded unsigned earn withdraw transaction to withdraw assets # Withdraw Instructions Source: https://dev.jup.ag/docs/api-reference/lend/earn/withdraw-instructions /openapi-spec/lend/lend.yaml post /earn/withdraw-instructions Request for the instruction of an earn withdraw transaction to withdraw assets # Get Platforms Source: https://dev.jup.ag/docs/api-reference/portfolio/get-platforms /openapi-spec/portfolio/portfolio.yaml get /platforms Request for platform information # Get Positions Source: https://dev.jup.ag/docs/api-reference/portfolio/get-positions /openapi-spec/portfolio/portfolio.yaml get /positions/{address} Request for Jupiter positions of an address # Get Staked JUP Source: https://dev.jup.ag/docs/api-reference/portfolio/get-staked-jup /openapi-spec/portfolio/portfolio.yaml get /staked-jup/{address} Request for staked JUP information of an address # Claim Position Source: https://dev.jup.ag/docs/api-reference/prediction/claim-position /openapi-spec/prediction/prediction.yaml post /positions/{positionPubkey}/claim Request an unsigned transaction to claim payout from a winning position # Close All Positions Source: https://dev.jup.ag/docs/api-reference/prediction/close-all-positions /openapi-spec/prediction/prediction.yaml delete /positions Request unsigned transactions to close all open positions # Close Position Source: https://dev.jup.ag/docs/api-reference/prediction/close-position /openapi-spec/prediction/prediction.yaml delete /positions/{positionPubkey} Request an unsigned transaction to sell all contracts in a position # Create Order Source: https://dev.jup.ag/docs/api-reference/prediction/create-order /openapi-spec/prediction/prediction.yaml post /orders Request an unsigned transaction to create a new order # Get Event Source: https://dev.jup.ag/docs/api-reference/prediction/get-event /openapi-spec/prediction/prediction.yaml get /events/{eventId} Get detailed information about a specific event # Get Event Market Source: https://dev.jup.ag/docs/api-reference/prediction/get-event-market /openapi-spec/prediction/prediction.yaml get /events/{eventId}/markets/{marketId} Get detailed market information for a specific market within an event # Get Event Markets Source: https://dev.jup.ag/docs/api-reference/prediction/get-event-markets /openapi-spec/prediction/prediction.yaml get /events/{eventId}/markets Get all markets for a specific event # Get Events Source: https://dev.jup.ag/docs/api-reference/prediction/get-events /openapi-spec/prediction/prediction.yaml get /events Get a list of all available prediction events with optional filtering and pagination # Get History Source: https://dev.jup.ag/docs/api-reference/prediction/get-history /openapi-spec/prediction/prediction.yaml get /history Get trading history and event records for an account # Get Leaderboards Source: https://dev.jup.ag/docs/api-reference/prediction/get-leaderboards /openapi-spec/prediction/prediction.yaml get /leaderboards Get leaderboard rankings by various metrics # Get Market Source: https://dev.jup.ag/docs/api-reference/prediction/get-market /openapi-spec/prediction/prediction.yaml get /markets/{marketId} Get detailed market information by market ID # Get Order Source: https://dev.jup.ag/docs/api-reference/prediction/get-order /openapi-spec/prediction/prediction.yaml get /orders/{orderPubkey} Get detailed information about a specific order # Get Order Status Source: https://dev.jup.ag/docs/api-reference/prediction/get-order-status /openapi-spec/prediction/prediction.yaml get /orders/status/{orderPubkey} Get the latest status and history for an order # Get Orderbook Source: https://dev.jup.ag/docs/api-reference/prediction/get-orderbook /openapi-spec/prediction/prediction.yaml get /orderbook/{marketId} Get orderbook data for a specific market # Get Orders Source: https://dev.jup.ag/docs/api-reference/prediction/get-orders /openapi-spec/prediction/prediction.yaml get /orders Get a list of orders with optional filtering by owner or market # Get PnL History Source: https://dev.jup.ag/docs/api-reference/prediction/get-pnl-history /openapi-spec/prediction/prediction.yaml get /profiles/{ownerPubkey}/pnl-history Get historical PnL data for charting # Get Position Source: https://dev.jup.ag/docs/api-reference/prediction/get-position /openapi-spec/prediction/prediction.yaml get /positions/{positionPubkey} Get detailed information about a specific position # Get Positions Source: https://dev.jup.ag/docs/api-reference/prediction/get-positions /openapi-spec/prediction/prediction.yaml get /positions Get a list of positions with optional filtering # Get Profile Source: https://dev.jup.ag/docs/api-reference/prediction/get-profile /openapi-spec/prediction/prediction.yaml get /profiles/{ownerPubkey} Get profile statistics for a user # Get Suggested Events Source: https://dev.jup.ag/docs/api-reference/prediction/get-suggested-events /openapi-spec/prediction/prediction.yaml get /events/suggested/{pubkey} Get personalized event suggestions based on user activity # Get Trades Source: https://dev.jup.ag/docs/api-reference/prediction/get-trades /openapi-spec/prediction/prediction.yaml get /trades Get recent filled trades across all markets # Get Trading Status Source: https://dev.jup.ag/docs/api-reference/prediction/get-trading-status /openapi-spec/prediction/prediction.yaml get /trading-status Get current trading status of the prediction market # Get Vault Info Source: https://dev.jup.ag/docs/api-reference/prediction/get-vault-info /openapi-spec/prediction/prediction.yaml get /vault-info Get vault account information and balance # Search Events Source: https://dev.jup.ag/docs/api-reference/prediction/search-events /openapi-spec/prediction/prediction.yaml get /events/search Search for events by title or keyword # Price Source: https://dev.jup.ag/docs/api-reference/price/index /openapi-spec/price/v3/price.yaml get /price/v3 Returns prices of specified tokens # Cancel Order Source: https://dev.jup.ag/docs/api-reference/recurring/cancel-order /openapi-spec/recurring/recurring.yaml post /cancelOrder Request for a base64-encoded unsigned recurring order cancellation transaction to be used in POST /recurring/v1/execute **NOTE** * `recurringType` is used to denote the type of recurring order, only `time` * **DEPRECATED**: `recurringType: price` based orders are deprecated * Refer to [Recurring API doc](/docs/recurring/cancel-order) for more information. # Create Order Source: https://dev.jup.ag/docs/api-reference/recurring/create-order /openapi-spec/recurring/recurring.yaml post /createOrder Request for a base64-encoded unsigned recurring order creation transaction to be used in POST /recurring/v1/execute **NOTE** * Pass in the correct recurring type in the `params` field, only `time` * **DEPRECATED**: `params.price` based orders are deprecated * Refer to [Recurring API doc](/docs/recurring/create-order) for more information. # Execute Source: https://dev.jup.ag/docs/api-reference/recurring/execute /openapi-spec/recurring/recurring.yaml post /execute Execute the signed transaction and get the execution status # Get Recurring Orders Source: https://dev.jup.ag/docs/api-reference/recurring/get-recurring-orders /openapi-spec/recurring/recurring.yaml get /getRecurringOrders Request for active or historical recurring orders associated to the provided account **NOTE** * `recurringType` is used to denote the type of recurring order, only `time` * **DEPRECATED**: `recurringType: price` based orders are deprecated # Price Deposit Source: https://dev.jup.ag/docs/api-reference/recurring/price-deposit /openapi-spec/recurring/recurring.yaml post /priceDeposit Request for a base64-encoded unsigned price-based recurring order deposit transaction. Price-based recurring orders are deprecated, please use time-based recurring orders instead # Price Withdraw Source: https://dev.jup.ag/docs/api-reference/recurring/price-withdraw /openapi-spec/recurring/recurring.yaml post /priceWithdraw Request for a base64-encoded unsigned price-based recurring order withdrawal transaction. Price-based recurring orders are deprecated, please use time-based recurring orders instead # Craft Clawback Source: https://dev.jup.ag/docs/api-reference/send/craft-clawback /openapi-spec/send/send.yaml post /craft-clawback Request for a base64-encoded unsigned Send transaction # Craft Send Source: https://dev.jup.ag/docs/api-reference/send/craft-send /openapi-spec/send/send.yaml post /craft-send Request for a base64-encoded unsigned Send transaction # Invite History Source: https://dev.jup.ag/docs/api-reference/send/invite-history /openapi-spec/send/send.yaml get /invite-history Request for the invite history of an address # Pending Invites Source: https://dev.jup.ag/docs/api-reference/send/pending-invites /openapi-spec/send/send.yaml get /pending-invites Request for the pending invites of an address # DBC Fee Source: https://dev.jup.ag/docs/api-reference/studio/dbc-fee /openapi-spec/studio/studio.yaml post /dbc/fee Request for unclaimed creator trading fees of a Dynamic Bonding Curve pool # DBC Fee Create TX Source: https://dev.jup.ag/docs/api-reference/studio/dbc-fee-create-tx /openapi-spec/studio/studio.yaml post /dbc/fee/create-tx Request for a base64-encoded unsigned transaction to claim creator trading fees of a Dynamic Bonding Curve pool # DBC Pool Addresses by Mint Source: https://dev.jup.ag/docs/api-reference/studio/dbc-pool-addresses-by-mint /openapi-spec/studio/studio.yaml get /dbc-pool/addresses/{mint} Request for pool addresses for a given token mint # DBC Pool Create TX Source: https://dev.jup.ag/docs/api-reference/studio/dbc-pool-create-tx /openapi-spec/studio/studio.yaml post /dbc-pool/create-tx Request for a base64-encoded unsigned transaction to create a Dynamic Bonding Curve pool with token metadata # DBC Pool Submit Source: https://dev.jup.ag/docs/api-reference/studio/dbc-pool-submit /openapi-spec/studio/studio.yaml post /dbc-pool/submit Execute the signed transaction, and optionally upload content and header image # Build Transaction Source: https://dev.jup.ag/docs/api-reference/swap/build /openapi-spec/swap/v2/swap.yaml get /build Get a swap quote with raw instructions for building custom transactions # Execute Transaction Source: https://dev.jup.ag/docs/api-reference/swap/execute /openapi-spec/swap/v2/swap.yaml post /execute Execute a signed transaction from /order with managed landing # Get Order Source: https://dev.jup.ag/docs/api-reference/swap/order /openapi-spec/swap/v2/swap.yaml get /order Get a swap quote and assembled transaction # Category Source: https://dev.jup.ag/docs/api-reference/tokens/category /openapi-spec/tokens/v2/tokens.yaml get /{category}/{interval} Returns an array of mints and their information for the given category and interval # Get Content Source: https://dev.jup.ag/docs/api-reference/tokens/get-content /openapi-spec/content/content.yaml get /content Retrieves approved content for up to 50 Solana token mint addresses # Get Content Cooking Source: https://dev.jup.ag/docs/api-reference/tokens/get-content-cooking /openapi-spec/content/content.yaml get /content/cooking Retrieves approved content for currently trending tokens on Jupiter # Get Content Feed Source: https://dev.jup.ag/docs/api-reference/tokens/get-content-feed /openapi-spec/content/content.yaml get /content/feed Retrieves a paginated feed of content for a specific mint # Recent Source: https://dev.jup.ag/docs/api-reference/tokens/recent /openapi-spec/tokens/v2/tokens.yaml get /recent Returns an array of mints that recently had their first created pool # Search Source: https://dev.jup.ag/docs/api-reference/tokens/search /openapi-spec/tokens/v2/tokens.yaml get /search Request a search by token's symbol, name or mint address # Tag Source: https://dev.jup.ag/docs/api-reference/tokens/tag /openapi-spec/tokens/v2/tokens.yaml get /tag Request an array of mints and their information by a tag # Check Eligibility Source: https://dev.jup.ag/docs/api-reference/tokens/verify-check-eligibility /openapi-spec/tokens/v2/verification.yaml get /express/check-eligibility Check if a token is eligible for express verification and metadata updates # Craft Transaction Source: https://dev.jup.ag/docs/api-reference/tokens/verify-craft-txn /openapi-spec/tokens/v2/verification.yaml get /express/craft-txn Craft an unsigned 1000 JUP payment transaction for express verification # Execute Source: https://dev.jup.ag/docs/api-reference/tokens/verify-execute /openapi-spec/tokens/v2/verification.yaml post /express/execute Submit signed transaction with verification and metadata details # Submit Transaction Source: https://dev.jup.ag/docs/api-reference/transaction/submit /openapi-spec/transaction/transaction.yaml post /submit Submit a signed transaction through Jupiter's landing infrastructure # Cancel Order Source: https://dev.jup.ag/docs/api-reference/trigger/cancel-order /openapi-spec/trigger/v2/trigger.yaml post /orders/price/cancel/{orderId} Cancel a pending trigger order # Request Challenge Source: https://dev.jup.ag/docs/api-reference/trigger/challenge /openapi-spec/trigger/v2/trigger.yaml post /auth/challenge Request a sign-in challenge for wallet authentication # Confirm Cancel Source: https://dev.jup.ag/docs/api-reference/trigger/confirm-cancel /openapi-spec/trigger/v2/trigger.yaml post /orders/price/confirm-cancel/{orderId} Confirm and execute a pending order cancellation # Create Order Source: https://dev.jup.ag/docs/api-reference/trigger/create-order /openapi-spec/trigger/v2/trigger.yaml post /orders/price Create a new trigger order # Craft Deposit Source: https://dev.jup.ag/docs/api-reference/trigger/deposit-craft /openapi-spec/trigger/v2/trigger.yaml post /deposit/craft Craft a deposit transaction for the trigger vault # Order History Source: https://dev.jup.ag/docs/api-reference/trigger/order-history /openapi-spec/trigger/v2/trigger.yaml get /orders/history Get historical trigger orders for an account # Update Order Source: https://dev.jup.ag/docs/api-reference/trigger/update-order /openapi-spec/trigger/v2/trigger.yaml patch /orders/price/{orderId} Update parameters of an existing trigger order # Get Vault Source: https://dev.jup.ag/docs/api-reference/trigger/vault /openapi-spec/trigger/v2/trigger.yaml get /vault Get vault information and balance for an account # Register Vault Source: https://dev.jup.ag/docs/api-reference/trigger/vault-register /openapi-spec/trigger/v2/trigger.yaml get /vault/register Register a new trigger vault for the account # Verify Challenge Source: https://dev.jup.ag/docs/api-reference/trigger/verify /openapi-spec/trigger/v2/trigger.yaml post /auth/verify Submit the signed challenge to receive a JWT token # Changelog Source: https://dev.jup.ag/docs/changelog/index Latest announcements and breaking changes across Jupiter APIs. Follow our various announcements channels to stay up to date with recent updates and announcements. Discord Telegram *** ## Trigger API: Upcoming Craft Deposit Request Change **Action Required** - A breaking change is planned for Thursday, May 14, 2026 at 4:00 AM UTC / 12:00 PM SGT. Update Trigger V2 integrations that craft price-order deposits before enforcement. `POST https://api.jup.ag/trigger/v2/deposit/craft` will require explicit order metadata when crafting deposits for price orders: * Add `orderType: "price"` to the craft-deposit request body * Add `orderSubType: "single"`, `"oco"`, or `"otoco"` based on the order you will create * Requests that omit `orderType`, or omit `orderSubType` for price orders, will return a `4xx` after enforcement No change is required on `POST /trigger/v2/orders/price`. The deposit craft response may include `inputTokenAccount`, and includes `outputTokenAccount` for `orderSubType: "otoco"`. You do not need to pass those token account fields into the create-order request. * [Create Trigger Order](/docs/trigger/create-order) * [Craft Deposit API Reference](/docs/api-reference/trigger/deposit-craft) *** ## Prediction Markets API: Breaking Changes **Action Required** - Two breaking changes are rolling out in April 2026. Update your integration before the deadlines below. ### `markets[].metadata` removal - April 10, 2026 All fields previously nested under `markets[].metadata` are moving to the top level of the market object. This affects all `/events/*` and `/markets` GET endpoints. | Old path | New path | | :---------------------------------- | :------------------------- | | `markets[].metadata.title` | `markets[].title` | | `markets[].metadata.isTeamMarket` | `markets[].isTeamMarket` | | `markets[].metadata.rulesPrimary` | `markets[].rulesPrimary` | | `markets[].metadata.rulesSecondary` | `markets[].rulesSecondary` | | `markets[].metadata.openTime` | `markets[].openTime` | | `markets[].metadata.closeTime` | `markets[].closeTime` | After April 10, `markets[].metadata` will no longer be included in responses. Update your code to read these fields from the top-level market object. ### Minimum order size increase to \$5 - April 14, 2026 The minimum order amount is increasing from $1 to $5. Orders below $5 will be rejected starting April 14. Ensure all order amounts in your integration are at least $5. * [Prediction Market Docs](/docs/prediction) * [API Reference](/docs/api-reference/prediction/create-order) *** ## Transaction Submission API `POST https://api.jup.ag/tx/v1/submit` is now publicly available. Submit any signed Solana transaction through Jupiter's optimised landing infrastructure, including Jupiter Beam for sub-second landing and MEV protection. * Requires a minimum tip of 0.001 SOL to one of the supported tip receiver addresses * Works with any signed Solana transaction, not just Jupiter swaps - [Transaction Submission Docs](/docs/transaction/submit) - [API Reference](/docs/api-reference/transaction/submit) *** ## Swap API: RTSE Slippage Estimation Real-Time Slippage Estimation (RTSE) documentation is now available. RTSE estimates slippage based on current market conditions. * Automatic with `/order` - no configuration needed * Opt-in with `/build` via `slippageBps=rtse` - [Slippage Estimation (RTSE)](/docs/swap/advanced/slippage) *** ## VRFD Express Verification API The VRFD Express Verification API lets token projects verify their tokens on Jupiter through a three-step flow: 1. **Check eligibility** - confirm the token meets verification requirements 2. **Craft transaction** - build the verification transaction 3. **Execute verification** - submit and complete verification New Tokens documentation, API reference pages, and verification OpenAPI spec are now available. * [Verification Docs](/docs/tokens/verification) * [API Reference](/docs/api-reference/tokens/verify-check-eligibility) *** ## Jupiter Developer Platform Portal documentation has been rewritten for the Jupiter Developer Platform launch, covering the full platform experience: * **Setup** - creating an account and generating API keys * **Plans** - free and paid tiers with rate limits and features * **Rate Limits** - per-endpoint limits and how throttling works * **Migration** - moving from `lite-api.jup.ag` to `api.jup.ag` * **Responses** - standard response formats and error codes * **FAQ** - common questions and troubleshooting - [Get Started](/docs/portal/setup) - [Migration Guide](/docs/portal/migration) *** ## JupUSD and JUICED Developer Documentation Developer documentation for JupUSD and JUICED is now available: * **JupUSD** - mint and redeem Jupiter's native stablecoin, with API integration guides * **JUICED** - collateral integration documentation for leveraged vault positions - [JupUSD Docs](/docs/jupusd) - [JUICED Docs](/docs/jupusd/juiced) *** ## Swap API V2 The unified Swap API consolidates Ultra and Metis into a single entry point at `api.jup.ag/swap/v2`. Three endpoints: * **`GET /order`**: default path. Returns an assembled transaction with the best price across all routers (Metis, JupiterZ, Dflow, OKX). Includes RTSE, Jupiter Beam, gasless, and RFQ competition. Sign and send to `/execute`. * **`GET /build`**: advanced path. Returns raw swap instructions for building custom transactions (add custom instructions, CPI, composability). Metis-only routing, no Jupiter swap fees. * **`POST /execute`**: managed transaction landing for `/order` transactions. Start with the Meta-Aggregator (`/order`). It gives the best price because all routers compete, including JupiterZ market makers who often beat onchain routing on major pairs. Only use the Router (`/build`) if you need to modify the transaction. Ultra and Metis APIs remain available. New integrations should use the Swap API, and existing integrations are encouraged to migrate when convenient. See the [migration guides](/docs/swap/migration/metis-to-build) for details. * [Swap API overview](/docs/swap) * [Order & Execute](/docs/swap/order-and-execute) * [Build](/docs/swap/build) * [API Reference](/docs/api-reference/swap) *** ### Lend Earn API: Earnings endpoint schema change The `GET /lend/v1/earn/earnings` response schema has been updated: * **Removed:** `totalDeposits`, `totalWithdraws`, `totalBalance`, `totalAssets` fields * **Changed:** `earnings` type from `string` to `number` * **Added:** `slot` field (`number`) indicating the slot at which earnings were computed *** ## Trigger Order API V2 The Trigger Order API has been upgraded to V2 with a new authentication model and expanded capabilities: * **Authentication flow** - challenge-response auth using wallet signatures instead of API keys * **Vault registration** - register a vault to hold funds for trigger orders * **Create and manage orders** - create, update, and cancel limit and DCA orders * **Order history** - query active and historical orders with filtering The V1 API remains available but is no longer actively maintained. New integrations should use V2. * [Trigger Order V2 Docs](/docs/trigger) * [API Reference](/docs/api-reference/trigger/challenge) *** ## Jupiter CLI A new Jupiter CLI page is now available, along with a reworked AI section focused on trading and building workflows: * Use Jupiter APIs directly from the command line for swaps, price checks, and token lookups * AI docs reorganised around practical trading and building use cases - [Jupiter CLI](/docs/ai/cli) - [AI Overview](/docs/ai) *** ### Metis Swap API: `forJitoBundle` Parameter A new `forJitoBundle` parameter is available on the Metis Swap quote endpoint. When set to `true`, it excludes DEXes that are incompatible with Jito bundles, ensuring the resulting transaction can be submitted as part of a Jito bundle. * [Quote API Reference](/docs/api-reference/swap/v1/quote) *** ## Prediction Market API Jupiter Prediction Market API is now available in beta. Trade on the outcomes of real-world events across categories like Sports, Crypto, Politics, E-sports, Culture, Economics, and Tech. * Binary prediction markets on Solana with YES/NO contracts * Buy and sell contracts at dynamic prices reflecting market sentiment * Track positions, P\&L, and trading history via dedicated endpoints * Claim JupUSD payouts when predictions are correct The Prediction Market API is currently in beta and subject to breaking changes. *** ## Ultra Manual Mode Ultra now supports manual mode for integrators building user-facing trading UIs. Override automatic slippage, priority fee, and broadcast settings when explicit control over execution behaviour is needed. * Intended for manual trading experiences (similar to jup.ag's manual mode) or personal, self-directed usage * Default Ultra behaviour remains recommended for production integrations * Transactions with manual overrides fall outside Jupiter's supported execution model *** ## Portfolio API (Beta) The Jupiter Portfolio API is now available in beta, providing comprehensive portfolio tracking across the Solana ecosystem. * Query user DeFi positions across protocols on Solana (lending, staking, LP positions) * Retrieve staked JUP amounts * Built by the Sonarwatch team, now part of Jupiter *** ## Deprecate Lite API URL **Update (February 2026):** The deprecation has been postponed for a few months while we implement a new pricing structure. There is no immediate deadline, but we recommend migrating at your convenience. * We'll be deprecating the Lite API URL `lite-api.jup.ag`. * ~~This will take effect on 31st January 2026.~~ Postponed - new date TBA. * Please migrate to the API URL `api.jup.ag`. * The paths remain unchanged, only domain/hostname changes. * Generate an API key for free at [https://portal.jup.ag](https://portal.jup.ag). **Action Required** * **For free users**: Migrate to `api.jup.ag` **and use with an API key**. * **For paid users**: No action is required. * **For Ultra users**: If you are using `lite-api.jup.ag/ultra`, please migrate to `api.jup.ag/ultra` and use with an API key. *** ## Metis Binary Migration * [Tweet announcement](https://x.com/jupiterexchange/status/1990479870502031424?s=46) **Breaking Changes** * Migrated self-hosted binary to [https://metis.builders](https://metis.builders) * Renamed to `Metis Binary` * Requires a `BINARY_KEY` or `--binary-key` to authenticate the usage of the binary * Refer to [Binary Key](https://metis.builders/docs/binary-key) for more details *** ### Ultra API ### Deprecate `ctLikes` and `smartCtLikes` response field in search endpoint * We'll be deprecating the `ctLikes` and `smartCtLikes` response field in the search endpoints. * This will take effect next week and it affects the search endpoints in Ultra API. * If you are using the field for any purpose, please move off and stop using it. *** ### Tokens API ### Deprecate `ctLikes` and `smartCtLikes` response field in search endpoint * We'll be deprecating the `ctLikes` and `smartCtLikes` response field in the search endpoints. * This will take effect next week and it affects the search endpoints in Tokens API. * If you are using the field for any purpose, please move off and stop using it. *** ## Metis Swap API ### `routePlan[].percent` may return null * The `routePlan[].percent` field in the Metis Swap API quote response may return `null` - due to an an upgrade on the routing algorithm. * Please update your code to handle null values for this field. * This change will affect `instructionVersion=V2` only and has taken effect. * [npm package version 6.0.47](https://www.npmjs.com/package/@jup-ag/api/v/6.0.47) has been released with the latest schema. ### Deprecate `feeAmount` and `feeMint` fields in `SwapInfo` * We will be deprecating the `feeAmount` and `feeMint` fields from the `routePlan[].swapInfo` schema in a quote response. * Since `outAmount` already factor in these fees. * These fees are related to each AMM's own fee, not to any Jupiter or platform fees you may add. * To smooth the migration, we will just show `0` for `feeAmount` and the input mint as the `feeMint`. * Refer to [`SwapInfo` API Reference](/docs/api-reference/swap/v1/quote#response-route-plan-swap-info) for more details. * [npm package version 6.0.47](https://www.npmjs.com/package/@jup-ag/api/v/6.0.47) has been released with the latest schema. ### `nativeDestinationAccount` * We've added a new parameter to the Metis Swap API that lets you send native SOL directly to any account. * This is similar to `destinationTokenAccount`, but instead of receiving WSOL in a token account, you receive native SOL in a regular account. * Refer to [`nativeDestinationAccount` API Reference](/docs/api-reference/swap/v1/swap#body-native-destination-account) for more details. * [npm package version 6.0.46](https://www.npmjs.com/package/@jup-ag/api/v/6.0.46) has been released with the latest schema. *** ## Ultra Swap API ### `receiver` parameter * A new `receiver` parameter has been added to the Ultra Swap API. * This allows specifying a different wallet to receive the output tokens, decoupling the payer from the recipient. * Refer to the [Ultra API Reference](/docs/api-reference/ultra) for details. ## Ultra V3 We're excited to introduce Ultra V3, featuring major improvements on quoting and swap execution for the Ultra Swap API. * [Read the full technical deep dive in the Jupiter Developers Blog](https://developers.jup.ag/blog/ultra-v3). * **Improved Routers in Meta Aggregation**: Granular splitting of 0.01%; and began usage of Golden-section and Brent's method for routing algorithms. * **Ultra Signaling for Tighter Prop AMM Quotes**: Ultra signals to Prop AMMs, allowing them to confidently provide tighter quotes by distinguishing Ultra trades as "non-toxic" order flow from other "toxic" order flow - 3 bps tighter (50% better) quotes for our Ultra users compared to other platforms. * **Predictive Execution to Simulate Executable Price & Potential Slippage**: Simulates routes on-chain to verify executable price versus quote and predict potential slippage to select the route with the least overall incurred slippage at the time of execution. * **Jupiter Beam: Sub-Second Transaction Landing & MEV Protection**: Transaction sending infrastructure helps reduce landing time by 50-66% compared to traditional methods and significantly reduces MEV opportunities by 34x. * **Real-Time Slippage Estimator (RTSE) Optimizations**: Automatically prioritize slippage-protected routes over purely price-optimized routes and increase volatility sensitivity for tokens with high historical volatility patterns. * **Gasless Support Coverage**: Expanded gasless support coverage to Token2022 tokens, memecoin-to-memecoin swaps (when liquidity permits), and reduced minimum trade size to \~\$10 USD. * **Just-In-Time Market Revival**: Dynamically re-indexes markets to enable tradability for all tokens. * **Reduce Pre-Graduation Quote Latency**: Optimized pre-graduated bonding curve markets routing logic by skipping multi-route aggregation to improve quote latency from 200ms to 10ms - a 90% improvement. * **[Try Ultra Swap API](/docs/ultra)**: Ultra V3 features are live in the Ultra Swap API V1, try it and let us know your feedback! *** ## Jupiter Aggregator V6 Program Update * 4 new instruction types are introduced: * `route_v2` * `exact_out_route_v2` * `shared_accounts_route_v2` * `shared_accounts_exact_out_route_v2` * You can find the details in the latest IDL: [Solscan](https://solscan.io/account/JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4#programIdl). * V1 instructions will continue to be valid and usable. * This enables: * Collect fees when the swap pair consists of a Token2022 mint. * Set fee beyond the previous cap of 255 bps. ## Integrator Fee **Ultra Swap API** * Integrator fee for Ultra now supports Token2022 tokens. * No additional parameters are required, simply create Token2022 referral token accounts for your referral account. * You can find the details in the [Add Fees To Ultra Swap](/docs/ultra/add-fees-to-ultra) guide. **Metis Swap API** * Integrator fee for Metis Swap now supports Token2022 tokens. * New [`instructionVersion` parameter](/docs/api-reference/swap/v1/quote#parameter-instruction-version) is introduced to the Metis Swap API's Quote endpoint to support the new instruction types. * To collect fees in Token2022 tokens, create Token2022 token accounts and pass in via `feeAccount`. * You can find the details in the [Add Fees To Swap](/docs/swap/v1/add-fees-to-swap) guide. *** ## Sunsetting Legacy Endpoints We’re sunsetting several legacy endpoints over the next few weeks by gradually reducing access/rate limits. Please migrate to the latest versions ASAP. **Action Required** * Old Quote API V6: `http://quote-api.jup.ag/v6/` * Old Tokens API: `http://tokens.jup.ag` * Old Price API: `http://price.jup.ag` * Tokens V1: `http://lite-api.jup.ag/tokens/v1` * Price V2: `http://lite-api.jup.ag/price/v2` *** ## Deprecation of Price API V2 and Tokens API V1 [**Price API upgrades to V3**](/docs/price/v3) to support more reliable and timely pricing data - derived by the last swap price (across all transactions) and a set of heuristics to ensure the accuracy of the price and eliminate any outliers. [**Tokens API upgrades to V2**](/docs/tokens/v2) to support an easier and reliable usage with new data addition such as [Organic Score](/docs/tokens/organic-score), more trading categories like toporganicscore, and more. **Action Required** * If you are using **Price API V2** and **Tokens API V1** * Please migrate to their new versions respectively * The older versions will be deprecated by 30 September 2025 *** ## API Gateway: Improvements **Improved API Gateway!** For those that have been using the new hostnames at `api.jup.ag/**`, we have made improvements to the infrastructure * Reduced latency in responses and much more consistent now * Infrastructure costs reduction (will help us look into reducing costs of the plans with higher rate limits) **Dual endpoint moving forward.** We will be deploying 2 different endpoints, 1 for free usage and 1 for plans with higher rate limits via [https://portal.jup.ag/](https://portal.jup.ag/) * `api.jup.ag` will serve only pro/paid users * `lite-api.jup.ag` will be the endpoint to provide free usage **Action Required (Free plan)** * Migrate to `lite-api.jup.ag` **BY 1 MAY 2025** * The paths remain unchanged, only domain/hostname changes * The same rate limits still apply * You do not need an API Key to use the APIs for free * If you are still on `api.jup.ag` without an API key, you will get a 401 response **NO Action Required (Pro plan)** * Your usage on `api.jup.ag` remains unchanged * You can only use `api.jup.ag` with an API Key *** ## Trigger API: New Hostname and Breaking Changes * The `/limit/v2` path will be deprecated soon, please update your API calls to use the `/trigger/v1` path immediately. * `/execute` endpoint is introduced. * `/createOrder` endpoint now includes an additional `requestId` parameter to be used with the `/execute` endpoint. * `/cancelOrder` endpoint only builds the transaction for 1 order, while `/cancelOrders` endpoint builds the transaction for multiple orders. * The `tx` field in the responses are now `transaction` or `transactions`. * `/getTriggerOrders` endpoint is introduces a new format to get either active or historical orders (based on the query parameters). * [Please refer to the documentation for usage](/docs/trigger/create-order). | Old Paths | New Paths | | :------------------------------------------------ | :----------------------------------------------------- | | `/limit/v2/createOrder` | `/trigger/v1/createOrder` | | `/limit/v2/executeOrder` | `/trigger/v1/executeOrder` | | `/limit/v2/cancelOrder` | `/trigger/v1/cancelOrder` `/trigger/v1/cancelOrders` | | `/limit/v2/openOrders` `/limit/v2/orderHistory` | `/trigger/v1/getTriggerOrders` | *** ## API Gateway: New Hostnames and API Keys * API will now be served through new hostnames. * API will now be served through API keys. * API Keys will be distributed via [https://portal.jup.ag](https://portal.jup.ag) (Refer to [API Setup](/docs/portal/setup) to get started). * Old hostnames will be slowly phased out. * Old hostnames during this period will have reduced rate limits to facilitate migration to the new API. | Service Types | Description | | :------------------------- | :------------------------------------------------------- | | Free with no API key | Decreased rate limits to only accommodate for testing. | | Paid plan with API key | Fixed rate limits, self served through an API dashboard. | | Old Hostnames | New Hostnames | | :---------------------------------------- | :-------------------------------------------- | | `quote-api.jup.ag/v6/quote` | `lite-api.jup.ag/swap/v1/quote` | | `quote-api.jup.ag/v6/swap` | `lite-api.jup.ag/swap/v1/swap` | | `quote-api.jup.ag/v6/swap-instructions` | `lite-api.jup.ag/swap/v1/swap-instructions` | | `quote-api.jup.ag/v6/program-id-to-label` | `lite-api.jup.ag/swap/v1/program-id-to-label` | | `price.jup.ag/v6` | `lite-api.jup.ag/price/v2` | | `tokens.jup.ag/token/:mint` | `lite-api.jup.ag/tokens/v1/token/:mint` | | `tokens.jup.ag/tokens?tags=:tags` | `lite-api.jup.ag/tokens/v1/tagged/:tag` | | `tokens.jup.ag/tokens_with_markets` | `lite-api.jup.ag/tokens/v1/mints/tradable` | # Development Basics Source: https://dev.jup.ag/docs/get-started/development-basics Solana fundamentals for Jupiter developers: accounts, programs, transactions, priority fees, and how the Swap API simplifies it all. Solana uses an account-based architecture where data is stored in accounts and mutated by programs (smart contracts). Jupiter is deployed on Solana **mainnet** only. ## Core Concepts * [**Programs**](https://solana.com/docs/core/programs) - Executable code deployed on-chain. They define instructions, process transactions, and interact with accounts. * [**Accounts**](https://solana.com/docs/core/accounts) - Store data on-chain. Mutable by their owning program. * [**Instructions**](https://solana.com/docs/core/transactions#instruction) - Defined by programs, similar to API endpoints. * [**Transactions**](https://solana.com/docs/core/transactions#transaction) - Bundles of one or more instructions sent to the network. See the official Solana docs for [Web3.js](https://solana.com/docs/clients/javascript) and [Rust client](https://solana.com/docs/clients/rust) libraries. ## Interacting with Jupiter | Method | Description | | :----------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Swap API](/docs/swap/order-and-execute) | Get an order, sign, and submit. | | [Cross Program Invocation (CPI)](https://solana.com/docs/core/cpi) | Call Jupiter Swap from your on-chain program. Recommended since the [Loosen CPI restriction](https://github.com/solana-labs/solana/issues/26641) feature. | | Flash Fill | Alternative to CPI using Versioned Transactions and Address Lookup Tables to reduce account size. | The [Swap API's order and execute path](/docs/swap/order-and-execute) handles transaction building, sending, priority fees, and compute optimisation for you. No RPC required. ## Transaction Fundamentals ### Priority Fees An optional fee to improve transaction landing speed. Higher priority fee = higher position in the execution queue. **Priority Fee** = Compute Budget x Compute Unit Price (excluding the 5,000 lamport base fee). | Term | Description | | :------------------ | :----------------------------------------------------------- | | Global Priority Fee | Fee estimation across the entire network | | Local Fee Market | Fee estimation for a specific writable account (hot account) | | Compute Budget | How much compute the transaction is expected to consume | | Compute Unit Price | Micro-lamports per compute unit | Overpaying priority fees drives up costs across the network over time. Estimate appropriately rather than always bidding high. ### Compute Units Compute Units (CU) measure the resources a transaction needs. The Solana runtime caps transactions at 1.4M CU, with a default of 200K CU per instruction. You can set a custom limit with `SetComputeUnitLimit`. ### Slippage A threshold (percentage or bps) that causes the transaction to fail if the actual output falls below the quoted amount by that margin. Tighter slippage protects against price movement but makes landing harder. ### Transaction Broadcasting Transactions reach the network via: 1. Standard RPCs 2. RPCs with Stake-Weighted Quality of Service (SWQoS) 3. Jito RPC # Environment Setup Source: https://dev.jup.ag/docs/get-started/environment-setup Install required libraries, configure an RPC connection, and set up a development wallet. ## Libraries Install `@solana/web3.js` (v1) for transaction handling and `@solana/spl-token` for SPL token operations: ```bash theme={null} npm install @solana/web3.js@1 @solana/spl-token bs58 ``` This documentation uses `@solana/web3.js` **v1**. Version 2 has a different API for transaction handling. ## RPC Connection ```javascript theme={null} import { Connection } from '@solana/web3.js'; const connection = new Connection('https://api.mainnet-beta.solana.com'); ``` Solana provides a [default RPC endpoint](https://solana.com/docs/core/clusters), but as your application grows, use a dedicated provider like [Helius](https://helius.dev/) or [Triton](https://triton.one/). ## Development Wallet Never hardcode private keys in source code. Use environment variables or the Solana CLI keyfile. ```javascript .env file theme={null} import { Keypair } from '@solana/web3.js'; import bs58 from 'bs58'; import 'dotenv/config'; const wallet = Keypair.fromSecretKey(bs58.decode(process.env.PRIVATE_KEY)); ``` ```javascript Solana CLI keyfile theme={null} import { Keypair } from '@solana/web3.js'; import fs from 'fs'; const privateKeyArray = JSON.parse( fs.readFileSync('/Path/to/.config/solana/id.json', 'utf8').trim() ); const wallet = Keypair.fromSecretKey(new Uint8Array(privateKeyArray)); ``` # Jupiter Developer Docs Source: https://dev.jup.ag/docs/get-started/index DeFi infrastructure on Solana for swaps, lending, limit orders, DCA, and more ## Why Jupiter Jupiter is the liquidity infrastructure behind the majority of DeFi on Solana. Whether you're building a trading terminal, a DeFi protocol, a payments app, or an AI agent, Jupiter gives you the APIs to ship fast and at scale. The same infrastructure that powers jup.ag is available to you as production-grade REST APIs. No RPC nodes, no blockchain state management, no transaction complexity. Jupiter abstracts all of it so you can focus on your product. Every API returns clean JSON, works with a single API key, and is designed to be consumed by both developers and AI agents. ### APIs No RPC nodes, no blockchain state management. Jupiter handles all on-chain interactions for you. Metis, JupiterZ, and third-party routers compete on every swap. Your users get the best price available. Clean JSON, simple REST, and purpose-built tools (llms.txt, MCP, Skills, CLI) for AI agents and LLMs. ### Developer Platform A single key from the [Developer Platform](https://developers.jup.ag/portal) unlocks every Jupiter API. Start free, no upfront payments. Real-time analytics, request logs, and usage dashboards. Debug and monitor your integration from the platform. Organisation management, role-based access, shared API keys, audit logs, and 2FA. ## Products Token swaps with managed execution (/order) or raw instructions for custom transactions (/build). Search, metadata, verification status, organic score, and trading metrics for any Solana token. Heuristics-based USD pricing for up to 50 tokens per request. Earn yield on deposits, borrow against collateral, and execute flashloans. Vault-based limit orders with single, OCO (TP/SL), and OTOCO order types. Automated dollar-cost averaging with time-based recurring orders. Binary prediction markets for real-world events. Leveraged perpetuals trading on Solana (on-chain program). ## Developer Resources Step-by-step tutorials for common integration tasks. Powerful tools and SDKs to integrate Jupiter with minimal effort. Get your API key, monitor usage, and manage your integrations. ## AI Jupiter is built for AI agents and LLM-powered development. Every API returns clean JSON with no RPC complexity. Trade from your terminal, Telegram, or through AI agents. JSON-native, designed for both humans and LLMs. Pre-built context files that give coding agents structured integration guidance. Search and query Jupiter docs via Model Context Protocol from any AI editor. LLM-optimised documentation index for RAG pipelines and AI consumption. ## Community Developer support, integrator channels, and ecosystem discussions. Open-source SDKs, examples, and the docs repo. Direct support channels and resources for integrators. ## Socials Product updates, technical deep dives, and launch announcements. Follow Jupiter for real-time updates, ecosystem news, and releases. ## Get Started New to Jupiter development? Start with the essentials: * [Environment Setup](/docs/get-started/environment-setup) for libraries, RPC connection, and wallet setup * [Development Basics](/docs/get-started/development-basics) for accounts, transactions, priority fees, and compute units # How to Build a Prediction Market App on Solana Source: https://dev.jup.ag/docs/guides/how-to-build-a-prediction-market-app-on-solana Build prediction market features into your Solana app using Jupiter's Prediction API. ## TL;DR Jupiter's Prediction API lets you add prediction market trading to your Solana app. Users can trade on real-world event outcomes (sports, crypto, politics) with liquidity aggregated from Polymarket and Kalshi. The API handles order matching, position tracking, and settlement. **Base URL:** `https://api.jup.ag/prediction/v1` **Video walkthrough + source code:** Watch the [video walkthrough](https://x.com/JupDevRel/status/2031926314811486657) and grab the [demo app source code](https://github.com/jup-ag/api-examples/tree/main/apps/prediction-API-video-demo) on GitHub. *** ## Prerequisites 1. Get an API key at [Portal](https://developers.jup.ag/portal) 2. All requests require the `x-api-key` header 3. Users need JupUSD (or USDC) to trade **BETA** The Prediction Market API is currently in beta and subject to breaking changes. If you have feedback, reach out in [Discord](https://discord.gg/jup). *** ## Quick start ```bash theme={null} # Get available prediction events curl -X GET "https://api.jup.ag/prediction/v1/events?category=crypto" \ -H "x-api-key: YOUR_API_KEY" ``` *** ## When you need this You're building an app where users can: * **Trade on event outcomes.** "Will BTC hit \$100k by end of 2026?" * **Bet on sports, politics, or crypto.** Binary YES/NO markets. * **Build a prediction market frontend.** Custom UI for trading. * **Add speculation features.** Let users put money on their predictions. * **Track trading performance.** Leaderboards, P\&L history, profiles. Common searches that lead here: * "prediction market api solana" * "binary options solana" * "bet on events solana api" * "polymarket on solana" *** ## Why Jupiter Building prediction markets from scratch requires: * Liquidity sourcing and market making * Order matching infrastructure * Settlement and payout systems * Real-world event data feeds Jupiter handles all of this: * **Aggregates liquidity** from Polymarket and Kalshi. * **Keeper network** matches and fills orders. * **On-chain settlement** with guaranteed payouts. * **No payout fees.** Winners receive the full \$1 per contract. You get prediction market functionality without building the infrastructure. *** ## How prediction markets work **Binary outcomes**: Every market is YES or NO. "Will X happen?" → YES or NO. **Contract pricing**: Prices range from $0.01 to $0.99. Price = implied probability. * 70¢ YES price = market thinks 70% chance of YES * If you buy YES at 70¢ and YES wins, you profit 30¢ per contract * Losing contracts expire worthless **Settlement**: When the event resolves, winning contracts pay out \$1 each. No fees on payouts. *** ## API reference **Base URL:** `https://api.jup.ag/prediction/v1` | Endpoint | Description | | ---------------------------------------- | ------------------------------------- | | `GET /events` | List prediction events with filters | | `GET /events/search?query={term}` | Search events by keyword | | `GET /events/{eventId}` | Get event details | | `GET /markets/{marketId}` | Get market pricing and status | | `POST /orders` | Create order (returns unsigned tx) | | `GET /orders?ownerPubkey={pubkey}` | Get user's orders | | `GET /orders/status/{orderPubkey}` | Get order fill status | | `GET /positions?ownerPubkey={pubkey}` | Get user's positions | | `DELETE /positions/{positionPubkey}` | Close a position (sell all contracts) | | `DELETE /positions` | Close all positions | | `POST /positions/{positionPubkey}/claim` | Claim winnings (returns unsigned tx) | *** ## Code examples ### Browse available events ```bash curl theme={null} curl -X GET "https://api.jup.ag/prediction/v1/events?category=crypto&includeMarkets=true" \ -H "x-api-key: YOUR_API_KEY" ``` ```javascript JavaScript theme={null} const response = await fetch( 'https://api.jup.ag/prediction/v1/events?category=crypto&includeMarkets=true', { headers: { 'x-api-key': 'YOUR_API_KEY' } } ); const { data: events } = await response.json(); // Each event contains markets with pricing events.forEach(event => { console.log(`${event.metadata.title}`); event.markets?.forEach(market => { console.log(` ${market.metadata.title}: YES ${market.pricing.buyYesPriceUsd}¢`); }); }); ``` **Filter options:** * `category`: `all`, `crypto`, `sports`, `politics`, `esports`, `culture`, `economics`, `tech` * `filter`: `new` (last 24h), `live` (in progress), `trending` * `provider`: `polymarket` (default), `kalshi` ### Search for specific events ```javascript theme={null} const response = await fetch( 'https://api.jup.ag/prediction/v1/events/search?query=bitcoin&limit=10', { headers: { 'x-api-key': 'YOUR_API_KEY' } } ); const { data: events } = await response.json(); ``` ### Create a buy order ```bash curl theme={null} curl -X POST "https://api.jup.ag/prediction/v1/orders" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "ownerPubkey": "USER_WALLET_PUBKEY", "marketId": "MARKET_ID", "isYes": true, "isBuy": true, "depositAmount": "2000000", "depositMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }' ``` ```javascript JavaScript theme={null} const response = await fetch('https://api.jup.ag/prediction/v1/orders', { method: 'POST', headers: { 'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ ownerPubkey: userWallet.publicKey.toString(), marketId: 'MARKET_ID', isYes: true, // YES side (false for NO) isBuy: true, // Buy order (false to sell) depositAmount: '2000000', // $2 in native token units (1,000,000 = $1) depositMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' // USDC }) }); const orderResponse = await response.json(); // Deserialize, sign, and send const transaction = VersionedTransaction.deserialize( Buffer.from(orderResponse.transaction, 'base64') ); transaction.sign([userWallet]); const signature = await connection.sendRawTransaction(transaction.serialize(), { skipPreflight: true, }); ``` **Amount format**: All USD values use native token units where 1,000,000 = \$1.00. * `depositAmount: '2000000'` = \$2.00 * `depositMint` accepts USDC (`EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`) or JupUSD (`JuprjznTrTSp2UFa3ZBUFgwdAmtZCq4MQCwysN55USD`) ### Get user positions ```javascript theme={null} const response = await fetch( `https://api.jup.ag/prediction/v1/positions?ownerPubkey=${userPubkey}`, { headers: { 'x-api-key': 'YOUR_API_KEY' } } ); const { data: positions } = await response.json(); positions.forEach(pos => { const side = pos.isYes ? 'YES' : 'NO'; const pnl = pos.pnlUsd ? (parseInt(pos.pnlUsd) / 1_000_000).toFixed(2) : 'N/A'; console.log(`${pos.marketMetadata.title}: ${pos.contracts} ${side} contracts, P&L: $${pnl}`); }); ``` ### Claim winnings from a settled position ```javascript theme={null} // Check if position is claimable if (position.claimable) { const response = await fetch( `https://api.jup.ag/prediction/v1/positions/${position.pubkey}/claim`, { method: 'POST', headers: { 'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ ownerPubkey: userPubkey }) } ); const claimResponse = await response.json(); // Deserialize, sign, and send const transaction = VersionedTransaction.deserialize( Buffer.from(claimResponse.transaction, 'base64') ); transaction.sign([userWallet]); const signature = await connection.sendRawTransaction(transaction.serialize(), { skipPreflight: true, }); } ``` *** ## Response format ### Event ```typescript theme={null} interface Event { eventId: string; isActive: boolean; // Whether the event is listed isLive: boolean; // Whether the event is currently live category: 'crypto' | 'sports' | 'politics' | 'esports' | 'culture' | 'economics' | 'tech'; subcategory: string; // Subcategory within the category tags: string[]; // Tags associated with the event metadata: { eventId: string; title: string; subtitle: string; slug: string; // URL-friendly identifier series: string; // Groups related events (e.g., "NFL Week 1") closeTime: string; // ISO 8601 formatted close time imageUrl: string; isLive: boolean; }; markets: Market[]; volumeUsd: string; // Total volume (micro USD) closeCondition: string; beginAt: string | null; // When the event begins rulesPdf: string; // URL to full rules document } ``` ### Market ```typescript theme={null} interface Market { marketId: string; status: 'open' | 'closed' | 'cancelled'; result: null | 'yes' | 'no'; openTime: number; // Unix timestamp closeTime: number; // Unix timestamp resolveAt: number | null; // Unix timestamp when market resolved marketResultPubkey: string | null; // Market result account public key imageUrl: string; // Market image URL metadata: { title: string; status: string; openTime: number; closeTime: number; isTeamMarket: boolean; // Whether this is a team market rulesPrimary: string; rulesSecondary: string; }; pricing: { buyYesPriceUsd: number | null; // Price to buy YES (micro USD) buyNoPriceUsd: number | null; // Price to buy NO (micro USD) sellYesPriceUsd: number | null; // Price to sell YES (micro USD) sellNoPriceUsd: number | null; // Price to sell NO (micro USD) volume: number; // Trading volume for this market }; } ``` ### Position ```typescript theme={null} interface Position { pubkey: string; // Position account ownerPubkey: string; // User's wallet marketId: string; isYes: boolean; // YES or NO side contracts: string; // Contracts held (u64 as string) avgPriceUsd: string; // Average entry price (micro USD) totalCostUsd: string; // Cost basis (micro USD) sizeUsd: string; // Alias of totalCostUsd (micro USD) valueUsd: string | null; // Mark-to-market value (null if market closed) markPriceUsd: string | null; // Current mark price (null if market closed) sellPriceUsd: string | null; // Best exit price (null if unavailable) pnlUsd: string | null; // Unrealized P&L (micro USD) pnlUsdPercent: number | null; pnlUsdAfterFees: string | null; // P&L after fees (micro USD) pnlUsdAfterFeesPercent: number | null; realizedPnlUsd: number; // Realized P&L (micro USD) feesPaidUsd: string; // Total fees paid (micro USD) payoutUsd: string; // Payout if position wins (contracts x $1) claimable: boolean; // Can claim payout? claimed: boolean; // Has payout been claimed? claimedUsd: string; // Amount claimed (micro USD) openOrders: number; // Number of open orders openedAt: number; // Unix timestamp when position opened updatedAt: number; // Unix timestamp of last update claimableAt: number | null; // When position becomes claimable settlementDate: number | null; // When market settles eventMetadata: EventMetadata; marketMetadata: MarketMetadata; } ``` ### Create order response ```typescript theme={null} interface CreateOrderResponse { transaction: string; // Base64 encoded unsigned transaction txMeta: { blockhash: string; lastValidBlockHeight: number; }; order: { orderPubkey: string; positionPubkey: string; contracts: string; orderCostUsd: string; estimatedTotalFeeUsd: string; }; } ``` ### History event ```typescript theme={null} interface HistoryEvent { id: number; // Unique event identifier eventType: 'order_created' | 'order_filled' | 'order_failed' | 'payout_claimed' | 'position_updated' | 'position_lost'; signature: string; // Solana transaction signature slot: string; // Solana slot number timestamp: number; // Unix timestamp (seconds) orderPubkey: string; // Associated order account positionPubkey: string; // Associated position account marketId: string; ownerPubkey: string; keeperPubkey: string; // Keeper that processed the tx externalOrderId: string; // Client-provided order ID orderId: string; // Venue order ID isBuy: boolean; // Buy or sell isYes: boolean; // YES or NO side contracts: string; // Contracts in the order filledContracts: string; // Contracts filled contractsSettled: string; // Contracts settled avgFillPriceUsd: string; // Average fill price (micro USD) maxFillPriceUsd: string; // Max fill price (micro USD) maxBuyPriceUsd: string | null; // Buyer max price (micro USD) minSellPriceUsd: string | null; // Seller min price (micro USD) depositAmountUsd: string; // Deposit amount (micro USD) totalCostUsd: string; // Total cost (micro USD) feeUsd: string | null; // Fee charged (micro USD) grossProceedsUsd: string; // Gross proceeds (micro USD) netProceedsUsd: string; // Net proceeds (micro USD) transferAmountToken: string | null; // Token amount transferred realizedPnl: string | null; // Realized P&L (micro USD) realizedPnlBeforeFees: string | null; // Realized P&L before fees (micro USD) payoutAmountUsd: string; // Payout amount (micro USD) eventId: string; marketMetadata: MarketMetadata; eventMetadata: EventMetadata; } ``` *** ## Order lifecycle 1. **Create order**: Call `POST /orders` → get unsigned transaction 2. **Sign & submit**: User signs, you submit to Solana 3. **Keeper fills**: Jupiter's keeper network matches the order 4. **Position updates**: Position reflects new contracts 5. **Market settles**: When event resolves, result is recorded 6. **Claim payout**: If position won, call `/claim` to withdraw *** ## Common questions JupUSD or USDC. Specify via `depositMint` parameter (defaults to USDC). Check `market.status === 'open'`. A market with status `open` is actively trading. You can close a position using `DELETE /positions/{positionPubkey}`, which sells all contracts. Unfilled orders that fail are closed automatically by the keeper network. Use `GET /orders/status/{orderPubkey}` to check if an order is `pending`, `filled`, or `failed`. ```javascript theme={null} const contracts = 10; const buyPrice = 0.70; // 70¢ const potentialProfit = contracts * (1 - buyPrice); // $3.00 if wins const potentialLoss = contracts * buyPrice; // $7.00 if loses ``` ```javascript theme={null} // Convert micro USD to USD for display const displayPrice = (microUsd) => (parseInt(microUsd) / 1_000_000).toFixed(2); // Convert USD to micro USD for API const toMicroUsd = (usd) => Math.round(usd * 1_000_000).toString(); ``` Polymarket (default) has more markets. Kalshi is US-regulated. Use the `provider` query param to switch. *** ## Next steps * **[Prediction API Reference](/docs/api-reference/prediction).** Full endpoint documentation. * **[About Prediction Markets](/docs/prediction/index).** Architecture and concepts. * **[Portal](https://developers.jup.ag/portal).** Get your API key. * **[Jupiter Dev Notifications](https://t.me/jup_dev).** API updates and announcements. # How to Embed a Swap Widget in Your App Source: https://dev.jup.ag/docs/guides/how-to-embed-a-swap-widget Add a full-featured token swap to your app with one script tag. No RPC, no wallet infrastructure, no UI to build. ## TL;DR Jupiter Plugin gives you the same swap experience as [jup.ag](https://jup.ag), embedded directly in your app. One script tag, one function call. No RPC node, no wallet adapter code, no UI to build. Powered by [Ultra](/docs/ultra/index), which handles routing, slippage, MEV protection, and transaction sending. **Video walkthrough + source code:** Watch the [video walkthrough](https://x.com/JupDevRel/status/2033528378134028756) and grab the [demo app source code](https://github.com/jup-ag/api-examples/tree/main/apps/plugin-community-site) on GitHub. *** ## Prerequisites No API key or RPC node required. Jupiter Plugin handles all infrastructure. For framework-based apps, you need **Node.js and npm** installed from [nodejs.org](https://nodejs.org). For plain HTML, you just need a browser. *** ## Quick start The simplest way to add a swap widget: a single HTML file: ```html theme={null}

My App

``` Save this as `swap.html`, serve it locally, and open it in your browser: ```bash theme={null} npx http-server -o /swap.html ``` ## Try it yourself Not ready to write code? The [Plugin Playground](https://plugin.jup.ag/) lets you experience the full swap widget live in your browser. Switch display modes, set token defaults, tweak colours, and copy the generated code when you're ready to integrate. Plugin Playground *** ## When you need this You want to add swap functionality to your app or website without building any of it yourself: * **App with swap:** Your app needs token swaps but you don't want to build the UI, handle transactions, or run an RPC node. * **Community token site:** Let your community buy your token directly on your website by locking the output mint with `fixedMint`. * **Quick swap access:** Add a floating widget to any page for convenient swapping. Common searches that lead here: * "embed swap widget solana" * "add token swap to my website" * "jupiter plugin integration" * "buy token widget solana" * "solana swap widget no backend" * "drop-in swap component solana" * "add jupiter swap to react app" * "token swap widget html" *** ## Why Jupiter Plugin Building a swap interface from scratch means: * Running an RPC node * Integrating a wallet adapter * Building the swap UI * Handling quoting, routing, slippage, and MEV protection * Managing transaction errors and retries Jupiter Plugin handles all of this. You get the full [jup.ag](https://jup.ag) swap experience as a drop-in component: * **No RPC:** Powered by Ultra, which handles all transaction sending. * **No wallet code:** Plugin provides wallet connection out of the box (users connect their existing browser wallet like Phantom or Backpack). * **No UI to build:** Complete swap interface with token search, price display, and transaction status. * **No error handling:** Plugin manages slippage, retries, and transaction failures. *** ## Code examples Add the plugin script to your page, then call `window.Jupiter.init()`. Here's a complete working example for each framework: ```html HTML theme={null} Jupiter Plugin Demo

Jupiter Plugin Demo

``` ```tsx React theme={null} import { useEffect } from "react"; // Add to public/index.html : // export default function App() { useEffect(() => { window.Jupiter.init({ displayMode: "integrated", integratedTargetId: "jupiter-plugin", }); }, []); return (

Jupiter Plugin Demo

); } ``` ```tsx Next.js theme={null} "use client"; import { useEffect } from "react"; import Script from "next/script"; export default function SwapPage() { return ( <>

Jupiter Plugin Demo

``` ## Step 3: Run the Project Run the project using `http-server`: ```bash theme={null} http-server ``` There you have it! You've successfully integrated Jupiter Plugin into your HTML application. * Please test the swap functionality and check the transaction. * If you require more customizations, check out the [Plugin Playground](https://plugin.jup.ag) or the [Customization](/docs/tool-kits/plugin/customization) documentation. * If you have any questions or issues, please refer to the [FAQ](/docs/tool-kits/plugin/faq) or contact us on [Discord](https://discord.gg/jup). # Integrate Jupiter Plugin Source: https://dev.jup.ag/docs/tool-kits/plugin/index Seamlessly integrate end-to-end Ultra Swap functionality into any application with just a few lines of code. Jupiter Plugin is an open-source, lightweight, plug-and-play version of Jupiter Ultra Swap, allowing you to bring the exact jup.ag swap experience to any application. Try out the [Plugin Playground](https://plugin.jup.ag/) to experience the entire suite of customizations. To view the open-source code, visit the [GitHub repository](https://github.com/jup-ag/plugin). Plugin Playground **QUICK START** To quick start your integration, check out the [Next.js](/docs/tool-kits/plugin/nextjs-app-example), [React](/docs/tool-kits/plugin/react-app-example) or [HTML](/docs/tool-kits/plugin/html-app-example) app examples. Refer to [Customization](/docs/tool-kits/plugin/customization) and [FAQ](/docs/tool-kits/plugin/faq) for more information. ## Key Features * **Seamless Integration**: Embed Jupiter's swap functionality directly into your application without redirects. * **Multiple Display Options**: Choose between integrated, widget, or modal display modes. * **Customizable Options**: Configure the swap form to match your application's needs. * **RPC-less**: Integrate Plugin without any RPCs, Ultra handles transaction sending, wallet balances and token information. * **Ultra Mode**: Access to all features of Ultra Mode, read more about it in the [Ultra Swap API docs](/docs/ultra/). ## Getting Started When integrating Plugin, there are a few integration methods to think about, and choose the one that best fits your application's architecture and requirements. ### Integration Methods * **Using Window Object** - Simplest way to add and initialize Plugin. * [**Using NPM Package**](https://www.npmjs.com/package/@jup-ag/plugin) - Install via `npm install @jup-ag/plugin` and initialize as a module (will require you to maintain its dependencies). ### Wallet Integration * **Wallet Standard Support**: For applications without existing wallet provider, Plugin will provide a wallet adapter and connection - powered by [Unified Wallet Kit](/docs/tool-kits/wallet-kit/). * **Passthrough Wallet**: For applications with existing wallet provider(s), set `enableWalletPassthrough=true` with context, and Plugin will allow the application to pass through the existing wallet provider's connection to Plugin. ### Adding Fees to plugin * **Referral Account**: You can create a referral account via [scripts](/docs/ultra/add-fees-to-ultra) or [Referral Dashboard](https://referral.jup.ag/). * **Referral Fee**: You can set the referral fee and account in the `formProps` interface when you initialize the Plugin. ### Quick Start Guides In the next sections, we'll walk you through the steps to integrate Jupiter Plugin into different types of web applications from scratch. By integrating Jupiter Plugin into your application, you can seamlessly integrate a fully functional swap interface into your application with minimal effort, while staying at the forefront of Solana DeFi innovation. # Next.js App Example Source: https://dev.jup.ag/docs/tool-kits/plugin/nextjs-app-example Step-by-step guide to integrate Jupiter Plugin into a Next.js application. This guide walks through integrating Jupiter Plugin into a Next.js application from scratch. It covers both App Router and Pages Router setups, TypeScript declarations, and two initialization methods: the window object approach and the `@jup-ag/plugin` npm package. ## Prerequisites Before you begin, make sure you have the following installed on your system. **Node.js and npm**: Download and install from [nodejs.org](https://nodejs.org) ## Step 1: Create a New Next.js Project Head to your preferred directory and create a new Next.js project using `create-next-app` with TypeScript template (you can use other templates or methods to start your project too): ```bash theme={null} npx create-next-app@latest plugin-demo --typescript cd plugin-demo npm run dev ``` ## Step 2: Add TypeScript Support Create a type declaration file `plugin.d.ts` in your project's `/src/types` folder: ```js theme={null} declare global { interface Window { Jupiter: JupiterPlugin; } }; export {}; ``` ```js theme={null} declare global { interface Window { Jupiter: JupiterPlugin; } } export type WidgetPosition = 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right'; export type WidgetSize = 'sm' | 'default'; export type SwapMode = "ExactInOrOut" | "ExactIn" | "ExactOut"; export type DEFAULT_EXPLORER = 'Solana Explorer' | 'Solscan' | 'Solana Beach' | 'SolanaFM'; export interface FormProps { swapMode?: SwapMode; initialAmount?: string; initialInputMint?: string; initialOutputMint?: string; fixedAmount?: boolean; fixedMint?: string; referralAccount?: string; referralFee?: number; } export interface IInit { localStoragePrefix?: string; formProps?: FormProps; defaultExplorer?: DEFAULT_EXPLORER; autoConnect?: boolean; displayMode?: 'modal' | 'integrated' | 'widget'; integratedTargetId?: string; widgetStyle?: { position?: WidgetPosition; size?: WidgetSize; }; containerStyles?: CSSProperties; containerClassName?: string; enableWalletPassthrough?: boolean; passthroughWalletContextState?: WalletContextState; onRequestConnectWallet?: () => void | Promise; onSwapError?: ({ error, quoteResponseMeta, }: { error?: TransactionError; quoteResponseMeta: QuoteResponse | null; }) => void; onSuccess?: ({ txid, swapResult, quoteResponseMeta, }: { txid: string; swapResult: SwapResult; quoteResponseMeta: QuoteResponse | null; }) => void; onFormUpdate?: (form: IForm) => void; onScreenUpdate?: (screen: IScreen) => void; } export interface JupiterPlugin { _instance: JSX.Element | null; init: (props: IInit) => void; resume: () => void; close: () => void; root: Root | null; enableWalletPassthrough: boolean; onRequestConnectWallet: IInit['onRequestConnectWallet']; store: ReturnType; syncProps: (props: { passthroughWalletContextState?: IInit['passthroughWalletContextState'] }) => void; onSwapError: IInit['onSwapError']; onSuccess: IInit['onSuccess']; onFormUpdate: IInit['onFormUpdate']; onScreenUpdate: IInit['onScreenUpdate']; localStoragePrefix: string; } export { }; ``` ## Step 3: Embed the Plugin Script For Next.js applications, you can add the script in two ways: ### Using App Router (Next.js 13+) In your `app/layout.tsx`: ```js theme={null} import Script from "next/script"; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( ``` ## Step 4: Initialize Plugin There are two ways to initialize Jupiter Plugin in a React application: ### Method 1: Using Window Object In your `/src/App.tsx`, use the following code to initialize the plugin. ```bash theme={null} import React, { useEffect } from 'react'; import './App.css'; import './types/plugin.d'; export default function App() { useEffect(() => { // Initialize plugin window.Jupiter.init({ displayMode: "widget", integratedTargetId: "jupiter-plugin", }); }, []); return (

Jupiter Plugin Demo

); } ``` ### Method 2: Using @jup-ag/plugin Package **WARNING** Do note that using this method will require you to maintain its dependencies. Install the package: ```bash theme={null} npm install @jup-ag/plugin ``` Initialize the plugin: ```bash theme={null} import React, { useEffect } from "react"; import "@jup-ag/plugin/css"; import "./App.css"; import "./types/plugin.d"; export default function App() { useEffect(() => { import("@jup-ag/plugin").then((mod) => { const { init } = mod; init({ displayMode: "widget", integratedTargetId: "jupiter-plugin", }); }); }, []); return (

Jupiter Plugin Demo

); } ``` There you have it! You've successfully integrated Jupiter Plugin into your Next.js application. * Please test the swap functionality and check the transaction. * If you require more customizations, check out the [Plugin Playground](https://plugin.jup.ag) or the [Customization](/docs/tool-kits/plugin/customization) documentation. * If you have any questions or issues, please refer to the [FAQ](/docs/tool-kits/plugin/faq) or contact us on [Discord](https://discord.gg/jup). # Referral Program Source: https://dev.jup.ag/docs/tool-kits/referral-program Earn on-chain fees from user trades through the open-source Jupiter Referral Program. The Referral Program is an open-source on-chain program that lets developers earn fees through Jupiter API integrations. It supports Swap API, Trigger API, and Plugin. Any Solana program can also integrate the Referral Program to share revenue with its own integrators. **REFERRAL PROGRAM SOURCE CODE** [Open Source Repository](https://github.com/TeamRaccoons/referral): To understand and make use of the referral program better. ## Jupiter API Integrators The Jupiter Programs use the Referral Program to allow developers to earn fees when integrating with Jupiter. Below are some resources to help you quickly get started. There are a different ways to setup such as via the Jupiter Referral Dashboard or using the provided scripts. * [Jupiter Referral Dashboard](https://referral.jup.ag/): To view and manage your referral accounts used with Jupiter APIs. * [Add Fees to Swap API](/docs/swap/order-and-execute#fees): To add fees to your Swap API integration. * [Add Fees to Jupiter Plugin](/docs/tool-kits/plugin#adding-fees-to-plugin): To add fees to your Plugin integration. ## Other Program Integrators ### Project Usage If you have a project/product that runs a program on the Solana blockchain, you can integrate the Referral Program to allow/share revenue with the integrators of your program. Similar to how Jupiter Programs uses the Referral Program to help developers earn fees and/or share the revenue with Jupiter. For example, Jupiter Ultra uses the Jupiter Swap program which relies on the Referral Program. * Create a `Project` by calling `initialize_project` with your chosen `base` key and a project `name` (`base` key refers to a key identifier of your project). * Set a `default_share_bps` to share the fees with your referrers (or integrators). * An example of a `Project` account: [Jupiter Ultra Project](https://solscan.io/account/DkiqsTrw1u1bYFumumC7sCG2S8K25qc2vemJFHyW2wJc) ### Referrer Usage If you are a referrer such as a developer or integrator of a project that runs a program on the Solana blockchain, you can create the necessary accounts via the Referral Program to earn fees. * The program must be integrated with the Referral Program. * Create a `Referral` account by calling `initialize_referral_account` with the correct `Project` account, the `Referral` account, and your own `Partner` account (`Partner` account is the admin of this referral account). * Create the necessary `Referral` token accounts for the `Referral` account to receive fees in. # Integrate Wallet Kit Source: https://dev.jup.ag/docs/tool-kits/wallet-kit/index Integrate Jupiter Wallet Kit into your application to simplify wallet connectivity across all Solana wallets, all in a unified wallet interface The Jupiter Wallet Kit is an open-source, Swiss Army Knife wallet adapter designed to streamline your development on Solana by eliminating redundancies and providing wallet adapter building blocks in a simple, plug-and-play package. This allows developers to focus on what matters most: building innovative features for your users. ## Overview * Creating a wallet notification system. * Managing wallet states (connected, disconnected, etc). * Implementing a mobile-friendly wallet connector. * Support for 20+ wallet adapters via a unified interface. * Support for all wallets built with [Solana's Wallet Standard](https://github.com/anza-xyz/wallet-standard). * Support for [Jupiter Wallet Extension](/docs/tool-kits/wallet-kit/jupiter-wallet-extension). * Support for [Jupiter Mobile Adapter QR code login](/docs/tool-kits/wallet-kit/jupiter-mobile-adapter). To play with different settings,features and styling. To understand and make use of the wallet adapter better. To reference code snippets and examples. ## Technical Features | Feature | Description | | :---------------------------- | :------------------------------------------------------------------------------------------------------------------- | | **Compact Bundle** | Main ESM bundle is a lightweight 94KB (20KB gzipped). | | **Built-in Support** | Comes with Wallet Standard and Mobile Wallet Adapter support. | | **Abstracted Wallet Adapter** | Use the Bring Your Own Wallet (BYOW) approach to select custom and legacy wallets. | | **Mobile Responsive** | Designed to be mobile-first. | | **Smart Notification System** | Integrates seamlessly with your existing notification system or can be used independently. | | **Internationalization** | Supports multiple languages including English, Chinese, Vietnamese, French, Japanese, Bahasa Indonesia, and Russian. | | **Theming Options** | Choose from light, dark, and Jupiter modes, with more customization options coming soon. | | **New User Onboarding** | Simplifies the onboarding process for new users. | # Jupiter Mobile Adapter Source: https://dev.jup.ag/docs/tool-kits/wallet-kit/jupiter-mobile-adapter Integrate Jupiter Mobile QR code login into your app with WalletConnect support. The Jupiter Mobile Adapter lets users connect to your application by scanning a QR code with Jupiter Mobile. It uses the `@jup-ag/jup-mobile-adapter` package and Reown's AppKit for WalletConnect integration. This guide covers installation, Reown project ID setup, and adding the adapter to Wallet Kit. The Jupiter Mobile Adapter allows you to integrate Jupiter Mobile login functionality into your app! By allowing Jupiter Mobile users to simply use the app to scan a QR code to login, they can utilize their wallets on Jupiter Mobile across any platform. ## Overview Install [@jup-ag/jup-mobile-adapter](https://www.npmjs.com/package/@jup-ag/jup-mobile-adapter) Use `useWrappedReownAdapter` (Prerequisite to create an app id on [https://dashboard.reown.com/](https://dashboard.reown.com/)) Add the `jupiterAdapter` to wallets ## Prerequisite Building on top of the example in [Jupiter Wallet Extension example](/docs/tool-kits/wallet-kit/jupiter-wallet-extension), we will pass in the Jupiter Mobile Adapter (which uses Reown's AppKit). ## Step 1: Install dependency You will need to install the following dependency: ```bash theme={null} npm i @jup-ag/jup-mobile-adapter ``` ## Step 2: Get Reown project ID You need to input the project ID on from your [Reown's dashboard](https://dashboard.reown.com/), before you can use the Jupiter Mobile Adapter. This project ID is required for the AppKit integration that powers the mobile wallet connection functionality. To get your project ID: 1. Visit [https://dashboard.reown.com/](https://dashboard.reown.com/) 2. Sign up or log in to your account 3. Create a new project 4. Copy the project ID from your project settings (should be in the navbar) ## Step 3: Add Jupiter Mobile Adapter to wallets In your `/src/app/page.tsx` file, add the Jupiter Mobile Adapter as a wallet. ```js expandable theme={null} "use client"; import { Adapter, UnifiedWalletButton, UnifiedWalletProvider } from "@jup-ag/wallet-adapter"; import { useWrappedReownAdapter } from '@jup-ag/jup-mobile-adapter'; import { WalletNotification } from "../components/WalletNotification"; import { useMemo } from "react"; export default function Home() { // Initialize Jupiter Mobile Adapter with WalletConnect/Reown configuration // This adapter enables mobile wallet connections through WalletConnect protocol const { jupiterAdapter } = useWrappedReownAdapter({ appKitOptions: { metadata: { name: 'Jupiter Wallet Kit Demo', description: `This is a Jupiter Wallet Kit Demo with Jupiter Mobile Adapter`, url: 'https://localhost:3000', icons: ['https://jup.ag/favicon.ico'], }, projectId: '', // Get your project id from https://dashboard.reown.com/ features: { analytics: false, socials: ['google', 'x', 'apple'], email: false, }, // Disable built-in wallet list to use only Jupiter Mobile Adapter enableWallets: false, }, }); // Configure wallet adapters for the UnifiedWalletProvider // This memoized array includes the Jupiter Mobile Adapter and filters out any invalid adapters // The filter ensures each adapter has required properties (name and icon) before being used const wallets: Adapter[] = useMemo(() => { return [ jupiterAdapter, // Jupiter Mobile Adapter with WalletConnect integration ].filter((item) => item && item.name && item.icon) as Adapter[]; }, []); return (

Jupiter Mobile Adapter Demo

Connect your Solana wallet to get started

Powered by Jupiter Wallet Kit

); }; ``` There you have it! You've successfully integrated Jupiter Wallet Kit into your Next.js application and able to connect the Jupiter Mobile Adapter! * Please test the wallet functionality and build into your own application. * If you require more customizations, check out the [Wallet Kit Playground](https://wallet-kit.jup.ag) or [Github repo](https://github.com/TeamRaccoons/Unified-Wallet-Kit). * If you have any questions or issues, please reach out to us in [Discord](https://discord.gg/jup). # Jupiter Wallet Extension Source: https://dev.jup.ag/docs/tool-kits/wallet-kit/jupiter-wallet-extension Step-by-step guide to integrate Jupiter Wallet Extension into a Next.js application. This guide walks through integrating Jupiter Wallet Extension into a Next.js application using the `@jup-ag/wallet-adapter` package. It covers setting up UnifiedWalletProvider, creating wallet notifications, and detecting the Jupiter Wallet Extension browser addon. ## Prerequisites Before you begin, make sure you have the following installed on your system. This is what we will be using in this example. **Node.js and npm**: Download and install from [nodejs.org](https://nodejs.org) ## Step 1: Create a new project Head to your preferred directory and create a new project using `create-next-app` with TypeScript template (you can use other templates or methods to start your project too): ```bash theme={null} npx create-next-app@latest wallet-kit-demo --typescript cd wallet-kit-demo npm run dev ``` ## Step 2: Install dependency ```bash theme={null} npm i @jup-ag/wallet-adapter ``` ## Step 3: Add notification functionality In `/src/components`, create a new file `WalletNotification.tsx` with the following content: In this example, we will use a simple browser notification system to handle the wallet connection events. ```typescript expandable theme={null} "use client"; interface IWalletNotification { publicKey?: string; shortAddress?: string; walletName?: string; metadata?: { name: string; url: string; icon: string; supportedTransactionVersions?: any; }; } // Simple notification component - you can replace this with your preferred notification library const showNotification = (message: string, type: 'success' | 'error' | 'info' = 'info') => { // For demo purposes, we'll use browser notifications // In a real app, you'd want to use a proper notification library like react-hot-toast console.log(`[${type.toUpperCase()}] ${message}`); // Simple visual feedback if (typeof window !== 'undefined') { const notification = document.createElement('div'); notification.style.cssText = ` position: fixed; top: 20px; right: 20px; background: ${type === 'error' ? '#ef4444' : type === 'success' ? '#10b981' : '#3b82f6'}; color: white; padding: 12px 16px; border-radius: 8px; z-index: 9999; font-family: system-ui, -apple-system, sans-serif; box-shadow: 0 4px 12px rgba(0,0,0,0.15); `; notification.textContent = message; document.body.appendChild(notification); setTimeout(() => { document.body.removeChild(notification); }, 3000); } }; export const WalletNotification = { onConnect: ({ shortAddress, walletName }: IWalletNotification) => { showNotification(`Connected to ${walletName} (${shortAddress})`, 'success'); }, onConnecting: ({ walletName }: IWalletNotification) => { showNotification(`Connecting to ${walletName}...`, 'info'); }, onDisconnect: ({ walletName }: IWalletNotification) => { showNotification(`Disconnected from ${walletName}`, 'info'); }, onError: ({ walletName }: IWalletNotification) => { showNotification(`Failed to connect to ${walletName}`, 'error'); }, onNotInstalled: ({ walletName }: IWalletNotification) => { showNotification(`${walletName} is not installed`, 'error'); }, }; export default WalletNotification; ``` ## Step 4: Wrap your app in the Wallet Kit In `/src/app/page.tsx`, wrap your app with ``. This example code covers the base usage of the wallet kit which allows all wallets in your browser to be detected and used. If you have downloaded the [Jupiter Wallet Extension](https://chromewebstore.google.com/detail/iledlaeogohbilgbfhmbgkgmpplbfboh) , you should be able to see and connect to it. ```typescript expandable theme={null} "use client"; import { Adapter, UnifiedWalletButton, UnifiedWalletProvider } from "@jup-ag/wallet-adapter"; import { WalletNotification } from "../components/WalletNotification"; export default function Home() { // You can add specific wallet adapters here if needed // For now, we'll rely on the Unified Wallet Kit's built-in wallet discovery const wallets: Adapter[] = []; return (

Jupiter Wallet Extension Demo

Connect your Solana wallet to get started

Powered by Jupiter Wallet Kit

); } ``` There you have it! You've successfully integrated Jupiter Wallet Kit into your Next.js application and able to connect the Jupiter Wallet Extension! * Please test the wallet functionality and build into your own application. * If you require more customizations, check out the [Wallet Kit Playground](https://wallet-kit.jup.ag) or [Github repo](https://github.com/TeamRaccoons/Unified-Wallet-Kit). * If you have any questions or issues, please reach out to us in [Discord](https://discord.gg/jup). # Transaction Submission Source: https://dev.jup.ag/docs/transaction/submit Submit transactions through Jupiter's proprietary infrastructure for fast landing and MEV protection `/submit` sends your signed transactions through Jupiter's proprietary transaction landing infrastructure. This is the same infrastructure that powers Jupiter's own swap products, now open to any integrator. It accepts any valid signed Solana transaction with a SOL tip, costs zero API credits, and works on all plans including keyless access. ## Why /submit is competitive Jupiter's transaction landing stack is purpose-built for high throughput and low latency: * **[SWQoS via high-stake validator](https://solana.com/developers/guides/advanced/stake-weighted-qos).** Jupiter operates [one of the highest-staked validators on Solana](https://solanabeach.io/validators). Solana's Stake-Weighted Quality of Service (SWQoS) reserves \~80% of a leader's TPU capacity for staked validators proportional to their stake. Higher stake means more reserved bandwidth when forwarding transactions to the current leader. * **Beam (custom TPU forwarder).** Jupiter's own TPU client bypasses standard RPC nodes and sends transactions directly to leaders via staked QUIC connections. This removes intermediaries that could be malicious actors and eliminates RPC processing overhead. * **[DoubleZero](https://doublezero.xyz/).** Dedicated fiber network for validator communication, with FPGA-based spam filtering and transaction deduplication at the network edge. Cleaner transaction set, faster propagation between validators. * **Ultra-low-latency fiber.** Private fiber links from Tokyo to Frankfurt reduce physical propagation time between Jupiter's infrastructure and leader validators globally. * **High-performance, scalable infrastructure.** Built to handle the volume of Jupiter's own products, where millions of swaps land daily. ## How it works 1. Build your transaction (using `/build`, or assemble your own) 2. Include a SOL tip transfer instruction (minimum 0.001 SOL) to one of 16 tip receiver accounts 3. Sign the transaction 4. POST the base64-encoded signed transaction to `https://api.jup.ag/tx/v1/submit` For `/build` transactions, use the `tipAmount` parameter to have the tip instruction included automatically. For non-Jupiter transactions, add a standard SOL transfer instruction to one of the [tip receiver accounts](#adding-tip-instruction-manually). ## Requirements | Requirement | Details | | ---------------------------- | ----------------------------------------------------------------------------------------- | | **Valid signed transaction** | Must be a valid Solana transaction with all required signatures | | **SOL tip** | Minimum 1,000,000 lamports (0.001 SOL) transferred to one of the 16 tip receiver accounts | | **Transaction size** | Must not exceed the Solana transaction size limit (1232 bytes) | | **API access** | Works with any API key or keyless access | `/submit` has its own dedicated rate limit bucket (Keyless 20, Free 50, Paid 100 RPS), separate from your general API limit. See [Rate Limits](/docs/portal/rate-limits#dedicated-rate-limit-buckets). ## Code example ### Using /build Use [`/build`](/docs/swap/build) with the `tipAmount` parameter to automatically include a tip instruction in the response. ```typescript @solana/web3.js expandable theme={null} import { AddressLookupTableAccount, ComputeBudgetProgram, Connection, Keypair, PublicKey, TransactionInstruction, TransactionMessage, VersionedTransaction, } from "@solana/web3.js"; import bs58 from "bs58"; // ── Types matching the /build response ─────────────────────────────────────── type ApiAccount = { pubkey: string; isSigner: boolean; isWritable: boolean }; type ApiInstruction = { programId: string; accounts: ApiAccount[]; data: string; // base64 }; type BuildResponse = { computeBudgetInstructions: ApiInstruction[]; setupInstructions: ApiInstruction[]; swapInstruction: ApiInstruction; cleanupInstruction: ApiInstruction | null; otherInstructions: ApiInstruction[]; tipInstruction: ApiInstruction; addressesByLookupTableAddress: Record | null; blockhashWithMetadata: { blockhash: number[]; lastValidBlockHeight: number; }; }; // ── Helpers ────────────────────────────────────────────────────────────────── const CU_LIMIT_MAX = 1_400_000; function toInstruction(ix: ApiInstruction): TransactionInstruction { return new TransactionInstruction({ programId: new PublicKey(ix.programId), keys: ix.accounts.map((acc) => ({ pubkey: new PublicKey(acc.pubkey), isSigner: acc.isSigner, isWritable: acc.isWritable, })), data: Buffer.from(ix.data, "base64"), }); } // ── Main ───────────────────────────────────────────────────────────────────── const API_KEY = process.env.JUPITER_API_KEY!; const connection = new Connection(process.env.RPC_URL!); const signer = Keypair.fromSecretKey( bs58.decode(process.env.BS58_PRIVATE_KEY!), ); // 1. Call /build with your swap parameters const buildRes = await fetch( "https://api.jup.ag/swap/v2/build?" + new URLSearchParams({ inputMint: "So11111111111111111111111111111111111111112", outputMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", amount: "100000000", taker: signer.publicKey.toString(), tipAmount: "1000000", }), { headers: { "x-api-key": API_KEY } }, ); const build: BuildResponse = await buildRes.json(); // 2. Collect instructions (excluding compute budget — we handle CU limit ourselves) const instructions = [ ...build.setupInstructions.map(toInstruction), toInstruction(build.swapInstruction), ...(build.cleanupInstruction ? [toInstruction(build.cleanupInstruction)] : []), ...build.otherInstructions.map(toInstruction), toInstruction(build.tipInstruction), ]; // 3. Prepare blockhash and address lookup tables const addressLookupTableAccounts: AddressLookupTableAccount[] = []; for (const addr of Object.keys(build.addressesByLookupTableAddress ?? {})) { const result = await connection.getAddressLookupTable(new PublicKey(addr)); if (result.value) addressLookupTableAccounts.push(result.value); } const recentBlockhash = bs58.encode( Buffer.from(build.blockhashWithMetadata.blockhash), ); const { lastValidBlockHeight } = build.blockhashWithMetadata; // 4. Simulate to estimate CU usage, then apply 1.2x buffer const simMessage = new TransactionMessage({ payerKey: signer.publicKey, recentBlockhash, instructions: [ ComputeBudgetProgram.setComputeUnitLimit({ units: CU_LIMIT_MAX }), ...instructions, ], }).compileToV0Message(addressLookupTableAccounts); const sim = await connection.simulateTransaction( new VersionedTransaction(simMessage), { sigVerify: false, replaceRecentBlockhash: true }, ); if (sim.value.err) { console.error("Simulation failed:", sim.value.err); process.exit(1); } const estimatedCUL = sim.value.unitsConsumed ? Math.min(Math.ceil(sim.value.unitsConsumed * 1.2), CU_LIMIT_MAX) : CU_LIMIT_MAX; // 5. Build final transaction with estimated CU limit + CU price from response const messageV0 = new TransactionMessage({ payerKey: signer.publicKey, recentBlockhash, instructions: [ ComputeBudgetProgram.setComputeUnitLimit({ units: estimatedCUL }), ...build.computeBudgetInstructions.map(toInstruction), ...instructions, ], }).compileToV0Message(addressLookupTableAccounts); const transaction = new VersionedTransaction(messageV0); transaction.sign([signer]); // 6. Sign and submit via /submit (or use your own RPC / transaction pipeline) const submitRes = await fetch("https://api.jup.ag/tx/v1/submit", { method: "POST", headers: { "Content-Type": "application/json", "x-api-key": API_KEY, }, body: JSON.stringify({ signedTransaction: Buffer.from(transaction.serialize()).toString("base64"), }), }); const { signature } = await submitRes.json(); console.log("Submitted:", `https://solscan.io/tx/${signature}`); // 7. Confirm the transaction landed const confirmation = await connection.confirmTransaction( { signature, blockhash: recentBlockhash, lastValidBlockHeight }, "confirmed", ); if (confirmation.value.err) { console.error("Transaction failed:", confirmation.value.err); process.exit(1); } console.log("Confirmed:", signature); ``` ```typescript @solana/kit expandable theme={null} import { AccountRole, Address, address, AddressesByLookupTableAddress, appendTransactionMessageInstructions, Base64EncodedBytes, Blockhash, compileTransaction, compressTransactionMessageUsingAddressLookupTables, createKeyPairSignerFromBytes, createSolanaRpc, createTransactionMessage, getBase58Decoder, getBase58Encoder, getBase64Codec, getBase64EncodedWireTransaction, AccountMeta, Instruction, pipe, setTransactionMessageFeePayer, setTransactionMessageLifetimeUsingBlockhash, signTransaction, } from "@solana/kit"; // ── Types matching the /build response ─────────────────────────────────────── type Account = { pubkey: Address; isSigner: boolean; isWritable: boolean }; type ApiInstruction = { programId: Address; accounts: Account[]; data: Base64EncodedBytes; }; type BuildResponse = { computeBudgetInstructions: ApiInstruction[]; setupInstructions: ApiInstruction[]; swapInstruction: ApiInstruction; cleanupInstruction: ApiInstruction | null; otherInstructions: ApiInstruction[]; tipInstruction: ApiInstruction; addressesByLookupTableAddress: Record | null; blockhashWithMetadata: { blockhash: number[]; lastValidBlockHeight: number; }; }; // ── Helpers ────────────────────────────────────────────────────────────────── const COMPUTE_BUDGET_PROGRAM = address( "ComputeBudget111111111111111111111111111111", ); const CU_LIMIT_MAX = 1_400_000; function createInstruction(ix: ApiInstruction): Instruction { return { programAddress: ix.programId, accounts: ix.accounts.map((acc) => ({ address: acc.pubkey, role: acc.isSigner && acc.isWritable ? AccountRole.WRITABLE_SIGNER : acc.isSigner ? AccountRole.READONLY_SIGNER : acc.isWritable ? AccountRole.WRITABLE : AccountRole.READONLY, })), data: Uint8Array.from(getBase64Codec().encode(ix.data)), }; } function makeSetComputeUnitLimitIx(units: number): ApiInstruction { const data = Buffer.alloc(5); data.writeUInt8(0x02, 0); data.writeUInt32LE(units, 1); return { programId: COMPUTE_BUDGET_PROGRAM, accounts: [], data: data.toString("base64") as ApiInstruction["data"], }; } function transformBlockhash(meta: BuildResponse["blockhashWithMetadata"]) { return { blockhash: getBase58Decoder().decode( Uint8Array.from(meta.blockhash), ) as Blockhash, lastValidBlockHeight: BigInt(meta.lastValidBlockHeight), }; } function transformALTs( raw: Record | null, ): AddressesByLookupTableAddress { if (!raw) return {}; return Object.fromEntries( Object.entries(raw).map(([key, addrs]) => [ address(key), addrs.map((a) => address(a)), ]), ); } function buildTransaction( ixs: Instruction[], blockhash: { blockhash: Blockhash; lastValidBlockHeight: bigint }, alts: AddressesByLookupTableAddress, feePayer: Address, ) { return pipe( createTransactionMessage({ version: 0 }), (msg) => appendTransactionMessageInstructions(ixs, msg), (msg) => compressTransactionMessageUsingAddressLookupTables(msg, alts), (msg) => setTransactionMessageFeePayer(feePayer, msg), (msg) => setTransactionMessageLifetimeUsingBlockhash(blockhash, msg), (msg) => compileTransaction(msg), ); } // ── Main ───────────────────────────────────────────────────────────────────── const API_KEY = process.env.JUPITER_API_KEY!; const rpc = createSolanaRpc(process.env.RPC_URL!); const signer = await createKeyPairSignerFromBytes( getBase58Encoder().encode(process.env.BS58_PRIVATE_KEY!), ); // 1. Call /build with your swap parameters const buildRes = await fetch( "https://api.jup.ag/swap/v2/build?" + new URLSearchParams({ inputMint: "So11111111111111111111111111111111111111112", outputMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", amount: "100000000", taker: signer.address, tipAmount: "1000000", }), { headers: { "x-api-key": API_KEY } }, ); const build: BuildResponse = await buildRes.json(); // 2. Collect instructions (excluding compute budget — we handle CU limit ourselves) const instructions = [ ...build.setupInstructions.map(createInstruction), createInstruction(build.swapInstruction), ...(build.cleanupInstruction ? [createInstruction(build.cleanupInstruction)] : []), ...build.otherInstructions.map(createInstruction), createInstruction(build.tipInstruction), ]; // 3. Prepare blockhash and address lookup tables const blockhash = transformBlockhash(build.blockhashWithMetadata); const alts = transformALTs(build.addressesByLookupTableAddress); // 4. Simulate to estimate CU usage, then apply 1.2x buffer const simTx = buildTransaction( [createInstruction(makeSetComputeUnitLimitIx(CU_LIMIT_MAX)), ...instructions], blockhash, alts, signer.address, ); const sim = await rpc .simulateTransaction(getBase64EncodedWireTransaction(simTx), { encoding: "base64", commitment: "confirmed", replaceRecentBlockhash: true, }) .send(); if (sim.value.err) { console.error("Simulation failed:", sim.value.err); process.exit(1); } const estimatedCUL = sim.value.unitsConsumed ? Math.min( Math.ceil(Number(sim.value.unitsConsumed) * 1.2), CU_LIMIT_MAX, ) : CU_LIMIT_MAX; // 5. Build final transaction with estimated CU limit + CU price from response const compiledTx = buildTransaction( [ createInstruction(makeSetComputeUnitLimitIx(estimatedCUL)), ...build.computeBudgetInstructions.map(createInstruction), ...instructions, ], blockhash, alts, signer.address, ); // 6. Sign and submit via /submit (or use your own RPC / transaction pipeline) const signedTx = await signTransaction([signer.keyPair], compiledTx); const submitRes = await fetch("https://api.jup.ag/tx/v1/submit", { method: "POST", headers: { "Content-Type": "application/json", "x-api-key": API_KEY, }, body: JSON.stringify({ signedTransaction: getBase64EncodedWireTransaction(signedTx), }), }); const { signature } = await submitRes.json(); console.log("Submitted:", `https://solscan.io/tx/${signature}`); // 7. Confirm the transaction landed const confirmation = await rpc .confirmTransaction(signature, { strategy: { type: "blockhash", ...blockhash }, commitment: "confirmed", }) .send(); if (confirmation.value.err) { console.error("Transaction failed:", confirmation.value.err); process.exit(1); } console.log("Confirmed:", signature); ``` ### Adding tip instruction manually For non-Jupiter transactions (another swap protocol, a program call, a transfer), add a standard SOL transfer to one of the 16 tip receiver accounts. Randomise which account you send to on each transaction to reduce write-lock contention. ```typescript @solana/web3.js expandable theme={null} import { SystemProgram, PublicKey } from "@solana/web3.js"; const TIP_ACCOUNTS = [ "GGztQqQ6pCPaJQnNpXBgELr5cs3WwDakRbh1iEMzjgSJ", "2MFoS3MPtvyQ4Wh4M9pdfPjz6UhVoNbFbGJAskCPCj3h", "BQ72nSv9f3PRyRKCBnHLVrerrv37CYTHm5h3s9VSGQDV", "6U91aKa8pmMxkJwBCfPTmUEfZi6dHe7DcFq2ALvB2tbB", "4xDsmeTWPNjgSVSS1VTfzFq3iHZhp77ffPkAmkZkdu71", "CapuXNQoDviLvU1PxFiizLgPNQCxrsag1uMeyk6zLVps", "9nnLbotNTcUhvbrsA6Mdkx45Sm82G35zo28AqUvjExn8", "6LXutJvKUw8Q5ue2gCgKHQdAN4suWW8awzFVC6XCguFx", "HFqp6ErWHY6Uzhj8rFyjYuDya2mXUpYEk8VW75K9PSiY", "DSN3j1ykL3obAVNv7ZX49VsFCPe4LqzxHnmtLiPwY6xg", "69yhtoJR4JYPPABZcSNkzuqbaFbwHsCkja1sP1Q2aVT5", "HU23r7UoZbqTUuh3vA7emAGztFtqwTeVips789vqxxBw", "3LoAYHuSd7Gh8d7RTFnhvYtiTiefdZ5ByamU42vkzd76", "3CgvbiM3op4vjrrjH2zcrQUwsqh5veNVRjFCB9N6sRoD", "GP8StUXNYSZjPikyRsvkTbvRV1GBxMErb59cpeCJnDf1", "7iWnBRRhBCiNXXPhqiGzvvBkKrvFSWqqmxRyu9VyYBxE", ]; const tipIx = SystemProgram.transfer({ fromPubkey: signer.publicKey, toPubkey: new PublicKey( TIP_ACCOUNTS[Math.floor(Math.random() * TIP_ACCOUNTS.length)] ), lamports: 1_000_000, // 0.001 SOL minimum }); // Add tipIx to your transaction, sign, then submit via /submit ``` ```typescript @solana/kit expandable theme={null} import { getTransferSolInstruction } from "@solana-program/system"; const TIP_ACCOUNTS = [ "GGztQqQ6pCPaJQnNpXBgELr5cs3WwDakRbh1iEMzjgSJ", "2MFoS3MPtvyQ4Wh4M9pdfPjz6UhVoNbFbGJAskCPCj3h", "BQ72nSv9f3PRyRKCBnHLVrerrv37CYTHm5h3s9VSGQDV", "6U91aKa8pmMxkJwBCfPTmUEfZi6dHe7DcFq2ALvB2tbB", "4xDsmeTWPNjgSVSS1VTfzFq3iHZhp77ffPkAmkZkdu71", "CapuXNQoDviLvU1PxFiizLgPNQCxrsag1uMeyk6zLVps", "9nnLbotNTcUhvbrsA6Mdkx45Sm82G35zo28AqUvjExn8", "6LXutJvKUw8Q5ue2gCgKHQdAN4suWW8awzFVC6XCguFx", "HFqp6ErWHY6Uzhj8rFyjYuDya2mXUpYEk8VW75K9PSiY", "DSN3j1ykL3obAVNv7ZX49VsFCPe4LqzxHnmtLiPwY6xg", "69yhtoJR4JYPPABZcSNkzuqbaFbwHsCkja1sP1Q2aVT5", "HU23r7UoZbqTUuh3vA7emAGztFtqwTeVips789vqxxBw", "3LoAYHuSd7Gh8d7RTFnhvYtiTiefdZ5ByamU42vkzd76", "3CgvbiM3op4vjrrjH2zcrQUwsqh5veNVRjFCB9N6sRoD", "GP8StUXNYSZjPikyRsvkTbvRV1GBxMErb59cpeCJnDf1", "7iWnBRRhBCiNXXPhqiGzvvBkKrvFSWqqmxRyu9VyYBxE", ]; const tipIx = getTransferSolInstruction({ source: signer, destination: address( TIP_ACCOUNTS[Math.floor(Math.random() * TIP_ACCOUNTS.length)] ), amount: 1_000_000n, // 0.001 SOL minimum }); // Add tipIx to your transaction, sign, then submit via /submit ``` ## Best practices * **Randomise tip accounts:** there are 16 tip receiver accounts. Randomise which one you send to on each transaction to reduce write-lock contention across concurrent submissions. * **Use `tipAmount` with `/build`:** pass `tipAmount` as a query parameter to have the tip instruction included automatically, rather than adding it manually. * **Set `maxRetries: 0` on RPC fallback:** if you run `/submit` in parallel with `sendRawTransaction`, let your application control retry logic rather than the RPC node, so you can refresh the blockhash between attempts. * **Poll for confirmation:** use `confirmTransaction` with the blockhash and `lastValidBlockHeight` from your transaction. If the blockhash expires without confirmation, rebuild with a fresh blockhash and resubmit. * **`/submit` does not simulate:** we send directly to the TPU for fastest possible delivery. If you require simulation, do it before making a request to `/submit`. * **Colocate for lowest latency:** Jupiter's API gateway runs in [six AWS regions](/docs/portal/latency). Deploy your servers in the nearest region to minimise round-trip time. ## How /submit differs from /execute | | `/execute` | `/submit` | | ---------------------- | ------------------------------------------------ | --------------------------------------------------------- | | **Paired with** | `/order` (meta-aggregator flow) | `/build` or any signed transaction | | **Fee model** | Jupiter swap fees (included in the order) | SOL tips (minimum 0.001 SOL) | | **Transaction source** | Must match the exact transaction from `/order` | Any valid signed Solana transaction | | **Credit cost** | 0 credits | 0 credits | | **Use case** | Managed swap execution for `/order` transactions | Any transaction: `/build` swaps, non-Jupiter transactions | ## API reference **Endpoint:** `POST https://api.jup.ag/tx/v1/submit` See the [POST /submit API reference](/docs/api-reference/transaction/submit) for the full specification. ## Related * [Build](/docs/swap/build): build custom transactions with `/build` (use `tipAmount` for automatic tip inclusion) * [Order & Execute](/docs/swap/order-and-execute): the standard swap flow using `/order` + `/execute` * [Reduce Latency](/docs/swap/advanced/reduce-latency): use `mode=fast` on `/build` for faster routing * [Plans and Pricing](/docs/portal/plans): all plans include `/submit` at zero credit cost * [Latency and Server Locations](/docs/portal/latency): API gateway regions and colocation guidance # Authentication Source: https://dev.jup.ag/docs/trigger/authentication Authenticate with the Trigger Order API using a challenge-response JWT flow. The Trigger Order API V2 uses a challenge-response flow to authenticate users. Your wallet signs a challenge, and the server issues a JWT token valid for 24 hours. ## Authentication Flow ``` 1. Request challenge → POST /v2/auth/challenge 2. Sign with wallet → (client-side) 3. Submit signature → POST /v2/auth/verify → JWT token 4. Use JWT → Authorization: Bearer ``` ## Prerequisites Signing challenges and transactions requires `@solana/web3.js` and `bs58`: ```bash theme={null} npm install @solana/web3.js bs58 ``` ## Step 1: Request a Challenge Request a challenge for your wallet. Choose `message` for standard wallets or `transaction` for hardware wallets that only support transaction signing. ```typescript theme={null} const challengeResponse = await fetch('https://api.jup.ag/trigger/v2/auth/challenge', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': 'your-api-key', }, body: JSON.stringify({ walletPubkey: walletAddress, type: 'message', // or 'transaction' for hardware wallets }), }); const challenge = await challengeResponse.json(); ``` **Message challenge response:** ```json theme={null} { "type": "message", "challenge": "Sign this message to authenticate with Jupiter Trigger Order API..." } ``` **Transaction challenge response:** ```json theme={null} { "type": "transaction", "transaction": "Base64EncodedTransactionWithMemoInstruction..." } ``` Challenges expire after 5 minutes. Request a new one if your challenge expires. ## Step 2: Sign and Verify Sign the challenge with your wallet, then submit the signature to receive a JWT token. **For message signing:** ```typescript theme={null} import bs58 from 'bs58'; // Sign the challenge message with your wallet const encodedMessage = new TextEncoder().encode(challenge.challenge); const signature = await wallet.signMessage(encodedMessage); const verifyResponse = await fetch('https://api.jup.ag/trigger/v2/auth/verify', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': 'your-api-key', }, body: JSON.stringify({ type: 'message', walletPubkey: walletAddress, signature: bs58.encode(signature), }), }); const { token } = await verifyResponse.json(); // Use this token in Authorization: Bearer for all authenticated requests ``` **For transaction signing (hardware wallets):** ```typescript theme={null} import { VersionedTransaction } from '@solana/web3.js'; const signedTx = await wallet.signTransaction( VersionedTransaction.deserialize(Buffer.from(challenge.transaction, 'base64')) ); const verifyResponse = await fetch('https://api.jup.ag/trigger/v2/auth/verify', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': 'your-api-key', }, body: JSON.stringify({ type: 'transaction', walletPubkey: walletAddress, signedTransaction: Buffer.from(signedTx.serialize()).toString('base64'), }), }); const { token } = await verifyResponse.json(); ``` ## Using the JWT Include the JWT in all authenticated requests: ```typescript theme={null} const response = await fetch('https://api.jup.ag/trigger/v2/vault', { headers: { 'x-api-key': 'your-api-key', 'Authorization': `Bearer ${token}`, }, }); ``` ## Token Lifecycle | Property | Value | | :---------------- | :-------- | | **Challenge TTL** | 5 minutes | | **JWT TTL** | 24 hours | When a token expires, repeat the challenge-response flow to obtain a new one. There is no refresh endpoint. ## Security Notes **For integrators building user-facing applications:** * Never store JWT tokens in local storage. Use secure, httpOnly cookies or in-memory storage * Always verify the challenge content before signing. Do not blindly sign arbitrary messages * Implement token refresh logic to handle expiration gracefully * The JWT is tied to the wallet public key. Do not reuse tokens across wallets ### What Happens if a JWT is Leaked The JWT grants limited access. An attacker with a leaked token can: * **Cancel orders**: This transitions the order from `open` to `ready_to_cancel`, but does **not** withdraw funds. Withdrawal requires signing a transaction with the wallet private key. * **Edit order parameters**: Updating trigger prices or slippage does not require transaction signing. An attacker **cannot**: * **Withdraw funds**: All withdrawal operations require the wallet owner to sign a transaction. The vault's funds remain secure. * **Create new orders**: Depositing tokens requires signing a deposit transaction with the wallet. All operations involving funds (deposits, withdrawals) require the wallet owner to sign a transaction. A leaked JWT alone cannot result in loss of funds. However, if the wallet private key is also compromised, an attacker could sign transactions and withdraw funds from the vault. # Best Practices Source: https://dev.jup.ag/docs/trigger/best-practices Guidelines for order expiry, slippage, error handling, and integration patterns for the Trigger Order V2 API. The Trigger Order V2 API is in **beta** and under active development. Behaviour, endpoints, and response formats may change as we iterate based on integrator feedback. Pin to specific response schemas and handle unknown fields gracefully. ## Reference Implementation The [jup.ag](https://jup.ag) frontend is the canonical reference for how to interact with the V2 API. When in doubt about edge cases, validation logic, or UX patterns, refer to how jup.ag handles it. This includes: * Order creation flows and parameter validation * Price and slippage presentation * Error handling and retry logic * Order state management and polling ## Order Expiry Every order requires an `expiresAt` timestamp. Unlike V1 where orders could exist indefinitely, V2 enforces expiry on all orders. This allows the system to prune stale orders, improving execution quality for active orders. | Use case | Recommended expiry | | :---------------------- | :----------------------------- | | Short-term trades | 1-7 days | | Swing trades | 7-30 days | | Long-duration positions | 30 days, with periodic renewal | For long-lived orders, set a 30-day expiry and renew by updating the order before it expires via the [update endpoint](/docs/trigger/manage-orders#update-an-order). There is no "no expiry" option by design. ## Slippage | Order type | Default | Recommendation | | :---------------------- | :------------- | :--------------------------------------------------------------------------- | | Take-profit / buy below | Auto (RTSE) | Use the default unless you have specific requirements | | Stop-loss / buy above | 20% (2000 bps) | Keep high for execution certainty -- tighten only if you accept missed fills | | Parent (OTOCO) | Auto (RTSE) | Use the default | Stop-loss orders use a higher default because execution certainty matters more than price precision when cutting losses. If you lower stop-loss slippage, the order may not fill during volatile conditions. ## Error Handling * **Validation errors** (400) include a `details` object with per-field messages. Parse these to surface specific issues to users. * **Authentication errors** (401) mean the JWT has expired. Re-authenticate with a new challenge-response flow rather than retrying the same token. * **Minimum order size** is 10 USD. Enforce this client-side to avoid unnecessary API calls. * Handle unknown fields in responses gracefully. As the API evolves during beta, new fields may be added to response objects. ## Order Summary The API does not validate whether your trigger price makes economic sense. If a user sets a buy order above market price or a sell order below market price, the keeper will execute as instructed and the difference is lost. Display a human-readable summary of what the order will do before the user confirms. On [jup.ag](https://jup.ag), the confirmation shows a plain-language description like: > Buy SOL with 15 USDC when price goes below $76.37 (-10% from market). If triggered, automatically set TP for SOL at $84.01. This helps users catch mistakes before submitting. For OCO and OTOCO orders, include both the trigger conditions and the child order parameters in the summary. ## Token Compatibility * Tokens with transfer tax extensions (Token-2022) are not supported * Input and output mints must be different ## Order Lifecycle Poll the [history endpoint](/docs/trigger/order-history) to track order state. Key states to handle: | State | Meaning | Action | | :---------- | :-------------------------- | :------------------------------------------------- | | `open` | Active, waiting for trigger | No action needed | | `filled` | Fully executed | Show completion to user | | `cancelled` | Cancelled by user | Confirm funds returned to vault | | `expired` | Past `expiresAt` | Prompt user to withdraw funds or recreate | | `failed` | Execution failed | Show error, suggest retry with adjusted parameters | # Create Order Source: https://dev.jup.ag/docs/trigger/create-order Create trigger orders with vault-based deposits. Supports single limit orders, OCO (take-profit/stop-loss), and OTOCO (conditional chains). Creating an order in V2 is a two-step process: craft and sign a deposit transaction, then submit it alongside your order parameters. **Action required:** This change is planned for Thursday, May 14, 2026 at 4:00 AM UTC / 12:00 PM SGT. Price-order deposits crafted with `POST /trigger/v2/deposit/craft` must include `orderType: "price"` and `orderSubType`. Requests missing either field will return a `4xx`. For a working reference of the full order creation flow, see how [jup.ag](https://jup.ag) handles it. The frontend implements the same API with validation, error handling, and UX patterns you can use as a guide. ## Prerequisites Signing deposit transactions requires `@solana/web3.js`: ```bash theme={null} npm install @solana/web3.js ``` ## End-to-End Flow ``` 1. Get vault → GET /v2/vault (or /v2/vault/register on first use) 2. Craft deposit → POST /v2/deposit/craft 3. Sign deposit tx → (client-side) 4. Create order → POST /v2/orders/price (with signed tx) ``` ## Step 1: Get Your Vault Retrieve your vault, or register one if this is your first time. The vault is a Privy-managed custodial account that holds deposits for your orders. ```typescript theme={null} let vaultResponse = await fetch('https://api.jup.ag/trigger/v2/vault', { headers: { 'x-api-key': 'your-api-key', 'Authorization': `Bearer ${token}`, }, }); // First time user — register a new vault if (!vaultResponse.ok) { vaultResponse = await fetch('https://api.jup.ag/trigger/v2/vault/register', { headers: { 'x-api-key': 'your-api-key', 'Authorization': `Bearer ${token}`, }, }); } const vault = await vaultResponse.json(); // { userPubkey: "...", vaultPubkey: "...", privyVaultId: "..." } ``` ## Step 2: Craft a Deposit Transaction The deposit endpoint builds an unsigned transaction that transfers tokens from your wallet to your vault. ```typescript theme={null} const depositResponse = await fetch('https://api.jup.ag/trigger/v2/deposit/craft', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': 'your-api-key', 'Authorization': `Bearer ${token}`, }, body: JSON.stringify({ inputMint: 'So11111111111111111111111111111111111111112', // SOL outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC userAddress: walletAddress, amount: '1000000000', // 1 SOL in lamports orderType: 'price', orderSubType: 'single', }), }); const deposit = await depositResponse.json(); ``` Set `orderSubType` to match the price order you will create: | Order create type | Deposit `orderSubType` | Use it for | | :---------------- | :--------------------- | :----------------------------------------------------------------------------------------- | | `single` | `single` | A standalone price order | | `oco` | `oco` | A one-cancels-other pair sharing one deposit | | `otoco` | `otoco` | A parent trigger that activates an OCO pair. This also provisions an output token account. | **Response:** ```json theme={null} { "transaction": "Base64EncodedUnsignedTransaction...", "requestId": "01234567-89ab-cdef-0123-456789abcdef", "receiverAddress": "VaultPublicKey...", "mint": "So11111111111111111111111111111111111111112", "amount": "1000000000", "tokenDecimals": 9, "inputTokenAccount": "InputTokenAccountPubkey..." } ``` The vault address is automatically resolved from your JWT. You do not specify it in the request. You also do not pass `inputTokenAccount` or `outputTokenAccount` into `POST /trigger/v2/orders/price`; the API stores those accounts against the deposit `requestId`. For `orderSubType: "otoco"`, the response also includes `outputTokenAccount` for the output token account used by the conditional OCO pair. ## Step 3: Sign the Deposit Transaction ```typescript theme={null} import { VersionedTransaction } from '@solana/web3.js'; const transaction = VersionedTransaction.deserialize( Buffer.from(deposit.transaction, 'base64') ); const signedTransaction = await wallet.signTransaction(transaction); const depositSignedTx = Buffer.from(signedTransaction.serialize()).toString('base64'); ``` ## Step 4: Create the Order Submit the signed deposit alongside your order parameters. The order type determines which fields are required. ### Single Order (Limit) A single order triggers when the price of `triggerMint` crosses above or below the target price. ```typescript theme={null} const orderResponse = await fetch('https://api.jup.ag/trigger/v2/orders/price', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': 'your-api-key', 'Authorization': `Bearer ${token}`, }, body: JSON.stringify({ orderType: 'single', depositRequestId: deposit.requestId, depositSignedTx: depositSignedTx, userPubkey: walletAddress, inputMint: 'So11111111111111111111111111111111111111112', inputAmount: '1000000000', outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', triggerMint: 'So11111111111111111111111111111111111111112', triggerCondition: 'above', // 'above' or 'below' triggerPriceUsd: 200.00, slippageBps: 100, // 1% expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000, // 7 days }), }); const order = await orderResponse.json(); // { id: "order-uuid", txSignature: "..." } ``` ### OCO Order (One-Cancels-Other) An OCO order creates a take-profit and stop-loss pair sharing one deposit. When one side fills, the other cancels automatically. ```typescript theme={null} const orderResponse = await fetch('https://api.jup.ag/trigger/v2/orders/price', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': 'your-api-key', 'Authorization': `Bearer ${token}`, }, body: JSON.stringify({ orderType: 'oco', depositRequestId: deposit.requestId, depositSignedTx: depositSignedTx, userPubkey: walletAddress, inputMint: 'So11111111111111111111111111111111111111112', inputAmount: '1000000000', outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', triggerMint: 'So11111111111111111111111111111111111111112', tpPriceUsd: 250.00, // Take profit price slPriceUsd: 150.00, // Stop loss price tpSlippageBps: 100, slSlippageBps: 100, expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000, }), }); ``` The take-profit price must be greater than the stop-loss price. ### OTOCO Order (One-Triggers-One-Cancels-Other) An OTOCO order has a parent trigger that executes first. Once filled, it automatically activates a TP/SL pair (OCO) on the output tokens. ```typescript theme={null} const orderResponse = await fetch('https://api.jup.ag/trigger/v2/orders/price', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': 'your-api-key', 'Authorization': `Bearer ${token}`, }, body: JSON.stringify({ orderType: 'otoco', depositRequestId: deposit.requestId, depositSignedTx: depositSignedTx, userPubkey: walletAddress, inputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', inputAmount: '200000000', // 200 USDC outputMint: 'So11111111111111111111111111111111111111112', triggerMint: 'So11111111111111111111111111111111111111112', triggerCondition: 'below', triggerPriceUsd: 180.00, // Entry: buy SOL when it drops to \$180 tpPriceUsd: 220.00, // Take profit at \$220 slPriceUsd: 160.00, // Stop loss at \$160 slippageBps: 100, // Parent order slippage tpSlippageBps: 100, slSlippageBps: 100, expiresAt: Date.now() + 30 * 24 * 60 * 60 * 1000, // 30 days }), }); ``` ## Order Parameters Reference ### Common Fields (All Order Types) | Parameter | Type | Required | Description | | :----------------- | :------- | :------- | :---------------------------------------- | | `orderType` | `string` | Yes | `single`, `oco`, or `otoco` | | `depositRequestId` | `string` | Yes | From the deposit craft response | | `depositSignedTx` | `string` | Yes | Base64-encoded signed deposit transaction | | `userPubkey` | `string` | Yes | Your wallet public key | | `inputMint` | `string` | Yes | Mint address of the token to sell | | `inputAmount` | `string` | Yes | Amount in smallest unit (lamports, etc.) | | `outputMint` | `string` | Yes | Mint address of the token to buy | | `triggerMint` | `string` | Yes | Mint address to monitor for price trigger | | `expiresAt` | `number` | Yes | Expiration timestamp in milliseconds | ### Single Order Fields | Parameter | Type | Required | Description | | :----------------- | :------- | :------- | :------------------------------------------- | | `triggerCondition` | `string` | Yes | `above` or `below` | | `triggerPriceUsd` | `number` | Yes | USD price that triggers execution | | `slippageBps` | `number` | No | Slippage tolerance in basis points (0-10000) | ### OCO Order Fields | Parameter | Type | Required | Description | | :-------------- | :------- | :------- | :---------------------------------- | | `tpPriceUsd` | `number` | Yes | Take-profit trigger price (USD) | | `slPriceUsd` | `number` | Yes | Stop-loss trigger price (USD) | | `tpSlippageBps` | `number` | No | Take-profit slippage (basis points) | | `slSlippageBps` | `number` | No | Stop-loss slippage (basis points) | ### OTOCO Order Fields | Parameter | Type | Required | Description | | :----------------- | :------- | :------- | :----------------------------------- | | `triggerCondition` | `string` | Yes | Parent trigger: `above` or `below` | | `triggerPriceUsd` | `number` | Yes | Parent trigger price (USD) | | `tpPriceUsd` | `number` | Yes | Take-profit price after parent fills | | `slPriceUsd` | `number` | Yes | Stop-loss price after parent fills | | `slippageBps` | `number` | No | Parent order slippage | | `tpSlippageBps` | `number` | No | Take-profit slippage | | `slSlippageBps` | `number` | No | Stop-loss slippage | ## Default Slippage If slippage is not specified, defaults vary by order type and trigger condition: | Order side | Default slippage | | :------------------------------------------------- | :---------------------------------------------------- | | **Take-profit / buy below** (buying into strength) | Auto slippage via RTSE (Real-Time Slippage Estimator) | | **Stop-loss / buy above** (selling into weakness) | 20% (2000 bps) | Stop-loss orders use a higher default because execution certainty is more important than price precision when cutting losses. ## Validation Rules * Minimum order size: 10 USD * Input and output mints must be different * Slippage: 0-10000 basis points * `expiresAt` is required and must be a future timestamp (milliseconds) * OCO/OTOCO: take-profit price must be greater than stop-loss price Unlike V1 where orders could exist indefinitely, V2 requires an expiration on every order. Adding a TTL allows the system to prune orders that are unlikely to fill, improving execution quality for active orders. For long-lived orders, use a far-future timestamp (e.g. 30 days). ## Response ```json theme={null} { "id": "order-uuid", "txSignature": "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d..." } ``` The `txSignature` confirms the deposit transaction landed on-chain. The order is now active and will execute when price conditions are met. # Trigger Order API Overview Source: https://dev.jup.ag/docs/trigger/index Create advanced trigger orders on Solana with vault-based execution, including limit orders, take-profit/stop-loss (OCO), and conditional chains (OTOCO). The Jupiter Trigger Order API enables advanced order types on Solana, allowing users to set price conditions for token swaps that execute automatically when market conditions are met. V1 required traders to think in pool ratios — calculating how many tokens per SOL a pool needed to reach before an order would trigger. V2 replaces this with USD price triggers: set a dollar price and Jupiter handles conversion, routing, and execution. Orders are stored off-chain and private by default, closing the most common MEV attack vector of visible pending orders. ## What's New in V2 | Feature | V1 | V2 | | :------------------ | :----------------------------------------------- | :------------------------------------------------------------------ | | **Trigger type** | Pool rate only (e.g. "1 Fartcoin = 0.00025 SOL") | USD price | | **Order direction** | Buy below, sell above | Buy above, buy below, sell above, sell below | | **TP/SL** | Not supported | Take-profit and stop-loss with OCO bundling | | **Edit orders** | Must cancel and recreate | Edit trigger price and slippage in-place | | **Partial fills** | Not supported | Orders fill partially for optimal execution prices | | **Output amount** | Guaranteed (fixed pool rate) | Not guaranteed (prioritises trigger execution, pool price may vary) | | **Authentication** | API key only | Challenge-response JWT + API key | | **Order privacy** | Pending orders visible on-chain (PDA accounts) | Orders stored off-chain, private until execution | | **Deposits** | Program-derived address (PDA) order accounts | Vault accounts (custodial) by Privy | | **Route prefix** | `/trigger/v1` | `/trigger/v2` | There are no current plans to deprecate V1. However, all development efforts, research, and maintenance are focused entirely on V2. V1 will only receive updates for critical issues. ## Order Types | Type | Description | Use case | | :--------- | :-------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------ | | **Single** | Triggers when USD price crosses above or below a threshold | Standard limit orders, stop-loss | | **OCO** | Two orders sharing one deposit: one take-profit, one stop-loss. When one fills, the other cancels automatically | Risk management with TP/SL brackets (e.g. sell SOL at \$300 TP or \$200 SL while market is \$250) | | **OTOCO** | A parent order triggers first, then activates a TP/SL pair (OCO) on the output | Conditional entry with automatic exit strategy | ## How It Works ``` Your Wallet ──→ Vault (1 per wallet) ──→ Order A ──→ Order B ──→ Order C ``` Each wallet gets a single vault (a Privy-managed custodial account). When you create orders, tokens are deposited from your wallet into your vault. The vault holds funds for all your active orders. 1. [**Authenticate**](/docs/trigger/authentication): Sign a challenge with your wallet to receive a JWT token 2. [**Get your vault**](/docs/trigger/create-order#step-1-get-your-vault): Retrieve your vault, or register one on first use 3. [**Create an order**](/docs/trigger/create-order): Deposit tokens into your vault and submit order parameters 4. **Monitor**: Track order state and history via the [history endpoint](/docs/trigger/order-history) 5. [**Manage**](/docs/trigger/manage-orders): Update order parameters, or cancel with a two-step withdrawal flow ## Base URL ``` https://api.jup.ag/trigger/v2 ``` All endpoints require an API key via the `x-api-key` header. Authenticated endpoints additionally require a JWT token via the `Authorization: Bearer ` header. ## FAQ Funds remain in the vault. To retrieve them, use the same two-step cancel flow: initiate cancellation on the expired order, sign the withdrawal transaction, and confirm. See [Expired Order Withdrawal](/docs/trigger/manage-orders#expired-order-withdrawal). Yes. You can update trigger prices and slippage in-place without cancelling and recreating the order. See [Update an Order](/docs/trigger/manage-orders#update-an-order). V2 uses USD price triggers rather than pool rate triggers. When the price condition is met, the order executes a swap at the current market rate via Jupiter routing. The actual output depends on liquidity and slippage at execution time. 10 USD equivalent. Open orders continue to be monitored and will execute normally. The JWT is only required for API calls (creating, editing, cancelling orders). When your token expires, re-authenticate to manage your orders. A One-Cancels-Other order creates a take-profit and stop-loss pair that share one deposit. When one side fills, the other cancels automatically, returning unused funds to the vault. A One-Triggers-One-Cancels-Other order has a parent trigger that executes first. Once the parent fills, it automatically activates a TP/SL pair (OCO) on the output tokens. If the parent expires or fails, the child orders are never created. Take-profit and buy-below orders use auto slippage via RTSE (Real-Time Slippage Estimator). Stop-loss and buy-above orders default to 20% (2000 bps) because execution certainty is more important when cutting losses. You can always set a custom slippage. The API accepts USD price triggers only (`triggerPriceUsd`). Market cap targeting is a convenience feature on the jup.ag frontend — it converts the market cap to a USD price before submitting to the API. To replicate this, divide the target market cap by the token's total supply to get the per-token USD price. No. V2 orders are stored off-chain and private by default. Order details (price, size, direction) are not revealed until the trigger condition is met and execution begins. In V1, pending orders were stored in on-chain PDA accounts, giving bots a roadmap to front-run profitable trades. Not currently, and there is no timeline for adding them. There is no atomic workaround because the keeper executes the transaction and the order is opaque to integrators. The only option is to run a separate transfer transaction outside the order flow. # Manage Orders Source: https://dev.jup.ag/docs/trigger/manage-orders Update order parameters, cancel orders with two-step withdrawal, and withdraw funds from your vault. ## Prerequisites Signing withdrawal transactions requires `@solana/web3.js`: ```bash theme={null} npm install @solana/web3.js ``` ## Update an Order Modify the trigger price or slippage of an existing order without cancelling and recreating it. ```typescript theme={null} const updateResponse = await fetch(`https://api.jup.ag/trigger/v2/orders/price/${orderId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json', 'x-api-key': 'your-api-key', 'Authorization': `Bearer ${token}`, }, body: JSON.stringify({ orderType: 'single', triggerPriceUsd: 210.00, slippageBps: 150, }), }); const result = await updateResponse.json(); // { id: "order-uuid" } ``` ### Update Fields by Order Type **Single:** ```json theme={null} { "orderType": "single", "triggerPriceUsd": 210.00, "slippageBps": 150 } ``` **OCO:** ```json theme={null} { "orderType": "oco", "tpPriceUsd": 260.00, "slPriceUsd": 145.00 } ``` **OTOCO:** ```json theme={null} { "orderType": "otoco", "triggerPriceUsd": 185.00, "tpPriceUsd": 230.00, "slPriceUsd": 155.00 } ``` ## Cancel an Order Cancellation is a two-step process. The first step returns a withdrawal transaction that moves funds from the vault back to your wallet. You sign and submit it in the second step. ### Step 1: Initiate Cancellation This immediately moves the order from `open` to `ready_to_cancel`. The order will no longer be filled, even if step 2 has not yet completed. This prevents a race condition where the order could still execute while you are signing the withdrawal transaction. ```typescript theme={null} const cancelResponse = await fetch( `https://api.jup.ag/trigger/v2/orders/price/cancel/${orderId}`, { method: 'POST', headers: { 'x-api-key': 'your-api-key', 'Authorization': `Bearer ${token}`, }, } ); const cancelData = await cancelResponse.json(); ``` **Response:** ```json theme={null} { "id": "order-uuid", "transaction": "Base64EncodedUnsignedWithdrawalTransaction...", "requestId": "cancel-request-uuid" } ``` ### Step 2: Sign and Confirm Sign the withdrawal transaction and submit it to complete the cancellation. ```typescript theme={null} import { VersionedTransaction } from '@solana/web3.js'; const transaction = VersionedTransaction.deserialize( Buffer.from(cancelData.transaction, 'base64') ); const signedTransaction = await wallet.signTransaction(transaction); const confirmResponse = await fetch( `https://api.jup.ag/trigger/v2/orders/price/confirm-cancel/${orderId}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': 'your-api-key', 'Authorization': `Bearer ${token}`, }, body: JSON.stringify({ signedTransaction: Buffer.from(signedTransaction.serialize()).toString('base64'), cancelRequestId: cancelData.requestId, }), } ); const result = await confirmResponse.json(); // { id: "order-uuid", txSignature: "..." } ``` If step 2 fails (the transaction doesn't land), you can retry by calling the confirm endpoint again with the same `cancelRequestId`. The order remains in `ready_to_cancel` state until the withdrawal confirms. ## Expired Order Withdrawal If an order expires before execution, the funds remain in the vault. To retrieve them, use the same two-step cancel flow: initiate cancellation on the expired order, sign the withdrawal transaction, and confirm. The order transitions through `ready_to_cancel` and then to `cancelled` once the withdrawal confirms on-chain. ## Error Handling | Status | Meaning | | :----- | :---------------------------------------------------------------------- | | `400` | Invalid order ID, order not in a cancellable state, or validation error | | `401` | Invalid API key, or JWT expired/invalid | | `403` | Order belongs to a different wallet | | `404` | Order not found | # Order History Source: https://dev.jup.ag/docs/trigger/order-history Query order history, filter by state, and understand the order lifecycle. ## Get Order History Retrieve your orders with optional filters for state, mint, and pagination. ```typescript theme={null} const historyResponse = await fetch( 'https://api.jup.ag/trigger/v2/orders/history?state=active&limit=20&offset=0', { headers: { 'x-api-key': 'your-api-key', 'Authorization': `Bearer ${token}`, }, } ); const history = await historyResponse.json(); ``` ### Query Parameters | Parameter | Type | Default | Description | | :-------- | :------- | :----------- | :---------------------------------------------------------- | | `state` | `string` | — | `active` (open orders) or `past` (filled/cancelled/expired) | | `mint` | `string` | — | Filter by token mint address (input or output) | | `limit` | `number` | `20` | Results per page (1-100) | | `offset` | `number` | `0` | Number of results to skip | | `sort` | `string` | `updated_at` | Sort field: `updated_at`, `created_at`, `expires_at` | | `dir` | `string` | `desc` | Sort direction: `asc` or `desc` | ### Response ```json theme={null} { "orders": [ { "id": "order-uuid", "orderType": "single", "orderState": "open", "rawState": "open", "userPubkey": "YourWalletPublicKey...", "privyWalletPubkey": "VaultPublicKey...", "inputMint": "So11111111111111111111111111111111111111112", "initialInputAmount": "1000000000", "remainingInputAmount": "1000000000", "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "triggerMint": "So11111111111111111111111111111111111111112", "triggerCondition": "above", "triggerPriceUsd": 200.00, "slippageBps": 100, "expiresAt": 1704067200000, "createdAt": 1704000000000, "updatedAt": 1704000000000, "events": [ { "type": "deposit", "timestamp": 1704000000000, "txSignature": "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d...", "mint": "So11111111111111111111111111111111111111112", "amount": "1000000000", "state": "success" } ] } ], "pagination": { "total": 50, "limit": 20, "offset": 0 } } ``` ### Additional Fields for Filled Orders Orders that have been fully or partially filled include extra fields: | Field | Description | | :------------- | :----------------------------------------- | | `triggeredAt` | Timestamp when the price condition was met | | `outputAmount` | Total output tokens received | | `inputUsed` | Total input tokens consumed | | `fillPercent` | Fill ratio (1.0 = fully filled) | ### Execution Attempts Order history includes execution attempts for each order. When an order fails to execute (due to slippage, quote generation failure, or other reasons), the attempt is recorded in the history. The reason for failure is not included in the response. Users can adjust slippage settings via the [update endpoint](/docs/trigger/manage-orders) if execution keeps failing due to slippage. ### Event Types Each order includes an `events` array tracking its lifecycle: | Event Type | Description | | :----------- | :------------------------------- | | `deposit` | Tokens deposited into vault | | `fill` | Order executed (full or partial) | | `withdrawal` | Tokens withdrawn back to wallet | | `cancelled` | Order cancelled by user | | `expired` | Order expired | Each event includes `type`, `timestamp`, and `state`. Events that involve token movement (`deposit`, `fill`, `withdrawal`) also include: | Field | Description | | :------------ | :------------------------------ | | `txSignature` | On-chain transaction signature | | `mint` | Token mint address | | `amount` | Token amount (in smallest unit) | Fill events include additional fields: | Field | Description | | :------------- | :--------------------------------------------------------------------------- | | `outputMint` | Output token mint address | | `outputAmount` | Output amount received | | `orderContext` | Semantic order type: `take_profit`, `stop_loss`, `buy_above`, or `buy_below` | ## Order States Orders follow a state machine from creation to completion. The `orderState` field provides a human-friendly state, while `rawState` shows the exact internal state. ### Display States | State | Description | | :----------------- | :------------------------------------------------- | | `pending` | Deposit is being processed | | `open` | Active and waiting for price trigger | | `executing` | Price condition met, swap in progress | | `filled` | Order completed successfully | | `pending_withdraw` | Cancellation initiated, awaiting signed withdrawal | | `cancelled` | User cancelled the order | | `expired` | Order expired before execution | | `failed` | Execution failed | ### Raw States The `rawState` field exposes the internal processing state. Multiple raw states map to each display state: | `orderState` | `rawState` | Meaning | | :----------------- | :---------------------- | :------------------------------------------------------------------- | | `pending` | `pending_deposit` | Deposit transaction not yet submitted | | `pending` | `depositing` | Deposit transaction submitted, awaiting confirmation | | `open` | `open` | Active and monitoring price | | `executing` | `ready_execute` | Price condition met, preparing swap | | `executing` | `ready_expire` | Order expiry detected, processing | | `executing` | `executing` | Swap transaction in flight | | `executing` | `execute_success` | Swap landed, validating output | | `executing` | `execute_failed` | Swap attempt failed, may retry | | `executing` | `ready_withdraw_output` | Output ready to withdraw to wallet | | `executing` | `withdrawing` | Withdrawal transaction in flight | | `filled` | `fill_success` | Order fully filled and output withdrawn | | `executing` | `partial_fill_success` | Order partially filled, may continue filling | | `pending_withdraw` | `ready_to_cancel` | Cancellation initiated, awaiting signed withdrawal | | `cancelled` | `cancelled` | User cancelled the order | | `cancelled` | `oco_cancelled` | Automatically cancelled because the other side of an OCO pair filled | | `expired` | `expired` | Order expired before execution | | `failed` | `deposit_failed` | Deposit transaction failed on-chain (e.g. insufficient balance) | | `failed` | `withdraw_failed` | Output withdrawal failed after execution | | `failed` | `fill_failed` | Fill validation failed after execution | ### State Flow ``` pending ──→ open ──→ executing ──→ filled │ │ │ │ │ └──→ failed └──→ failed│ (deposit) ├──→ expired │ └──→ pending_withdraw ──→ cancelled ``` For OCO orders, when one side fills, the other transitions to `cancelled` automatically (displayed as `oco_cancelled` in the raw state). For OTOCO orders, the child OCO pair only activates after the parent order reaches `filled`. If the parent expires or fails, the children are never created.