Stablecoin to Fiat transfers (Off-ramps)

Overview

Send cryptocurrency from your wallet to traditional bank accounts, mobile money services, and other fiat payment rails. This guide covers the complete process including blockchain transaction signing and submission.

Key Features:

  • Multi-network support - Ethereum, Polygon, Tron, and other blockchain networks
  • Global fiat rails - Bank transfers (ACH, SEPA, SWIFT), mobile money, local payment systems
  • Real-time conversion - Live exchange rates with transparent fee breakdown
  • Secure signing - Client-side transaction signing maintains custody control

Step-by-Step Process

1. Get Available Channels

Discover supported crypto-to-fiat combinations

curl -H "Authorization: Bearer your_api_key" \
-H "Due-Account-Id: your_account_id" \
https://api.due.network/v1/channels

Look for channels where:

  • Source channels: type: "deposit" on crypto rails (ethereum, tron, polygon)
  • Destination channels: type: "withdrawal" on fiat rails (sepa, ach, bank_swift)

2. Create Recipient

Set up the bank account or mobile money destination for your payout.

curl -X POST https://api.due.network/v1/recipients \
-H "Authorization: Bearer your_api_key" \
-H "Due-Account-Id: your_account_id" \
-H "Content-Type: application/json" \
-d '{
  "name": "John Smith",
  "details": {
    "schema": "bank_us",
    "bankName": "JPMorgan Chase Bank",
    "accountName": "John Smith",
    "accountNumber": "123456789",
    "routingNumber": "021000021",
    "beneficiaryAddress": {
      "street_line_1": "123 Main Street", 
      "city": "New York",
      "postal_code": "10001",
      "country": "USA",
      "state": "NY"
    }
  },
  "isExternal": true
}'

3. Generate Quote

Get real-time pricing for your crypto-to-fiat conversion.

curl -X POST https://api.due.network/v1/transfers/quote \
-H "Authorization: Bearer your_api_key" \
-H "Due-Account-Id: your_account_id" \
-H "Content-Type: application/json" \
-d '{
  "source": {
    "rail": "ethereum",
    "currency": "USDC",
    "amount": "1000.00"
  },
  "destination": {
    "rail": "ach", 
    "currency": "USD",
    "amount": "0"
  }
}'

Response:

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "source": {
    "rail": "ethereum",
    "currency": "USDC", 
    "amount": "1000.00",
    "fee": "0.00"
  },
  "destination": {
    "rail": "ach",
    "currency": "USD",
    "amount": "997.50",
    "fee": "2.50"
  },
  "fxRate": 1.0,
  "fxMarkup": 0,
  "expiresAt": "2024-03-15T10:32:15Z"
}

4. Create Transfer

Initialize the crypto-to-fiat transfer using your quote and recipient.

curl -X POST https://api.due.network/v1/transfers \
-H "Authorization: Bearer your_api_key" \
-H "Due-Account-Id: your_account_id" \
-H "Content-Type: application/json" \
-d '{
  "quote": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "sender": "{wallet_id}",
  "recipient": "{recipient_id}",
  "memo": "Crypto payout - Invoice #12345"
}'

Response:

{
  "id": "{transfer_id}",
  "ownerId": "{owner_id}",
  "status": "awaiting_funds",
  "source": {
    "amount": "1000.00",
    "fee": "0.00", 
    "currency": "USDC",
    "rail": "ethereum",
    "id": "{wallet_id}",
    "label": "My Ethereum Wallet",
    "details": {
      "schema": "evm",
      "address": "0x742d35Cc6665C0532925a3b8D98d0dfBb67B1BF8"
    }
  },
  "destination": {
    "amount": "997.50",
    "fee": "2.50",
    "currency": "USD", 
    "rail": "ach",
    "id": "{recipient_id}",
    "label": "John Smith",
    "details": {
      "schema": "bank_us",
      "bankName": "JPMorgan Chase Bank",
      "accountName": "John Smith",
      "accountNumber": "123456789",
      "routingNumber": "021000021"
    },
    "memo": "Crypto payout - Invoice #12345"
  },
  "fxRate": 1.0,
  "fxMarkup": 0,
  "transferInstructions": {
    "type": "TransferIntent"
  },
  "createdAt": "2024-03-15T10:30:15Z",
  "expiresAt": "2024-03-15T10:35:15Z"
}

Key Response Fields:

  • status: "awaiting_funds" - Transfer is waiting for blockchain transaction
  • transferInstructions.type: "TransferIntent" - Indicates crypto transfer requiring intent creation
  • expiresAt - Transfer expires in 5 minutes if not completed

5.a. Create Transfer Intent

Generate blockchain transaction data for signing.

curl -X POST https://api.due.network/v1/transfers/{transfer_id}/transfer_intent \
-H "Authorization: Bearer your_api_key" \
-H "Due-Account-Id: your_account_id"

Response:

{
  "token": "intent_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "id": "{intent_id}",
  "sender": "0x742d35Cc6665C0532925a3b8D98d0dfBb67B1BF8",
  "amountIn": "1000000000",
  "to": {
    "0x1234567890123456789012345678901234567890": "1000000000"
  },
  "tokenIn": "USDC",
  "tokenOut": "USDC", 
  "networkIdIn": "ethereum",
  "networkIdOut": "ethereum",
  "gasFee": "21000000000000000",
  "signables": [
    {
      "hash": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
      "type": "EIP712",
      "data": {
        "types": {
          "Transfer": [
            {"name": "to", "type": "address"},
            {"name": "amount", "type": "uint256"},
            {"name": "nonce", "type": "uint256"}
          ]
        },
        "domain": {
          "name": "DueProtocol",
          "version": "1",
          "chainId": 1
        },
        "message": {
          "to": "0x1234567890123456789012345678901234567890",
          "amount": "1000000000",
          "nonce": "123"
        }
      }
    }
  ],
  "nonce": "0x7b",
  "hash": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
  "reference": "{transfer_id}_deposit",
  "expiresAt": "2024-03-15T10:40:15Z",
  "createdAt": "2024-03-15T10:30:45Z"
}

Key Response Fields:

  • signables - Array of transactions requiring cryptographic signatures
  • gasFee - Estimated gas cost in wei for transaction execution
  • to - Destination address mapping with amounts to transfer
  • hash - Intent hash for verification and submission

5.b. Create Funding Address (Alternative to 5.a)

Instead of creating, signing, and submitting a transfer intent, you can obtain a temporary deposit address and send funds directly to complete the transfer.

Currently supported: EVM networks with USDC only (Ethereum, Polygon, Avalanche, Arbitrum, Base)

curl -X POST https://api.due.network/v1/transfers/{transfer_id}/funding_address \
-H "Authorization: Bearer your_api_key" \
-H "Due-Account-Id: your_account_id"

Response:

{
  "details": {
    "address": "0x2Fdb8B341f6c26Ee829455A9F25c83F037beb684",
    "schema": "evm"
  }
}

Important Requirements:

  • Exact amount - Send the precise amount specified in source.amount from the transfer response
  • Single transaction - The full amount must be sent in one transaction (splitting is not supported)
  • Authorized sender - Transaction must originate from the wallet address specified in the transfer's sender field
  • Time limit - Address remains valid until transfer is executed or expires (expiresAt)

Note: If you choose the funding address method (5.b), steps 6-7 are not required. The transfer will process automatically upon receiving the correct payment.

6. Sign Transaction

Use your wallet infrastructure to sign the blockchain transaction data.

Example using ethers.js:

import { ethers } from 'ethers';

// Connect to your wallet
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();

// Extract signable data from transfer intent
const signable = transferIntent.signables[0];
const domain = signable.data.domain;
const types = signable.data.types;
const message = signable.data.message;

// Sign the EIP-712 message
const signature = await signer._signTypedData(domain, types, message);

console.log('Transaction signature:', signature);

7. Submit Signed Transaction

Submit the signed transaction to complete the crypto-to-fiat payout.

Important:

  • In submit, you need to send the intent returned from the transfer_intent endpoint with signatures added to its signables.
  • Each signable should have a separate signature.
curl -X POST https://api.due.network/v1/transfer_intents/submit \
-H "Authorization: Bearer your_api_key" \
-H "Due-Account-Id: your_account_id" \
-H "Content-Type: application/json" \
-d '{
  "token": "intent_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "id": "{intent_id}",
  "sender": "0x742d35Cc6665C0532925a3b8D98d0dfBb67B1BF8",
  "amountIn": "1000000000",
  "to": {
    "0x1234567890123456789012345678901234567890": "1000000000"
  },
  "tokenIn": "USDC",
  "tokenOut": "USDC", 
  "networkIdIn": "ethereum",
  "networkIdOut": "ethereum",
  "gasFee": "21000000000000000",
  "signables": [
    {
      "signature": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12345678901c",
      "hash": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
      "type": "EIP712",
      "data": {
        "types": {
          "Transfer": [
            {"name": "to", "type": "address"},
            {"name": "amount", "type": "uint256"},
            {"name": "nonce", "type": "uint256"}
          ]
        },
        "domain": {
          "name": "DueProtocol",
          "version": "1",
          "chainId": 1
        },
        "message": {
          "to": "0x1234567890123456789012345678901234567890",
          "amount": "1000000000",
          "nonce": "123"
        }
      }
    }
  ],
  "nonce": "0x7b",
  "hash": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
  "reference": "{transfer_id}_deposit",
  "expiresAt": "2024-03-15T10:40:15Z",
  "createdAt": "2024-03-15T10:30:45Z"
}'

Upon successful submission, the blockchain transaction will be processed. Monitor the transfer status to track progress.