How To: Implement ACH Payments

Developers can use this documentation to implement processing payments via ACH.

Implementing ACH Payments

Implementing ACH payments depends largely on if you’re settling on-chain versus off-chain. Merchants who are settling on-chain to a contract may need to pass a transaction to the CoinflowPurchase component or to our ach checkout endpoint. Passing a transaction is not always required but it will allow Coinflow to run a transaction to complete the user’s purchase if there’s on-chain logic to run once the funds have settled.

How It Works

  1. The merchant submits a transaction to Coinflow.
  2. The user initiates an ACH purchase.
  3. Coinflow initiates the ACH transfer and monitors the payment until it is received (typically 3 business days).
  4. Once the transfer is completed, Coinflow executes the on-chain transaction you provided using our USDC payer, fulfilling the purchase on behalf of the user.

How to Implement ACH via UI

The example below shows how to implement ACH using our React SDK. If needed, Coinflow also supports other frameworks and integrations.

  1. Generate a session key for the payer.
    Request
    1curl --request GET \
    2 --url https://api-sandbox.coinflow.cash/api/auth/session-key \
    3 --header 'Authorization: YOUR_API_KEY' \
    4 --header 'accept: application/json' \
    5 --header 'x-coinflow-auth-user-id: user123'
    Response
    1{
    2 "key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21lcklkIjoidXNlcjEyMyIsIm1lcmNoYW50SWQiOiJ0ZXN0dGVzdCIsImlhdCI6MTc0MTgwNTk3MywiZXhwIjoxNzQxODkyMzczfQ.mau9HPQXZQ040-bkQ0tMg57N9IVTbEQZMtV4O9kgkjg"
    3}
  • 🚧 Session keys are valid for 30 minutes and must be refreshed afterwards.

  1. Tokenize the checkout parameters.
    This encrypts the checkout parameters so bad actors cannot tamper with the checkout args.
Request
1curl --request POST \
2 --url https://api-sandbox.coinflow.cash/api/checkout/jwt-token \
3 --header 'Authorization: YOUR_API_KEY' \
4 --header 'accept: application/json' \
5 --header 'content-type: application/json' \
6 --data '
7 {
8 "webhookInfo": {
9 "example": "{\"description\":\"asdF\"}"
10 },
11 "subtotal": {
12 "currency": "USD",
13 "cents": 500
14 },
15 "email": "iamapayer@gmail.com",
16 "blockchain": "solana",
17 "settlementType": "USDC"
18 }
19 '
Response
{
"checkoutJwtToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoi456C4oKW26LXguCjgOKYgueAleiAnN2j5IGM4LGn46CD5oOb4LCF44CQ7Iqy4YCF6KSz4KCI7KaczLDGkOuhgNqE44iA7rWwybDgp6DHgOCumeawgOSQqeSio0LgsJ3njaPmoYXItOa1ku6AjOyFieKmlOiTke67iOWCguWxiOmroOSNuO65suOou-mUremsreWZqOSytueBrOeBpOGgqOSZiOaxrOKhiOiRpOmitOGxiOG7vuuYnOeDmOeBjOChhuCglOuTiOunuOyYlOawmOqXtuujvuSyuuuSnOy7mOqglOSZqOahpOeVrOiwmOShsOKglOaphuGhjOuXjeiRhuaStOSZjFx1ZGQxY-K7k-uQlFx1ZDg2NO-kqOmUq-qHg-6Xqu-pmuySoeGxhuSVhueDquqYiOmHlOShmuGzmOKgnOaikeSuuFx1ZGExOOebvuKisuuguOiSqdOD4LCy4Y6B7IqZ5LO045Cb6qeM4o2D6Iyc7KOR4ZKt4ZyC6I2h6oCy44SMzZPSheyHmeixmOOyhsyE5IWC7oCo5LCO46uJ0rfvg6Dos6jMmOWqguiMi-qSjOu4nOqdkuivsuerpeWljOGmlemCi-6ZmeyFsOuItOCouuKDpeqCoeuAnOiImeGciuyNqeaIiuSxseWkrtek64S4XHVkODRi4YiN6LqnwqDngLjojJrhnIzsrYLpm43rqI3jjKbotoztmJjigYLlkoTihILoloXpi5HtkafijJHolZTogYLosoHnlZvmmonohYDnhbHooLTrjIXcr-mWou2GsOSwsuGchOm6g-qrmOGBmeieoOyfoemhiOWBsOGSqeWohOyzkO6rm-yhmeOQrOaAq-STqeGnpuSxteCoquWSgO6JkuqwnuGBmtys6Yax4rGQ5JS46rSH6ICF74iAIiwibWVyY2hhbnRJZCI6InRlc3R0ZXN0IiwiaWRlbXBvdGVuY3lLZXkiOiJJSzVlZWE3YzI3LWEyMjgtNDcyMC1iYTVkLWI1ZDA0ZDUzMzA3MCIsInN1YnRvdGFsIjp7ImN1cnJlbmN5IjoiVVNEIiwiY2VudHMiOjUwMH0sImlhdCI6MTc0Mjg1NTY3OCwiZXhwIjoxNzQyOTQyMDc4fQ.2dGfWnazfyHaz_uEWKM9RU-jh-tXUSMPFZJdNvmMPwo"
}
  1. Implement the Coinflow Checkout Component.
1<CoinflowPurchase
2 sessionKey={'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21lcklkIjoidXNlcjEyMyIsIm1lcmNoYW50SWQiOiJ0ZXN0dGVzdCIsImlhdCI6MTc0MTgwNTk3MywiZXhwIjoxNzQxODkyMzczfQ.mau9HPQXZQ040-bkQ0tMg57N9IVTbEQZMtV4O9kgkjg'}
3 merchantId={'testtest'} // Replace with your merchantId
4 env={'sandbox'}
5 onSuccess={(...args) => {
6 console.log('Purchase Success', args); // Redirect the user
7 }}
8 settlementType={SettlementType.USDC}
9 subtotal={{cents: 300, currency: Currency.USD}} // Amount purchase is in (exclude prop if user is to choose a custom amount)
10 email={'user@email.com'} // User's email address
11 jwtToken = {'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoi456C4oKW26LXguCjgOKYgueAleiAnN2j5IGM4LGn46CD5oOb4LCF44CQ7Iqy4YCF6KSz4KCI7KaczLDGkOuhgNqE44iA7rWwybDgp6DHgOCumeawgOSQqeSio0LgsJ3njaPmoYXItOa1ku6AjOyFieKmlOiTke67iOWCguWxiOmroOSNuO65suOou-mUremsreWZqOSytueBrOeBpOGgqOSZiOaxrOKhiOiRpOmitOGxiOG7vuuYnOeDmOeBjOChhuCglOuTiOunuOyYlOawmOqXtuujvuSyuuuSnOy7mOqglOSZqOahpOeVrOiwmOShsOKglOaphuGhjOuXjeiRhuaStOSZjFx1ZGQxY-K7k-uQlFx1ZDg2NO-kqOmUq-qHg-6Xqu-pmuySoeGxhuSVhueDquqYiOmHlOShmuGzmOKgnOaikeSuuFx1ZGExOOebvuKisuuguOiSqdOD4LCy4Y6B7IqZ5LO045Cb6qeM4o2D6Iyc7KOR4ZKt4ZyC6I2h6oCy44SMzZPSheyHmeixmOOyhsyE5IWC7oCo5LCO46uJ0rfvg6Dos6jMmOWqguiMi-qSjOu4nOqdkuivsuerpeWljOGmlemCi-6ZmeyFsOuItOCouuKDpeqCoeuAnOiImeGciuyNqeaIiuSxseWkrtek64S4XHVkODRi4YiN6LqnwqDngLjojJrhnIzsrYLpm43rqI3jjKbotoztmJjigYLlkoTihILoloXpi5HtkafijJHolZTogYLosoHnlZvmmonohYDnhbHooLTrjIXcr-mWou2GsOSwsuGchOm6g-qrmOGBmeieoOyfoemhiOWBsOGSqeWohOyzkO6rm-yhmeOQrOaAq-STqeGnpuSxteCoquWSgO6JkuqwnuGBmtys6Yax4rGQ5JS46rSH6ICF74iAIiwibWVyY2hhbnRJZCI6InRlc3R0ZXN0IiwiaWRlbXBvdGVuY3lLZXkiOiJJSzVlZWE3YzI3LWEyMjgtNDcyMC1iYTVkLWI1ZDA0ZDUzMzA3MCIsInN1YnRvdGFsIjp7ImN1cnJlbmN5IjoiVVNEIiwiY2VudHMiOjUwMH0sImlhdCI6MTc0Mjg1NTY3OCwiZXhwIjoxNzQyOTQyMDc4fQ.2dGfWnazfyHaz_uEWKM9RU-jh-tXUSMPFZJdNvmMPwo'}
12 />

🚧 Merchants who are settling on-chain may need to make adjustments to the transaction prop passed to Coinflow. Jump to section: β€œOn-Chain ACH Transactions” for more details.

How to Implement ACH via API

  1. Tokenize the payment data
    Request
    1curl --request POST \
    2 --url https://api-sandbox.coinflow.cash/api/checkout/jwt-token \
    3 --header 'Authorization: YOUR_API_KEY' \
    4 --header 'accept: application/json' \
    5 --header 'content-type: application/json' \
    6 --data '
    7{
    8 "subtotal": {
    9 "currency": "USD",
    10 "cents": 500
    11 },
    12 "email": "payer@gmail.com",
    13 "blockchain": "solana", // Change according to the chain youre on. Merchants settling to Coinflow wallet do not need to pass blockchain
    14 "settlementType": "USDC"
    15}
    16'
    Response
    1{
    2 "checkoutJwtToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoi456C4oKW26LXgsuA2IHpoI3og4bEsOKGgseA5piB5Lew7ICj5IiQ4Y6A5ZiB4aKT5ZK144CJ6Z2n4KuO4YCB6oSQ6IG25qCB46CE74CA7oCF7YKGXCLlpKXmhoLhiq7gs5jlgrLshY7hsYLrlJvln4XpqprjoajhipDgu4nkrrLki5brhKDkiprqpazolIruk6XmlpLmsKzioYjkoqTvoYjRsOmQiOKylOWZluGjrOKghOuguOSjlOKEmOShsOGhhua4mOGZmOqQiOCjuOqoruWilOqToeaZluiRluqTlO2RmOKxtOGitOuTmO-RiOmzruC1qem5mO-grOGRpOeApOChqFx1ZGU5NOmSme-FquyEoMK-5ICAIiwibWVyY2hhbnRJZCI6Im1lbGxvIiwiaWRlbXBvdGVuY3lLZXkiOiJJS2ZjODY5ZmY4LTk1MTgtNDA0ZS1hYTI5LWEzNzk3ZjZiZjcwOSIsInN1YnRvdGFsIjp7ImN1cnJlbmN5IjoiVVNEIiwiY2VudHMiOjUwMH0sImlhdCI6MTc1MjY4NzY3NiwiZXhwIjoxNzUyNjg5NDc2fQ.Jv7VLntabr8id94FXgseErN_wpzsjDRmEFMmWdVqwes"
    3}
  2. Get the total purchase amount including all fees.
    Request
    1curl --request POST \
    2 --url https://api-sandbox.coinflow.cash/api/checkout/totals/mello \
    3 --header 'accept: application/json' \
    4 --header 'content-type: application/json' \
    5 --header 'x-coinflow-auth-session-key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21lcklkIjoidXNlcjEyMyIsIm1lcmNoYW50SWQiOiJtZWxsbyIsImlhdCI6MTc1MjY4NzQ5NCwiZXhwIjoxNzUyNzczODk0fQ.4_azA_nfReFeCaRE4K3PCqtBqYqSKEBqKL-Qw-8E4d4' \
    6 --data '
    7{
    8 "subtotal": {
    9 "currency": "USD",
    10 "cents": 500
    11 },
    12 "jwtToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoi456C4oKW26LXgsuA2IHpoI3og4bEsOKGgseA5piB5Lew7ICj5IiQ4Y6A5ZiB4aKT5ZK144CJ6Z2n4KuO4YCB6oSQ6IG25qCB46CE74CA7oCF7YKGXCLlpKXmhoLhiq7gs5jlgrLshY7hsYLrlJvln4XpqprjoajhipDgu4nkrrLki5brhKDkiprqpazolIruk6XmlpLmsKzioYjkoqTvoYjRsOmQiOKylOWZluGjrOKghOuguOSjlOKEmOShsOGhhua4mOGZmOqQiOCjuOqoruWilOqToeaZluiRluqTlO2RmOKxtOGitOuTmO-RiOmzruC1qem5mO-grOGRpOeApOChqFx1ZGU5NOmSme-FquyEoMK-5ICAIiwibWVyY2hhbnRJZCI6Im1lbGxvIiwiaWRlbXBvdGVuY3lLZXkiOiJJS2ZjODY5ZmY4LTk1MTgtNDA0ZS1hYTI5LWEzNzk3ZjZiZjcwOSIsInN1YnRvdGFsIjp7ImN1cnJlbmN5IjoiVVNEIiwiY2VudHMiOjUwMH0sImlhdCI6MTc1MjY4NzY3NiwiZXhwIjoxNzUyNjg5NDc2fQ.Jv7VLntabr8id94FXgseErN_wpzsjDRmEFMmWdVqwes" // JWT Token from step 1
    13}
    14'
    Response
    {
    "card": {
    "subtotal": {
    "currency": "USD",
    "cents": 500
    },
    "creditCardFees": {
    "cents": 0,
    "currency": "USD"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "gasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "total": {
    "cents": 500,
    "currency": "USD"
    },
    "merchantPaidCreditCardFees": {
    "cents": 25,
    "currency": "USD"
    },
    "merchantPaidGasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "merchantPaidChargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "settlement": {
    "subtotal": {
    "currency": "USD",
    "cents": 500
    },
    "creditCardFees": {
    "cents": 0,
    "currency": "USD"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "gasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "total": {
    "cents": 500,
    "currency": "USD"
    },
    "merchantPaidCreditCardFees": {
    "cents": 25,
    "currency": "USD"
    },
    "merchantPaidGasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "merchantPaidChargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    }
    },
    "exchangeRate": 1,
    "basis": {
    "currency": "USD",
    "cents": 500
    }
    },
    "ach": {
    "subtotal": {
    "currency": "USD",
    "cents": 500
    },
    "creditCardFees": {
    "cents": 100,
    "currency": "USD"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "gasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "total": {
    "cents": 600,
    "currency": "USD"
    },
    "merchantPaidGasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "settlement": {
    "subtotal": {
    "currency": "USD",
    "cents": 500
    },
    "creditCardFees": {
    "cents": 100,
    "currency": "USD"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "gasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "total": {
    "cents": 600,
    "currency": "USD"
    },
    "merchantPaidGasFees": {
    "cents": 0,
    "currency": "USD"
    }
    },
    "exchangeRate": 1,
    "basis": {
    "currency": "USD",
    "cents": 500
    }
    },
    "fasterPayments": {
    "subtotal": {
    "cents": 373,
    "currency": "GBP"
    },
    "creditCardFees": {
    "cents": 200,
    "currency": "GBP"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "GBP"
    },
    "gasFees": {
    "cents": 0,
    "currency": "GBP"
    },
    "total": {
    "cents": 573,
    "currency": "GBP"
    },
    "merchantPaidGasFees": {
    "cents": 0,
    "currency": "GBP"
    },
    "settlement": {
    "subtotal": {
    "cents": 500,
    "currency": "USD"
    },
    "creditCardFees": {
    "cents": 269,
    "currency": "USD"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "gasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "total": {
    "cents": 769,
    "currency": "USD"
    },
    "merchantPaidGasFees": {
    "cents": 0,
    "currency": "USD"
    }
    },
    "exchangeRate": 0.744658,
    "basis": {
    "currency": "USD",
    "cents": 500
    }
    },
    "sepa": {
    "subtotal": {
    "cents": 430,
    "currency": "EUR"
    },
    "creditCardFees": {
    "cents": 200,
    "currency": "EUR"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "EUR"
    },
    "gasFees": {
    "cents": 0,
    "currency": "EUR"
    },
    "total": {
    "cents": 630,
    "currency": "EUR"
    },
    "merchantPaidGasFees": {
    "cents": 0,
    "currency": "EUR"
    },
    "settlement": {
    "subtotal": {
    "cents": 500,
    "currency": "USD"
    },
    "creditCardFees": {
    "cents": 233,
    "currency": "USD"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "gasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "total": {
    "cents": 733,
    "currency": "USD"
    },
    "merchantPaidGasFees": {
    "cents": 0,
    "currency": "USD"
    }
    },
    "exchangeRate": 0.858423,
    "basis": {
    "currency": "USD",
    "cents": 500
    }
    },
    "pix": {
    "subtotal": {
    "cents": 2775,
    "currency": "BRL"
    },
    "creditCardFees": {
    "cents": 31,
    "currency": "BRL"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "BRL"
    },
    "gasFees": {
    "cents": 0,
    "currency": "BRL"
    },
    "total": {
    "cents": 2806,
    "currency": "BRL"
    },
    "settlement": {
    "subtotal": {
    "cents": 500,
    "currency": "USD"
    },
    "creditCardFees": {
    "cents": 6,
    "currency": "USD"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "gasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "total": {
    "cents": 506,
    "currency": "USD"
    }
    },
    "exchangeRate": 5.5487,
    "basis": {
    "currency": "USD",
    "cents": 500
    }
    },
    "usdc": {
    "subtotal": {
    "currency": "USD",
    "cents": 500
    },
    "creditCardFees": {
    "cents": 0,
    "currency": "USD"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "gasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "total": {
    "cents": 500,
    "currency": "USD"
    },
    "merchantPaidGasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "settlement": {
    "subtotal": {
    "currency": "USD",
    "cents": 500
    },
    "creditCardFees": {
    "cents": 0,
    "currency": "USD"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "gasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "total": {
    "cents": 500,
    "currency": "USD"
    },
    "merchantPaidGasFees": {
    "cents": 0,
    "currency": "USD"
    }
    },
    "exchangeRate": 1,
    "basis": {
    "currency": "USD",
    "cents": 500
    }
    },
    "googlePay": {
    "subtotal": {
    "currency": "USD",
    "cents": 500
    },
    "creditCardFees": {
    "cents": 0,
    "currency": "USD"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "gasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "total": {
    "cents": 500,
    "currency": "USD"
    },
    "merchantPaidCreditCardFees": {
    "cents": 25,
    "currency": "USD"
    },
    "merchantPaidGasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "merchantPaidChargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "settlement": {
    "subtotal": {
    "currency": "USD",
    "cents": 500
    },
    "creditCardFees": {
    "cents": 0,
    "currency": "USD"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "gasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "total": {
    "cents": 500,
    "currency": "USD"
    },
    "merchantPaidCreditCardFees": {
    "cents": 25,
    "currency": "USD"
    },
    "merchantPaidGasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "merchantPaidChargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    }
    },
    "exchangeRate": 1,
    "basis": {
    "currency": "USD",
    "cents": 500
    }
    },
    "applePay": {
    "subtotal": {
    "currency": "USD",
    "cents": 500
    },
    "creditCardFees": {
    "cents": 0,
    "currency": "USD"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "gasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "total": {
    "cents": 500,
    "currency": "USD"
    },
    "merchantPaidCreditCardFees": {
    "cents": 25,
    "currency": "USD"
    },
    "merchantPaidGasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "merchantPaidChargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "settlement": {
    "subtotal": {
    "currency": "USD",
    "cents": 500
    },
    "creditCardFees": {
    "cents": 0,
    "currency": "USD"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "gasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "total": {
    "cents": 500,
    "currency": "USD"
    },
    "merchantPaidCreditCardFees": {
    "cents": 25,
    "currency": "USD"
    },
    "merchantPaidGasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "merchantPaidChargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    }
    },
    "exchangeRate": 1,
    "basis": {
    "currency": "USD",
    "cents": 500
    }
    },
    "credits": {
    "subtotal": {
    "currency": "USD",
    "cents": 500
    },
    "creditCardFees": {
    "cents": 0,
    "currency": "USD"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "gasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "total": {
    "cents": 500,
    "currency": "USD"
    },
    "merchantPaidGasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "settlement": {
    "subtotal": {
    "currency": "USD",
    "cents": 500
    },
    "creditCardFees": {
    "cents": 0,
    "currency": "USD"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "gasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "total": {
    "cents": 500,
    "currency": "USD"
    },
    "merchantPaidGasFees": {
    "cents": 0,
    "currency": "USD"
    }
    },
    "exchangeRate": 1,
    "basis": {
    "currency": "USD",
    "cents": 500
    }
    },
    "crypto": {
    "subtotal": {
    "currency": "USD",
    "cents": 500
    },
    "creditCardFees": {
    "cents": 0,
    "currency": "USD"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "gasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "total": {
    "cents": 500,
    "currency": "USD"
    },
    "merchantPaidGasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "settlement": {
    "subtotal": {
    "currency": "USD",
    "cents": 500
    },
    "creditCardFees": {
    "cents": 0,
    "currency": "USD"
    },
    "chargebackProtectionFees": {
    "cents": 0,
    "currency": "USD"
    },
    "gasFees": {
    "cents": 0,
    "currency": "USD"
    },
    "total": {
    "cents": 500,
    "currency": "USD"
    },
    "merchantPaidGasFees": {
    "cents": 0,
    "currency": "USD"
    }
    },
    "exchangeRate": 1,
    "basis": {
    "currency": "USD",
    "cents": 500
    }
    }
    }
  3. Enable a customer to add a bank account.
    curl --request POST \
    --url https://api-sandbox.coinflow.cash/api/customer/v2/bankAccount \
    --header 'Authorization: YOUR_API_KEY' \
    --header 'content-type: application/json' \
    --header 'x-coinflow-auth-user-id: user123' \
    --data '
    {
    "type": "checking",
    "email": "payer@gmail.com",
    "alias": "My Checking Account",
    "routingNumber": "0123456789",
    "account_number": "09876554321",
    "firstName": "Dwayne",
    "lastName": "Johnson",
    "address1": "201 E Randolph St",
    "city": "Chicago",
    "state": "IL",
    "zip": "60601"
    }
    '
  4. Get the customer’s tokenized bank account.
    Request
    1curl --request GET \
    2 --url https://api-sandbox.coinflow.cash/api/customer/v2 \
    3 --header 'accept: application/json' \
    4 --header 'x-coinflow-auth-session-key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21lcklkIjoidXNlcjEyMyIsIm1lcmNoYW50SWQiOiJtZWxsbyIsImlhdCI6MTc1MjY4NzQ5NCwiZXhwIjoxNzUyNzczODk0fQ.4_azA_nfReFeCaRE4K3PCqtBqYqSKEBqKL-Qw-8E4d4'
    Response
    {
    "customer": {
    "_id": "684c5779677bd46e4455f085",
    "customerId": "user123",
    "blockchain": "user",
    "email": "payer@gmail.com",
    "availability": {
    "status": "Functional",
    "reason": "Initial",
    "editor": "system",
    "updatedAt": "2025-06-13T16:53:13.194Z"
    },
    "chargebackProtectionEnabled": true,
    "merchant": "6840bca9c7cb21ee5baaae76",
    "failedAttemptSetting": "Standard",
    "verificationSetting": "Enforced",
    "exempt3DS": false,
    "createdAt": "2025-06-13T16:53:13.196Z",
    "__v": 0,
    "bankAccounts": [
    {
    "alias": "My Checking Account",
    "token": "27ed7e14-076e-4c7f-8e65-fa321acce2b9",
    "routingNumber": "0123456789",
    "last4": "4321",
    "accountHash": "843d87649f2396062dd192243b367c30bd38e23a",
    "rtpEligible": true,
    "reference": "684c5779677bd46e4455f096"
    }
    ],
    "cards": [],
    "sepas": [],
    "fasterPayments": []
    }
    }
  5. Send an ACH Checkout
    Request
    1curl --request POST \
    2 --url https://api-sandbox.coinflow.cash/api/checkout/ach/mello \
    3 --header 'accept: application/json' \
    4 --header 'content-type: application/json' \
    5 --header 'x-coinflow-auth-session-key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21lcklkIjoidXNlcjEyMyIsIm1lcmNoYW50SWQiOiJtZWxsbyIsImlhdCI6MTc1MjY4NzQ5NCwiZXhwIjoxNzUyNzczODk0fQ.4_azA_nfReFeCaRE4K3PCqtBqYqSKEBqKL-Qw-8E4d4' \
    6 --data '
    7{
    8 "subtotal": {
    9 "cents": 500
    10 },
    11 "jwtToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoi456C4oKW26LXgsuA2IHpoI3og4bEsOKGgseA5piB5Lew7ICj5IiQ4Y6A5ZiB4aKT5ZK144CJ6Z2n4KuO4YCB6oSQ6IG25qCB46CE74CA7oCF7YKGXCLlpKXmhoLhiq7gs5jlgrLshY7hsYLrlJvln4XpqprjoajhipDgu4nkrrLki5brhKDkiprqpazolIruk6XmlpLmsKzioYjkoqTvoYjRsOmQiOKylOWZluGjrOKghOuguOSjlOKEmOShsOGhhua4mOGZmOqQiOCjuOqoruWilOqToeaZluiRluqTlO2RmOKxtOGitOuTmO-RiOmzruC1qem5mO-grOGRpOeApOChqFx1ZGU5NOmSme-FquyEoMK-5ICAIiwibWVyY2hhbnRJZCI6Im1lbGxvIiwiaWRlbXBvdGVuY3lLZXkiOiJJS2ZjODY5ZmY4LTk1MTgtNDA0ZS1hYTI5LWEzNzk3ZjZiZjcwOSIsInN1YnRvdGFsIjp7ImN1cnJlbmN5IjoiVVNEIiwiY2VudHMiOjUwMH0sImlhdCI6MTc1MjY4NzY3NiwiZXhwIjoxNzUyNjg5NDc2fQ.Jv7VLntabr8id94FXgseErN_wpzsjDRmEFMmWdVqwes", // JWT from calling Get checkout JWT Token
    12 "token": "27ed7e14-076e-4c7f-8e65-fa321acce2b9" // Tokenized bank account from calling Get Customer
    13}
    14'
    Response
    {
    "paymentId": "138fd1c7-60da-415b-a993-b13dbb92fe52"
    }

On-Chain ACH Transactions

When Do ACH Payments Settle for On-Chain Transactions?

To prevent fraud, Coinflow does not finalize credits, USDC, or bank transfers until the ACH payment has fully settled. Due to the delayed settlement of ACH payments, merchants using on-chain settlements must configure their smart contracts to handle separate wallets for initiating and receiving payments. This setup allows Coinflow to finalize the transaction on-chain after the ACH payment has settled.

Transactions on Solana

Solana transactions specify all accounts that are read from or written to during the transaction. For on-chain settlements, replace the user’s wallet (or the wallet making the USDC payment) in your transaction instructions with the placeholder key 22222222222222222222222222222222222222222222. Similarly, replace the USDC payer’s token account with the placeholder key 33333333333333333333333333333333333333333333.

For example, if your standard transaction instruction looks like this:

1const transferIx = createTransferInstruction(
2 getTokenAddressSync(usersWallet, USDC_MINT), // spender token account
3 destinationTokenAccount, // destination token account
4 usersWallet, // Owner of spender token account
5 1 // amount
6);

Modify it as follows for on-chain ACH settlement:

1const transferIx = createTransferInstruction(
2 new PublicKey('33333333333333333333333333333333333333333333'), // spender token account
3 destinationTokenAccount, // destination token account
4 new PublicKey('22222222222222222222222222222222222222222222'), // Owner of spender token account
5 1 // amount
6);

Coinflow will dynamically replace these placeholders with the appropriate signer and the signer’s token account, enabling the secure payment of USDC on behalf of the user.

πŸ“˜ If you support both card and ACH payments, add the placeholders, and when you call redeem transaction, Coinflow will automatically replace the placeholders with the users wallet and their token account.

Transactions on EVM

Evm transactions inherently includes a have a msg.sender and a from field. Our system will automatically set that to our payer.