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

# Monetize swaps with partner fees

> Earn revenue from every swap routed through Velora using either partner fees or surplus sharing.

## Monetization models

* **Partner fee.**: Take a fixed percentage of every swap. Revenue is predictable, but the fee is reflected in the user's quote.
* **Surplus share.**: Earn 50% of any positive slippage captured during execution. The quoted output remains unchanged, but revenue varies from trade to trade.

Choose the model that best fits your product. Partner fees maximize predictability, while surplus sharing maximizes quote competitiveness.

A swap can use one model or the other, not both. If both are provided, `partnerFeeBps` takes precedence.

To activate monetization, include your own `partner` identifier. Requests without one use the default `anon` partner and a flat 1 bps fee. See [Pro API accounts](/overview/pro-api-accounts).

## Revenue split

The amount you earn depends on the monetization model and execution path.

| Lever         | Delta                    | Market                   |
| ------------- | ------------------------ | ------------------------ |
| Partner fee\* | 100% partner             | 85% partner / 15% Velora |
| Surplus share | 50% partner / 50% Velora | 50% partner / 50% Velora |

Why the difference?

* **Delta** funds itself through surplus capture, so partner fees are passed through entirely.
* **Market** retains 15% of partner fees to fund routing infrastructure.
* **Surplus sharing** is always split evenly between the partner and Velora.

You can also redirect your share of the surplus to the end user with `isSurplusToUser: true`.

<sub>\* Tailored arrangements available on request.</sub>

## How it maps to the API

Delta (`GET /v2/quote`) and Market (`GET /prices`, `POST /transactions`) accept the same monetization parameters per request. `isDirectFeeTransfer` is Market-only.

| Parameter<span style={{display: 'inline-block', width: '11rem'}} /> | Type         | Default | Purpose                                                                        |
| ------------------------------------------------------------------- | ------------ | ------- | ------------------------------------------------------------------------------ |
| `partner`                                                           | string       | `anon`  | Identifies your integration; ties the request to your partner economics        |
| `partnerAddress`                                                    | address      | —       | On-chain recipient of fees or surplus share                                    |
| `partnerFeeBps`                                                     | string (bps) | —       | Fixed fee in basis points. `"200"` = 2%. Max enforced by your partner tier     |
| `takeSurplus`                                                       | boolean      | `false` | Opt into surplus collection. Requires `partner` or `partnerAddress`            |
| `isSurplusToUser`                                                   | boolean      | `false` | Route surplus to the end user. Requires `takeSurplus: true`                    |
| `isDirectFeeTransfer`<sup>Market</sup>                              | boolean      | `false` | Bypass the Fee Claimer contract and transfer fees to `partnerAddress` per swap |

<Note>
  `partnerFeeBps` and `takeSurplus` are mutually exclusive: set one or the other. The legacy `positiveSlippageToUser` flag is deprecated; use `isSurplusToUser` instead.
</Note>

Pass `partnerFeeBps` to the quote endpoint (`GET /prices` or `GET /v2/quote`) so the fee is reflected in the displayed quote.

## How payouts work

On Market, partner fees accrue inside the Fee Claimer contract by default. Partners claim accumulated balances through the Velora Fee Claimer UI, signed by `partnerAddress`. This batches gas across many swaps but adds a claim step. To skip the Fee Claimer and pay fees directly to `partnerAddress` on every swap, set `isDirectFeeTransfer: true`. There's nothing to claim, but each swap carries an extra fee-transfer, and the user pays that gas on every trade, including very low-value ones where it can eat a meaningful share of the output.

On Delta, fees accrue inside the main Delta contract and partners claim them directly from there; there is no separate Fee Claimer contract. This works in Delta's favor: the fee is accounted for as part of the fill itself, with no extra fee-transfer per swap, so taking a partner fee adds essentially no gas overhead to the trade.

Surplus routed to the user (`isSurplusToUser: true`) is settled in the same transaction as the swap, so there's no claim step either way.

## How to claim

### Fee Claimer UI

Accumulated Market fees are claimable from the [Fee Claimer app](https://velora.xyz/fee_claimer). Connect the wallet matching `partnerAddress`, pick the chain, review the available balances per token, and submit a claim transaction. Each chain is claimed separately; gas is paid by the claimer.

<Note>
  The UI covers Market fees only. Delta fees are claimed programmatically from the Delta contract, as shown below.
</Note>

### Programmatically

Both fee contracts can be called directly, so claims can run from a script or a scheduled job instead of the UI. In either case, sign the transaction with the wallet matching `partnerAddress`: balances are keyed to it, and each call sweeps the full accrued balance of one token to a recipient you choose. Delta fees accrue in the Delta contract and are withdrawn with `withdrawAllFees`; Market fees accrue in the Fee Claimer contract and are withdrawn with `withdrawAllERC20`. Each contract uses the same address on every chain where it's deployed (see [Chains & contracts](/resources/chains-and-contracts)), so the same code works on another chain by swapping the viem chain object.

<CodeGroup>
  ```ts Claim Delta fees theme={null}
  import { createPublicClient, createWalletClient, http, parseAbi } from "viem";
  import { Address, privateKeyToAccount } from "viem/accounts";
  import { mainnet } from "viem/chains";

  // Delta address on Ethereum mainnet
  const DELTA_ADDRESS = "0x0000000000bbf5c5fd284e657f01bd000933c96d";

  const feeClaimerModuleAbi = parseAbi([
    "function getCollectedFees(address partner, address token) view returns (uint256)",
    "function withdrawAllFees(address token, address recipient) returns (uint256 amount)",
  ]);

  const account = privateKeyToAccount(process.env.PRIVATE_KEY);

  const publicClient = createPublicClient({
    chain: mainnet,
    transport: http(),
  });

  const walletClient = createWalletClient({
    account,
    chain: mainnet,
    transport: http(),
  });

  async function withdrawAllFees(
    tokenAddress: Address,
    recipientAddress: Address
  ) {
    const collectedFees = await publicClient.readContract({
      address: DELTA_ADDRESS,
      abi: feeClaimerModuleAbi,
      functionName: "getCollectedFees",
      args: [account.address, tokenAddress],
    });

    console.log(
      `Collected fees for token ${tokenAddress}:`,
      collectedFees.toString()
    );

    if (collectedFees === 0n) {
      console.log("No fees to withdraw for this token.");
      return;
    }

    // Simulate first to catch reverts
    const { request } = await publicClient.simulateContract({
      account,
      address: DELTA_ADDRESS,
      abi: feeClaimerModuleAbi,
      functionName: "withdrawAllFees",
      args: [tokenAddress, recipientAddress],
    });

    const hash = await walletClient.writeContract(request);
    console.log("Transaction sent:", hash);

    const receipt = await publicClient.waitForTransactionReceipt({ hash });
    console.log("Withdrawal confirmed in block:", receipt.blockNumber);

    return receipt;
  }

  // Withdraw all accrued USDC fees to the caller's address
  await withdrawAllFees(
    "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
    account.address
  );
  ```

  ```ts Claim Market fees theme={null}
  import { createPublicClient, createWalletClient, http, parseAbi } from "viem";
  import { Address, privateKeyToAccount } from "viem/accounts";
  import { mainnet } from "viem/chains";

  // FeeClaimer on Ethereum mainnet
  const FEE_CLAIMER_ADDRESS = "0x00700052c0608F670705380a4900e0a8080010CC";

  const feeClaimerAbi = parseAbi([
    "function getBalance(address token, address partner) view returns (uint256)",
    "function withdrawAllERC20(address _token, address _recipient) returns (bool)",
  ]);

  const account = privateKeyToAccount(process.env.PRIVATE_KEY);

  const publicClient = createPublicClient({
    chain: mainnet,
    transport: http(),
  });

  const walletClient = createWalletClient({
    account,
    chain: mainnet,
    transport: http(),
  });

  async function withdrawAllFees(
    tokenAddress: Address,
    recipientAddress: Address
  ) {
    const balance = await publicClient.readContract({
      address: FEE_CLAIMER_ADDRESS,
      abi: feeClaimerAbi,
      functionName: "getBalance",
      args: [tokenAddress, account.address],
    });

    console.log(`Current fee balance for token ${tokenAddress}:`, balance);

    if (balance === 0n) {
      console.log("No fees to withdraw for this token.");
      return;
    }

    // Simulate first to catch reverts
    const { request } = await publicClient.simulateContract({
      account,
      address: FEE_CLAIMER_ADDRESS,
      abi: feeClaimerAbi,
      functionName: "withdrawAllERC20",
      args: [tokenAddress, recipientAddress],
    });

    const hash = await walletClient.writeContract(request);
    console.log("Transaction sent:", hash);

    const receipt = await publicClient.waitForTransactionReceipt({ hash });
    console.log("Withdrawal confirmed in block:", receipt.blockNumber);

    return receipt;
  }

  // Withdraw all accrued USDC fees to the caller's address
  await withdrawAllFees(
    "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
    account.address
  );
  ```
</CodeGroup>

Not sure which tokens your fees accrued in? Each side has a fees endpoint that returns every token your address has earned fees in on a chain. The amounts are lifetime totals per token, claimed and unclaimed combined, so check the live on-chain balance (as the claim snippets above do) before withdrawing.

<CodeGroup>
  ```ts Check Delta fee tokens theme={null}
  const PARTNER_ADDRESS = "0x..."; // your partnerAddress
  const CHAIN_ID = 1;

  const parameters = JSON.stringify([
    {
      type: "category",
      value: PARTNER_ADDRESS,
      target: ["variable", ["template-tag", "partner_address"]],
    },
    {
      type: "category",
      value: CHAIN_ID,
      target: ["variable", ["template-tag", "chain_id"]],
    },
  ]);

  const res = await fetch(
    `https://proxy.paraswap.io/fees/delta?parameters=${encodeURIComponent(
      parameters
    )}`
  );
  const { data } = await res.json();

  // Each row is [chain_id, fee_token, total_amount]
  for (const [, token, total] of data.rows) {
    console.log(`${token}: ${total}`);
  }
  ```

  ```ts Check Market fee tokens theme={null}
  const PARTNER_ADDRESS = "0x..."; // your partnerAddress
  const CHAIN_ID = 1;

  const parameters = JSON.stringify([
    {
      type: "category",
      value: PARTNER_ADDRESS,
      target: ["variable", ["template-tag", "partneraddress"]],
    },
    {
      type: "category",
      value: CHAIN_ID,
      target: ["variable", ["template-tag", "chainId"]],
    },
    {
      type: "category",
      value: "partner",
      target: ["variable", ["template-tag", "feeType"]],
    },
  ]);

  const res = await fetch(
    `https://proxy.paraswap.io/fees/since-v6?parameters=${encodeURIComponent(
      parameters
    )}`
  );
  const { data } = await res.json();

  // Each row is [corrected_sum, partnerfeetoken, chainid]
  for (const [total, token] of data.rows) {
    console.log(`${token}: ${total}`);
  }
  ```
</CodeGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Pro API accounts" icon="briefcase" href="/overview/pro-api-accounts">
    Free partner IDs, plus paid tiers for higher rate limits and SLA.
  </Card>

  <Card title="Widget monetization" icon="puzzle-piece" href="/widget/monetize">
    Drop-in `partnerConfig` for the React widget.
  </Card>

  <Card title="Delta overview" icon="bolt" href="/delta/overview">
    Gasless intents, solver competition, and surplus economics.
  </Card>

  <Card title="Delta API overview" icon="signature" href="/api-reference/delta/overview">
    `GET /v2/quote` and intent submission reference.
  </Card>

  <Card title="Market API overview" icon="chart-line" href="/api-reference/market/overview">
    `GET /prices` and `POST /transactions` reference.
  </Card>
</CardGroup>

<Tip>
  Endpoints work without a `partner` identifier, but fees and surplus only activate once one is attached; picking your own `partner` value costs nothing. When you outgrow the free tier, [Pro API accounts](/overview/pro-api-accounts) layer on higher limits, a dashboard, and SLA, or [reach out](https://www.velora.xyz/contact) for custom terms.
</Tip>
