Return Transaction (Void or Refund)
Description: Returns a transaction for a given merchant. The system automatically determines whether to void or refund the transaction based on its settlement status. Unsettled transactions are voided (no funds transferred), while settled transactions are refunded (funds returned to customer).
- Void: Cancels a transaction before funds are settled (usually same day). The customer never sees the charge on their statement.
- Refund: Returns funds after the transaction has settled (1-2 days after transaction). The customer sees both the original charge and the refund on their statement.
This endpoint handles both automatically - you don't need to specify which one to perform. The system determines the appropriate action based on settlement status.
- Voids completely cancel the transaction - no funds are ever transferred
- Refunds return money to the customer and may take 3-5 business days to appear
- Partial returns are not supported by this endpoint - use the refunds endpoint for partial refunds
- Once returned, a transaction cannot be un-returned
Path Parameters
Authentication
This endpoint requires bearer token authentication using the Authorization header.
Code Examples
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
public class TransactionClient
{
private readonly HttpClient _httpClient;
private readonly string _baseUrl = "https://your-api-domain.com";
private readonly string _bearerToken;
public TransactionClient(string bearerToken)
{
_bearerToken = bearerToken;
_httpClient = new HttpClient();
_httpClient.BaseAddress = new Uri(_baseUrl);
_httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", _bearerToken);
_httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<string> ReturnTransactionAsync(
string merchantId,
string transactionId)
{
try
{
string endpoint = $"/v1/rest/merchants/{merchantId}/transactions/{transactionId}";
HttpResponseMessage response = await _httpClient.DeleteAsync(endpoint);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
catch (HttpRequestException e)
{
Console.WriteLine($"Request error: {e.Message}");
throw;
}
}
// With confirmation prompt
public async Task<bool> ReturnTransactionWithConfirmationAsync(
string merchantId,
string transactionId,
string amount)
{
Console.WriteLine($"WARNING: You are about to return a transaction for ${amount}");
Console.Write("Are you sure you want to proceed? (yes/no): ");
string confirmation = Console.ReadLine();
if (confirmation?.ToLower() != "yes")
{
Console.WriteLine("Return cancelled.");
return false;
}
try
{
string result = await ReturnTransactionAsync(merchantId, transactionId);
Console.WriteLine("Transaction returned successfully.");
Console.WriteLine(result);
return true;
}
catch (Exception ex)
{
Console.WriteLine($"Failed to return transaction: {ex.Message}");
return false;
}
}
}
// Example usage: Return a transaction
var client = new TransactionClient("your-bearer-token-here");
string result = await client.ReturnTransactionAsync(
"12345678901", // merchantId
"a1b2c3d4-e5f6-7890-abcd-ef1234567890" // transactionId
);
Console.WriteLine(result);
// With confirmation
bool returned = await client.ReturnTransactionWithConfirmationAsync(
"12345678901",
"a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"150.00"
);
Imports System
Imports System.Net.Http
Imports System.Net.Http.Headers
Imports System.Threading.Tasks
Public Class TransactionClient
Private ReadOnly _httpClient As HttpClient
Private ReadOnly _baseUrl As String = "https://your-api-domain.com"
Private ReadOnly _bearerToken As String
Public Sub New(bearerToken As String)
_bearerToken = bearerToken
_httpClient = New HttpClient()
_httpClient.BaseAddress = New Uri(_baseUrl)
_httpClient.DefaultRequestHeaders.Authorization =
New AuthenticationHeaderValue("Bearer", _bearerToken)
_httpClient.DefaultRequestHeaders.Accept.Add(
New MediaTypeWithQualityHeaderValue("application/json"))
End Sub
Public Async Function ReturnTransactionAsync(
merchantId As String,
transactionId As String) As Task(Of String)
Try
Dim endpoint As String = $"/v1/rest/merchants/{merchantId}/transactions/{transactionId}"
Dim response As HttpResponseMessage = Await _httpClient.DeleteAsync(endpoint)
response.EnsureSuccessStatusCode()
Return Await response.Content.ReadAsStringAsync()
Catch e As HttpRequestException
Console.WriteLine($"Request error: {e.Message}")
Throw
End Try
End Function
End Class
' Example usage
Dim client As New TransactionClient("your-bearer-token-here")
Dim result As String = Await client.ReturnTransactionAsync(
"12345678901",
"a1b2c3d4-e5f6-7890-abcd-ef1234567890"
)
Console.WriteLine(result)
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class TransactionClient {
private final String baseUrl;
private final String bearerToken;
private final HttpClient httpClient;
public TransactionClient(String baseUrl, String bearerToken) {
this.baseUrl = baseUrl;
this.bearerToken = bearerToken;
this.httpClient = HttpClient.newHttpClient();
}
public String returnTransaction(String merchantId, String transactionId)
throws IOException, InterruptedException {
String endpoint = baseUrl + "/v1/rest/merchants/" + merchantId +
"/transactions/" + transactionId;
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(endpoint))
.header("Authorization", "Bearer " + bearerToken)
.header("Accept", "application/json")
.DELETE()
.build();
HttpResponse<String> response = httpClient.send(
request,
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() != 200) {
throw new IOException("HTTP Error: " + response.statusCode() +
" - " + response.body());
}
return response.body();
}
}
// Example usage
TransactionClient client = new TransactionClient(
"https://your-api-domain.com",
"your-bearer-token-here"
);
String result = client.returnTransaction(
"12345678901",
"a1b2c3d4-e5f6-7890-abcd-ef1234567890"
);
System.out.println(result);
require 'net/http'
require 'uri'
require 'json'
class TransactionClient
def initialize(base_url, bearer_token)
@base_url = base_url
@bearer_token = bearer_token
end
def return_transaction(merchant_id, transaction_id)
endpoint = "#{@base_url}/v1/rest/merchants/#{merchant_id}/transactions/#{transaction_id}"
uri = URI.parse(endpoint)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Delete.new(uri.request_uri)
request['Authorization'] = "Bearer #{@bearer_token}"
request['Accept'] = 'application/json'
response = http.request(request)
if response.code.to_i != 200
raise "HTTP Error: #{response.code} - #{response.body}"
end
response.body
end
end
# Example usage
client = TransactionClient.new(
'https://your-api-domain.com',
'your-bearer-token-here'
)
result = client.return_transaction(
'12345678901',
'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
)
puts result
Response Format
Success Response (HTTP 200) - Void
{
"responseStatus": "TransactionRefunded",
"responseMessage": "Transaction voided successfully",
"responseCode": "200",
"responseReason": null,
"responseResult": "success",
"legacyResponseCode": "A",
"correlationId": "void-123-456-789",
"transactionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"retref": 123456789,
"merchid": "12345678901",
"transactionAmount": "150.00",
"authAmount": "150.00",
"accttype": "VISA",
"maskedAccountNumber": "************1234",
"lastfour": "1234",
"accountHolderName": "John Doe",
"orderid": "ORD-2026-12345",
"settlementStatus": "Voided",
"requestDate": "2026-04-02T10:30:00Z",
"authDate": "2026-04-02T10:30:03Z",
"retdecdate": "2026-04-02T14:15:00Z"
}
Success Response (HTTP 200) - Refund
{
"responseStatus": "TransactionRefunded",
"responseMessage": "Transaction refunded successfully",
"responseCode": "200",
"responseReason": null,
"responseResult": "success",
"legacyResponseCode": "A",
"correlationId": "refund-789-012-345",
"transactionId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"retref": 123456790,
"merchid": "12345678901",
"transactionAmount": "150.00",
"authAmount": "150.00",
"accttype": "VISA",
"maskedAccountNumber": "************1234",
"lastfour": "1234",
"accountHolderName": "John Doe",
"orderid": "ORD-2026-12345",
"settlementStatus": "Refunded",
"requestDate": "2026-04-02T10:30:00Z",
"authDate": "2026-04-02T10:30:03Z",
"settlementDate": "2026-04-03T03:00:00Z",
"retdecdate": "2026-04-04T12:00:00Z",
"linkedTransactionId": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
}
HTTP Status Codes
| Status Code | Description |
|---|---|
| 200 | Success - Transaction voided or refunded successfully |
| 400 | Bad Request - Invalid request or transaction cannot be returned |
| 403 | Forbidden - Merchant does not own this transaction |
| 404 | Not Found - Transaction with specified ID does not exist |
| 409 | Conflict - Transaction already returned/voided |
| 500 | Internal Server Error - Server error processing return |
Error Responses
Already Returned (HTTP 409)
{
"responseStatus": "Error",
"responseMessage": "Transaction already returned",
"responseCode": "409",
"responseReason": "This transaction was previously refunded or voided",
"responseResult": "failure",
"correlationId": "error-409-123-456"
}
Forbidden - Not Your Transaction (HTTP 403)
{
"responseStatus": "Error",
"responseMessage": "Forbidden",
"responseCode": "403",
"responseReason": "Merchant does not own this transaction",
"responseResult": "failure",
"correlationId": "error-403-789-012"
}
Understanding Settlement Status After Return
| Settlement Status | Meaning | Customer Impact |
|---|---|---|
| Voided | Transaction cancelled before settlement | Charge never appears on customer's statement |
| Refunded | Funds returned after settlement | Customer sees original charge and separate refund |
| PartiallyRefunded | Only part of the transaction was refunded | Customer receives partial refund amount |
Void vs Refund Decision Tree
- Check transaction's settlement status
- If settlement status is "Authorized" or "QueuedForCapture" → VOID
- If settlement status is "Accepted" or "Settled" → REFUND
- If already voided/refunded → Return 409 Conflict
You don't need to specify which action to take - the API determines this automatically.
Best Practices
1. Always Confirm Before Returning
Implement a confirmation step before processing returns, especially for large amounts. Returns cannot be undone.
// Good - requires confirmation
Console.WriteLine($"Returning transaction for ${amount}");
Console.Write("Type 'CONFIRM' to proceed: ");
if (Console.ReadLine() == "CONFIRM")
{
await client.ReturnTransactionAsync(merchantId, transactionId);
}
2. Handle 409 Conflicts Gracefully
A 409 status means the transaction was already returned. This isn't necessarily an error - inform the user that the return was already processed.
try
{
await client.ReturnTransactionAsync(merchantId, transactionId);
}
catch (HttpRequestException ex) when (response.StatusCode == HttpStatusCode.Conflict)
{
Console.WriteLine("This transaction was already returned.");
// This is acceptable - no need to show as error
}
3. Log All Return Requests
Keep an audit log of who requested returns, when, and why. This is important for accounting and fraud prevention.
await AuditLog.LogAsync(new AuditEntry
{
Action = "ReturnTransaction",
UserId = currentUserId,
TransactionId = transactionId,
Amount = amount,
Reason = returnReason,
Timestamp = DateTime.UtcNow
});
await client.ReturnTransactionAsync(merchantId, transactionId);
4. Notify Customers
Send an email or notification to the customer when their transaction is voided or refunded. Include expected timeframe for refund to appear.
5. Act Quickly for Voids
If you need to cancel a transaction, do it as soon as possible (same day) to ensure it's voided rather than refunded. Voids are instant; refunds take days.
6. Check Settlement Status First
Before returning a transaction, retrieve it first to check its current status and inform the user whether it will be voided or refunded.
// Get transaction details first
var txn = await client.GetTransactionAsync(merchantId, transactionId);
if (txn.SettlementStatus == "Authorized")
{
Console.WriteLine("This will be VOIDED (immediate cancellation)");
}
else if (txn.SettlementStatus == "Accepted")
{
Console.WriteLine("This will be REFUNDED (funds returned in 3-5 days)");
}
// Then proceed with return
await client.ReturnTransactionAsync(merchantId, transactionId);
Common Use Cases
1. Order Cancellation (Same Day)
Customer cancels order before shipment:
// Cancel the transaction (will be voided if same day) await client.ReturnTransactionAsync(merchantId, transactionId); // Update order status await UpdateOrderStatus(orderId, "Cancelled"); // Notify customer await SendEmail(customerEmail, "Order Cancelled - No Charge");
2. Product Return (After Delivery)
Customer returns product and requests refund:
// Process refund (transaction already settled)
await client.ReturnTransactionAsync(merchantId, transactionId);
// Update inventory
await RestockProduct(productId, quantity);
// Notify customer
await SendEmail(customerEmail,
"Refund Processed - Please allow 3-5 business days for funds to appear");
3. Duplicate Charge
Customer was accidentally charged twice:
// Find duplicate transactions
var duplicates = await FindDuplicateTransactions(orderId);
// Return the duplicate
foreach (var dupTxnId in duplicates.Skip(1))
{
await client.ReturnTransactionAsync(merchantId, dupTxnId);
Console.WriteLine($"Returned duplicate charge: {dupTxnId}");
}
4. Fraudulent Transaction
Transaction flagged as fraudulent:
// Immediately return the transaction await client.ReturnTransactionAsync(merchantId, transactionId); // Flag account await FlagAccountForReview(accountId, "Fraudulent transaction"); // Log incident await LogSecurityIncident(transactionId, "Fraud detected");
5. Customer Service Goodwill Refund
Refunding due to service issue:
// Process goodwill refund
await client.ReturnTransactionAsync(merchantId, transactionId);
// Log the reason
await UpdateTransaction(transactionId, new {
customAttributes = new {
returnReason = "Customer service goodwill refund",
approvedBy = currentUserId,
supportTicket = ticketNumber
}
});
// Notify customer with apology
await SendEmail(customerEmail,
"We apologize for the inconvenience - Full refund processed");
Timing Considerations
- Void window: Usually same business day (before batch closes)
- Refund timing: 3-5 business days for funds to appear on customer's card
- Void window: Very limited or not available (ACH processes in batches)
- Return timing: 5-7 business days for funds to return
- Important: ACH returns can happen up to 60 days after the transaction
Troubleshooting
- The transaction was already voided or refunded
- Check the transaction's settlement status to confirm
- This is not an error - the desired state is achieved
- Inform the user the return was already processed
- The merchant ID doesn't own this transaction
- Verify you're using the correct merchant ID
- The transaction may belong to a different merchant in your organization
- Check transaction ownership using the GET endpoint first
- Refunds take 3-5 business days for credit cards, 5-7 for ACH
- Verify the return was successful by checking settlement status
- Check that the transaction was refunded, not just voided (voided transactions don't show refunds)
- Contact the payment processor if refund is delayed beyond expected timeframe
- This endpoint returns the full transaction amount
- For partial refunds, use the POST refunds endpoint instead
POST /merchants/{merchantId}/transactions/{transactionId}/refunds
Additional Notes
- This endpoint returns the FULL transaction amount - use the refunds endpoint for partial returns
- Returns cannot be undone - ensure you have proper authorization before processing
- The
retdecdatefield in the response indicates when the return was processed - Voided transactions never settled, so funds were never transferred
- Refunded transactions return funds that were already transferred
- The
linkedTransactionIdfield links the refund to the original transaction - Settlement status changes to "Voided" or "Refunded" after successful return
- Always store the correlationId for customer service and troubleshooting
- ACH returns may show as pending for several days before completing