# Crosschain Payments

{% hint style="info" %}
**Reach out**

For more details on how to start accepting crypto payments, [get in touch](https://2deywy.share-eu1.hsforms.com/2b92phs9LR_eJdeZoxzmoMA?utm_source=request.network\&utm_medium=docs\&utm_campaign=evergreen\&utm_content=get_in_touch) and we will reach out.
{% endhint %}

Crosschain payments allow users to pay a request using a stablecoin from a different blockchain network than the one specified on the request. For example, a payer can pay a request for USDC on Base using USDT from their Optimism wallet.

## Benefits

* **Flexibility:** Payers can pay with their preferred currency.
* **Cost-Effective:** Automated routing balances cost and speed.
* **Time-Saving:** Payers don't need to swap or bridge tokens manually.
* **Simplified UX:** Payment settlement requires only 1 or 2 signatures from the Payer.

## Crosschain Payments Supported Chains and Currencies

For Crosschain (and Samechain) Payments, the Request Network API supports 12 stablecoins: USDC/USDT/DAI on 4 chains (Ethereum, Arbitrum One, Base, OP Mainnet).

### Crosschain Payments Supported Chains

Crosschain payments are supported on the following blockchain networks:

* Ethereum
* Arbitrum One
* Base
* OP Mainnet

### Crosschain Payments Supported Currencies

{% hint style="warning" %}
**Warning:** Crosschain payments work only with mainnet funds (real money). Test networks are not supported.
{% endhint %}

The following stablecoins are supported for crosschain payments on both the sending and receiving networks.

* USDC
* USDT
* DAI

## How it works

### 1. Request creation

To enable crosschain payments, the request must be created with the following parameters:

* `paymentCurrency` included in the [#supported-stablecoins](#supported-stablecoins "mention") and [#supported-networks](#supported-networks "mention").
* `amount` greater than 1 - *executing* crosschain payments under 1 stablecoins is not allowed, even though *creating* requests has no restrictions on `amount` .

For more details about creating requests, please see the [#post-v2-request](https://docs.request.network/create-and-pay-requests#post-v2-request "mention") endpoint.

### 2. Payment route fetching

To display a list of possible routes for a given request and payer address, use the [#get-v2-request-requestid-routes](#get-v2-request-requestid-routes "mention") endpoint. It returns all of the possible routes based on the payer's token balances.

#### Route Ranking

The API automatically ranks available payment routes based on the following factors:

* Transaction fees
* Processing speed

Routes that offer a *balanced* combination of lower fees and faster processing times are ranked higher in the results.

#### Fee breakdown

When fetching payment routes, each route displays the total estimated fees in the payment currency. This fee represents the combined costs associated with processing the transactio&#x6E;**,** including:

1. **Gas Fees:**

   The total fee includes all gas costs incurred by the payment processor wallet for processing the transaction. This covers:

   \- Transferring tokens from the payer's wallet.

   \- Approving the payment execution smart contract.

   \- Executing the crosschain payment transaction.

   **For tokens supporting EIP-2612:**

   \- The payment processor wallet also covers for the onchain permit transaction.

   **For tokens that do not support EIP-2612:**

   \- The payer must perform an onchain approval transaction and pay for the gas fee directly. This fee is **not** included in the total fee shown for the route.
2. **Service Fees:**

   The total fees also include any service fees charged by the crosschain infrastructure for facilitating transfers or swaps between different blockchains.

#### Samechain routes

The API may return samechain routes if the payer address has supported currencies on the same chain as the `paymentCurrency` .

* Example: `paymentCurrency` is USDC on Base, and the payer has USDT on Base
* Gasless transactions - the transaction fees are added on top of the request amount
* No native token (ETH, etc..) needed for gas

## Get payment routes

> Get available payment routes for a request. This endpoint analyzes the payer's wallet balance across supported chains and returns possible payment methods. Routes include direct same-chain payments and crosschain bridging options when the payer has sufficient balance on different chains than the request's native chain.

```json
{"openapi":"3.0.0","info":{"title":"Request Network API","version":"0.18.0"},"tags":[{"name":"V2/Request","description":"Core payment request operations (V2)"}],"servers":[{"url":"https://api.request.network","description":"Production server"},{"url":"https://api.stage.request.network","description":"Staging server"},{"url":"http://127.0.0.1:8080","description":"Local development server"}],"paths":{"/v2/request/{requestId}/routes":{"get":{"description":"Get available payment routes for a request. This endpoint analyzes the payer's wallet balance across supported chains and returns possible payment methods. Routes include direct same-chain payments and crosschain bridging options when the payer has sufficient balance on different chains than the request's native chain.","operationId":"RequestControllerV2_getRequestPaymentRoutes_v2","parameters":[{"name":"requestId","required":true,"in":"path","description":"The requestId of the request","schema":{"type":"string"}},{"name":"x-api-key","in":"header","description":"API key for authentication (optional if using Client ID)","required":false,"schema":{"type":"string"}},{"name":"x-client-id","in":"header","description":"Client ID for frontend authentication (optional if using API key)","required":false,"schema":{"type":"string"}},{"name":"Origin","in":"header","description":"Origin header (required for Client ID auth, automatically set by browser)","required":false,"schema":{"type":"string"}},{"name":"wallet","required":true,"in":"query","description":"The wallet address of the payer","schema":{"type":"string"}},{"name":"amount","required":false,"in":"query","description":"The amount to pay, in human readable format","schema":{"type":"string"}},{"name":"feePercentage","required":false,"in":"query","description":"Fee percentage to apply at payment time (e.g., '2.5' for 2.5%)","schema":{"type":"string"}},{"name":"feeAddress","required":false,"in":"query","description":"Address to receive the fee","schema":{"type":"string"}}],"responses":{"200":{"description":"Available payment routes","content":{"application/json":{"schema":{"type":"object","description":"Available payment routes for the request","properties":{"routes":{"type":"array","description":"Array of available payment routes","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the route"},"fee":{"type":"number","description":"Total fee for this route (as a decimal, e.g., 0.001 = 0.1%)"},"feeBreakdown":{"type":"array","description":"Detailed breakdown of all fees for this route","items":{"type":"object","properties":{"type":{"type":"string","enum":["gas","platform","crosschain","crypto-to-fiat","offramp"],"description":"Type of fee"},"stage":{"type":"string","enum":["sending","receiving","proxying","refunding","overall"],"description":"Stage when the fee is applied"},"provider":{"type":"string","description":"Provider that charged the fee"},"amount":{"type":"string","description":"Fee amount in human-readable format (formatted with token decimals)"},"amountInUSD":{"type":"string","description":"Fee amount in USD"},"currency":{"type":"string","description":"Fee currency"},"receiverAddress":{"type":"string","description":"Address that received the fee"},"network":{"type":"string","description":"Network where the fee was paid"},"rateProvider":{"type":"string","description":"Provider used for rate conversion"}}}},"speed":{"oneOf":[{"type":"string"},{"type":"number"}],"description":"Route speed - 'FAST' for direct payments, number of seconds for crosschain"},"price_impact":{"type":"number","description":"Price impact of the route (as a decimal)"},"chain":{"type":"string","description":"Source chain for the payment"},"token":{"type":"string","description":"Token symbol for the payment"}},"required":["id","fee","speed","chain","token"]}}},"required":["routes"]}}}},"400":{"description":"Invalid or missing wallet address"},"404":{"description":"Request not found"},"429":{"description":"Too Many Requests"}},"summary":"Get payment routes","tags":["Request","V2/Request"]}}}}
```

### 3. Getting payment calldata

Once the route is selected, the payer needs to fetch the unsigned payment calldata or intents.\
\
If the selected route is a crosschain payment, the [#get-v2-request-requestid-pay](#get-v2-request-requestid-pay "mention") endpoint returns an unsigned payment intent. It will also return an unsigned approval permit or unsigned approval calldata, depending on whether the `paymentCurrency` supports [EIP-2612 Permit](https://eips.ethereum.org/EIPS/eip-2612). For crosschain payments, this endpoint is NOT approval aware - it will return an approval permit or approval calldata even if approval has already been granted.

If the selected route is a direct payment, the [#get-v2-request-requestid-pay](#get-v2-request-requestid-pay "mention") returns an unsigned payment calldata. It may also return an approval calldata. For direct payments, this endpoint IS approval aware - it will omit the approval calldata if sufficient approval has already been granted.

## Get payment calldata

> Get the calldata needed to pay a request. For same-chain payments, returns transaction calldata that can be directly executed. For crosschain payments (when chain and token parameters are provided and differ from the request's native chain), returns executable transaction calldata for the route, including any required approval transaction before the LiFi transaction. For off-ramp payments, use the query parameters clientUserId and paymentDetailsId. Note: Crosschain requests with an expectedAmount less than 1 are rejected.

```json
{"openapi":"3.0.0","info":{"title":"Request Network API","version":"0.18.0"},"tags":[{"name":"V2/Request","description":"Core payment request operations (V2)"}],"servers":[{"url":"https://api.request.network","description":"Production server"},{"url":"https://api.stage.request.network","description":"Staging server"},{"url":"http://127.0.0.1:8080","description":"Local development server"}],"paths":{"/v2/request/{requestId}/pay":{"get":{"description":"Get the calldata needed to pay a request. For same-chain payments, returns transaction calldata that can be directly executed. For crosschain payments (when chain and token parameters are provided and differ from the request's native chain), returns executable transaction calldata for the route, including any required approval transaction before the LiFi transaction. For off-ramp payments, use the query parameters clientUserId and paymentDetailsId. Note: Crosschain requests with an expectedAmount less than 1 are rejected.","operationId":"RequestControllerV2_getPaymentCalldata_v2","parameters":[{"name":"requestId","required":true,"in":"path","description":"The requestId of the request","schema":{"type":"string"}},{"name":"x-api-key","in":"header","description":"API key for authentication (optional if using Client ID)","required":false,"schema":{"type":"string"}},{"name":"x-client-id","in":"header","description":"Client ID for frontend authentication (optional if using API key)","required":false,"schema":{"type":"string"}},{"name":"Origin","in":"header","description":"Origin header (required for Client ID auth, automatically set by browser)","required":false,"schema":{"type":"string"}},{"name":"wallet","required":false,"in":"query","description":"The wallet address of the payer.","schema":{"type":"string"}},{"name":"chain","required":false,"in":"query","description":"The source chain of the crosschain payment","schema":{"enum":["BASE","OPTIMISM","ARBITRUM","ETHEREUM"],"type":"string"}},{"name":"token","required":false,"in":"query","description":"The source token of the crosschain payment","schema":{"enum":["USDC","USDT"],"type":"string"}},{"name":"amount","required":false,"in":"query","description":"The amount to pay, in human readable format","schema":{"type":"string"}},{"name":"clientUserId","required":false,"in":"query","description":"Optional client user ID for off-ramp payments","schema":{"type":"string"}},{"name":"paymentDetailsId","required":false,"in":"query","description":"Optional payment details ID for off-ramp payments","schema":{"type":"string"}},{"name":"feePercentage","required":false,"in":"query","description":"Fee percentage to apply at payment time (e.g., '2.5' for 2.5%)","schema":{"type":"string"}},{"name":"feeAddress","required":false,"in":"query","description":"Address to receive the fee","schema":{"type":"string"}}],"responses":{"200":{"description":"Payment calldata retrieved successfully","content":{"application/json":{"schema":{"anyOf":[{"type":"object","title":"Same-chain Payment Response","description":"Response for same-chain payments with transaction calldata","properties":{"transactions":{"type":"array","description":"Array of transactions to execute for the payment","items":{"type":"object","properties":{"data":{"type":"string","description":"Transaction calldata"},"to":{"type":"string","description":"Target contract address"},"value":{"type":"object","description":"Payment amount in EVM-compatible format","properties":{"type":{"type":"string","enum":["BigNumber"]},"hex":{"type":"string","description":"Amount encoded in hex"}}}},"required":["data","to","value"]}},"metadata":{"type":"object","description":"Metadata about the payment requirements","properties":{"stepsRequired":{"type":"number","description":"Number of transactions required"},"needsApproval":{"type":"boolean","description":"Whether token approval is needed"},"approvalTransactionIndex":{"type":"number","nullable":true,"description":"Index of the approval transaction if needed"},"hasEnoughBalance":{"type":"boolean","description":"Whether payer has sufficient balance"},"hasEnoughGas":{"type":"boolean","description":"Whether payer has sufficient gas"}},"required":["stepsRequired","needsApproval","hasEnoughBalance","hasEnoughGas"]}},"required":["transactions","metadata"]},{"type":"object","title":"Crosschain Payment Response","description":"Response for crosschain payments with executable transaction calldata","properties":{"transactions":{"type":"array","description":"Array of transactions to execute for the selected route","items":{"type":"object","properties":{"data":{"type":"string","description":"Transaction calldata"},"to":{"type":"string","description":"Target contract address"},"value":{"oneOf":[{"type":"string"},{"type":"object","properties":{"type":{"type":"string","enum":["BigNumber"]},"hex":{"type":"string"}}}],"description":"Transaction value"},"chainType":{"type":"string","enum":["evm","tron"],"nullable":true}},"required":["data","to","value"]}},"metadata":{"type":"object","description":"Metadata about the crosschain payment","properties":{"stepsRequired":{"type":"number","description":"Number of transactions required"},"needsApproval":{"type":"boolean","description":"Whether token approval is needed"},"approvalTransactionIndex":{"type":"number","nullable":true,"description":"Index of the approval transaction if needed"},"paymentTransactionIndex":{"type":"number","description":"Index of the executable crosschain transaction"},"hasEnoughBalance":{"type":"boolean","description":"Whether payer has sufficient token balance"},"routeType":{"type":"string","enum":["crosschain","samechain"]},"quoteExpiresAt":{"type":"number","description":"Route quote expiry timestamp"}},"required":["stepsRequired","needsApproval","paymentTransactionIndex","hasEnoughBalance","routeType"]}},"required":["transactions","metadata"]}]}}}},"400":{"description":"Validation failed","content":{"application/json":{}}},"404":{"description":"Request not found"},"429":{"description":"Too Many Requests"}},"summary":"Get payment calldata","tags":["Request","V2/Request"]}}}}
```

### 4. Signing the payment intent

The intents and calldata returned by the [#get-v2-request-requestid-pay](#get-v2-request-requestid-pay "mention") endpoint in the previous step must be signed by the payer's wallet to authorize the crosschain payment. The process for signing the approval varies depending on whether the `paymentCurrency` supports [EIP-2612 Permit](https://eips.ethereum.org/EIPS/eip-2612), indicated by the `metadata` response parameter.

```json
    "metadata": {
        "supportsEIP2612": true
    }
```

If the token does not support EIP-2612 Permit, the payer must sign and submit a standard ERC20 approval transaction.

{% tabs %}
{% tab title="Ethers V5" %}

```typescript
import { ethers } from "ethers";

const ethersProvider = new ethers.providers.Web3Provider(
  // Connected wallet provider
  walletProvider as ethers.providers.ExternalProvider,
);
const signer = await ethersProvider.getSigner();

// Response from the `GET /request/{requestId}/pay` endpoint
const response = ...

const paymentIntent = JSON.parse(paymentData.paymentIntent);
const supportsEIP2612 = paymentData.metadata.supportsEIP2612;
let approvalSignature = undefined;
let approval = undefined;

if (supportsEIP2612) {
  approval = JSON.parse(paymentData.approvalPermitPayload);

  approvalSignature = await signer._signTypedData(
    approval.domain,
    approval.types,
    approval.values,
  );
} else {
  const tx = await signer.sendTransaction(paymentData.approvalCalldata);
  await tx.wait();
}

const paymentIntentSignature = await signer._signTypedData(
  paymentIntent.domain,
  paymentIntent.types,
  paymentIntent.values,
);

const signedData = {
  signedPaymentIntent: {
    signature: paymentIntentSignature,
    nonce: paymentIntent.values.nonce.toString(),
    deadline: paymentIntent.values.deadline.toString(),
  },
  signedApprovalPermit: approvalSignature
    ? {
      signature: approvalSignature,
      nonce: approval.values.nonce.toString(),
      deadline: approval?.values?.deadline
        ? approval.values.deadline.toString()
        : approval.values.expiry.toString(),
    }
    : undefined,
};
```

{% endtab %}
{% endtabs %}

### 5. Sending the signed data

Finally, the signed payment intent (and possibly the signed approval permit) are sent back to execute the crosschain payment via the [#post-v2-request-payment-intents-paymentintentid](#post-v2-request-payment-intents-paymentintentid "mention") endpoint. It will handle all the necessary steps to complete the payment. A `payment.complete` event will be sent to the platform's webhooks when the payment is completed.

## Custom fee configuration

It will be possible in the future to add a custom fee to the payment, this is currently under development.
