One-Time Purchase Integration - Solana Contract Settlement
This page is for advanced / cryptocurrency-native companies. If that’s not you, head back to the Quickstart for the standard flows.
This guide walks you through integrating Coinflow checkout to accept one-time credit card purchases with USDC settlement to your whitelisted Solana program.
Prerequisites
Complete these steps before starting the integration.
Create your sandbox account
Register or login to your sandbox merchant account
Generate API keys
Create a sandbox API key for authentication
Add chargeback protection
Add the protection script to every page of your app
Whitelist your Solana program
Whitelist your program to receive USDC settlement
Quick Reference
Authorization Headers
| Header | Description |
|---|---|
Authorization |
Your API key from the merchant dashboard |
x-coinflow-auth-wallet |
User’s Solana wallet address |
x-coinflow-auth-blockchain |
Use solana for Solana contract settlement |
x-coinflow-auth-session-key |
JWT token authorizing the payer |
Helpful Resources
- How Solana contract settlement works
- Test card numbers for sandbox
- Checkout webhooks
- Custom branding
Choose Your Implementation
Checkout Link
Best for simple integrations. Generate a hosted checkout URL to redirect users or embed in an iframe.
Step 1: Generate the checkout link
curl --request POST \
--url https://api-sandbox.coinflow.cash/api/checkout/link \
--header 'Authorization: YOUR_API_KEY' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'x-coinflow-auth-blockchain: solana' \
--header 'x-coinflow-auth-wallet: USER_WALLET_ADDRESS' \
--data '{
"webhookInfo": {
"depositId": "123-abc-456"
},
"subtotal": {
"currency": "USD",
"cents": 500
},
"settlementType": "Credits",
"email": "customer@example.com",
"blockchain": "solana",
"chargebackProtectionData": [{
"productType": "inGameProduct",
"productName": "In-Game Credits",
"quantity": 1,
"rawProductData": {
"description": "Purchase credits for gameplay"
}
}],
"deviceId": "123456789",
"supportEmail": "support@yourcompany.com"
}'
{
"link": "https://sandbox.coinflow.cash/solana/purchase-v2/your-merchant?sessionKey=..."
}
Step 2: Create a redeem transaction
After the payer completes checkout, create a redeem transaction to settle USDC to your contract. Create a base58 encoded transaction for your whitelisted program.
curl --request POST \
--url https://api-sandbox.coinflow.cash/api/redeem \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'x-coinflow-auth-blockchain: solana' \
--header 'x-coinflow-auth-wallet: USER_WALLET_ADDRESS' \
--data '{
"subtotal": {
"currency": "USD",
"cents": 500
},
"merchantId": "YOUR_MERCHANT_ID",
"transaction": "BASE58_ENCODED_TRANSACTION",
"chargebackProtectionData": [{
"productType": "inGameProduct",
"productName": "In-Game Credits",
"quantity": 1
}]
}'
{
"transaction": "5hAzkEBF2jNWz4Yo5mv63p2Nc8HKFyC4PhKmvtE5KbEd..."
}
Step 3: Sign and send the transaction
Have the user’s wallet sign and send the transaction.
const { Connection, Keypair, VersionedTransaction } = require('@solana/web3.js');
const bs58 = require('bs58');
async function signTransaction(base58Transaction, keypair) {
const decodedTransactionBytes = bs58.decode(base58Transaction);
const versionedTransaction = VersionedTransaction.deserialize(decodedTransactionBytes);
versionedTransaction.sign([keypair]);
const serializedTransaction = versionedTransaction.serialize();
return bs58.encode(serializedTransaction);
}
curl --request POST \
--url https://api-sandbox.coinflow.cash/api/utils/send-coinflow-tx \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"merchantId": "YOUR_MERCHANT_ID",
"signedTransaction": "SIGNED_BASE58_TRANSACTION"
}'
React SDK
Best for React applications. Provides a pre-built checkout component.
Step 1: Install the SDK
npm install @coinflowlabs/react
Step 2: Render the checkout component
import { CoinflowPurchase, SettlementType, Currency } from '@coinflowlabs/react';
import { Connection, PublicKey } from '@solana/web3.js';
function Checkout({ wallet, connection }) {
return (
<CoinflowPurchase
wallet={{
publicKey: new PublicKey(wallet.publicKey),
signMessage: wallet.signMessage,
sendTransaction: wallet.sendTransaction
}}
connection={connection}
blockchain="solana"
merchantId="your-merchant-id"
env="sandbox"
settlementType={SettlementType.Credits}
subtotal={{ cents: 500, currency: Currency.USD }}
email="customer@example.com"
webhookInfo={{
productId: "123abc",
item: "sword"
}}
chargebackProtectionData={[{
productName: "In-Game Credits",
productType: "inGameProduct",
quantity: 1,
rawProductData: {
productID: "credits-500",
productDescription: "500 in-game credits"
}
}]}
onSuccess={(paymentId) => {
console.log('Payment successful:', paymentId);
// Create redeem transaction after success
}}
/>
);
}
Step 3: Create a redeem transaction on success
After the card payment completes, create and submit the redeem transaction.
curl --request POST \
--url https://api-sandbox.coinflow.cash/api/redeem \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'x-coinflow-auth-blockchain: solana' \
--header 'x-coinflow-auth-wallet: USER_WALLET_ADDRESS' \
--data '{
"subtotal": {
"currency": "USD",
"cents": 500
},
"merchantId": "YOUR_MERCHANT_ID",
"transaction": "BASE58_ENCODED_TRANSACTION",
"chargebackProtectionData": [{
"productType": "inGameProduct",
"productName": "In-Game Credits",
"quantity": 1
}]
}'
{
"transaction": "5hAzkEBF2jNWz4Yo5mv63p2Nc8HKFyC4PhKmvtE5KbEd..."
}
Step 4: Sign and send the transaction
async function signTransaction(base58Transaction, keypair) {
const decodedTransactionBytes = bs58.decode(base58Transaction);
const versionedTransaction = VersionedTransaction.deserialize(decodedTransactionBytes);
versionedTransaction.sign([keypair]);
const serializedTransaction = versionedTransaction.serialize();
return bs58.encode(serializedTransaction);
}
curl --request POST \
--url https://api-sandbox.coinflow.cash/api/utils/send-coinflow-tx \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"merchantId": "YOUR_MERCHANT_ID",
"signedTransaction": "SIGNED_BASE58_TRANSACTION"
}'
API Only
Best for custom checkout UIs. Full control over the payment flow.
Step 1: Get a session key
curl --request GET \
--url https://api-sandbox.coinflow.cash/api/auth/session-key \
--header 'Authorization: YOUR_API_KEY' \
--header 'accept: application/json' \
--header 'x-coinflow-auth-blockchain: solana' \
--header 'x-coinflow-auth-wallet: USER_WALLET_ADDRESS'
{
"key": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Session keys expire after 24 hours. Refresh them before expiration.
Step 2: Get pricing totals
curl --request POST \
--url https://api-sandbox.coinflow.cash/api/checkout/totals/YOUR_MERCHANT_ID \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'x-coinflow-auth-session-key: SESSION_KEY' \
--data '{
"subtotal": { "cents": 500 }
}'
{
"card": {
"subtotal": { "cents": 500 },
"creditCardFees": { "cents": 0 },
"total": { "cents": 500 }
}
}
Step 3: Tokenize the credit card
See PCI-compliant card tokenization for implementation details.
Step 4: Process the new card payment
curl --request POST \
--url https://api-sandbox.coinflow.cash/api/checkout/card/YOUR_MERCHANT_ID \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'x-coinflow-auth-session-key: SESSION_KEY' \
--data '{
"subtotal": { "currency": "USD", "cents": 500 },
"webhookInfo": {
"description": "Purchase credits"
},
"card": {
"expYear": "29",
"expMonth": "10",
"email": "customer@example.com",
"firstName": "John",
"lastName": "Doe",
"address1": "123 Main St",
"city": "Chicago",
"zip": "60606",
"state": "IL",
"country": "US",
"cardToken": "TOKENIZED_CARD"
},
"settlementType": "Credits",
"authentication3DS": {
"colorDepth": 30,
"screenHeight": 1000,
"screenWidth": 2000,
"timeZone": 5
},
"chargebackProtectionData": [{
"productType": "inGameProduct",
"productName": "In-Game Credits",
"quantity": 1
}]
}'
{
"paymentId": "bdc22a87-fb72-4f9d-a445-f26c04c8376c"
}
Step 5: Process saved card payments (returning users)
Re-tokenize the saved card with CVV first (see card tokenization docs), then:
curl --request POST \
--url https://api-sandbox.coinflow.cash/api/checkout/token/YOUR_MERCHANT_ID \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'x-coinflow-auth-session-key: SESSION_KEY' \
--header 'x-device-id: 123456789' \
--data '{
"settlementType": "Credits",
"subtotal": { "currency": "USD", "cents": 500 },
"webhookInfo": {
"description": "Purchase credits"
},
"authentication3DS": {
"colorDepth": 30,
"screenHeight": 1000,
"screenWidth": 2000,
"timeZone": 5
},
"chargebackProtectionData": [{
"productType": "inGameProduct",
"productName": "In-Game Credits",
"quantity": 1
}],
"token": "REFRESHED_CARD_TOKEN"
}'
{
"paymentId": "e416a462-33a3-4e80-ab8d-ffa2de666a2b"
}
Step 6: Create a redeem transaction
curl --request POST \
--url https://api-sandbox.coinflow.cash/api/redeem \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'x-coinflow-auth-blockchain: solana' \
--header 'x-coinflow-auth-wallet: USER_WALLET_ADDRESS' \
--data '{
"subtotal": { "currency": "USD", "cents": 500 },
"merchantId": "YOUR_MERCHANT_ID",
"transaction": "BASE58_ENCODED_TRANSACTION",
"chargebackProtectionData": [{
"productType": "inGameProduct",
"productName": "In-Game Credits",
"quantity": 1
}]
}'
{
"transaction": "5hAzkEBF2jNWz4Yo5mv63p2Nc8HKFyC4PhKmvtE5KbEd..."
}
Step 7: Sign and send the transaction
async function signTransaction(base58Transaction, keypair) {
const decodedTransactionBytes = bs58.decode(base58Transaction);
const versionedTransaction = VersionedTransaction.deserialize(decodedTransactionBytes);
versionedTransaction.sign([keypair]);
const serializedTransaction = versionedTransaction.serialize();
return bs58.encode(serializedTransaction);
}
curl --request POST \
--url https://api-sandbox.coinflow.cash/api/utils/send-coinflow-tx \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"merchantId": "YOUR_MERCHANT_ID",
"signedTransaction": "SIGNED_BASE58_TRANSACTION"
}'
Chargeback Protection
Add the protection script
Add the chargeback protection script to every page of your app.
Send user events
Track key user actions throughout their journey.
curl --request POST \
--url https://api-sandbox.coinflow.cash/api/events \
--header 'Authorization: YOUR_API_KEY' \
--header 'content-type: application/json' \
--data '{
"eventType": "SignUp",
"customerId": "user-123-abc",
"country": "US",
"username": "johndoe",
"email": "john@example.com",
"firstName": "John",
"lastName": "Doe"
}'
curl --request POST \
--url https://api-sandbox.coinflow.cash/api/events \
--header 'Authorization: YOUR_API_KEY' \
--header 'content-type: application/json' \
--data '{
"eventType": "SignIn",
"customerId": "user-123-abc",
"country": "US",
"email": "john@example.com"
}'
On sandbox, use the test partnerId provided by the Coinflow team when configuring the protection script.
Next Steps
Test Your Integration
Use sandbox test cards to verify your implementation
Configure Webhooks
Receive real-time payment notifications
Go Live
Create your production merchant account
API Reference
Explore the complete API documentation