Deposit Addresses

Generate a counterfactual deposit address that users can send funds to in order to initiate a crosschain transfer.

Early Access.
Deposit addresses are available for approved integrators. Reach out on Telegram to get access.

Supported routes.
Deposit addresses currently only support USDC (Ethereum, Base and Arbitrum only) to USDH (HyperEVM, HyperCore). More routes will be added soon.

Overview

Deposit addresses let users initiate crosschain transfers by sending tokens to a generated address. Call /swap/counterfactual with your route parameters and receive a unique depositAddress. The user sends the input token to that address on the origin chain. Across detects the transfer, sweeps the funds, and completes the crosschain transfer to the recipient on the destination chain.

This is ideal for:

  • Onramps: user withdraws from a CEX or fiat onramp directly to a deposit address
  • Bots and automation: no wallet signing flow needed
  • Simplified UX: reduce the integration to a single token transfer

How It Works

API key required.
This endpoint requires a valid API key in the Authorization header. Requests without one will return a 403 error. Request your API key and integrator ID

Generate a deposit address

Call /swap/counterfactual with the route parameters, recipient, and refund address.

generate-deposit-address.ts
const params = new URLSearchParams({
  useDepositAddress: "true",
  originChainId: "42161",
  destinationChainId: "1337",
  inputToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC on Arbitrum
  outputToken: "0x2000000000000000000000000000000000000168", // USDH on HyperCore
  amount: "1000000",
  recipient: "0xRecipientAddress",
  refundAddress: "0xUserOriginAddress",
});

const response = await fetch(
  `https://app.across.to/api/swap/counterfactual?${params}`,
  {
    headers: {
      Authorization: "Bearer YOUR_API_KEY",
    },
  }
);
const data = await response.json();

console.log("Deposit address:", data.depositAddress);
console.log("Send", data.inputToken.symbol, "to this address on origin chain");

Send tokens to the deposit address

Transfer the input token to the depositAddress on the origin chain. This is a standard ERC-20 transfer, no special calldata needed.

send-tokens.ts
import { erc20Abi } from "viem";

const hash = await walletClient.writeContract({
  address: data.inputToken.address,
  abi: erc20Abi,
  functionName: "transfer",
  args: [data.depositAddress, BigInt(data.inputAmount)],
});

console.log("Transfer tx:", hash);

Across handles the rest

After detecting the token transfer, Across:

  1. Fetches a fresh quote for the route
  2. Deploys the deposit address contract and sweeps funds into the SpokePool
  3. Completes the crosschain swap

The recipient receives the output token on the destination chain.

Track the deposit

Poll /deposit/status with the depositAddress to monitor progress:

track-deposit.ts
const statusRes = await fetch(
  `https://app.across.to/api/deposit/status?depositAddress=${data.depositAddress}&index=0`
);
const status = await statusRes.json();

console.log("Status:", status.status);
console.log("Deposit tx ref:", status.depositTxnRef);

Once you have the depositTxnRef, query /deposit for full execution details including fees:

get-deposit-details.ts
const depositRes = await fetch(
  `https://app.across.to/api/deposit?depositTxnRef=${status.depositTxnRef}`
);
const deposit = await depositRes.json();

console.log("Fill tx:", deposit.fillTxnRef);

API Parameters

Request

ParameterTypeRequiredDescription
useDepositAddressbooleanYesMust be true
inputTokenstringYesToken address on origin chain
outputTokenstringYesToken address on destination chain
originChainIdnumberYesOrigin chain ID
destinationChainIdnumberYesDestination chain ID
amountstringYesAmount in smallest unit (wei)
recipientstringYesAddress receiving tokens on destination
refundAddressstringYesAddress for refunds on origin chain

Response

FieldTypeDescription
depositAddressstringAddress to send tokens to on origin chain
idstringUnique quote identifier
crossSwapTypestringType of crosschain swap (e.g. "bridgeableToBridgeable")
amountTypestringAmount type used (e.g. "exactInput")
inputTokenobjectInput token details: address, symbol, name, decimals, chainId
outputTokenobjectOutput token details: address, symbol, name, decimals, chainId
refundTokenobjectToken used for refunds: address, symbol, name, decimals, chainId
inputAmountstringAmount of input token (smallest unit)
maxInputAmountstringMaximum input amount
expectedOutputAmountstringExpected output amount after fees
minOutputAmountstringMinimum guaranteed output amount
expectedFillTimenumberExpected fill time in seconds
quoteExpiryTimestampnumberUnix timestamp when this quote expires
checksobjectAllowance and balance checks: allowance (token, spender, actual, expected) and balance (token, actual, expected)
stepsobjectBreakdown of the bridge step including inputAmount, outputAmount, tokenIn, tokenOut, fees, and provider
feesobjectFee breakdown: total (amount, amountUsd, pct, details), totalMax, and originGas
swapTxobjectTransaction to execute: ecosystem, simulationSuccess, chainId, to, data, value, gas

The fees.total.details object contains a full breakdown including bridge fees (relayer capital, destination gas, LP fee) and swapImpact. See the API playground for the complete nested structure.

Address Lifecycle

Each call to /swap/counterfactual returns a new, unique address. Deposit addresses are not intended to be reused.

BehaviorDetail
UniquenessNew address generated per quote
TTL24 hours: address expires if no token transfer is received
After first transferAcross processes the transfer and stops monitoring the address
Reuse within TTLIf additional transfers are sent within the TTL, they will be processed, but this is not the intended flow

Do not cache or persist deposit addresses. Generate a new one for each transfer.

Tracking Status

Track deposit status using the depositAddress and index parameters on /deposit/status:

GET /deposit/status?depositAddress=0x1234...abcd&index=0

The index is 0-based. Use 0 for the first (and typically only) deposit to that address.

The response uses the same status values as standard deposits: pending > filled / expired > refunded.

See Tracking Deposits for the full polling guide.

Fees

There is currently no deployment fee charged for generating deposit addresses. If a fee is introduced in the future, it will be:

  • A fixed amount (not a percentage)
  • Deducted from the user's input amount
  • Included in the quote response

Bridge fees (relayer capital, destination gas, LP) are included in the response under fees.total and steps.bridge.fees.

Refund Behavior

Always set refundAddress to an address the user controls on the origin chain. This address receives refunds if the transfer cannot be completed.

If there's ever an issue with your bridge transaction while using /swap/counterfactual, please know your funds are not lost. Deposit addresses have built-in safeguards to ensure funds can always be recovered.

Below is a breakdown of each scenario, what happens automatically, and what steps you need to take to resolve it.

ScenarioWhat happensWhat to do
Deposit is showing pending statusThe transfer is still being processed. This can take longer than usual during periods of high network congestion or relayer unprofitability.Wait and monitor using /deposit/status. Most pending deposits resolve automatically.
Deposit filled but relayer can't complete the transferRefund is sent automatically to refundAddress on the origin chain.No action needed — wait for the automatic refund. This typically completes within a few hours.
Correct token, wrong chainFunds are stuck at the deposit address on the wrong chain. Manual recovery is required.Reach out to our team (see below).
Wrong token, correct chainThe deposit address only processes the expected token. The wrong token will not be swept or filled. Manual recovery is required.Reach out to our team (see below).
Wrong token, wrong chainFunds are stuck at the deposit address on the wrong chain with the wrong token. Manual recovery is required.Reach out to our team (see below).

Need help recovering funds?

For any scenario that requires manual recovery, reach out to us with the following details:

  1. depositAddress — the address returned by /swap/counterfactual
  2. Token address — the contract address of the token you sent
  3. Chain ID — the chain where the funds were actually sent

Contact us via Telegram, Discord, or Slack if your team has a shared channel with us.

This refund behavior is specific to /swap/counterfactual. For general refund timing and behavior applicable on all other APIs, see Refunds.

Try it in the API playground: /swap/counterfactual

On this page