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

# Fee collectors

> Collect your own fee on Solana transfers your clients send through Portal.

Fee collectors let you charge a fee on transfers your clients send with the [Build a transaction](/apis/client/reference) flow on Solana. You configure a destination address and a rate per environment in the Portal dashboard, and Portal appends the fee to each transfer it builds. The address and rate live in your dashboard configuration, never in the request, so a compromised client cannot redirect or change the fee.

Fees are paid in whatever token is being sent. If your client sends USDC, the fee arrives as USDC at your fee address.

## Supported chains and tokens

Fee collectors currently apply to Solana and Solana Devnet, for:

* Native SOL transfers
* SPL token transfers
* Token-2022 token transfers

Token-2022 mints that use a transfer hook are not supported yet: building a transfer for one returns a `400`, since the hook's extra accounts would make the transaction fail on-chain.

Fees apply to transactions built by `POST /api/v3/clients/me/chains/{chain}/assets/send/build-transaction` and its custodian equivalent. Transactions your app builds itself and only signs through Portal do not go through fee collection.

The build also checks that the sender's balance covers the amount plus all fees, and returns a `400` if it does not, rather than returning a transaction that would fail when broadcast.

## Setting up a fee collector

In the dashboard, go to **Fee Collectors** under Configuration, then click **Add fee collector**. Choose a chain, the address that receives the fee, and a fee type:

* **Percentage of the amount sent** charges a percentage of every transfer, on top of the amount sent. Rates go up to 100% in steps of 0.01%.
* **Recover the network fee** charges what the transfer costs the network: the signature fee plus rent for any token accounts the transfer creates. You set a percentage of that cost, up to 200%, so 100% recovers exactly cost. The cost is converted into the token being sent using current market prices. If no fresh price is available for either asset, the fee is skipped for that transfer rather than charged on a stale quote.

New collectors start disabled so you can verify the address before any transfer pays it. A collector's chain and address cannot be changed after creation. To move a fee to a new address, add a new collector and delete the old one.

You can enable up to five collectors per environment and chain, with at most one collector per address on a given chain. Each enabled collector adds its own fee transfer to the transaction, and every fee is computed against the full send amount, so the order of collectors does not change what any of them receives.

## How fees appear in transactions

The fee rides in the same transaction as the transfer, as an additional transfer instruction after the main one. For SPL and Token-2022 sends, the fee is paid to your fee address's associated token account for that mint. The first time a collector is paid in a given token, the transaction also creates that token account, and the fee payer (the gas sponsor when one is enabled, otherwise the sender) covers its rent.

The build response reports what was charged in the Solana metadata:

```json theme={null}
{
  "metadata": {
    "amount": "0.05",
    "rawAmount": "50000",
    "fees": [
      {
        "address": "HUT3JXAZWq8XtPuyv8bbx5zduvvLyovtNfzGNv6spwqD",
        "amount": "162799",
        "collectorId": "cmtivu9yt00yetu49sqgnnozl",
        "feeType": "GAS_COST",
        "feeValue": 5000,
        "name": "Transfer Fee"
      }
    ],
    "totalFeeRawAmount": "162799"
  }
}
```

`amount` in each fee entry and `totalFeeRawAmount` are in the sent token's base units. `feeValue` is the configured rate in basis points.

## When a fee is skipped

A fee problem never fails a transfer. Portal drops an individual collector's fee, and the transfer goes through without it, when:

* The fee rounds down to zero base units, so dust transfers do not pay one base unit to every collector.
* A "Recover the network fee" collector has no fresh market price to convert the cost with. Portal skips the fee rather than charging on a stale quote.
* A native SOL fee would leave the collector's account below Solana's rent-exempt minimum (about 0.00089 SOL). Fund the fee address with a small SOL balance once and every fee after that is collected regardless of size. SPL fees are unaffected.
* The collector's address is the transfer's sender, which would pay the fee to itself.

## Letting clients skip a fee

Each collector has a **Let clients skip this fee** toggle. When it is off, the fee is applied to every transfer Portal builds and the request cannot bypass it. When it is on, a client request can pass `skipFeeCollection: true` to build the transfer without that collector's fee:

```bash theme={null}
curl -X POST "https://api.portalhq.io/api/v3/clients/me/chains/solana/assets/send/build-transaction" \
  -H "Authorization: Bearer {clientToken}" \
  -H "Content-Type: application/json" \
  -d '{"to": "8APEEA4SHrfGteABQcUmH2yEHy7nEe8DqgvmKGAStHR", "token": "USDC", "amount": "0.05", "skipFeeCollection": true}'
```

`skipFeeCollection` only skips collectors with the toggle on. Collectors with the toggle off are always charged. Keep the toggle off unless your app has a real reason to let end clients opt out, since anything a legitimate client request can do, a compromised one can too.
