{
  "id": "txn_01HZXK8M9N2P3Q4R5S6T7U8V9X",
  "bridge_transfer_id": "transfer_def456abc789",
  "state": "pending",
  "amount": "1000.00",
  "source": {
    "payment_rail": "ach_push",
    "currency": "usd"
  },
  "destination": {
    "payment_rail": "ethereum",
    "currency": "usdc",
    "to_address": "0x742d35Cc6634C0532925a3b8D4C9db96c4b4d8e1"
  },
  "customer": {
    "first_name": "John",
    "last_name": "Doe",
    "email": "john.doe@example.com",
    "address": "123 Main St, New York, NY 10001",
    "country": "United States",
    "phone_number": "+1-555-123-4567"
  },
  "reference": {
    "ach_reference": "INV12345"
  },
  "created_at": "2023-07-01T12:00:00.000Z",
  "updated_at": "2023-07-01T12:00:00.000Z"
}
The Create Bank Payment Intent API enables fiat-to-stablecoin transfers through traditional banking rails. This feature is perfect for onboarding users from traditional banking to crypto, supporting ACH, Wire, and SEPA payment methods with seamless conversion to stablecoins.

Endpoint Details

method
string
POST
url
string
/api/v0/payment-intents/bank
Authentication: Required (API Key & Secret)
Idempotency: Supported (recommended for all payment operations)

Authentication

All requests require API key authentication using the following headers:
  • x-client-key: Your application’s client key
  • x-client-secret: Your application’s client secret

Idempotency

The endpoint supports idempotency to prevent duplicate payments:
  • idempotency-key: Include a unique UUID v4 in the header
  • Subsequent requests with the same key return the original response
  • Keys expire after 24 hours

Supported Payment Rails

Payment RailDescriptionProcessing TimeCurrencies
ACH PushUS bank transfers1-2 business daysUSD
WireInternational wire transfersSame dayUSD, EUR
SEPAEuropean bank transfersSame day / next dayEUR

Supported Currencies

Fiat Currencies (Source)

CurrencyCodePayment Rails
US DollarusdACH Push, Wire
EuroeurSEPA, Wire

Stablecoins (Destination)

CurrencyCodeDescription
USDCusdcUSD Coin
EURCeurcEuro Coin

Request Parameters

Required Parameters

sourcePaymentRail
enum
required
The banking payment method to use for the transfer
Values: "ach_push", "wire", "sepa"
Example: "ach_push"
destinationCurrency
enum
required
The stablecoin currency to convert TO
Values: "usdc", "eurc"
Example: "usdc"
destinationNetwork
enum
required
The blockchain network where the stablecoin will be delivered
Values: "ethereum", "polygon", "solana", "base", "arbitrum", "optimism", "avalanche_c_chain", "stellar", "tron"
Example: "ethereum"

Optional Parameters

sourceCurrency
enum
The fiat currency to convert FROM (defaults based on payment rail)
Values: "usd", "eur"
Example: "usd"
destinationAddress
string
Destination wallet address (Ethereum 0x… or Solana format)
Example: "0x742d35Cc6634C0532925a3b8D4C9db96c4b4d8e1"
amount
string
Payment amount (omit for flexible amount)
Example: "1000.00"
customer_first_name
string
Customer’s first name (max 100 chars)
Example: "John"
customer_last_name
string
Customer’s last name (max 100 chars)
Example: "Doe"
customer_email
string
Customer’s email address (max 255 chars)
Example: "john.doe@example.com"
customer_address
string
Customer’s physical address (max 500 chars)
Example: "123 Main St, New York, NY 10001"
customer_country
string
Customer’s country (max 100 chars)
Example: "United States"
customer_countryISO
string
Customer’s country ISO code (2 letters)
Example: "US"
customer_province
string
Customer’s province/state (max 100 chars)
Example: "New York"
customer_provinceISO
string
Customer’s province/state ISO code (max 10 chars)
Example: "NY"
phoneNumber
string
Customer’s phone number with country code (max 20 chars)
Example: "+1-555-123-4567"

Payment-Specific Parameters

wire_message
string
Wire transfer message (for WIRE transfers, max 256 chars)
Example: "Payment for invoice #12345"
sepa_reference
string
SEPA reference (for SEPA transfers, 6-140 chars)
Example: "REF-123456789"
Pattern: ^[a-zA-Z0-9&\-.\/ ]+$
ach_reference
string
ACH reference (for ACH transfers, max 10 chars)
Example: "ACH123456"
Pattern: ^[a-zA-Z0-9 ]+$

Request Examples

curl -X POST "https://api.devdraft.ai/api/v0/payment-intents/bank" \
  -H "Content-Type: application/json" \
  -H "x-client-key: YOUR_CLIENT_KEY" \
  -H "x-client-secret: YOUR_CLIENT_SECRET" \
  -H "idempotency-key: $(uuidgen)" \
  -d '{
    "sourcePaymentRail": "ach_push",
    "sourceCurrency": "usd",
    "destinationCurrency": "usdc",
    "destinationNetwork": "ethereum",
    "destinationAddress": "0x742d35Cc6634C0532925a3b8D4C9db96c4b4d8e1",
    "amount": "1000.00",
    "customer_first_name": "John",
    "customer_last_name": "Doe",
    "customer_email": "john.doe@example.com",
    "customer_address": "123 Main St, New York, NY 10001",
    "customer_country": "United States",
    "customer_countryISO": "US",
    "customer_province": "New York",
    "customer_provinceISO": "NY",
    "phoneNumber": "+1-555-123-4567",
    "ach_reference": "INV12345"
  }'

Response Format

Success Response (201 Created)

{
  "id": "txn_01HZXK8M9N2P3Q4R5S6T7U8V9X",
  "bridge_transfer_id": "transfer_def456abc789",
  "state": "pending",
  "amount": "1000.00",
  "source": {
    "payment_rail": "ach_push",
    "currency": "usd"
  },
  "destination": {
    "payment_rail": "ethereum",
    "currency": "usdc",
    "to_address": "0x742d35Cc6634C0532925a3b8D4C9db96c4b4d8e1"
  },
  "customer": {
    "first_name": "John",
    "last_name": "Doe",
    "email": "john.doe@example.com",
    "address": "123 Main St, New York, NY 10001",
    "country": "United States",
    "phone_number": "+1-555-123-4567"
  },
  "reference": {
    "ach_reference": "INV12345"
  },
  "created_at": "2023-07-01T12:00:00.000Z",
  "updated_at": "2023-07-01T12:00:00.000Z"
}

Response Fields

id
string
Unique transaction identifier in our database
bridge_transfer_id
string
External bridge service transfer ID
state
string
Current state: pending, processing, completed, failed, cancelled
amount
string | null
Payment amount (null for flexible amounts until user specifies)
source
object
Source payment details including payment rail and currency
destination
object
Destination payment details including network, currency, and address
customer
object
Customer information (if provided)
reference
object
Payment-specific reference information (ACH, SEPA, Wire)
created_at
string
Creation timestamp (ISO 8601)
updated_at
string
Last update timestamp (ISO 8601)

Error Responses

{
  "statusCode": 400,
  "message": [
    "Please select a valid source payment rail",
    "Destination currency is required"
  ],
  "error": "Bad Request"
}

Payment Rail Specifications

ACH Push

  • Processing Time: 1-2 business days
  • Cut-off Time: 1:00 PM ET daily
  • Currency: USD only
  • Reference: Max 10 alphanumeric characters + spaces
  • Best For: Domestic US payments under $25,000

Wire Transfer

  • Processing Time: Same day (if submitted before 4:45 PM ET)
  • Currency: USD, EUR
  • Reference: Custom message up to 256 characters
  • Best For: Large amounts, international transfers, urgent payments

SEPA

  • Processing Time: Same day or next business day
  • Availability: 24/7/365 (SEPA Instant where supported)
  • Currency: EUR only
  • Reference: 6-140 characters with specific format requirements
  • Best For: European domestic and cross-border EUR payments

Use Cases

1. Fiat Onboarding

Help traditional banking users enter the crypto ecosystem by converting their fiat holdings to stablecoins.

2. DeFi Participation

Enable users to participate in DeFi protocols by converting bank deposits directly to stablecoins on their preferred networks.

3. Cross-Border Payments

Facilitate international money transfers by converting local fiat to stablecoins and leveraging blockchain networks.

4. Treasury Management

Allow businesses to efficiently move funds from traditional bank accounts to crypto treasuries.

5. Recurring Conversions

Set up regular conversions from fiat salaries or business income to stablecoin holdings.

Best Practices

Compliance and KYC

  • Collect required customer information for amounts over $1,000
  • Implement proper AML checks for large transactions
  • Maintain transaction records for regulatory compliance
  • Verify customer identity for high-value transfers

Reference Management

  • Use descriptive references that help with reconciliation
  • Follow format requirements for each payment rail
  • Include invoice or order numbers in references
  • Keep references consistent across related transactions

Error Handling

  • Implement retry logic for transient network failures
  • Handle payment rail-specific validation errors
  • Provide clear error messages to users
  • Monitor payment status and notify users of changes

Security

  • Always use HTTPS for API communications
  • Implement proper API key management
  • Use idempotency keys to prevent duplicate payments
  • Validate all input parameters before processing

Payment Processing Times

Payment RailTypical ProcessingCut-off TimesAvailability
ACH Push1-2 business days1:00 PM ETBusiness days only
Wire (Domestic)Same day4:45 PM ETBusiness days only
Wire (International)1-2 business days4:45 PM ETBusiness days only
SEPA StandardNext business day9:00 AM CETBusiness days only
SEPA InstantUnder 30 secondsN/A24/7/365

Integration Examples

Payment Status Monitoring

class PaymentStatusTracker {
  constructor(paymentIntents) {
    this.paymentIntents = paymentIntents;
    this.statusCallbacks = new Map();
  }

  async monitorPayment(paymentId, onStatusChange) {
    this.statusCallbacks.set(paymentId, onStatusChange);
    
    // Poll payment status every 30 seconds
    const pollInterval = setInterval(async () => {
      try {
        const payment = await this.getPaymentStatus(paymentId);
        const callback = this.statusCallbacks.get(paymentId);
        
        if (callback) {
          callback(payment.state, payment);
        }
        
        // Stop polling if payment is final
        if (['completed', 'failed', 'cancelled'].includes(payment.state)) {
          clearInterval(pollInterval);
          this.statusCallbacks.delete(paymentId);
        }
      } catch (error) {
        console.error(`Error polling payment ${paymentId}:`, error);
      }
    }, 30000);
    
    return pollInterval;
  }

  async getPaymentStatus(paymentId) {
    // Implementation would fetch current payment status
    // This is a placeholder
    return { id: paymentId, state: 'pending' };
  }
}

Multi-Rail Optimization

class PaymentRailOptimizer {
  constructor() {
    this.railCosts = {
      ach_push: { cost: 'low', speed: 'slow', limit: 25000 },
      wire: { cost: 'high', speed: 'fast', limit: 1000000 },
      sepa: { cost: 'low', speed: 'medium', limit: 999999 }
    };
  }

  suggestOptimalRail(amount, priority = 'cost', currency = 'usd') {
    const numericAmount = parseFloat(amount);
    
    // Currency-based filtering
    const availableRails = currency === 'eur' 
      ? ['sepa', 'wire'] 
      : ['ach_push', 'wire'];
    
    // Amount-based filtering
    const viableRails = availableRails.filter(rail => {
      const railInfo = this.railCosts[rail];
      return numericAmount <= railInfo.limit;
    });
    
    if (priority === 'speed' && viableRails.includes('wire')) {
      return {
        rail: 'wire',
        reason: 'Fastest processing for urgent payments'
      };
    }
    
    if (priority === 'cost') {
      if (currency === 'eur' && viableRails.includes('sepa')) {
        return {
          rail: 'sepa',
          reason: 'Lowest cost for EUR payments'
        };
      }
      
      if (currency === 'usd' && numericAmount < 25000 && viableRails.includes('ach_push')) {
        return {
          rail: 'ach_push',
          reason: 'Lowest cost for USD payments under $25K'
        };
      }
    }
    
    return {
      rail: viableRails[0] || 'wire',
      reason: 'Default option based on constraints'
    };
  }

  estimateFees(rail, amount) {
    const fees = {
      ach_push: Math.min(5.0, parseFloat(amount) * 0.005),
      wire: 25.0,
      sepa: Math.min(2.0, parseFloat(amount) * 0.002)
    };

    return {
      rail,
      fee: fees[rail] || 0,
      feePercentage: (fees[rail] / parseFloat(amount)) * 100
    };
  }
}

Support

For additional support or questions about the Create Bank Payment Intent API:
  1. Check our API status page for known issues
  2. Review the error codes and messages in your responses
  3. Contact our support team with your bridge_transfer_id for specific transaction issues
  4. Use our testing environment to validate integrations before going live