> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbitflare.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Metis Swap API

> Low-level Jupiter routing engine for swaps — CPI, custom instructions, and full transaction control

## Overview

Metis is Jupiter's low-level swap routing engine. It exposes granular control over every aspect of a swap transaction: route selection, instruction composition, priority fees, compute unit limits, slippage, and broadcasting. Unlike Jupiter Ultra, Metis requires you to handle these yourself — but in return you get maximum flexibility for integrations that need CPI, custom instructions, or a specific transaction broadcasting strategy.

**Use Metis when you need:**

* CPI (Cross Program Invocation) with your own on-chain program
* Custom instruction composition around the swap
* Full control over priority fees, compute units, and slippage
* Your own RPC or Jito broadcasting

**Consider Ultra instead when:**

* You want end-to-end execution without managing slippage, fees, or broadcasting
* You need Real-Time Slippage Estimator (RTSE), only available via Ultra

<Note>
  Metis Swap API access is available on OrbitFlare **Dedicated Nodes** via the `/jup` path prefix on your node endpoint. For the hosted Jupiter API, use `https://api.jup.ag/swap/v1/...` with your `x-api-key`.
</Note>

## How It Works

<Steps>
  <Step title="Get Quote">
    Call `GET /swap/v1/quote` with the input mint, output mint, amount, and slippage to receive the best route from the Metis routing engine.
  </Step>

  <Step title="Build Swap Transaction">
    Post the quote response to `POST /swap/v1/swap`. The API returns a serialized, ready-to-sign transaction with optional priority fee estimation, dynamic compute unit limits, and dynamic slippage.
  </Step>

  <Step title="Sign and Send">
    Deserialize the base64 transaction, sign it with your wallet, and broadcast via `connection.sendRawTransaction()` or through Jito.
  </Step>
</Steps>

***

## Step 1 — Get Quote

**Endpoint:** `GET /swap/v1/quote`

### Required Parameters

| Parameter     | Description                                                                                           |
| ------------- | ----------------------------------------------------------------------------------------------------- |
| `inputMint`   | Token mint address of the input token (e.g. `So11111111111111111111111111111111111111112` for SOL)    |
| `outputMint`  | Token mint address of the output token (e.g. `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` for USDC) |
| `amount`      | Raw integer amount of input tokens before decimals (lamports for SOL, atomic units for all others)    |
| `slippageBps` | Maximum slippage tolerance in basis points (e.g. `50` = 0.5%)                                         |

### Example — Quote 1 SOL to USDC

```javascript theme={null}
const quoteResponse = await (
  await fetch(
    "https://api.jup.ag/swap/v1/quote?" +
      "inputMint=So11111111111111111111111111111111111111112" +
      "&outputMint=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" +
      "&amount=100000000" +
      "&slippageBps=50" +
      "&restrictIntermediateTokens=true",
    {
      headers: {
        "x-api-key": "YOUR_API_KEY",
      },
    }
  )
).json();

console.log(JSON.stringify(quoteResponse, null, 2));
```

### Example Response

```json theme={null}
{
  "inputMint": "So11111111111111111111111111111111111111112",
  "inAmount": "100000000",
  "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "outAmount": "16198753",
  "otherAmountThreshold": "16117760",
  "swapMode": "ExactIn",
  "slippageBps": 50,
  "platformFee": null,
  "priceImpactPct": "0",
  "routePlan": [
    {
      "swapInfo": {
        "ammKey": "5BKxfWMbmYBAEWvyPZS9esPducUba9GqyMjtLCfbaqyF",
        "label": "Meteora DLMM",
        "inputMint": "So11111111111111111111111111111111111111112",
        "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
        "inAmount": "100000000",
        "outAmount": "16198753"
      },
      "percent": 100
    }
  ],
  "contextSlot": 299283763,
  "timeTaken": 0.015257836
}
```

<Tip>
  `outAmount` is the best possible output at time of quote. `slippageBps` does not affect this value — it controls `otherAmountThreshold`, which is the minimum you will accept.
</Tip>

### Additional Quote Options

<AccordionGroup>
  <Accordion title="restrictIntermediateTokens">
    Set to `true` to ensure routing only goes through highly liquid intermediate tokens. This reduces routing failures caused by illiquid paths and improves route stability at a small potential cost to price.
  </Accordion>

  <Accordion title="onlyDirectRoutes">
    Set to `true` to restrict routing to a single market (no multi-hop). Returns no quote if no direct route exists. Can yield unfavorable prices — use with caution.
  </Accordion>

  <Accordion title="maxAccounts">
    Limits the total number of accounts in the inner swap instructions. Useful when you need to leave room for your own instructions. Recommended minimum is `64`. Setting it too low drops DEXes that require more accounts (e.g. Meteora DLMM requires up to 47).
  </Accordion>

  <Accordion title="platformFeeBps">
    Add a fee to the swap that is credited to your `feeAccount`. Combine with `feeAccount` in the swap request.
  </Accordion>
</AccordionGroup>

***

## Step 2 — Build Swap Transaction

**Endpoint:** `POST /swap/v1/swap`

Pass the quote response from Step 1 along with the user's public key. The API returns a serialized base64 transaction ready to sign and send.

### Build Transaction with Landing Optimizations

```javascript theme={null}
const swapResponse = await (
  await fetch("https://api.jup.ag/swap/v1/swap", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": "YOUR_API_KEY",
    },
    body: JSON.stringify({
      quoteResponse,
      userPublicKey: wallet.publicKey.toString(),

      // Optimize for transaction landing
      dynamicComputeUnitLimit: true,
      dynamicSlippage: true,
      prioritizationFeeLamports: {
        priorityLevelWithMaxLamports: {
          maxLamports: 1000000,
          priorityLevel: "veryHigh",
        },
      },
    }),
  })
).json();
```

### Example Response

```json theme={null}
{
  "swapTransaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAGDkS+...",
  "lastValidBlockHeight": 279632475,
  "prioritizationFeeLamports": 9999,
  "computeUnitLimit": 388876,
  "prioritizationType": {
    "computeBudget": {
      "microLamports": 25715,
      "estimatedMicroLamports": 785154
    }
  },
  "dynamicSlippageReport": {
    "slippageBps": 50,
    "otherAmount": 20612318,
    "simulatedIncurredSlippageBps": -18,
    "amplificationRatio": "1.5",
    "categoryName": "lst",
    "heuristicMaxSlippageBps": 100
  },
  "simulationError": null
}
```

### Priority Fee Levels

| `priorityLevel` | Percentile | Use Case                                          |
| --------------- | ---------- | ------------------------------------------------- |
| `medium`        | 25th       | Low congestion, non-time-sensitive                |
| `high`          | 50th       | Standard trading conditions                       |
| `veryHigh`      | 75th       | Competitive conditions, MEV, time-sensitive swaps |

Set `maxLamports` as a safety cap to prevent overpaying during fee spikes:

```javascript theme={null}
prioritizationFeeLamports: {
  priorityLevelWithMaxLamports: {
    maxLamports: 10000000,
    global: false,        // use local fee market (writable accounts), not global
    priorityLevel: "veryHigh",
  },
}
```

### Using Swap Instructions Instead

If you need to compose the swap with your own instructions, use `/swap/v1/swap-instructions` instead of `/swap/v1/swap`. It takes the same parameters but returns individual instruction objects rather than a serialized transaction:

```javascript theme={null}
const instructions = await (
  await fetch("https://api.jup.ag/swap/v1/swap-instructions", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": "YOUR_API_KEY",
    },
    body: JSON.stringify({
      quoteResponse,
      userPublicKey: wallet.publicKey.toString(),
    }),
  })
).json();

const {
  computeBudgetInstructions,
  setupInstructions,
  swapInstruction: swapInstructionPayload,
  cleanupInstruction,
  addressLookupTableAddresses,
} = instructions;
```

***

## Step 3 — Send Swap Transaction

### Deserialize, Sign, and Serialize

The `swapTransaction` field in the response is base64-encoded. Deserialize it to a `VersionedTransaction`, sign it, then convert back to binary for sending:

```javascript theme={null}
import { VersionedTransaction } from "@solana/web3.js";

const transactionBase64 = swapResponse.swapTransaction;
const transaction = VersionedTransaction.deserialize(
  Buffer.from(transactionBase64, "base64")
);

transaction.sign([wallet]);

const transactionBinary = transaction.serialize();
```

### Send the Transaction

```javascript theme={null}
const signature = await connection.sendRawTransaction(transactionBinary, {
  maxRetries: 2,
  skipPreflight: true,
});
```

| Option          | Description                                                                                                 |
| --------------- | ----------------------------------------------------------------------------------------------------------- |
| `maxRetries`    | Maximum retries before giving up. If omitted, the RPC retries until the blockhash expires.                  |
| `skipPreflight` | Skip signature verification and simulation before submitting. Recommended `true` for speed-sensitive swaps. |

### Confirm the Transaction

```javascript theme={null}
const confirmation = await connection.confirmTransaction(
  { signature },
  "finalized"
);

if (confirmation.value.err) {
  throw new Error(
    `Transaction failed: ${JSON.stringify(confirmation.value.err)}\nhttps://solscan.io/tx/${signature}/`
  );
} else {
  console.log(`Transaction successful: https://solscan.io/tx/${signature}/`);
}
```

### Broadcasting via Jito

To use Jito for faster inclusion and MEV protection, replace `prioritizationFeeLamports` with a Jito tip and submit to a Jito RPC endpoint:

```javascript theme={null}
body: JSON.stringify({
  quoteResponse,
  userPublicKey: wallet.publicKey.toString(),
  prioritizationFeeLamports: {
    jitoTipLamports: 1000000, // fixed lamports, not a cap
  },
}),
```

<Warning>
  Jito tips must be submitted to a Jito RPC endpoint to take effect. Sending to a standard RPC will not route through Jito's block engine.
</Warning>

***

## Advanced

<AccordionGroup>
  <Accordion title="Dynamic Slippage">
    Enable `dynamicSlippage: true` in the swap request. The backend simulates the transaction and applies heuristics based on token category to estimate an appropriate slippage value.

    Note: Dynamic Slippage development has been discontinued. For production use, Jupiter recommends the Ultra Swap API which includes Real-Time Slippage Estimator (RTSE) — a significantly more accurate and reactive system.
  </Accordion>

  <Accordion title="CPI (Cross Program Invocation)">
    As of January 2025, Jupiter Swap via CPI is the recommended method for on-chain program integration. Add the `jupiter-cpi` crate to your program:

    ```toml theme={null}
    [dependencies]
    jupiter-cpi = { git = "https://github.com/jup-ag/jupiter-cpi", rev = "5eb8977" }
    ```

    Then invoke the shared accounts route from your instruction handler. See the [Jupiter CPI example](https://github.com/jup-ag/jupiter-cpi-swap-example) for a full reference implementation.
  </Accordion>

  <Accordion title="Flash Fill (Legacy)">
    Flash Fill was an earlier workaround for CPI account size limitations using Versioned Transactions and Address Lookup Tables. It is no longer recommended now that Loosen CPI restrictions are live on Solana mainnet. See [sol-swap-flash-fill](https://github.com/jup-ag/sol-swap-flash-fill) for historical reference.
  </Accordion>

  <Accordion title="DEX Account Requirements">
    When using `maxAccounts`, these are the estimated account counts per DEX (min applies when ALTs are available, max when they are not):

    | DEX                   | Max Accounts | Min Accounts |
    | --------------------- | :----------: | :----------: |
    | Meteora DLMM          |      47      |      19      |
    | Meteora               |      45      |      18      |
    | Raydium               |      45      |      18      |
    | Raydium CLMM          |      45      |      19      |
    | Moonshot              |      37      |      15      |
    | Raydium CPMM          |      37      |      14      |
    | Pumpfun AMM           |      42      |      17      |
    | Pumpfun Bonding Curve |      40      |      16      |
    | Orca Whirlpool        |      30      |      12      |
    | Obric                 |      30      |      12      |
    | Solfi                 |      22      |       9      |
    | Sanctum               |      80      |      80      |
    | Sanctum Infinity      |      80      |      80      |

    Setting `maxAccounts` too low will silently drop DEXes from routing. Keep it as high as possible and only reduce if your transaction exceeds the 1232-byte size limit.
  </Accordion>
</AccordionGroup>

***

## Requirements & Resources

Metis Swap API access via OrbitFlare is available on **Dedicated Nodes** only. The API is accessible via the `/jup` path on your dedicated node endpoint, or directly at `https://api.jup.ag/swap/v1/...` with a Jupiter API key.

<CardGroup cols={2}>
  <Card title="Official Metis Docs" icon="book" href="https://dev.jup.ag/docs/swap">
    Complete API reference for all Metis endpoints, parameters, and response schemas.
  </Card>

  <Card title="Metis Binary (GitHub)" icon="code" href="https://github.com/jup-ag/metis-binary">
    The self-hostable Metis binary by Jupiter for running the routing engine on your own infrastructure.
  </Card>

  <Card title="Jito Bundle Simulation" icon="bolt" href="/trading-apis/jito-bundle-simulation">
    Simulate and validate Jito MEV bundles on your dedicated node before submission.
  </Card>

  <Card title="Dedicated Nodes" icon="server" href="/dedicated-nodes">
    Deploy isolated, unlimited-RPS Solana infrastructure with Metis Swap API access included.
  </Card>
</CardGroup>
