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

# Add Integrator Fees

> Add custom integrator fees to Ultra Swap using the Referral Program.

> [!WARNING]
>
> **Ultra Swap API** is no longer actively maintained and has been superseded by [Swap V2](https://developers.jup.ag/docs/swap.md).

> [!NOTE]
>
> If you are unfamiliar with [Ultra Swap Fees](https://developers.jup.ag/docs/ultra/fees), please refer to the doc.

## Key Points

The Jupiter Ultra Swap API allows you to add integrator fees to the orders.

**Key points summary:** Fees require Referral Program accounts, Jupiter takes 20% of your integrator fees, Ultra decides which mint to take fees in (based on a priority list), you must create referralTokenAccount for each expected feeMint, and fees enforce routing to Metis only.

> [accordion] Requires specific Referral Program Accounts
>
> The Ultra Swap Integrator Fees are governed by the [Referral Program](https://developers.jup.ag/docs/tool-kits/referral-program.md).
>
> It is required to create a valid **referral account** and it's **referral token accounts** for the specific token mints to collect fees in. These accounts are initalized under the [**Jupiter Ultra Referral Project**](https://solscan.io/account/DkiqsTrw1u1bYFumumC7sCG2S8K25qc2vemJFHyW2wJc).
>
> Refer to the rest of the guide for more details on the set up.

> [accordion] Fee split when adding fees
>
> If you plan to take 100bps, Jupiter will take 20bps for the fee split (there will be no Ultra base fee).
>
> | Type | Fee |
> | :- | :- |
> | Ultra default fees | 5 to 10 bps |
> | Added integrator fees | Ultra takes 20% of your integrator fees |

> [accordion] Ultra decides which mint to take fees in
>
> In the `/order` response, you will see the `feeMint` field which is the token mint we will collect the fees in for that particular order.
>
> Since Jupiter will always dictate which token mint to collect the fees in, you must ensure that you have the valid referral token account created for the specific fee mint.
>
> > [!NOTE]
> >
> > The `feeMint` is based on a priority list, you can refer to the [Ultra Fees](https://developers.jup.ag/docs/ultra/fees) doc for more details.
> >
> > | inputMint | outputMint | feeMint | Reason |
> > | - | - | - | - |
> > | SOL | USDC | SOL | SOL is of highest priority |
> > | USDC | SOL | SOL | SOL is of highest priority, regardless of side |
> > | MEME | USDC | USDC | Stablecoin (USDC) has higher priority |
>
> > [!WARNING]
> >
> > If the `referralTokenAccount` for the `feeMint` is not initialized, the order will still return and can be executed without your fees. This is to ensure your user still receives a quote to proceed with the swap.
> >
> > For example, if the `feeMint` is `SOL`, but the `referralTokenAccount` for `SOL` is not initialized, the order will still return but will be executed without your fees.
> >
> > You can refer to if `feeBps` tallies with what you specified in `referralFee`, in this case, the `feeBps` will default to Jupiter Ultra's default fees.

> [accordion] Check the feeBps field
>
> You can configure `referralFee` to be between 50bps to 255bps. The `/order` response will show the total fee in `feeBps` field which should be exactly what you specified in `referralFee`.
>
> > [!WARNING]
> >
> > If the `referralTokenAccount` for the `feeMint` is not initialized, the order will still return and can be executed without your fees. This is to ensure your user still receives a quote to proceed with the swap.
> >
> > For example, if the `feeMint` is `SOL`, but the `referralTokenAccount` for `SOL` is not initialized, the order will still return but will be executed without your fees.
> >
> > You can refer to if `feeBps` tallies with what you specified in `referralFee`, in this case, the `feeBps` will default to Jupiter Ultra's default fees.

> [accordion] Token support
>
> You can now take fees in SPL or Token2022 tokens. As long as you have the referral token account initialized before calling `/order`, and the `feeMint` is one of the token mints you have initialized for, your fees will apply.
>
> | Only initialized for this token mint | feeMint | Are your fees applied? |
> | :- | :- | :- |
> | SOL | SOL | Yes |
> | USDC | JupSOL | No |
> | XYZ | USDC | No |

> [accordion] Enforces routing to Metis and other DEX aggregator routes
>
> When integrator fees are being added, it defaults routing to Metis and other DEX aggregator routes.
>
> JupiterZ does not support integrator fees currently.

## Step-by-step

**Step 1**

Install additional dependencies or if you prefer, you can use the [Referral Dashboard](https://referral.jup.ag/), a simple interface to create referral accounts.

**Step 2**

Create `referralAccount`.

**Step 3**

Create `referralTokenAccount` for each token mint.

**Step 4**

Add `referralAccount` and `referralFee` to Ultra Swap `/order` endpoint.

**Step 5**

Sign and send the transaction via Ultra Swap `/execute` endpoint.

**Step 6**

Verify transaction and fees.

> [accordion] Full Code Example
>
> ```js theme={null}
> import { ReferralProvider } from "@jup-ag/referral-sdk";
> import { Connection, Keypair, PublicKey, sendAndConfirmTransaction, sendAndConfirmRawTransaction } from "@solana/web3.js";
> import fs from 'fs';
>
> const connection = new Connection("https://api.mainnet-beta.solana.com");
> const privateKeyArray = JSON.parse(fs.readFileSync('/Path/to/.config/solana/id.json', 'utf8').trim());
> const wallet = Keypair.fromSecretKey(new Uint8Array(privateKeyArray));
>
> const provider = new ReferralProvider(connection);
> const projectPubKey = new PublicKey('DkiqsTrw1u1bYFumumC7sCG2S8K25qc2vemJFHyW2wJc');
>
> async function initReferralAccount() {
>   const transaction = await provider.initializeReferralAccountWithName({
>     payerPubKey: wallet.publicKey,
>     partnerPubKey: wallet.publicKey,
>     projectPubKey: projectPubKey,
>     name: "insert-name-here",
>   });
>
>   const referralAccount = await connection.getAccountInfo(
>     transaction.referralAccountPubKey,
>   );
>
>   if (!referralAccount) {
>     const signature = await sendAndConfirmTransaction(connection, transaction.tx, [wallet]);
>     console.log('signature:', `https://solscan.io/tx/${signature}`);
>     console.log('created referralAccountPubkey:', transaction.referralAccountPubKey.toBase58());
>   } else {
>     console.log(
>       `referralAccount ${transaction.referralAccountPubKey.toBase58()} already exists`,
>     );
>   }
> }
>
> async function initReferralTokenAccount() {
>   const mint = new PublicKey("So11111111111111111111111111111111111111112"); // the token mint you want to collect fees in
>
>   const transaction = await provider.initializeReferralTokenAccountV2({
>     payerPubKey: wallet.publicKey,
>     referralAccountPubKey: new PublicKey("insert-referral-account-pubkey-here"), // you get this from the initReferralAccount function
>     mint,
>   });
>
>     const referralTokenAccount = await connection.getAccountInfo(
>       transaction.tokenAccount,
>     );
>
>     if (!referralTokenAccount) {
>       const signature = await sendAndConfirmTransaction(connection, transaction.tx, [wallet]);
>       console.log('signature:', `https://solscan.io/tx/${signature}`);
>       console.log('created referralTokenAccountPubKey:', transaction.tokenAccount.toBase58());
>       console.log('mint:', mint.toBase58());
>     } else {
>       console.log(
>         `referralTokenAccount ${transaction.tokenAccount.toBase58()} for mint ${mint.toBase58()} already exists`,
>       );
>     }
> }
>
> async function claimAllTokens() {
>   const transactions = await provider.claimAllV2({
>     payerPubKey: wallet.publicKey,
>     referralAccountPubKey: new PublicKey("insert-referral-account-pubkey-here"),
>   })
>
>   // Send each claim transaction one by one.
>   for (const transaction of transactions) {
>     transaction.sign([wallet]);
>
>     const signature = await sendAndConfirmRawTransaction(connection, transaction.serialize(), [wallet]);
>     console.log('signature:', `https://solscan.io/tx/${signature}`);
>   }
> }
>
> // initReferralAccount(); // you should only run this once
> // initReferralTokenAccount();
> // claimAllTokens();
> ```

### Dependencies

```bash theme={null}
npm install @jup-ag/referral-sdk
npm install @solana/web3.js@1 # Using v1 of web3.js instead of v2
```

> [accordion] RPC Connection and Wallet Setup
>
> **Set up RPC Connection**
>
> > [!NOTE]
> >
> > Solana provides a [default RPC endpoint](https://solana.com/docs/core/clusters). However, as your application grows, we recommend you to always use your own or provision a 3rd party provider’s RPC endpoint such as [Helius](https://helius.dev/) or [Triton](https://triton.one/).
>
> ```bash theme={null}
> const connection = new Connection('https://api.mainnet-beta.solana.com');
> ```
>
> **Set up Development Wallet**
>
> > [!NOTE]
> >
> > You can paste in your private key for testing but this is not recommended for production.
> >
> > * Either use your private key in the project directly, you can do it via a `.env` file.
> > * Or set up your private key in the [Solana CLI](https://solana.com/docs/intro/installation#create-wallet).
>
> ```javascript Store private key in .env theme={null}
> // In your .env file
> PRIVATE_KEY=""
>
> // In your index.js (or any file that needs the private key)
> import { Keypair } from '@solana/web3.js';
> import dotenv from 'dotenv';
> require('dotenv').config();
>
> const wallet = Keypair.fromSecretKey(bs58.decode(process.env.PRIVATE_KEY || '')));
> ```
>
> ```javascript Store private key in Solana CLI 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));
> ```

### Create `referralAccount`

* You should only need to create the referral account once.
* After this step, you need to [create the referral token accounts for each token mint](#create-referraltokenaccount).

```js expandable theme={null}
import { ReferralProvider } from "@jup-ag/referral-sdk";
import { Connection, Keypair, PublicKey, sendAndConfirmTransaction } from "@solana/web3.js";

const connection = new Connection("https://api.mainnet-beta.solana.com");
const privateKeyArray = JSON.parse(fs.readFileSync('/Path/to/.config/solana/id.json', 'utf8').trim());
const wallet = Keypair.fromSecretKey(new Uint8Array(privateKeyArray));
const provider = new ReferralProvider(connection);
const projectPubKey = new PublicKey('DkiqsTrw1u1bYFumumC7sCG2S8K25qc2vemJFHyW2wJc'); // Jupiter Ultra Referral Project

async function initReferralAccount() {
  const transaction = await provider.initializeReferralAccountWithName({
    payerPubKey: wallet.publicKey,
    partnerPubKey: wallet.publicKey,
    projectPubKey: projectPubKey,
    name: "insert-name-here",
  });

  const referralAccount = await connection.getAccountInfo(
    transaction.referralAccountPubKey,
  );

  if (!referralAccount) {
    const signature = await sendAndConfirmTransaction(connection, transaction.tx, [wallet]);
    console.log('signature:', `https://solscan.io/tx/${signature}`);
    console.log('created referralAccountPubkey:', transaction.referralAccountPubKey.toBase58());
  } else {
    console.log(
      `referralAccount ${transaction.referralAccountPubKey.toBase58()} already exists`,
    );
  }
}
```

### Create `referralTokenAccount`

* You need to [create the `referralAccount` first](#create-referralaccount).
* You need to create a `referralTokenAccount` for each token mint you want to collect fees in.
* We don't recommend creating a token account for **every** token mint, as it costs rent and most tokens might not be valuable, instead created token accounts for top mints to begin with (you can always add more later).

```js expandable theme={null}
import { ReferralProvider } from "@jup-ag/referral-sdk";
import { Connection, Keypair, PublicKey, sendAndConfirmTransaction } from "@solana/web3.js";

const connection = new Connection("https://api.mainnet-beta.solana.com");
const privateKeyArray = JSON.parse(fs.readFileSync('/Path/to/.config/solana/id.json', 'utf8').trim());
const wallet = Keypair.fromSecretKey(new Uint8Array(privateKeyArray));
const provider = new ReferralProvider(connection);

async function initReferralTokenAccount() {
  const mint = new PublicKey("So11111111111111111111111111111111111111112"); // the token mint you want to collect fees in

  const transaction = await provider.initializeReferralTokenAccountV2({
    payerPubKey: wallet.publicKey,
    referralAccountPubKey: new PublicKey("insert-referral-account-pubkey-here"),
    mint,
  });

    const referralTokenAccount = await connection.getAccountInfo(
      transaction.tokenAccount,
    );

    if (!referralTokenAccount) {
      const signature = await sendAndConfirmTransaction(connection, transaction.tx, [wallet]);
      console.log('signature:', `https://solscan.io/tx/${signature}`);
      console.log('created referralTokenAccountPubKey:', transaction.tokenAccount.toBase58());
      console.log('mint:', mint.toBase58());
    } else {
      console.log(
        `referralTokenAccount ${transaction.tokenAccount.toBase58()} for mint ${mint.toBase58()} already exists`,
      );
    }
}
```

### Usage in Ultra Swap

* After creating the necessary accounts, you can now add the `referralAccount` and `referralFee` to the Ultra Swap `/order` endpoint.
* From the order response, you should see the `feeMint` field, which is the token mint we will collect the fees in for that particular order.
* From the order response, you should see the `feeBps` field, which is the total fee in bps, which should be exactly what you specified in `referralFee`.
* Then, you can sign and send the transaction via the Ultra Swap `/execute` endpoint.

> [!WARNING]
>
> If the `referralTokenAccount` for the `feeMint` is not initialized, the order will still return and can be executed without your fees. This is to ensure your user still receives a quote to proceed with the swap.
>
> For example, if the `feeMint` is `SOL`, but the `referralTokenAccount` for `SOL` is not initialized, the order will still return but will be executed without your fees.
>
> You can refer to if `feeBps` tallies with what you specified in `referralFee`, in this case, the `feeBps` will default to Jupiter Ultra's default fees.

```js expandable theme={null}
import { Keypair, VersionedTransaction } 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));

const orderResponse = await (
  await fetch(
    'https://api.jup.ag/ultra/v1/order?' +
    'inputMint=So11111111111111111111111111111111111111112&' +
    'outputMint=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&' +
    'amount=100000000&' +
    'taker=jdocuPgEAjMfihABsPgKEvYtsmMzjUHeq9LX4Hvs7f3&' +
    'referralAccount=&' + // insert referral account public key here
    'referralFee=50', // insert referral fee in basis points (bps)
    {
      headers: {
        'x-api-key': 'your-api-key',
      },
    }
  )
).json();

console.log(JSON.stringify(orderResponse, null, 2));

const transactionBase64 = orderResponse.transaction // Extract the transaction from the order response
const transaction = VersionedTransaction.deserialize(Buffer.from(transactionBase64, 'base64')); // Deserialize the transaction
transaction.sign([wallet]); // Sign the transaction
const signedTransaction = Buffer.from(transaction.serialize()).toString('base64'); // Serialize the transaction to base64 format

const executeResponse = await (
    await fetch('https://api.jup.ag/ultra/v1/execute', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'x-api-key': 'your-api-key',
        },
        body: JSON.stringify({
            signedTransaction: signedTransaction,
            requestId: orderResponse.requestId,
        }),
    })
).json();

if (executeResponse.status === "Success") {
    console.log('Swap successful:', JSON.stringify(executeResponse, null, 2));
    console.log(`https://solscan.io/tx/${executeResponse.signature}`);
} else {
    console.error('Swap failed:', JSON.stringify(executeResponse, null, 2));
    console.log(`https://solscan.io/tx/${executeResponse.signature}`);
}
```

## Claim All Fees

* The `claimAllV2` method will return a list of transactions to claim all fees and are batched by 5 claims for each transaction.
* The code signs and sends the transactions one by one - you can also Jito Bundle to send multiple at once, if preferred.
* When claiming fees, the transaction will include the transfer of the fees to both your referral account and Jupiter's (20% of your integrator fees).

```js expandable theme={null}
import { ReferralProvider } from "@jup-ag/referral-sdk";
import { Connection, Keypair, PublicKey, sendAndConfirmRawTransaction } from "@solana/web3.js";

const connection = new Connection("https://api.mainnet-beta.solana.com");
const privateKeyArray = JSON.parse(fs.readFileSync('/Path/to/.config/solana/id.json', 'utf8').trim());
const wallet = Keypair.fromSecretKey(new Uint8Array(privateKeyArray));
const provider = new ReferralProvider(connection);

async function claimAllTokens() {
  const transactions = await provider.claimAllV2({
    payerPubKey: wallet.publicKey,
    referralAccountPubKey: new PublicKey("insert-referral-account-pubkey-here"),
  })

  // Send each claim transaction one by one.
  for (const transaction of transactions) {
    transaction.sign([wallet]);

    const signature = await sendAndConfirmRawTransaction(connection, transaction.serialize(), [wallet]);
    console.log('signature:', `https://solscan.io/tx/${signature}`);
  }
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.