For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
RegisterLoginSandbox Login
GuidesRecipesAPI Reference
GuidesRecipesAPI Reference
  • Getting Started
    • Getting Started with Checkout
    • ACH Checkout
    • Card Checkout with Credits
    • Card Checkout
    • Direct USDC Settlement
    • Fiat/Crypto Pay-ins
    • Secure Marketplace Checkout
    • EVM Checkout
    • How to Enable Checkout with Credit Cards
    • Quick Start Marketplace Implementation
    • Payouts
    • Common FAQs
  • Checkout
    • Settlement Locations
      • Account Funding Transactions (AFT)
      • Authorize & Capture
      • Complete Purchases with USDC & Credits
      • Custom Pay-in Fees
    • Checkout Webhooks
  • Payouts
    • Payout Overview
    • What is a Payout
  • Subscriptions
    • Subscriptions Overview
  • Marketplaces
    • Marketplace Overview
    • How Marketplaces Work
    • How to Withdraw USDC
    • Countries Eligible for USDC Withdraw
    • Marketplaces Webhooks
    • Marketplaces Implementation
  • Developer Resources
    • Custom Branding
    • Checkout Implementation
    • Webhooks
  • Merchant Dashboard
    • Login & Account Access
    • Users and Roles
    • Rate Limits
    • Developer Contact
LogoLogo
RegisterLoginSandbox Login
CheckoutPayment Scenarios

How To: Implement Purchases with USDC and Credits

Payers can use existing USDC and Credits in their EVM wallets to complete purchases.
Was this page helpful?
Previous

Custom Pay-in Fees

Add custom fee line items to purchase checkouts that appear as separate charges to customers.
Next
Built with

This guide shows how merchants can let payers use existing USDC and credits in their EVM wallets to complete a purchase. To allow credit purchases before redemption,see this guide. For USDC purchases, payers must use an exchange.

  1. Get USDC Authorization Message
    Get an authorization message that must be signed by the payer’s EVM wallet. This authorizes spending the defined amount of USDC in the payer’s wallet.

    Request
    1curl --request POST \
    2 --url https://api-sandbox.coinflow.cash/api/checkout/evm/usdc-authorization \
    3 --header 'accept: application/json' \
    4 --header 'content-type: application/json' \
    5 --header 'x-coinflow-auth-blockchain: polygon' \
    6 --header 'x-coinflow-auth-wallet: 0xd11cc1D037B49098130BDeB592d468E3fe131240' \
    7 --data '
    8{
    9 "amount": {
    10 "cents": 200
    11 }
    12}
    13'
    Response
    1{
    2 "message": "{\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"TransferWithAuthorization\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\"},{\"name\":\"validAfter\",\"type\":\"uint256\"},{\"name\":\"validBefore\",\"type\":\"uint256\"},{\"name\":\"nonce\",\"type\":\"bytes32\"}]},\"domain\":{\"name\":\"USDC\",\"version\":\"2\",\"chainId\":80002,\"verifyingContract\":\"0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582\"},\"primaryType\":\"TransferWithAuthorization\",\"message\":{\"from\":\"0xd11cc1D037B49098130BDeB592d468E3fe131240\",\"to\":\"0xfcc779B1bc3b6C05406244107bAe04B858E7ED38\",\"value\":\"2000000\",\"validAfter\":\"0\",\"validBefore\":\"1754349007\",\"nonce\":\"0x23dfed622fcdea1a16019dea5d2e303905b79a290bb7ecdfb17dd40c76757bda\"}}",
    3 "messageData": {
    4 "from": "0xd11cc1D037B49098130BDeB592d468E3fe131240",
    5 "to": "0xfcc779B1bc3b6C05406244107bAe04B858E7ED38",
    6 "value": "2000000",
    7 "validAfter": "0",
    8 "validBefore": "1754349007",
    9 "nonce": "0x23dfed622fcdea1a16019dea5d2e303905b79a290bb7ecdfb17dd40c76757bda"
    10 }
    11}
  2. Sign the USDC Auth Message
    This signs the message that authorizes spending usdc from the payer’s wallet.

    1const { ethers } = require("ethers");
    2
    3const POLYGON_TESTNET_RPC = "https://rpc-amoy.polygon.technology";
    4const provider = new ethers.providers.JsonRpcProvider(POLYGON_TESTNET_RPC);
    5
    6const privateKey = '123456789abcdefg'; // Replace with signers wallet private key
    7const wallet = new ethers.Wallet(privateKey, provider);
    8const message = {
    9 "types": {
    10 "EIP712Domain": [
    11 { "name": "name", "type": "string" },
    12 { "name": "version", "type": "string" },
    13 { "name": "chainId", "type": "uint256" },
    14 { "name": "verifyingContract", "type": "address" }
    15 ],
    16 "TransferWithAuthorization": [
    17 { "name": "from", "type": "address" },
    18 { "name": "to", "type": "address" },
    19 { "name": "value", "type": "uint256" },
    20 { "name": "validAfter", "type": "uint256" },
    21 { "name": "validBefore", "type": "uint256" },
    22 { "name": "nonce", "type": "bytes32" }
    23 ]
    24 },
    25 "domain": {
    26 "name": "USDC",
    27 "version": "2",
    28 "chainId": 80002,
    29 "verifyingContract": "0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582"
    30 },
    31 "primaryType": "TransferWithAuthorization",
    32 "message": {
    33 "from": "0xd11cc1D037B49098130BDeB592d468E3fe131240",
    34 "to": "0xfcc779B1bc3b6C05406244107bAe04B858E7ED38",
    35 "value": "2000000",
    36 "validAfter": "0",
    37 "validBefore": "1754349007",
    38 "nonce": "0x23dfed622fcdea1a16019dea5d2e303905b79a290bb7ecdfb17dd40c76757bda"
    39 }
    40}
    41
    42;
    43
    44async function signMessage(privateKey, message) {
    45 const domain = message.domain;
    46 const types = { CreditsAuthorization: message.types.CreditsAuthorization };
    47 const messageData = message.message;
    48
    49 // Sign the typed data (EIP-712)
    50 const signedMessage = await wallet._signTypedData(domain, types, messageData);
    51
    52 // Split signature into v, r, s
    53 const { v, r, s } = ethers.utils.splitSignature(signedMessage);
    54
    55 return {
    56 signedMessage,
    57 v,
    58 r,
    59 s
    60 };
    61}
    62
    63signMessage(privateKey, message)
    64 .then(({ signedMessage, v, r, s }) => {
    65 console.log('Signed Message:', signedMessage);
    66 console.log('v:', v);
    67 console.log('r:', r);
    68 console.log('s:', s);
    69 })
    70 .catch((error) => {
    71 console.error('Error signing message:', error);
    72 });
  3. Get Credits Authorization Message
    Get an authorization message that must be signed by the payer’s EVM wallet. This authorizes spending the defined amount of credits in the payer’s wallet.

    Request
    1curl --request POST \
    2 --url https://api-sandbox.coinflow.cash/api/redeem/evm/creditsAuthMsg \
    3 --header 'accept: application/json' \
    4 --header 'content-type: application/json' \
    5 --header 'x-coinflow-auth-blockchain: polygon' \
    6 --header 'x-coinflow-auth-wallet: 0xd11cc1D037B49098130BDeB592d468E3fe131240' \
    7 --data '
    8{
    9 "subtotal": {
    10 "currency": "USD",
    11 "cents": 300
    12 },
    13 "transactionData": {
    14 "type": "token",
    15 "destination": "0x70bd2A7a9eedE3aCb62cF839cEa1008b72FF7844"
    16 }, // Replace with any transaction data that suites your use case. This assumes we are settling direct to a merchants EVM wallet
    17 "merchantId": "mello",
    18 "usdcAmount": {
    19 "cents": 200
    20 }
    21}
    22'
    Response
    1{
    2 "message": "{\"domain\":{\"name\":\"Coinflow Credits Contract\",\"version\":\"1\",\"chainId\":80002,\"verifyingContract\":\"0xfcc779B1bc3b6C05406244107bAe04B858E7ED38\"},\"message\":{\"customerWallet\":\"0xd11cc1D037B49098130BDeB592d468E3fe131240\",\"creditSeed\":\"mello\",\"amount\":3000000,\"validBefore\":\"1754432077\",\"nonce\":\"0x2c8f63dfc74e880d4581563efd45f6216a26457dde384d6060bb75a05a1d7684\"},\"primaryType\":\"CreditsAuthorization\",\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"CreditsAuthorization\":[{\"name\":\"customerWallet\",\"type\":\"address\"},{\"name\":\"creditSeed\",\"type\":\"string\"},{\"name\":\"amount\",\"type\":\"uint256\"},{\"name\":\"validBefore\",\"type\":\"uint256\"},{\"name\":\"nonce\",\"type\":\"bytes32\"}]}}",
    3 "validBefore": "1754432077",
    4 "nonce": "0x2c8f63dfc74e880d4581563efd45f6216a26457dde384d6060bb75a05a1d7684",
    5 "creditsRawAmount": 3000000
    6}
  4. Sign Credits Authorization Message
    This signs the message that authorizes spending credits from the payer’s wallet.

    Text
    1const { ethers } = require("ethers");
    2
    3// Create RPC connection
    4const POLYGON_TESTNET_RPC = "https://rpc-amoy.polygon.technology";
    5const provider = new ethers.providers.JsonRpcProvider(POLYGON_TESTNET_RPC);
    6
    7const privateKey = '123456789abcdefg'; // Replace with payer's wallet private key
    8const wallet = new ethers.Wallet(privateKey, provider);
    9const message = {
    10 "domain": {
    11 "name": "Coinflow Credits Contract",
    12 "version": "1",
    13 "chainId": 80002,
    14 "verifyingContract": "0xfcc779B1bc3b6C05406244107bAe04B858E7ED38"
    15 },
    16 "message": {
    17 "customerWallet": "0xd11cc1D037B49098130BDeB592d468E3fe131240",
    18 "creditSeed": "mello",
    19 "amount": 3000000,
    20 "validBefore": "1754432077",
    21 "nonce": "0x2c8f63dfc74e880d4581563efd45f6216a26457dde384d6060bb75a05a1d7684"
    22 },
    23 "primaryType": "CreditsAuthorization",
    24 "types": {
    25 "EIP712Domain": [
    26 {
    27 "name": "name",
    28 "type": "string"
    29 },
    30 {
    31 "name": "version",
    32 "type": "string"
    33 },
    34 {
    35 "name": "chainId",
    36 "type": "uint256"
    37 },
    38 {
    39 "name": "verifyingContract",
    40 "type": "address"
    41 }
    42 ],
    43 "CreditsAuthorization": [
    44 {
    45 "name": "customerWallet",
    46 "type": "address"
    47 },
    48 {
    49 "name": "creditSeed",
    50 "type": "string"
    51 },
    52 {
    53 "name": "amount",
    54 "type": "uint256"
    55 },
    56 {
    57 "name": "validBefore",
    58 "type": "uint256"
    59 },
    60 {
    61 "name": "nonce",
    62 "type": "bytes32"
    63 }
    64 ]
    65 }
    66}
    67;
    68
    69async function signMessage(privateKey, message) {
    70 const domain = message.domain;
    71 const types = { CreditsAuthorization: message.types.CreditsAuthorization };
    72 const messageData = message.message;
    73
    74 // Sign the typed data (EIP-712)
    75 const signedMessage = await wallet._signTypedData(domain, types, messageData);
    76 return signedMessage;
    77}
    78
    79signMessage(privateKey, message)
    80 .then((signedMessage) => {
    81 console.log('Signed Message:', signedMessage);
    82 })
    83 .catch((error) => {
    84 console.error('Error signing message:', error);
    85 });
  5. Send redeem transaction
    By calling our redeem endpoint, you are creating a transacting and passing the signed credits authorization message and signed usdc authorization message. Upon sending to the blockchain, the payer’s credit balance and usdc balance in their wallet will decrement.

    Request
    1curl --request POST \
    2 --url https://api-sandbox.coinflow.cash/api/redeem/evm/sendGaslessTx \
    3 --header 'accept: application/json' \
    4 --header 'content-type: application/json' \
    5 --header 'x-coinflow-auth-blockchain: polygon' \
    6 --header 'x-coinflow-auth-wallet: 0xd11cc1D037B49098130BDeB592d468E3fe131240' \
    7 --data '
    8{
    9 "subtotal": {
    10 "currency": "USD",
    11 "cents": 300
    12 },
    13 "transactionData": {
    14 "type": "token",
    15 "destination": "0x70bd2A7a9eedE3aCb62cF839cEa1008b72FF7844"
    16 },
    17 "signedMessages": {
    18 "customerUsdcAuthData": {
    19 "s": "0x4f2d037027479a7c728bab0bcc6fc08d8cd27cde3a73dd7be2384be411ecd3b8",
    20 "r": "0x709795a8260afdd500c392203b9e9fb48071e69c49d7e8350c552af6519b59c0",
    21 "v": 27,
    22 "nonce": "0x23dfed622fcdea1a16019dea5d2e303905b79a290bb7ecdfb17dd40c76757bda",
    23 "validBefore": "1754349007",
    24 "validAfter": "0",
    25 "value": "2000000",
    26 "to": "0xfcc779B1bc3b6C05406244107bAe04B858E7ED38",
    27 "from": "0xd11cc1D037B49098130BDeB592d468E3fe131240"
    28 },
    29 "permitCredits": "0x5aecc8c89be221d0e1e0266252a49d6cca597ceabf52def39866e67858eaf3a50256deed3815265acf4ba410a60950a683269562e7e5f4b46f8183cfd466008d1b"
    30 },
    31 "usdcAmount": {
    32 "cents": 200
    33 },
    34 "validBefore": "1754432077",
    35 "nonce": "0x2c8f63dfc74e880d4581563efd45f6216a26457dde384d6060bb75a05a1d7684",
    36 "creditsRawAmount": 3000000,
    37 "merchantId": "mello"
    38}
    39'
    Response
    1{
    2 "hash": "0x1d6ba92970cf0285c40f167e7f5c030a7a8177e046caf270ca455ba9d040e734"
    3}
  6. Optional Implementation:Get Balances
    This endpoint will allow you to get the balance of credits/usdc in the payer’s wallet.