How App Fees work
- Set a fee — Add one or more recipients and set a fee in basis points of the input value in the quote request.
- Complete the transaction — Your user follows a normal Relay flow. Relay collects the fee at settlement.
- Collect fees — Collected fees accrue to the recipient’s USDC balance.
- Claim the balance — Withdraw through the Relay API or SDK. Multisigs and smart contracts can claim through EIP-1271.
Why use App Fees?
- Control your pricing — Set fees per quote and adjust them by product, customer, or promotion.
- Collect at settlement — Avoid separate invoices, payment collection, and settlement logic.
- Simplify accounting — Track one USDC balance instead of reconciling tokens across chains.
Setting up App Fees
App Fees are measured in basis points (bps) based on the input value of an order. When setting an app fee, an EVM-based claim address must be provided, which will be used for withdrawing accumulated fees. A single quote can include multiple App fees. You can accrue fees by includingAppFees in the Quote API:
- On same-chain operations where the solver holds neither the input or output currency, an extra swap is added within the transaction to swap from the input currency into a currency accepted by the solver for App Fees
- For this to occur, the fee to be taken needs to be greater than $0.025. This is to prevent the situation where the action of taking the app fee will consume more in gas than the fee itself.
- App Fee Recipients must be an EVM compatible wallet address, even for non-EVM chains.
- App fees can be an array, for setting multiple fees at once
- App fees work the same way with deposit address flows as with regular quote requests.
Chain-specific notes
EVM (same-chain): Fully supported. Fees can be collected from the input currency, the output currency, or via a parallel swap to USDC.
SVM (same-chain): Supported with input-currency collection only. Output-currency fee collection is not available — this applies to all output currencies, not just SOL. If the input currency is not a solver-held currency, the fee is collected via a secondary swap into USDC.
Cross-chain (all combinations): Fully supported. Same-chain limitations do not apply to cross-chain swaps — fees are calculated based on the solver’s deposit currency on the origin chain.
Verifying fee collection
You can verify that app fees are being collected correctly using the following endpoints:
Per-transaction: Use
/requests/v2 which returns both appFees (the fee quoted to the user) and paidAppFees (the fee actually collected). If appFees is present but paidAppFees is empty or zero, the fee was not collected for that transaction.
Accumulated balance: Use /app-fees/{address}/balances to check your total accumulated app fee balance available for withdrawal.
Withdrawing App Balance
App balance accrue in USDC from app fees, and can be claimed on any chain. The balance is free to claim on Base, and Relay app balance apply to claim on any other chain or in any other currency. The easiest way to claim your App Balance is to use the Relay App. The Relay App Balance page also supports withdrawing via a multisig. Here’s how you can withdraw via the API: Get App Balance To check your accrued App Balance, use the App fee balances API. Here’s an example curl command and response. The response includes thebalances.currency field reflecting your off-chain balance for each currency accumulated.
/execute/permit endpoint to verify ownership of your claim address. The SDK automates this process for you.
/execute/permit with the requestId and signature to claim your fees. An example request would be:
cURL
isValidSignature and use that method to verify the signature.
Here is an example of how this might work in practice:
- Wallet A (owner by contract owner), signs the message
- Then our backend gets the posted signature and calls the contract’s
isValidSignaturemethod to verify the signature - If the signature is valid, the funds get sent to the recipient. Let’s say in this case the contract’s
isValidSignaturemethod returns true if the signature was generated by wallet A.