Skip to main content

Overview

Refund APIs enable you to return cryptocurrency payments to customers. Whether handling order cancellations, customer dissatisfaction, or error corrections, refunds ensure smooth financial operations and maintain customer trust.

What is a Refund?

A refund returns cryptocurrency funds from a completed payment back to the customer's wallet. Each refund:

  • 💰 Returns funds in the original payment cryptocurrency (USDC/USDT)
  • 🔗 Links to the original Payment Intent and Charge
  • 📊 Tracks status through the refund lifecycle
  • 🏷️ Supports metadata for order tracking
  • 🔄 Processes through blockchain transactions

🔗 Related APIs: Refunds are created against successful Payment Intents. You must have a completed payment before issuing a refund.

Key Features

FeatureDescription
Partial RefundsIssue partial refunds for any amount up to the full payment
Full RefundsReturn the entire payment amount to the customer
Automatic CurrencyRefunds use the original transaction's cryptocurrency
Blockchain TrackingEach refund links to blockchain transactions
Status TrackingMonitor refund progress through lifecycle statuses
Metadata SupportAttach custom data for internal tracking
Network FeesSystem handles blockchain network fees automatically

How Refunds Work

Create Refund → Processing → Blockchain Transaction → Customer Receives Funds
↓ ↓ ↓ ↓
Pending → Processing → Blockchain → Succeeded

Refund Lifecycle

1. Refund Creation

  • Merchant initiates refund via API
  • Specifies amount (partial or full)
  • Provides reason and metadata
  • Status: Pending

2. Processing

  • System validates refund request
  • Creates blockchain transaction
  • Calculates network fees
  • Status: Processing

3. Blockchain Execution

  • Transaction submitted to blockchain
  • Funds transferred from merchant wallet to customer
  • Transaction hash recorded
  • Status: ProcessingSucceeded

4. Completion

  • Customer receives funds in their wallet
  • Refund marked as complete
  • Webhook refund.succeeded sent
  • Status: Success

Refund Status

StatusMeaningNext Steps
PendingRefund created, awaiting processingWait for processing to begin
ProcessingBlockchain transaction in progressMonitor transaction status
SuccessFunds successfully returned to customerNo action needed
FailedRefund failed to processCheck failure_reason, retry if needed

Refund Reasons

Specify a reason when creating refunds for better tracking:

ReasonWhen to Use
requested_by_customerCustomer requested a refund
duplicateDuplicate payment processed
fraudulentSuspected or confirmed fraud
order_cancelledOrder was cancelled
product_not_receivedCustomer didn't receive product
product_defectiveProduct was defective or damaged
otherOther reason not listed above

Best Practices

✅ DO:

  • Issue refunds promptly to maintain customer satisfaction
  • Include clear metadata for internal tracking
  • Specify accurate refund reasons for analytics
  • Monitor refund status via webhooks
  • Keep customers informed about refund progress

❌ DON'T:

  • Issue refunds for more than the original payment amount
  • Create duplicate refunds for the same payment
  • Skip including refund reasons (important for records)
  • Ignore failed refunds (investigate and resolve)

Important Notes

  1. Partial or Full Refunds: Merchants can issue either partial or full refunds depending on the situation.
  2. Refund Status: Refunds go through different statuses (e.g., pending, succeeded, failed) as they are processed.
  3. Associated Transactions: Each refund is linked to one or more blockchain transactions that facilitate the return of funds.
  4. Currency and Amount: Refunds are processed in the original transaction's currency and can be for any amount up to the full payment.
  5. Metadata: Additional information can be attached to refunds for internal tracking and reconciliation purposes.
  6. Network Fees: The merchant pays blockchain network fees for refund transactions.
  7. Processing Time: Refund processing time depends on blockchain network confirmation times.

Understanding and effectively managing refunds is crucial for maintaining customer satisfaction and ensuring smooth financial operations in your MartianPay integration.


API Reference

1. Create Refund

For detailed API reference, see: Create Refund API

Request:

curl --location --request POST 'https://api.martianpay.com/v1/refunds' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}' \
--data-raw '{
"amount": "2",
"metadata": {
"order_id": "12345"
},
"payment_intent_id": "pi_vfk7mLTHPs7Cf0UbU38tGiKq",
"reason": "requested_by_customer"
}'

Response:

{
"error_code": "success",
"msg": "success",
"data": {
"refunds": [
{
"id": "rf_fUlic9qfON8m9yinN4kw6Bqh",
"object": "refund",
"amount": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "2"
},
"network_fee": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "0.01"
},
"net_amount": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "2"
},
"created": 1748784087,
"description": "",
"transactions": [],
"failure_reason": "",
"metadata": {
"order_id": "12345"
},
"charge": "ch_c9tR5aQRdtmkKwCQDji9Z6ST",
"payment_intent": "pi_vfk7mLTHPs7Cf0UbU38tGiKq",
"refund_address": "0x36279Ac046498bF0cb742622cCe22F3cE3c2AfD9",
"reason": "requested_by_customer",
"status": "Pending"
}
]
}
}

Understanding the Response

How to Check if the Request Was Successful:

FieldValueMeaning
error_code"success"✅ Refund created successfully
error_codeOther value❌ Error occurred (e.g., "insufficient_funds", "invalid_payment_intent")

Key Fields:

FieldDescription
idUnique refund identifier (use to track refund status)
statusCurrent refund status: Pending, Processing, Success, Failed
amountRefund amount in original cryptocurrency
net_amountAmount customer receives (amount - network_fee)
network_feeBlockchain transaction fee (paid by merchant)
payment_intentOriginal payment intent ID being refunded
refund_addressCustomer's wallet address receiving the refund
reasonRefund reason for tracking and analytics

Next Steps:

  • Save the refund id for tracking and customer service
  • Monitor refund status via Get Refund API
  • Subscribe to webhook events to receive real-time updates
  • Inform customer that refund is being processed

Webhook Events for Refunds

MartianPay sends webhook notifications for refund events, enabling you to track refund processing in real-time and keep customers informed.

Refund Events

Event TypeDescriptionTriggered When
refund.createdRefund request createdA new refund is initially created and recorded
refund.updatedRefund status updatedStatus or details change (may occur multiple times during processing)
refund.succeededRefund completed successfullyFunds successfully returned to customer's wallet
refund.failedRefund processing failedProcessing failed due to network issues, invalid address, or insufficient funds

Webhook Payload Example

Here's an example of a refund webhook event payload:

{
"id": "evt_056qw9fr9PndljykFUqSIf6t",
"object": "event",
"api_version": "2025-01-22",
"created": 1748580845,
"data": {
"object": {
"id": "refund_4HbjPuW72pLq5f8yXPpTn7fv",
"object": "refund",
"amount": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "5"
},
"created": 1748580000,
"updated": 1748580845,
"charge": "ch_c9tR5aQRdtmkKwCQDji9Z6ST",
"payment_intent": "pi_vfk7mLTHPs7Cf0UbU38tGiKq",
"reason": "customer_request",
"status": "Success",
"metadata": {
"order_id": "order_123",
"reason_detail": "Customer changed mind"
},
"transactions": [
{
"tx_hash": "0x85b9b9b2fcd8b149a79efa6eee0d94f0d81c6d3172d1335fed897a374e81210c",
"status": "confirmed",
"amount": "5000000"
}
]
},
"previous_attributes": {
"status": "Processing",
"updated": 1748580500
}
},
"livemode": false,
"pending_webhooks": 0,
"type": "refund.succeeded"
}

Webhook Event Flow

Typical Refund Event Sequence:

  1. refund.created - Refund request submitted (status: Pending)
  2. refund.updated - Status changes (may occur multiple times as status progresses: Processing, In Transit, etc.)
  3. refund.succeeded - Funds returned successfully (status: Success)
    • OR refund.failed - Processing failed (status: Failed)

Status Transitions:

created → updated* → succeeded (SUCCESS)
↘ failed (FAILURE)

* refund.updated may fire multiple times as status changes

Best Practices

  1. Monitor refund.succeeded events - Confirm successful refunds and:

    • Update order status to "refunded"
    • Send refund confirmation emails to customers
    • Update accounting records
    • Close support tickets related to refund requests
  2. Alert on refund.failed events - Take immediate action when refunds fail:

    • Notify customer service team
    • Investigate failure reason (failure_reason field)
    • Retry refund if issue is transient
    • Provide alternative refund methods if blockchain issues persist
  3. Track refund progress - Use refund.updated events to:

    • Show real-time status to customers ("Your refund is being processed...")
    • Track time from request to completion
    • Identify slow refunds for investigation
    • Update support dashboards
  4. Handle idempotency - Store the event ID (evt_*) to prevent duplicate processing

  5. Reconcile with payment intent - Use the payment_intent and charge fields to:

    • Match refunds to original payments
    • Update payment records in your system
    • Track refund amounts against original payment amounts
  6. Extract transaction details - When refund.succeeded is received:

    • Store transaction hashes from transactions[] array
    • Provide blockchain explorer links to customers for verification
    • Keep records for accounting and dispute resolution
  7. Customer communication - Use webhook events to trigger automated messages:

    • refund.created: "Your refund request has been received"
    • refund.updated (Processing): "Your refund is being processed"
    • refund.succeeded: "Your refund of $X has been completed"
    • refund.failed: "There was an issue with your refund, our team is investigating"

For more details on webhook setup, signature verification, and complete event schemas, see the Webhook Events documentation.

2. Retrieve a Single Refund

For detailed API reference, see: Get Refund API

Request:

curl --location --request GET 'https://api.martianpay.com/v1/refunds/\{id\}' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}'

Response:

{
"error_code": "success",
"msg": "success",
"data": {
"id": "rf_fUlic9qfON8m9yinN4kw6Bqh",
"object": "refund",
"amount": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "2"
},
"network_fee": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "0.01"
},
"net_amount": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "2"
},
"created": 1748784087,
"description": "",
"transactions": [
{
"tx_id": "a80fa424-ffcb-45cb-a3a5-7391662272f7",
"source_address": "0x89Dbc88f04dc48572a2C7AfD609cdA144fc794D8",
"destination_address": "0x36279Ac046498bF0cb742622cCe22F3cE3c2AfD9",
"tx_hash": "0x59de6b933c6ded9ef95e80238951454b3e53c51cec463ac8ded4b07d9a19dc0e",
"amount": "2000000",
"decimals": 0,
"asset_id": "",
"token": "USDC",
"network": "Ethereum Sepolia",
"type": "refund",
"created_at": 1748784101,
"status": "confirmed",
"aml_status": "approved",
"aml_info": "",
"charge_id": "ch_c9tR5aQRdtmkKwCQDji9Z6ST",
"refund_id": "rf_fUlic9qfON8m9yinN4kw6Bqh",
"fee_info": "network_fee:\"0.000045059020501845\"",
"fee_currency": "ETH_TEST5"
}
],
"failure_reason": "",
"metadata": {
"order_id": "12345"
},
"charge": "ch_c9tR5aQRdtmkKwCQDji9Z6ST",
"payment_intent": "pi_vfk7mLTHPs7Cf0UbU38tGiKq",
"refund_address": "0x36279Ac046498bF0cb742622cCe22F3cE3c2AfD9",
"reason": "requested_by_customer",
"status": "Success"
}
}

Understanding the Response

How to Check if the Request Was Successful:

FieldValueMeaning
error_code"success"✅ Refund retrieved successfully
error_code"refund_not_found"❌ No refund exists with this ID
error_codeOther value❌ Other error occurred

Key Status Fields:

StatusMeaningNext Steps
Pending⏳ Refund created, awaiting processingWait for processing to begin
Processing🔄 Blockchain transaction in progressMonitor transaction via webhook events
SuccessComplete - Funds returned to customerNo action needed, customer has received funds
FailedFailed - Refund could not be processedCheck failure_reason field, retry if needed

Transaction Details:

The transactions array contains blockchain transaction information:

  • tx_hash: Blockchain transaction hash for verification
  • source_address: Your merchant wallet address
  • destination_address: Customer's refund wallet address
  • amount: Amount transferred (in smallest token unit)
  • status: Transaction confirmation status (confirmed, pending, failed)
  • network: Blockchain network used (e.g., "Ethereum Sepolia")
  • fee_info: Network fee details for the transaction

Use Cases:

  • Verify refund completion and share tx_hash with customer
  • Check transaction status on blockchain explorer
  • Track network fees for accounting purposes
  • Investigate failed refunds using failure_reason

Next Steps:

  • If status is Success, inform customer funds have been returned
  • If status is Failed, check failure_reason and determine if retry is needed
  • Share blockchain transaction hash (tx_hash) with customer for transparency

3. List Refunds

Fetches a list of refunds, with options for filtering and pagination. The payment_intent parameter is optional and can be used to filter refunds by a specific payment intent.

For detailed API reference, see: List Refunds API

Request:

curl --location --request GET 'https://api.martianpay.com/v1/refunds?page=0&page_size=10&payment_intent=pi_vfk7mLTHPs7Cf0UbU38tGiKq' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}'

Query Parameters:

  • page (required): Page number, starting from 0
  • page_size (required): Items per page
  • payment_intent (optional): Filter by payment intent ID

Response:

{
"error_code": "success",
"msg": "success",
"data": {
"refunds": [
{
"id": "rf_fUlic9qfON8m9yinN4kw6Bqh",
"object": "refund",
"amount": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "2"
},
"network_fee": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "0.01"
},
"net_amount": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "2"
},
"created": 1748784087,
"description": "",
"transactions": [
{
"tx_id": "a80fa424-ffcb-45cb-a3a5-7391662272f7",
"source_address": "0x89Dbc88f04dc48572a2C7AfD609cdA144fc794D8",
"destination_address": "0x36279Ac046498bF0cb742622cCe22F3cE3c2AfD9",
"tx_hash": "0x59de6b933c6ded9ef95e80238951454b3e53c51cec463ac8ded4b07d9a19dc0e",
"amount": "2000000",
"decimals": 0,
"asset_id": "",
"token": "USDC",
"network": "Ethereum Sepolia",
"type": "refund",
"created_at": 1748784101,
"status": "confirmed",
"aml_status": "approved",
"aml_info": "",
"charge_id": "ch_c9tR5aQRdtmkKwCQDji9Z6ST",
"refund_id": "rf_fUlic9qfON8m9yinN4kw6Bqh",
"fee_info": "network_fee:\"0.000045059020501845\"",
"fee_currency": "ETH_TEST5"
}
],
"failure_reason": "",
"metadata": {
"order_id": "12345"
},
"charge": "ch_c9tR5aQRdtmkKwCQDji9Z6ST",
"payment_intent": "pi_vfk7mLTHPs7Cf0UbU38tGiKq",
"refund_address": "0x36279Ac046498bF0cb742622cCe22F3cE3c2AfD9",
"reason": "requested_by_customer",
"status": "Success"
}
],
"total": 1,
"page": 0,
"page_size": 10
}
}

Understanding the Response

How to Check if the Request Was Successful:

FieldValueMeaning
error_code"success"✅ Refunds retrieved successfully
error_codeOther value❌ Error occurred

Key Fields:

  • total: Total number of refunds matching your query
  • page: Current page number (0-based)
  • page_size: Number of items per page
  • refunds: Array of refund objects

Pagination:

  • Use page and page_size to navigate through results
  • If total > page_size, there are more pages available
  • Next page: page=1, previous page: page=0

Filtering:

  • Use payment_intent parameter to find refunds for a specific payment
  • Empty refunds array means no matches found

Refund Status Summary:

StatusMeaning
Pending⏳ Refund created, awaiting processing
Processing🔄 Blockchain transaction in progress
Success✅ Funds returned to customer
Failed❌ Refund failed, check failure_reason

Next Steps:

  • Loop through refunds array to process each refund
  • Use refund id to fetch more details if needed
  • Monitor status field to track refund progress
  • Filter by payment_intent to reconcile specific orders
  • Adjust page and page_size for pagination