GuideReference

Quotes

Endpoint

POST https://api.bindpay.xyz/v1/quote

Guide to requesting and executing a quoteCopied!

This guide will walk you through the process of requesting a quote using the bindpay API. This is typically the first step in processing a payment transaction.

What is a Quote Request?

A quote request allows you to get pricing information for a potential transaction before actually executing it. This is useful for:

  1. Showing the user how much they'll pay before they commit

  2. Understanding the current exchange rates and fees

  3. Preparing the necessary transaction details

Prerequisites

Before you start, make sure you have:

  1. A bindpay API key

  2. The details of the transaction you want to quote

If you don't have an API key yet, you can register for one here.

Step-by-Step Guide

1. Prepare Your Request

You'll need to gather the following information:

  • fromChain: The ID of the blockchain network the payment is coming from.

    • Refer to our Active Chains list to find the correct chainID.

    • Example: "1" for Ethereum Mainnet, "8453" for Base

  • fromToken: The address of the token being used for payment.

    • This is a unique address for each token on each network.

    • Example: For ETH on Ethereum, you can use "ETH" or the zero address "0x0000000000000000000000000000000000000000"

  • fromAddress: The wallet address of the person making the payment.

    • This should be a valid address on the specified chain.

    • Example: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e"

  • usdAmount: The amount of the transaction in US Dollars.

    • This should be a string representing the dollar amount.

    • Example: "100" for a $100 transaction

2. Make the API Call

Now that you have all the necessary information, you can make the API call. Here's how to do it using cURL:

curl -X POST "https://api.bindpay.xyz/v1/quote" \
     -H "Content-Type: application/json" \
     -H "x-api-key: your_api_key_here" \
     -d '{
       "fromChain": "1",
       "fromToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
       "fromAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
       "usdAmount": 1
     }'

use reqwest::Client;
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let url = "https://api.bindpay.xyz/v1/quote";
    let client = Client::new();

    let response = client.post(url)
        .header("Content-Type", "application/json")
        .header("x-api-key", "your_api_key_here")
        .json(&json!({
            "fromChain": "1",
            "fromToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
            "fromAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
            "usdAmount": 100
        }))
        .send()
        .await?;

    println!("{}", response.text().await?);
    Ok(())
}
import axios from 'axios';

const url = 'https://api.bindpay.xyz/v1/quote';
const headers = {
    'Content-Type': 'application/json',
    'x-api-key': 'your_api_key_here'
};
const data = {
    fromChain: '1',
    fromToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
    fromAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
    usdAmount: 100
};

axios.post(url, data, { headers })
    .then(response => console.log(response.data))
    .catch(error => console.error('Error:', error));
const axios = require('axios');

const url = 'https://api.bindpay.xyz/v1/quote';
const headers = {
    'Content-Type': 'application/json',
    'x-api-key': 'your_api_key_here'
};
const data = {
    fromChain: '1',
    fromToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
    fromAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
    usdAmount: 100
};

axios.post(url, data, { headers })
    .then(response => console.log(response.data))
    .catch(error => console.error('Error:', error));

import requests

url = "https://api.bindpay.xyz/v1/quote"
headers = {
    "Content-Type": "application/json",
    "x-api-key": "your_api_key_here"
}
data = {
    "fromChain": "1",
    "fromToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    "fromAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
    "usdAmount": 100
}

response = requests.post(url, headers=headers, json=data)
print(response.json())

Replace your_api_key_here with your actual API key.

3. Understand the Response

The API will respond with a JSON object containing the quote details. Here's an example of what you might receive:

{
    "message": "Quote requested",
    "transactionId": "67e55737b7b3b7bc1deb8977",
    "quote": {
        "provider": "Relay",
        "provideRequestId": "0x006b09055cff301034ed164c81c56f8302a350d51210b8686f8d43a1fa13fc06",
        "fromToken": {
            "address": "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
            "decimals": 6,
            "symbol": "USDC",
            "price": 0.9998610423820736
        },
        "toToken": {
            "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
            "decimals": 6,
            "symbol": "USDC",
            "price": 0.9998609721944389
        },
        "fromAmount": "1000305",
        "toAmount": "999800",
        "fromAddress": "0x65dC5d3Dab013af752832a5B03De7Ae902aCF048",
        "toAddress": "0x15dC5d3Dab013af752832a5B03De7Ae902aCF049",
        "estimatedDuration": 4,
        "fees": {
            "bridge": 0.000505,
            "gas": "0.002094",
            "integrator": "0.001999"
        }
    },
    "approvalTxParams": {
        "from": "0x65dC5d3Dab013af752832a5B03De7Ae902aCF048",
        "to": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
        "gas": "0xe7db",
        "data": "0x095ea7b3000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e583100000000000000000000000000000000000000000000000000000000000f4371",
        "value": "0x0",
        "nonce": 41
    },
    "transactionRequest": {
        "from": "0x65dC5d3Dab013af752832a5B03De7Ae902aCF048",
        "to": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
        "data": "0xa9059cbb000000000000000000000000f70da97812cb96acdf810712aa562db8dfa3dbef00000000000000000000000000000000000000000000000000000000000f4371006b09055cff301034ed164c81c56f8302a350d51210b8686f8d43a1fa13fc06",
        "value": "0",
        "chainId": 42161,
        "requestId": "0x006b09055cff301034ed164c81c56f8302a350d51210b8686f8d43a1fa13fc06",
        "maxFeePerGas": "0x2d8f0fc",
        "maxPriorityFeePerGas": "0x0"
    }
}
  • quoteId: A unique identifier for this quote. You'll need this if you decide to execute the transaction.

  • exchangeRate: The current exchange rate between the from token and USD.

  • fromAmount: The amount of the from token that will be sent.

  • toAmount: The amount in USD that will be received.

  • fee: These fees are varible based on your sub-payee takerate

  • estimatedGas: An estimate of the gas required for the transaction.

  • estimatedDuration: An estimate of transfer time (seconds)

Approval Transaction Parameters (approvalTxParams):

  • from: The address of the user initiating the transaction.

  • to: The address of the contract that needs approval (USDC token contract in this case).

  • gas: Estimated gas limit for the approval transaction.

  • gasPrice: Gas price for the transaction.

  • data: The encoded data for the approval transaction (standard ERC-20 approval format).

  • value: The value in wei being sent with the transaction (usually 0 for approval transactions).

  • nonce: The transaction count from the from address (to prevent double-spends).

Transaction Request (transactionRequest):

  • to: The address that the transaction is being sent to (could be a smart contract or user address).

  • from: The user's address initiating the transaction.

  • data: Encoded call data for the transaction (typically contains function selectors and parameters for smart contract calls).

  • value: The amount of ETH (in wei) sent with the transaction.

  • chainId: The chain ID of the network. gasPrice: The gas price for the transaction.

  • gasLimit: The maximum gas allowed for this transaction.

Quote Expiry

Quotes from the bindpay API typically have a validity period of 15 seconds. This brief timeframe is intended to guarantee that users are making transactions that reflect the latest market conditions. Here are some important aspects regarding quote expiration:

  • Timeliness: Users should frequently request new quotes to ensure they are working with accurate and current data.

  • Time Limit: After receiving a quote, users must sign the transaction within 15 seconds to ensure its validity.

To facilitate seamless transactions and achieve the best pricing, it’s advisable to set up an automatic quote refresh system for users who haven't completed their transactions within the 15-second timeframe.

4. Next Steps

Once you have the quote:

  1. Display the relevant information to your user.

  2. If the user agrees to the quote, you can proceed to execute the transaction using the approval and transaction data.

  3. If the user wants to change something, you can request a new quote with updated parameters.

Executing a QuoteCopied!

After receiving a quote from the API, you'll need to handle the transaction execution process. This involves managing token approvals (if needed) and executing the main transfer transaction.

Prerequisites

  • Ability to sign transactions (via blockchain libraries, SDKs, etc.)

  • A valid quote response from the API

Quote Response Types from Request Quote

Direct Transfer Response :
{
  message: "Direct transfer transaction prepared",
  transactionId: string,
  type: "Direct",
  approvalTxParams: null
  transferTxParams: {
    to: string,
    data: string,
    value: string,
    gas: string
  },
}
Swap Transactions Response:
{
  message: "Quote requested",
  transactionId: string,
  type: "Provider",
  approvalTxParams?: {  // Present if token approval needed
    to: string,
    data: string,
    value: string,
    gas: string
  },
  transactionRequest: {
    to: string,
    data: string,
    value: string,
    gas: string
  }
}

Response Field Details

Common Fields
  • transactionId: Unique identifier for tracking the transfer

  • type: Indicates transfer type ("Direct" or "Provider")

  • gas: Estimated gas limit in hexadecimal

Transaction Parameters
  • to: Target contract or recipient address

  • data: Encoded transaction data (empty for native transfers)

  • value: Amount in wei (used for native token transfers)

Approval Parameters
  • Present only when token approval is needed

  • Contains parameters for approving token spending

  • Must be executed before the main transfer

Basic Implementation

import { ethers } from 'ethers';

async function executeQuote(quoteResponse: QuoteResponse) {
  // Initialize provider and signer
  const provider = new ethers.BrowserProvider(window.ethereum);
  const signer = await provider.getSigner();
  
  try {
    // Step 1: Handle token approval if needed
    if (quoteResponse.approvalTxParams) {
      const approvalTx = await signer.sendTransaction({
        to: quoteResponse.approvalTxParams.to,
        data: quoteResponse.approvalTxParams.data,
        value: ethers.toBigInt(quoteResponse.approvalTxParams.value || '0'),
        gasLimit: ethers.toBigInt(quoteResponse.approvalTxParams.gas)
      });
      
      // Wait for approval confirmation
      await approvalTx.wait();
    }

    // Step 2: Execute main transfer
    const txParams = quoteResponse.type === 'Direct' 
      ? quoteResponse.transferTxParams 
      : quoteResponse.transactionRequest;

    const tx = await signer.sendTransaction({
      to: txParams.to,
      data: txParams.data,
      value: ethers.toBigInt(txParams.value || '0'),
      gasLimit: ethers.toBigInt(txParams.gas)
    });

    return tx.hash;
  } catch (error) {
    console.error('Transaction failed:', error);
    throw error;
  }
}

Best Practices

  • Approval Handling

    • Always check for approvalTxParams before proceeding

    • Wait for approval confirmation before executing the main transfer

    • Handle approval failures appropriately

  • Transaction Execution

    • Use proper gas estimation from the quote

    • Handle both direct and cross-chain transfers

    • Monitor transaction status until completion

  • User Experience

    • Show clear loading states during transactions

    • Provide feedback during approval and transfer steps

    • Handle errors gracefully with user-friendly messages

  • Security

    • Validate all transaction parameters

    • Never modify gas limits without proper estimation

    • Always wait for transaction confirmations

Complete Implementation with Error Handling and Status Monitoring:

interface TransactionStatus {
  status: 'Pending' | 'Completed' | 'Failed';
  sourceTransactionHash?: string;
  destinationTransactionHash?: string;
  sourceAmount?: string;
  destinationAmount?: string;
}

async function executeQuoteWithMonitoring(quoteResponse: QuoteResponse): Promise<TransactionStatus> {
  const provider = new ethers.BrowserProvider(window.ethereum);
  const signer = await provider.getSigner();
  
  try {
    // Handle approval if needed
    if (quoteResponse.approvalTxParams) {
      const approvalTx = await signer.sendTransaction({
        to: quoteResponse.approvalTxParams.to,
        data: quoteResponse.approvalTxParams.data,
        value: ethers.toBigInt(quoteResponse.approvalTxParams.value || '0'),
        gasLimit: ethers.toBigInt(quoteResponse.approvalTxParams.gas)
      });
      
      console.log('Waiting for approval confirmation...');
      await approvalTx.wait();
      console.log('Approval confirmed');
    }

    // Execute transfer
    const txParams = quoteResponse.type === 'Direct' 
      ? quoteResponse.transferTxParams 
      : quoteResponse.transactionRequest;

    console.log('Executing transfer...');
    const tx = await signer.sendTransaction({
      to: txParams.to,
      data: txParams.data,
      value: ethers.toBigInt(txParams.value || '0'),
      gasLimit: ethers.toBigInt(txParams.gas)
    });
    
   // Monitor transaction status
    let status: TransactionStatus = { status: 'Pending' };
    
    while (status.status === 'Pending') {
      await new Promise(resolve => setTimeout(resolve, 5000)); // Poll every 5 seconds
      const response = await fetch(
        `/v1/status?transactionId=${quoteResponse.transactionId}`,
        {
          headers: {
            'x-api-key': 'YOUR_API_KEY'
          }
        }
      );
      status = await response.json();
    }

    return status;
  } catch (error) {
    if (error instanceof Error) {
      if (error.message.includes('user rejected')) {
        throw new Error('Transaction rejected by user');
      }
      if (error.message.includes('insufficient funds')) {
        throw new Error('Insufficient funds for transaction');
      }
    }
    throw error;
  }
}

Error Handling

The implementation handles common errors including:

  • User rejection

  • Insufficient funds

  • Network issues

  • Failed transactions

  • Timeout errors

Status Monitoring

The transaction status can be one of:

Pending Transaction is in progress

Completed Transaction successfully completed

Failed Transaction failed

Learn more about Transaction Status endpoint here.