Forwarding Address API Reference
The Forwarding Address API is in alpha. Breaking changes are expected. Do not move large amounts of funds through forwarding addresses during the alpha period.
Protocol
The API uses JSON-RPC 2.0 over HTTP POST with Content-Type: application/json.
Authentication
Most methods are public. Only the activation call (account_activateForwardingAddress) requires authentication: send Authorization: Bearer <account_api_key>. Account API keys are issued by Candide on request.
Discovery
forwarding_getRoutes
Returns all routes from a given source chain with their available tokens and fees. This is the single source of truth for which destination chains and tokens are supported. Routes, tokens, and fees can change dynamically.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
sourceChainId | number | Yes | Source chain ID to get routes from |
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "forwarding_getRoutes",
"params": [{ "sourceChainId": 1 }]
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"routes": [
{
"sourceChainId": 1,
"sourceChainName": "Ethereum",
"destinationChainId": 42161,
"destinationChainName": "Arbitrum One",
"tokens": [
{
"address": "0x0000000000000000000000000000000000000000",
"symbol": "ETH",
"decimals": 18,
"destinationAddress": "0x0000000000000000000000000000000000000000",
"feeBps": 50
},
{
"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"symbol": "USDT",
"decimals": 6,
"destinationAddress": "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9",
"feeBps": 50
}
]
}
]
}
}
Token fields:
| Field | Description |
|---|---|
address | Token contract address on the source chain. 0x000...000 represents native ETH |
symbol | Human-readable token symbol |
decimals | Token decimal places (source chain) |
destinationAddress | Token contract address on the destination chain. Use this when verifying arrival or displaying the output token |
feeBps | Service fee in basis points (50 = 0.5%) |
forwarding_getMinimumAmount
Returns the minimum deposit amount per bridge for a specific route. Use this to validate user input before calling forwarding_estimateOutput. Minimums are bridge-specific because each bridge has its own threshold below which deposits are not processed.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
sourceChainId | number | Yes | Source chain ID |
destinationChainId | number | Yes | Destination chain ID |
token | address | Yes | Token address on the source chain |
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "forwarding_getMinimumAmount",
"params": [{
"sourceChainId": 1,
"destinationChainId": 42161,
"token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
}]
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"bridges": {
"across": { "minAmount": "500000" },
"oft": { "minAmount": "1000000" }
}
}
}
| Field | Description |
|---|---|
bridges | Object keyed by bridge identifier. Each entry contains a minAmount in the smallest unit of the source token. A deposit below every bridge's minimum will not be forwarded |
Core
forwarding_getAddress
Computes the deterministic CREATE2 proxy address for a given parameter set. Pure computation with no side effects. Safe to call repeatedly. The same inputs always produce the same address.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
recipient | address | Yes | Destination address that receives forwarded tokens |
custodialWithdrawer | address | Yes | Emergency recovery address that can withdraw stuck funds after a timelock. For most integrations, use the platform's address. See custodialWithdrawer |
destinationChainId | number | Yes | Target chain ID where assets will be delivered |
salt | bytes32 | No | Optional 32-byte hex value. Use different salts to generate multiple forwarding addresses for the same recipient |
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "forwarding_getAddress",
"params": [{
"recipient": "0xAbCdEf0123456789AbCdEf0123456789AbCdEf01",
"custodialWithdrawer": "0xAbCdEf0123456789AbCdEf0123456789AbCdEf01",
"destinationChainId": 10
}]
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"address": "0xDEF456..."
}
}
account_activateForwardingAddress
Activates relayer monitoring for a forwarding address on specified source chains. Returns the address, active status, and TTL expiration timestamp.
Send Authorization: Bearer <account_api_key> with this request. Keys are issued by Candide. Each account can have up to 500 active forwarding addresses; refreshing an existing address does not count against the cap. Exceeding the cap returns error -32013.
Key behaviors:
- Idempotent: calling again resets the TTL. Use this to keep an address active.
- TTL-based: monitoring expires after the TTL. The address must be reactivated to resume forwarding.
- Reusable: call activate again after expiration.
- Same-chain forwarding: the destination chain is automatically included in the monitored set. You do not need to pass it in
sourceChainIdsto accept deposits on the destination chain itself.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
recipient | address | Yes | Destination recipient address |
custodialWithdrawer | address | Yes | Withdrawal-authorized address. See custodialWithdrawer |
destinationChainId | number | Yes | Target chain ID |
sourceChainIds | number[] | Yes | Array of source chain IDs to activate monitoring on |
salt | bytes32 | No | Optional salt (must match the one used in forwarding_getAddress) |
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "account_activateForwardingAddress",
"params": [{
"recipient": "0xAbCdEf0123456789AbCdEf0123456789AbCdEf01",
"custodialWithdrawer": "0xAbCdEf0123456789AbCdEf0123456789AbCdEf01",
"destinationChainId": 10,
"sourceChainIds": [1, 42161]
}]
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"address": "0xDEF456...",
"active": true,
"expiresAt": 1741132800
}
}
| Field | Description |
|---|---|
expiresAt | Unix timestamp (seconds) when monitoring expires. Do not hardcode this value; the default TTL may change |
forwarding_getActivation
Checks the activation status of a forwarding address across all source chains it was registered on.
This endpoint tracks activation status (whether the relayer is monitoring this address), not deposit or forwarding completion status.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
address | address | Yes | The forwarding address to check |
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "forwarding_getActivation",
"params": [{
"address": "0xDEF456..."
}]
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"address": "0xDEF456...",
"sourceChains": [
{
"sourceChainId": 1,
"status": "active",
"expiresAt": 1741132800
},
{
"sourceChainId": 42161,
"status": "expired",
"expiredAt": 1740528000
}
]
}
}
Estimation
forwarding_estimateOutput
Estimates the output amount a recipient will receive after relayer and bridge protocol fees. Returns the best available bridge for the route. This method is decoupled from forwarding addresses: it takes chain IDs directly and does not require the address to be activated.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
sourceChainId | number | Yes | Source chain where the deposit originates |
destinationChainId | number | Yes | Destination chain ID |
token | address | Yes | Token address on source chain (0x000...000 for native ETH) |
amount | string | Yes | Input amount in smallest unit (e.g. "1000000000000000000" for 1 ETH) |
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "forwarding_estimateOutput",
"params": [{
"sourceChainId": 1,
"destinationChainId": 42161,
"token": "0x0000000000000000000000000000000000000000",
"amount": "1000000000000000000"
}]
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"destinationChainId": 42161,
"outputToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
"outputTokenSymbol": "USDC",
"bridge": "across",
"outputAmount": "994005000",
"relayerBotFee": "5000000",
"bridgeProtocolFee": "995000"
}
}
| Field | Description |
|---|---|
bridge | Identifier of the bridge selected for this route (e.g. "across", "oft") |
outputToken | Token contract address on the destination chain |
outputAmount | Amount the recipient receives, in the smallest unit of the output token |
relayerBotFee | Relayer service fee in smallest unit (source token decimals). Same-chain forwards return "0" |
bridgeProtocolFee | Bridge protocol fee in smallest unit (source token decimals) |
To format outputAmount for display, look up the output token's decimals from forwarding_getRoutes (the matching destinationAddress on the route's token list).
Status
forwarding_getStatus
Returns confirmed forwards for a recipient on a destination chain, including per-bridge delivery statuses. Use this to track when a deposit has been picked up and whether it has been delivered, attested, refunded, etc.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
recipient | address | Yes | Destination recipient address |
destinationChainId | number | Yes | Destination chain ID |
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "forwarding_getStatus",
"params": [{
"recipient": "0xAbCdEf0123456789AbCdEf0123456789AbCdEf01",
"destinationChainId": 10
}]
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"transfers": [
{
"sourceTxHash": "0x123...abc",
"sourceChainId": 1,
"proxyAddress": "0xDEF456...",
"createdAt": 1741132800,
"bridgeStatuses": [
{
"bridge": "across",
"status": "delivered",
"destinationTxHash": "0x789...def"
}
]
}
]
}
}
| Field | Description |
|---|---|
transfers | Array of confirmed forwards routed through the proxy address derived from recipient |
bridgeStatuses[].status | One of pending, attested, delivered, failed, expired, refunded |
Emergency Recovery
The relayer auto-deploys the proxy contract on first deposit, so integrators typically do not need to deploy it manually. If tokens are stuck in a forwarding address (e.g. the relayer did not process them), the proxy must be deployed before funds can be withdrawn directly on-chain.
There is no JSON-RPC method for deploy or withdraw. Both actions are performed on-chain from a user's wallet. Direct users to the recovery frontend, which handles the deploy and withdraw transactions for the recipient or custodialWithdrawer.
TypeScript Types
These types match the API response shapes and can serve as a reference for building your integration.
interface RouteToken {
address: string;
symbol: string;
decimals: number;
destinationAddress: string; // token address on destination chain
feeBps: number; // basis points (50 = 0.5%)
}
interface Route {
sourceChainId: number;
sourceChainName: string;
destinationChainId: number;
destinationChainName: string;
tokens: RouteToken[];
}
interface RoutesResult {
routes: Route[];
}
interface MinimumAmountResult {
bridges: {
[bridgeName: string]: { minAmount: string }; // smallest unit, source token decimals
};
}
interface AddressResult {
address: string;
}
interface ActivationResult {
address: string;
active: boolean;
expiresAt: number; // Unix timestamp (seconds)
}
interface SourceChainActivation {
sourceChainId: number;
status: "active" | "expired";
expiresAt?: number; // present when active
expiredAt?: number; // present when expired
}
interface ActivationStatus {
address: string;
sourceChains: SourceChainActivation[];
}
interface EstimateResult {
destinationChainId: number;
outputToken: string;
outputTokenSymbol: string;
bridge: string; // bridge identifier selected for the route
outputAmount: string; // smallest unit, output token decimals
relayerBotFee: string; // smallest unit, source token decimals
bridgeProtocolFee: string; // smallest unit, source token decimals
}
Changelog
The Forwarding Address API is in alpha and evolves quickly. Breaking changes and new capabilities are tracked here so integrators can see what to update.
2026-05-06
Changed
forwarding_activatehas been renamed toaccount_activateForwardingAddressand now requiresAuthorization: Bearer <account_api_key>. Other methods remain public. Request an account API key from Candide.
Added
- Per-account cap of 500 active forwarding addresses. Refreshing an existing address does not count against the cap. Exceeding the cap returns error code
-32013. - New
forwarding_getStatusendpoint. Returns confirmed forwards for a recipient on a destination chain, with per-bridge delivery statuses (pending,attested,delivered,failed,expired,refunded). - Same-chain forwards is now fee free. Only the gas cost is taken into account in the relayer fee.
2026-04-22
Added
- New source and destination chain support: Tempo. Supported tokens are
USDC.e,USDT(Tempo's native token), andUSDT0. Queryforwarding_getRouteswith Tempo's chain ID to see accepted tokens and fees.
2026-04-14
Added
- New
forwarding_getMinimumAmountendpoint. Returns per-bridge minimum deposit amounts for a given source chain, destination chain, and token. Call this beforeforwarding_estimateOutputto validate user input. - New source and destination chain support: BNB Chain and Base. Query
forwarding_getRouteswith the chain's ID to see the accepted tokens and fees. forwarding_estimateOutputresponse now includes abridgefield identifying which bridge was selected for the route.forwarding_activatenow automatically includes the destination chain in the monitored set, so same-chain forwarding works without passing it insourceChainIds.
Changed
forwarding_getRoutesparametersourceChainIdis now required. The endpoint returns all routes originating from that source chain. Call it once per source chain to build the full map of supported destinations.RouteTokenno longer includes aminAmountfield. Minimums are now bridge-specific and returned byforwarding_getMinimumAmount.forwarding_estimateOutputresponse no longer includesoutputDecimals. To formatoutputAmount, read the output token'sdecimalsfromforwarding_getRoutes(match on the route'sdestinationAddress).
Removed
forwarding_estimateOutputno longer accepts amodeparameter. The service selects the best available bridge automatically and returns it in the responsebridgefield.forwarding_setModehas been removed. Bridging strategy is no longer user-configurable per address.forwarding_deployhas been removed as a JSON-RPC method. The relayer auto-deploys the proxy on first deposit. For emergency recovery of stuck funds, users deploy and withdraw on-chain from their own wallet via the recovery frontend.