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

# Fees

> Add optional integrator fees to BopAMM router swaps and /quote-generated fallback calldata.

BopAMM router fees let integrators take a share of successful BopAMM output. They are optional: pass `0` when you do not want a fee.

Fees apply only when the BopAMM leg succeeds. Fallback output from `swapWithFallback` is not fee-charged by the BopAMM router.

## How fees work

The requested `fee` is the total fee on gross BopAMM output, in basis points, capped at 1,000 bps. The router applies its configured protocol share to that total fee, sends the remainder to your `fee_recipient`, and delivers the remaining output to the swap recipient.

For example, if the gross BopAMM output is `1,000` units and `fee = 25`, the total router fee is `2.5` units. A configured protocol share applies to that `2.5`, and the rest goes to your fee recipient.

The router checks `minAmountOut` after fees. If you set a fee yourself, calculate your minimum from the post-fee amount.

```python theme={null}
amount_after_fee = amount_out * (10_000 - FEE_BPS) // 10_000
min_amount_out = amount_after_fee * (10_000 - SLIPPAGE_BPS) // 10_000
```

## Pack the router fee

`BopAmmRouter` takes a single packed `uint256` fee argument.

| Bits         | Value                             |
| ------------ | --------------------------------- |
| Low 160 bits | Integrator fee recipient address. |
| High bits    | Fee bps of gross BopAMM output.   |

```python theme={null}
from web3 import Web3


def pack_router_fee(fee_bps: int, fee_recipient: str | None) -> int:
    if fee_bps == 0:
        return 0
    if fee_recipient is None:
        raise ValueError("fee_recipient is required when fee_bps is non-zero")
    return (fee_bps << 160) | int(Web3.to_checksum_address(fee_recipient), 16)


FEE_BPS = 25  # 0.25% of gross BopAMM output
FEE_RECIPIENT = "0x0000000000000000000000000000000000000005"
FEE = pack_router_fee(FEE_BPS, FEE_RECIPIENT)
```

## Add a fee to router calldata

When you build `swapWithAllowance` calldata yourself, pass the packed fee as the final argument.

```python theme={null}
amount_out = core.functions.quote(USDC, WETH, amount_in).call(
    block_identifier=state["stateBlock"],
    state_override=state_override,
)
amount_after_fee = amount_out * (10_000 - FEE_BPS) // 10_000
min_amount_out = amount_after_fee * (10_000 - SLIPPAGE_BPS) // 10_000

swap = router.functions.swapWithAllowance(
    USDC,
    WETH,
    amount_in,
    min_amount_out,
    account.address,
    deadline,
    FEE,
)
```

The same packed `FEE` argument is used when composing `swapWithFallback` manually.

## Add a fee through `/quote`

For `/quote`-generated `swapWithFallback` calldata, pass `fee` and `fee_recipient` as query parameters. The endpoint packs them into `tx.data` for you.

```python theme={null}
quote = httpx.get(
    f"{API_BASE}/quote",
    params={
        "sell_tokens": USDC,
        "buy_tokens": WETH,
        "sell_amounts": str(amount_in),
        "taker_address": account.address,
        "slippage": "0.005",
        "approval_type": "Standard",
        "gasless": "false",
        "fee": "25",
        "fee_recipient": FEE_RECIPIENT,
    },
    headers={"Authorization": f"Bearer {API_KEY}"},
)
quote.raise_for_status()
quote = quote.json()
```

Quote response buy amounts are net of the total router fee. `buyTokens[].minimumAmount` already reflects fee plus slippage, and the returned `tx.data` carries the packed router fee.
