How To: Implement Purchases with USDC and Credits
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.
-
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.Request1 curl --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 ' Response1 { 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 } -
Sign the USDC Auth Message
This signs the message that authorizes spending usdc from the payer’s wallet.1 const { ethers } = require("ethers"); 2 3 const POLYGON_TESTNET_RPC = "https://rpc-amoy.polygon.technology"; 4 const provider = new ethers.providers.JsonRpcProvider(POLYGON_TESTNET_RPC); 5 6 const privateKey = '123456789abcdefg'; // Replace with signers wallet private key 7 const wallet = new ethers.Wallet(privateKey, provider); 8 const 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 44 async 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 63 signMessage(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 }); -
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.Request1 curl --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 ' Response1 { 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 } -
Sign Credits Authorization Message
This signs the message that authorizes spending credits from the payer’s wallet.Text1 const { ethers } = require("ethers"); 2 3 // Create RPC connection 4 const POLYGON_TESTNET_RPC = "https://rpc-amoy.polygon.technology"; 5 const provider = new ethers.providers.JsonRpcProvider(POLYGON_TESTNET_RPC); 6 7 const privateKey = '123456789abcdefg'; // Replace with payer's wallet private key 8 const wallet = new ethers.Wallet(privateKey, provider); 9 const 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 69 async 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 79 signMessage(privateKey, message) 80 .then((signedMessage) => { 81 console.log('Signed Message:', signedMessage); 82 }) 83 .catch((error) => { 84 console.error('Error signing message:', error); 85 }); -
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.Request1 curl --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 ' Response1 { 2 "hash": "0x1d6ba92970cf0285c40f167e7f5c030a7a8177e046caf270ca455ba9d040e734" 3 } -
Optional Implementation:Get Balances
This endpoint will allow you to get the balance of credits/usdc in the payer’s wallet.

