Gas top-up
Deliver some of the destination chain's native gas token along with the transfer, so the recipient can transact right away.
A recipient who arrives on a new chain holding only USDC cannot pay for their
next transaction. Add gasTopUp to the quote and Across also delivers a fixed
amount of the destination chain's native token, ETH on Base for example, to
the same recipient.
How it works
- Check that the route supports a top-up, and the most you can request.
- Add
gasTopUpto the quote. - Execute the quote as usual.
- Confirm the gas arrived on the transfer.
Check the route
Call GET /v1/capabilities with all four sides anchored, and read
capabilities.gasTopUp.
const BASE_URL = "https://api.across.to";
const API_KEY = process.env.ACROSS_API_KEY;
const res = await fetch(
`${BASE_URL}/v1/capabilities` +
"?originChainId=42161&originToken=0xaf88d065e77c8cC2239327C5EDb3A432268e5831" +
"&destinationChainId=8453&destinationToken=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" +
"&include=chains",
{ headers: { Authorization: `Bearer ${API_KEY}` } },
);
const { capabilities } = await res.json();
const gas = capabilities?.gasTopUp;"gasTopUp": {
"supported": true,
"token": { "kind": "native", "chainId": 8453, "address": "0x0000000000000000000000000000000000000000", "symbol": "ETH", "decimals": 18 },
"limits": {
"max": { "amount": "2183978334934917" },
"validUntil": "2026-11-03T21:07:02.375Z"
}
}| Field | Meaning |
|---|---|
supported | Whether this pair can carry a top-up |
token | The destination's native token, with its decimals |
limits.max.amount | The most you can request right now, in that token's base units |
limits.validUntil | When that maximum goes stale |
The block is absent until all four sides resolve. A missing limits means
no current maximum is known, not that there is none. The quote checks the
amount again either way.
The maximum is a USD limit per transfer, converted at the current native price: currently $25 on Ethereum and $5 on other destinations.
Quote with a top-up
Add gasTopUp.amount to your usual quote body, in native base units.
const res = await fetch(`${BASE_URL}/v1/quotes`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
origin: {
token: { chainId: 42161, address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831" },
amount: "10000000", // 10 USDC
depositor: "0xYourWalletAddress",
},
destination: {
token: { chainId: 8453, address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" },
recipient: "0xYourWalletAddress",
},
gasTopUp: { amount: "500000000000000" }, // 0.0005 ETH
}),
});
const quote = await res.json();
// quote.gasTopUp → { token: { symbol: "ETH", decimals: 18, ... }, amount: "500000000000000" }The top-up goes to destination.recipient; you cannot pick another
token or address. "0" is the same as leaving gasTopUp out.
The transfer pays for the top-up at the current native price:
exact_input: it comes out of the output.destination.amountis lower than without a top-up, anddestination.grossAmountis already net of it.exact_outputandmin_output: the output is unchanged andorigin.amountgoes up instead.
It is not a fee. It is not part of fee, and it does not count against
maxFee or subsidy. Your app fee is still charged on the full input.
Show it as something the user receives. List the top-up next to the output ("+ 0.0005 ETH for gas on Base"), not under fees or total cost.
Execute as usual
Follow the quote's nextActions exactly as you would without a top-up.
Nothing extra is signed or sent.
Confirm the gas arrived
GET /v1/transfers/{orderId} carries two gasTopUp objects, each with a
token and an amount:
| Field | Meaning |
|---|---|
quoted.gasTopUp | The amount the quote promised |
gasTopUp (top level) | The amount proven delivered on chain |
If quoted.gasTopUp is there and the top-level gasTopUp is not, the
payment is not confirmed yet, or the transfer refunded without gas. Wait
for status.finalized: true before treating the outcome as final. An
Across refund on the destination can pay the gas to the refund recipient;
CCTP and OFT refunds return only the bridged token.
Where it works
- Cross-chain routes between EVM chains, on Across, CCTP and OFT.
- From Solana to EVM chains.
- Wrapped native outputs, such as WETH, qualify. Native outputs, such as ETH, do not.
- With
destinationActions: the top-up is sent before the steps run, andonFailure.recipientmust bedestination.recipient.
Not available on same-chain swaps, or on Solana (coming soon), HyperCore,
Lighter and Tron destinations. Rely on capabilities.gasTopUp for a specific
pair rather than this list.
Errors
All carry param: "gasTopUp.amount".
| Error | Meaning |
|---|---|
400 request.unsupported_param | The route cannot carry a top-up |
400 policy.amount_out_of_range | Above the destination's USD limit |
400 request.invalid_field | The transfer is too small to pay for the top-up |