Refund & Dispute Handling
Refund checkout sessions and invoices in crypto.
Open the interactive version or read this guide as markdown.
Tags: Refunds, Webhooks, Support
Paste this prompt into Claude, ChatGPT, or any AI tool. It works best with the CoinCircuit MCP server connected: https://mcp.coincircuit.io
You are helping me add refund handling to my existing CoinCircuit payment integration. I have the CoinCircuit MCP server connected.
If you have access to the CoinCircuit MCP server, call these tools for the most accurate and detailed schema outputs:
- Call
search_apiwith featureRefundsin the CoinCircuit MCP to see all available refund endpoints (estimate, create session refund, create invoice refund, list, get by ID). - Call
get_endpointwith methodpostand path/api/v1/refunds/session/{sessionReference}for the session refund request/response schema. - Call
get_endpointwith methodpostand path/api/v1/refunds/invoice/{invoiceReference}for the invoice refund schema. - Call
get_endpointwith methodgetand path/api/v1/refunds/estimate/{reference}for the refund estimation schema. - Call
get_schemawith nameRefundCreatedWebhookDtofor the refund.created webhook payload. - Call
get_schemawith nameRefundSuccessWebhookDtofor the refund.success webhook payload. - Call
get_schemawith nameRefundFailedWebhookDtofor the refund.failed webhook payload. - Call
get_schemawith nameRefundResponseDtofor the full refund object shape used in both API responses and webhooks.
Use the live MCP data as your source of truth. The details below are a guide, but if the MCP returns something different, trust the MCP.
API Basics
- Base URL:
https://api.coincircuit.io - Auth:
x-api-keyheader on every request.
Project Context
I have an application using CoinCircuit for payments and I need to handle customer refund requests for both checkout session payments and invoice payments. CoinCircuit sends crypto refunds to a wallet address you specify.
What I Need You to Implement
1. Estimate refund before processing
Before issuing a refund, show the customer what they'll receive after fees.
Endpoint: GET /api/v1/refunds/estimate/{reference}?entity={type}
(Call get_endpoint with method get, path /api/v1/refunds/estimate/{reference} in the CoinCircuit MCP for the full parameter and response details.)
Path params:
reference(string) - the session reference (e.g.CS_1234567890) or invoice reference (e.g.INV_1234567890)
Query params:
entity(required) -"session"or"invoice"feePaidBy(optional) -"merchant"or"customer"
Response (200):
data.customerReceives- what the customer gets:amount,asset,chaindata.fees.amount- fee in the refund assetdata.fees.asset- asset the fee is charged indata.fees.fiatAmount- the same fee in the currency your payments settle intodata.fees.fiatCurrency- currency offiatAmountdata.fees.paidBy-"customer"or"merchant"data.customerPaid- the original payment:cryptoAmount,asset,fiatAmount,fiatCurrencydata.merchantCost- what is debited from your balance:amount,currency. Already includes the fee whenpaidByis"merchant".data.conversionRate- price of one unit of the refund asset inmerchantCost.currencydata.balanceSource-"settled"or"pending"."pending"means the original payment was never added to your balance.
Example:
{
"success": true,
"message": "Estimation retrieved successfully",
"data": {
"customerReceives": { "amount": "0.50098255", "asset": "SOL", "chain": "solana" },
"fees": {
"amount": "0.01038637",
"asset": "SOL",
"fiatAmount": "1.00",
"fiatCurrency": "USDT",
"paidBy": "customer"
},
"customerPaid": { "cryptoAmount": "0.52140427", "asset": "SOL", "fiatAmount": "50.00", "fiatCurrency": "USD" },
"merchantCost": { "amount": "50.00", "currency": "USDT" },
"conversionRate": "97.77676674533762",
"balanceSource": "settled"
}
}
Use customerReceives and fees for a confirmation screen, e.g. "Network fee: 0.01038637 SOL (1.00 USDT), Customer receives: 0.50098255 SOL".
2. Refund a checkout session
Endpoint: POST /api/v1/refunds/session/{sessionReference}
(Call get_endpoint with method post, path /api/v1/refunds/session/{sessionReference}, section request in the CoinCircuit MCP for the exact request body.)
Path params:
sessionReference(string) - the session reference from the original payment
Request body:
refundAddress(string, required) - the customer's wallet address to receive the refundreason(string, optional) - e.g. "Customer requested refund", "Product not delivered"feePaidBy(string, optional) -"merchant"or"customer". Defaults to your dashboard settings. Controls who absorbs the blockchain gas fee.
Example:
{
"refundAddress": "TF6yMCJqFcT6wFFutxVmRocKgJFD5imKUT",
"reason": "Customer requested refund - product not as described",
"feePaidBy": "merchant"
}
Response (201): Returns the refund object:
data.id- refund UUIDdata.entity-"session"data.reference- the session referencedata.status-"pending","processing","completed", or"failed"data.chain- blockchain used for the refund (matches original payment)data.asset- crypto asset (e.g."USDT")data.amount- crypto amount the customer receives (e.g."49.50000000")data.fee- network fee in crypto (e.g."0.50000000")data.feePaidBy-"merchant"or"customer"data.balanceSource-"settledBalance"or"pendingBalance"data.merchantDebitAmount- fiat amount debited from your balancedata.fiatAmount/data.fiatCurrency- fiat value of the refunddata.refundAddress- customer's walletdata.txHash- blockchain tx hash (populated on completion)data.explorerUrl- block explorer link (populated on completion)
(Call get_schema with name RefundResponseDto in the CoinCircuit MCP for every field in the refund object, including which are required vs optional.)
3. Refund an invoice
Endpoint: POST /api/v1/refunds/invoice/{invoiceReference}
(Call get_endpoint with method post, path /api/v1/refunds/invoice/{invoiceReference} in the CoinCircuit MCP for the full schema.)
Same request body as session refunds: refundAddress (required), reason (optional), feePaidBy (optional). Same response shape.
4. Track refund status via webhooks
(Call get_schema with name RefundSuccessWebhookDto in the CoinCircuit MCP for the full refund.success webhook payload. Call get_schema with name RefundFailedWebhookDto for the failure payload.)
Refund events (envelope: { event: string, data: { refund: RefundObject } }):
refund.created- refund initiated, blockchain transaction pending.data.refund.statusis"pending". (Callget_schemawith nameRefundCreatedWebhookDtofor the full payload.)refund.success- crypto sent to customer's wallet.data.refund.txHashanddata.refund.explorerUrlare populated.data.refund.completedAthas the timestamp.refund.failed- refund failed (e.g. invalid refund address).data.refund.statusis"failed".
Refund object fields in webhook:
data.refund.id- refund UUIDdata.refund.entity-"session"or"invoice"data.refund.reference- original session/invoice referencedata.refund.status-"pending","processing","completed","failed"data.refund.amount- crypto amount customer receivesdata.refund.fee- network feedata.refund.feePaidBy- who paid the feedata.refund.refundAddress- customer's walletdata.refund.txHash- blockchain tx hash (on success)data.refund.explorerUrl- block explorer URL (on success)data.refund.merchantDebitAmount- fiat amount debited from merchantdata.refund.fiatAmount/data.refund.fiatCurrency- fiat value
5. Query refund history
(Call search_api with feature Refunds in the CoinCircuit MCP to see all listing and detail endpoints.)
List all refunds: GET /api/v1/refunds (returns paginated list)
(Call get_endpoint with method get, path /api/v1/refunds in the CoinCircuit MCP for pagination params and response schema.)
Get single refund: GET /api/v1/refunds/{id}
(Call get_endpoint with method get, path /api/v1/refunds/{id} in the CoinCircuit MCP for the full response.)
Use these to build a support dashboard showing all refunds with their status, amounts, and transaction details.
6. Customer communication flow
Build email/notification triggers based on webhook events:
- On
refund.created: "Your refund has been initiated. We're sending {amount} {asset} to your wallet." - On
refund.success: "Your refund of {amount} {asset} has been sent to {refundAddress}. Track it here: {explorerUrl}" - On
refund.failed: "We encountered an issue processing your refund. Our team is looking into it. Reference: {reference}"
Constraints
refundAddressis required. CoinCircuit needs to know where to send the crypto.- Refunds are async. The API returns immediately with
"pending"status. Use webhooks for final status. - A session or invoice can only be refunded once.
- You cannot refund more than the original payment amount.
- The refund is sent in crypto (on the same chain/asset as the original payment) regardless of the original fiat denomination.
- Network fees (gas) may be deducted from the refund amount (if
feePaidBy: "customer") or from your merchant balance (iffeePaidBy: "merchant"). - Use the estimate endpoint first to show the customer what they'll receive.
- Refund statuses:
"pending"->"processing"->"completed"or"failed".