Delete All Saved Payment Methods
Description: Deletes all saved payment methods (credit cards and ACH accounts) for a merchant payor. The payor profile itself remains intact - only the payment methods are removed.
DELETE /v1/rest/merchants/{merchantId}/payors/{payorId} endpoint instead.
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;
using System.Collections.Generic;
using Newtonsoft.Json;
public class SavedPaymentMethodResponse
{
[JsonProperty("responseStatus")]
public string ResponseStatus { get; set; }
[JsonProperty("responseMessage")]
public string ResponseMessage { get; set; }
[JsonProperty("responseResult")]
public string ResponseResult { get; set; }
[JsonProperty("savedPaymentMethodId")]
public string SavedPaymentMethodId { get; set; }
[JsonProperty("isDeleted")]
public bool IsDeleted { get; set; }
[JsonProperty("deletedDate")]
public DateTime? DeletedDate { get; set; }
}
public class PayorClient
{
private readonly HttpClient _httpClient;
private readonly string _baseUrl = "https://your-api-domain.com"; // Replace with actual base URL
private readonly string _bearerToken;
public PayorClient(string bearerToken)
{
_bearerToken = bearerToken;
_httpClient = new HttpClient();
_httpClient.BaseAddress = new Uri(_baseUrl);
// Set the Authorization header with bearer token
_httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", _bearerToken);
// Set Accept header to request JSON
_httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<string> DeleteAllSavedPaymentMethodsAsync(
string merchantId,
string payorId)
{
try
{
// Construct the endpoint URL
string endpoint = $"/v1/rest/merchants/{merchantId}/payors/{payorId}" +
"/savedPaymentMethods";
// Make the DELETE request
HttpResponseMessage response = await _httpClient.DeleteAsync(endpoint);
// Check for partial success (207 Multi-Status)
if (response.StatusCode == System.Net.HttpStatusCode.MultiStatus)
{
string partialResponseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("WARNING: Some payment methods failed to delete.");
Console.WriteLine(partialResponseBody);
return partialResponseBody;
}
// Ensure the request was successful
response.EnsureSuccessStatusCode();
// Read and return the response content as a string
string responseBody = await response.Content.ReadAsStringAsync();
return responseBody;
}
catch (HttpRequestException e)
{
Console.WriteLine($"Request error: {e.Message}");
throw;
}
}
public async Task<(bool Success, int DeletedCount, List<string> Errors)>
DeleteAllWithDetailsAsync(string merchantId, string payorId)
{
try
{
// First, get the list of payment methods to know what we're deleting
var getEndpoint = $"/v1/rest/merchants/{merchantId}/payors/{payorId}" +
"/savedPaymentMethods";
var getResponse = await _httpClient.GetAsync(getEndpoint);
var paymentMethodsJson = await getResponse.Content.ReadAsStringAsync();
var paymentMethods = JsonConvert.DeserializeObject<List<SavedPaymentMethodResponse>>
(paymentMethodsJson);
int originalCount = paymentMethods?.Count ?? 0;
Console.WriteLine($"Found {originalCount} payment method(s) to delete.");
// Confirm with user
Console.Write("Are you sure you want to delete ALL payment methods? (yes/no): ");
string confirmation = Console.ReadLine();
if (confirmation?.ToLower() != "yes")
{
Console.WriteLine("Delete operation cancelled.");
return (false, 0, new List<string> { "Operation cancelled by user" });
}
// Proceed with deletion
var deleteEndpoint = $"/v1/rest/merchants/{merchantId}/payors/{payorId}" +
"/savedPaymentMethods";
var deleteResponse = await _httpClient.DeleteAsync(deleteEndpoint);
var errors = new List<string>();
if (deleteResponse.StatusCode == System.Net.HttpStatusCode.OK)
{
Console.WriteLine($"Successfully deleted all {originalCount} payment method(s).");
return (true, originalCount, errors);
}
else if (deleteResponse.StatusCode == System.Net.HttpStatusCode.MultiStatus)
{
Console.WriteLine("Partial success - some payment methods failed to delete.");
var responseBody = await deleteResponse.Content.ReadAsStringAsync();
errors.Add(responseBody);
return (false, 0, errors);
}
else
{
var errorBody = await deleteResponse.Content.ReadAsStringAsync();
errors.Add($"HTTP {deleteResponse.StatusCode}: {errorBody}");
return (false, 0, errors);
}
}
catch (Exception e)
{
Console.WriteLine($"Error: {e.Message}");
return (false, 0, new List<string> { e.Message });
}
}
}
// Example usage: Simple delete
var client = new PayorClient("your-bearer-token-here");
string result = await client.DeleteAllSavedPaymentMethodsAsync(
"12345678901", // merchantId
"5513027774438108364" // payorId
);
Console.WriteLine(result);
// Example usage: Delete with detailed feedback
var (success, deletedCount, errors) = await client.DeleteAllWithDetailsAsync(
"12345678901", // merchantId
"5513027774438108364" // payorId
);
if (success)
{
Console.WriteLine($"Successfully deleted {deletedCount} payment method(s).");
}
else
{
Console.WriteLine("Deletion failed or partially completed:");
errors.ForEach(error => Console.WriteLine($" - {error}"));
}
Imports System
Imports System.Net.Http
Imports System.Net.Http.Headers
Imports System.Threading.Tasks
Imports System.Collections.Generic
Imports Newtonsoft.Json
Public Class SavedPaymentMethodResponse
<JsonProperty("responseStatus")>
Public Property ResponseStatus As String
<JsonProperty("responseMessage")>
Public Property ResponseMessage As String
<JsonProperty("responseResult")>
Public Property ResponseResult As String
<JsonProperty("savedPaymentMethodId")>
Public Property SavedPaymentMethodId As String
<JsonProperty("isDeleted")>
Public Property IsDeleted As Boolean
<JsonProperty("deletedDate")>
Public Property DeletedDate As DateTime?
End Class
Public Class PayorClient
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 DeleteAllSavedPaymentMethodsAsync( _
merchantId As String, _
payorId As String) As Task(Of String)
Try
Dim endpoint As String = $"/v1/rest/merchants/{merchantId}/payors/{payorId}" & _
"/savedPaymentMethods"
Dim response As HttpResponseMessage = Await _httpClient.DeleteAsync(endpoint)
If response.StatusCode = Net.HttpStatusCode.MultiStatus Then
Dim partialResponseBody As String = Await response.Content.ReadAsStringAsync()
Console.WriteLine("WARNING: Some payment methods failed to delete.")
Console.WriteLine(partialResponseBody)
Return partialResponseBody
End If
response.EnsureSuccessStatusCode()
Dim responseBody As String = Await response.Content.ReadAsStringAsync()
Return responseBody
Catch ex As HttpRequestException
Console.WriteLine($"Request error: {ex.Message}")
Throw
End Try
End Function
Public Async Function DeleteAllWithDetailsAsync( _
merchantId As String, _
payorId As String) As Task(Of (Success As Boolean, DeletedCount As Integer, Errors As List(Of String)))
Try
Dim getEndpoint As String = $"/v1/rest/merchants/{merchantId}/payors/{payorId}" & _
"/savedPaymentMethods"
Dim getResponse As HttpResponseMessage = Await _httpClient.GetAsync(getEndpoint)
Dim paymentMethodsJson As String = Await getResponse.Content.ReadAsStringAsync()
Dim paymentMethods As List(Of SavedPaymentMethodResponse) = _
JsonConvert.DeserializeObject(Of List(Of SavedPaymentMethodResponse))(paymentMethodsJson)
Dim originalCount As Integer = If(paymentMethods IsNot Nothing, paymentMethods.Count, 0)
Console.WriteLine($"Found {originalCount} payment method(s) to delete.")
Console.Write("Are you sure you want to delete ALL payment methods? (yes/no): ")
Dim confirmation As String = Console.ReadLine()
If confirmation?.ToLower() <> "yes" Then
Console.WriteLine("Delete operation cancelled.")
Return (False, 0, New List(Of String) From {"Operation cancelled by user"})
End If
Dim deleteEndpoint As String = $"/v1/rest/merchants/{merchantId}/payors/{payorId}" & _
"/savedPaymentMethods"
Dim deleteResponse As HttpResponseMessage = Await _httpClient.DeleteAsync(deleteEndpoint)
Dim errors As New List(Of String)
If deleteResponse.StatusCode = Net.HttpStatusCode.OK Then
Console.WriteLine($"Successfully deleted all {originalCount} payment method(s).")
Return (True, originalCount, errors)
ElseIf deleteResponse.StatusCode = Net.HttpStatusCode.MultiStatus Then
Console.WriteLine("Partial success - some payment methods failed to delete.")
Dim responseBody As String = Await deleteResponse.Content.ReadAsStringAsync()
errors.Add(responseBody)
Return (False, 0, errors)
Else
Dim errorBody As String = Await deleteResponse.Content.ReadAsStringAsync()
errors.Add($"HTTP {deleteResponse.StatusCode}: {errorBody}")
Return (False, 0, errors)
End If
Catch ex As Exception
Console.WriteLine($"Error: {ex.Message}")
Return (False, 0, New List(Of String) From {ex.Message})
End Try
End Function
End Class
' Example usage: Simple delete
Dim client As New PayorClient("your-bearer-token-here")
Dim result As String = Await client.DeleteAllSavedPaymentMethodsAsync( _
"12345678901", _
"5513027774438108364")
Console.WriteLine(result)
' Example usage: Delete with detailed feedback
Dim deleteResult = Await client.DeleteAllWithDetailsAsync( _
"12345678901", _
"5513027774438108364")
If deleteResult.Success Then
Console.WriteLine($"Successfully deleted {deleteResult.DeletedCount} payment method(s).")
Else
Console.WriteLine("Deletion failed or partially completed:")
For Each errorMsg In deleteResult.Errors
Console.WriteLine($" - {errorMsg}")
Next
End If
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
public class SavedPaymentMethodResponse {
@JsonProperty("responseStatus")
private String responseStatus;
@JsonProperty("responseMessage")
private String responseMessage;
@JsonProperty("responseResult")
private String responseResult;
@JsonProperty("savedPaymentMethodId")
private String savedPaymentMethodId;
@JsonProperty("isDeleted")
private boolean isDeleted;
@JsonProperty("deletedDate")
private String deletedDate;
// Getters and setters omitted for brevity
}
public class PayorClient {
private final HttpClient httpClient;
private final String baseUrl = "https://your-api-domain.com";
private final String bearerToken;
private final ObjectMapper objectMapper;
public PayorClient(String bearerToken) {
this.bearerToken = bearerToken;
this.httpClient = HttpClient.newHttpClient();
this.objectMapper = new ObjectMapper();
}
public String deleteAllSavedPaymentMethods(String merchantId, String payorId)
throws IOException, InterruptedException {
try {
String endpoint = String.format("/v1/rest/merchants/%s/payors/%s/savedPaymentMethods",
merchantId, payorId);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + endpoint))
.header("Authorization", "Bearer " + bearerToken)
.header("Accept", "application/json")
.DELETE()
.build();
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 207) {
System.out.println("WARNING: Some payment methods failed to delete.");
System.out.println(response.body());
return response.body();
}
if (response.statusCode() < 200 || response.statusCode() >= 300) {
throw new IOException("HTTP " + response.statusCode() + ": " + response.body());
}
return response.body();
} catch (IOException | InterruptedException e) {
System.err.println("Request error: " + e.getMessage());
throw e;
}
}
public DeleteResult deleteAllWithDetails(String merchantId, String payorId)
throws IOException, InterruptedException {
try {
// First, get the list of payment methods
String getEndpoint = String.format("/v1/rest/merchants/%s/payors/%s/savedPaymentMethods",
merchantId, payorId);
HttpRequest getRequest = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + getEndpoint))
.header("Authorization", "Bearer " + bearerToken)
.header("Accept", "application/json")
.GET()
.build();
HttpResponse<String> getResponse = httpClient.send(getRequest,
HttpResponse.BodyHandlers.ofString());
SavedPaymentMethodResponse[] paymentMethods = objectMapper.readValue(
getResponse.body(), SavedPaymentMethodResponse[].class);
int originalCount = paymentMethods != null ? paymentMethods.length : 0;
System.out.println("Found " + originalCount + " payment method(s) to delete.");
// Confirm with user
Scanner scanner = new Scanner(System.in);
System.out.print("Are you sure you want to delete ALL payment methods? (yes/no): ");
String confirmation = scanner.nextLine();
if (!"yes".equalsIgnoreCase(confirmation)) {
System.out.println("Delete operation cancelled.");
List<String> errors = new ArrayList<>();
errors.add("Operation cancelled by user");
return new DeleteResult(false, 0, errors);
}
// Proceed with deletion
String deleteEndpoint = String.format("/v1/rest/merchants/%s/payors/%s/savedPaymentMethods",
merchantId, payorId);
HttpRequest deleteRequest = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + deleteEndpoint))
.header("Authorization", "Bearer " + bearerToken)
.header("Accept", "application/json")
.DELETE()
.build();
HttpResponse<String> deleteResponse = httpClient.send(deleteRequest,
HttpResponse.BodyHandlers.ofString());
List<String> errors = new ArrayList<>();
if (deleteResponse.statusCode() == 200) {
System.out.println("Successfully deleted all " + originalCount + " payment method(s).");
return new DeleteResult(true, originalCount, errors);
} else if (deleteResponse.statusCode() == 207) {
System.out.println("Partial success - some payment methods failed to delete.");
errors.add(deleteResponse.body());
return new DeleteResult(false, 0, errors);
} else {
errors.add("HTTP " + deleteResponse.statusCode() + ": " + deleteResponse.body());
return new DeleteResult(false, 0, errors);
}
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
List<String> errors = new ArrayList<>();
errors.add(e.getMessage());
return new DeleteResult(false, 0, errors);
}
}
public static class DeleteResult {
public final boolean success;
public final int deletedCount;
public final List<String> errors;
public DeleteResult(boolean success, int deletedCount, List<String> errors) {
this.success = success;
this.deletedCount = deletedCount;
this.errors = errors;
}
}
}
// Example usage: Simple delete
PayorClient client = new PayorClient("your-bearer-token-here");
String result = client.deleteAllSavedPaymentMethods(
"12345678901",
"5513027774438108364"
);
System.out.println(result);
// Example usage: Delete with detailed feedback
PayorClient.DeleteResult deleteResult = client.deleteAllWithDetails(
"12345678901",
"5513027774438108364"
);
if (deleteResult.success) {
System.out.println("Successfully deleted " + deleteResult.deletedCount + " payment method(s).");
} else {
System.out.println("Deletion failed or partially completed:");
for (String error : deleteResult.errors) {
System.out.println(" - " + error);
}
}
require 'net/http'
require 'uri'
require 'json'
require 'io/console'
class SavedPaymentMethodResponse
attr_accessor :response_status, :response_message, :response_result,
:saved_payment_method_id, :is_deleted, :deleted_date
def initialize(data)
@response_status = data['responseStatus']
@response_message = data['responseMessage']
@response_result = data['responseResult']
@saved_payment_method_id = data['savedPaymentMethodId']
@is_deleted = data['isDeleted']
@deleted_date = data['deletedDate']
end
end
class PayorClient
def initialize(bearer_token)
@bearer_token = bearer_token
@base_url = 'https://your-api-domain.com'
end
def delete_all_saved_payment_methods(merchant_id, payor_id)
endpoint = "/v1/rest/merchants/#{merchant_id}/payors/#{payor_id}" +
'/savedPaymentMethods'
uri = URI("#{@base_url}#{endpoint}")
request = Net::HTTP::Delete.new(uri)
request['Authorization'] = "Bearer #{@bearer_token}"
request['Accept'] = 'application/json'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
if response.code == '207'
puts 'WARNING: Some payment methods failed to delete.'
puts response.body
return response.body
end
unless response.is_a?(Net::HTTPSuccess)
raise "HTTP #{response.code}: #{response.body}"
end
response.body
rescue StandardError => e
puts "Request error: #{e.message}"
raise
end
def delete_all_with_details(merchant_id, payor_id)
# First, get the list of payment methods
get_endpoint = "/v1/rest/merchants/#{merchant_id}/payors/#{payor_id}" +
'/savedPaymentMethods'
get_uri = URI("#{@base_url}#{get_endpoint}")
get_request = Net::HTTP::Get.new(get_uri)
get_request['Authorization'] = "Bearer #{@bearer_token}"
get_request['Accept'] = 'application/json'
get_response = Net::HTTP.start(get_uri.hostname, get_uri.port, use_ssl: true) do |http|
http.request(get_request)
end
payment_methods = JSON.parse(get_response.body).map do |pm|
SavedPaymentMethodResponse.new(pm)
end
original_count = payment_methods.length
puts "Found #{original_count} payment method(s) to delete."
# Confirm with user
print 'Are you sure you want to delete ALL payment methods? (yes/no): '
confirmation = gets.chomp
unless confirmation.downcase == 'yes'
puts 'Delete operation cancelled.'
return { success: false, deleted_count: 0, errors: ['Operation cancelled by user'] }
end
# Proceed with deletion
delete_endpoint = "/v1/rest/merchants/#{merchant_id}/payors/#{payor_id}" +
'/savedPaymentMethods'
delete_uri = URI("#{@base_url}#{delete_endpoint}")
delete_request = Net::HTTP::Delete.new(delete_uri)
delete_request['Authorization'] = "Bearer #{@bearer_token}"
delete_request['Accept'] = 'application/json'
delete_response = Net::HTTP.start(delete_uri.hostname, delete_uri.port, use_ssl: true) do |http|
http.request(delete_request)
end
errors = []
case delete_response.code
when '200'
puts "Successfully deleted all #{original_count} payment method(s)."
{ success: true, deleted_count: original_count, errors: errors }
when '207'
puts 'Partial success - some payment methods failed to delete.'
errors << delete_response.body
{ success: false, deleted_count: 0, errors: errors }
else
errors << "HTTP #{delete_response.code}: #{delete_response.body}"
{ success: false, deleted_count: 0, errors: errors }
end
rescue StandardError => e
puts "Error: #{e.message}"
{ success: false, deleted_count: 0, errors: [e.message] }
end
end
# Example usage: Simple delete
client = PayorClient.new('your-bearer-token-here')
result = client.delete_all_saved_payment_methods(
'12345678901',
'5513027774438108364'
)
puts result
# Example usage: Delete with detailed feedback
delete_result = client.delete_all_with_details(
'12345678901',
'5513027774438108364'
)
if delete_result[:success]
puts "Successfully deleted #{delete_result[:deleted_count]} payment method(s)."
else
puts 'Deletion failed or partially completed:'
delete_result[:errors].each do |error|
puts " - #{error}"
end
end
Response Format
The response returns details about the deleted payment methods. The exact format follows the SavedPaymentMethodResponse schema.
Success Response (HTTP 200)
{
"responseStatus": "SavedPaymentMethodDeleted",
"responseMessage": "All saved payment methods deleted successfully",
"responseCode": "200",
"responseReason": null,
"responseResult": "success",
"legacyResponseCode": "A",
"correlationId": "delete-all-123-456",
"payorId": "5513027774438108364",
"savedPaymentMethodId": null,
"deletedDate": "2026-04-02T15:30:00Z"
}
Partial Success Response (HTTP 207)
When some payment methods fail to delete, you'll receive a 207 Multi-Status response:
{
"responseStatus": "PartialSuccess",
"responseMessage": "Some payment methods failed to delete",
"responseCode": "207",
"responseReason": "2 of 5 payment methods were deleted successfully",
"responseResult": "retry",
"correlationId": "partial-207-789-012",
"payorId": "5513027774438108364",
"deletedCount": 2,
"failedCount": 3,
"errors": [
{
"savedPaymentMethodId": "5513027774438108366",
"error": "Payment method is locked due to pending transaction"
},
{
"savedPaymentMethodId": "5513027774438108367",
"error": "Payment method is associated with active recurring payment"
},
{
"savedPaymentMethodId": "5513027774438108368",
"error": "Unable to process deletion request"
}
]
}
HTTP Status Codes
| Status Code | Description |
|---|---|
| 200 | Success - All saved payment methods deleted successfully |
| 207 | Multi-Status - Some payment methods were deleted successfully, but others failed |
| 400 | Bad Request - Invalid merchantId or payorId format |
| 404 | Not Found - Payor with the specified ID does not exist for this merchant |
| 500 | Internal Server Error - Server encountered an unexpected error |
Error Responses
Not Found Error (HTTP 404)
{
"responseStatus": "NotFound",
"responseMessage": "Payor not found",
"responseCode": "404",
"responseReason": "No payor exists with the specified ID for this merchant",
"responseResult": "failure",
"correlationId": "error-404-123-456"
}
Bad Request Error (HTTP 400)
{
"responseStatus": "BadRequest",
"responseMessage": "Invalid request parameters",
"responseCode": "400",
"responseReason": "Merchant ID must be exactly 11 digits",
"responseResult": "failure",
"correlationId": "error-400-789-012"
}
What Gets Deleted
When you delete all saved payment methods for a payor:
- All Credit Cards: All saved credit card payment methods are deleted
- All ACH Accounts: All saved checking and savings accounts are deleted
- Default Payment Method: The default payment method designation is cleared
- BIN Information: Associated BIN data is removed
- Custom Metadata: Any custom data associated with the payment methods is deleted
What is NOT deleted:
- Payor Profile: The payor record itself remains active and unchanged
- Transaction History: Past transactions using these payment methods are preserved
- Payor Metadata: Custom data on the payor profile is retained
After Deletion
After successfully deleting all payment methods:
- The payor profile remains active with
isDeleted: false - The
savedPaymentMethodIdsarray will be empty - The
defaultSavedPaymentMethodIdwill be null - The payor can still be used to create new payment methods
- The payor cannot process transactions until new payment methods are added
Understanding Multi-Status (207) Responses
A 207 Multi-Status response indicates that the deletion operation was only partially successful. This can happen when:
- Some payment methods are locked due to pending transactions
- Some payment methods are associated with active recurring payments
- Network issues occur during the deletion of some payment methods
- Some payment methods have downstream dependencies
Recommended Action: Review the error details in the response, resolve the issues (e.g., wait for pending transactions to complete), and retry the deletion.
Best Practices
1. Always Confirm Before Deleting
Show the user how many payment methods will be deleted and require explicit confirmation. Consider displaying the masked account numbers so users know what they're deleting.
// Example confirmation with details
var paymentMethods = await GetSavedPaymentMethodsAsync(merchantId, payorId);
Console.WriteLine("You are about to delete the following payment methods:");
foreach (var pm in paymentMethods)
{
Console.WriteLine($" - {pm.AccountType} ending in {pm.LastFour}");
}
Console.WriteLine($"\nTotal: {paymentMethods.Count} payment method(s)");
Console.Write("\nType 'DELETE ALL' to confirm: ");
if (Console.ReadLine() == "DELETE ALL")
{
await DeleteAllSavedPaymentMethodsAsync(merchantId, payorId);
}
2. Check for Active Subscriptions First
Before deleting all payment methods, verify there are no active recurring payments or scheduled transactions that depend on these payment methods.
// Check for active subscriptions before deletion
var activeSubscriptions = await GetActiveSubscriptionsAsync(payorId);
if (activeSubscriptions.Any())
{
Console.WriteLine("ERROR: Cannot delete payment methods.");
Console.WriteLine($"This payor has {activeSubscriptions.Count} active subscription(s).");
Console.WriteLine("Cancel or reassign subscriptions before deleting payment methods.");
return;
}
// Safe to proceed with deletion
await DeleteAllSavedPaymentMethodsAsync(merchantId, payorId);
3. Handle 207 Multi-Status Properly
Don't treat 207 as a complete failure. Some payment methods may have been successfully deleted. Parse the response to determine which ones failed and why.
if (response.StatusCode == HttpStatusCode.MultiStatus)
{
var result = JsonConvert.DeserializeObject<PartialDeleteResponse>(responseBody);
Console.WriteLine($"Deleted: {result.DeletedCount} payment method(s)");
Console.WriteLine($"Failed: {result.FailedCount} payment method(s)");
foreach (var error in result.Errors)
{
Console.WriteLine($" - {error.SavedPaymentMethodId}: {error.Error}");
}
// Allow user to retry failed deletions
Console.Write("\nRetry failed deletions? (yes/no): ");
if (Console.ReadLine()?.ToLower() == "yes")
{
await RetryFailedDeletionsAsync(merchantId, payorId, result.Errors);
}
}
4. Provide Alternative: Delete Individual Payment Methods
Instead of deleting all payment methods, consider offering the option to delete them individually. This gives users more control and reduces the risk of accidentally deleting payment methods they want to keep.
5. Log All Deletion Operations
Maintain an audit trail of all bulk payment method deletions:
await AuditLog.LogAsync(new AuditEntry
{
Action = "DeleteAllSavedPaymentMethods",
UserId = currentUserId,
MerchantId = merchantId,
PayorId = payorId,
PaymentMethodCount = paymentMethods.Count,
Timestamp = DateTime.UtcNow,
CorrelationId = response.CorrelationId
});
6. Update UI and Cache
After successful deletion, ensure your UI reflects the changes:
- Clear any cached payment method data
- Update the payor's payment method list to show empty state
- Disable any "Pay Now" buttons that require a payment method
- Show a prompt to add a new payment method
Common Use Cases
1. Compromised Account Security
When a customer reports their account may be compromised:
// Security incident response - remove all payment methods await DeleteAllSavedPaymentMethodsAsync(merchantId, payorId); await SendSecurityAlertEmail(customerEmail); await LogSecurityIncident(payorId, "Payment methods removed due to security concern"); // Require re-authentication before adding new payment methods await SetPayorRequireReauth(payorId, true);
2. Customer Requested Payment Method Reset
When a customer wants to start fresh with new payment methods:
// Clean slate - remove all old payment methods
Console.WriteLine("Removing all existing payment methods...");
await DeleteAllSavedPaymentMethodsAsync(merchantId, payorId);
Console.WriteLine("Payment methods removed. Ready to add new payment methods.");
// Redirect user to add payment method flow
3. Expired or Invalid Payment Methods Cleanup
When all payment methods are expired or invalid:
// Check if all payment methods are expired
var paymentMethods = await GetSavedPaymentMethodsAsync(merchantId, payorId);
var allExpired = paymentMethods.All(pm => IsExpired(pm));
if (allExpired)
{
Console.WriteLine("All payment methods are expired. Removing all...");
await DeleteAllSavedPaymentMethodsAsync(merchantId, payorId);
await NotifyCustomerToAddNewPaymentMethod(customerEmail);
}
4. Merchant Account Type Change
When switching between different merchant processors that require different tokenization:
// Migrate to new payment processor
Console.WriteLine("Preparing to migrate to new payment processor...");
// Export transaction history first
await ExportTransactionHistory(merchantId, payorId);
// Remove all payment methods (old tokens won't work with new processor)
await DeleteAllSavedPaymentMethodsAsync(merchantId, payorId);
// Update merchant processor configuration
await UpdateMerchantProcessor(merchantId, newProcessorId);
Console.WriteLine("Migration complete. Customers need to re-add payment methods.");
5. Batch Cleanup During Testing
When cleaning up test data:
// Batch cleanup of test payor payment methods
var testPayors = await GetTestPayorsAsync(merchantId);
Console.WriteLine($"Cleaning up {testPayors.Count} test payor(s)...");
int successCount = 0;
int failureCount = 0;
foreach (var payorId in testPayors)
{
try
{
await DeleteAllSavedPaymentMethodsAsync(merchantId, payorId);
successCount++;
Console.WriteLine($"✓ Cleaned payor {payorId}");
}
catch (Exception ex)
{
failureCount++;
Console.WriteLine($"✗ Failed to clean payor {payorId}: {ex.Message}");
}
}
Console.WriteLine($"\nCleanup complete: {successCount} success, {failureCount} failed");
Comparison with Related Endpoints
| Endpoint | What Gets Deleted | Payor Retained? |
|---|---|---|
DELETE /merchants/{merchantId}/payors/{payorId} |
Payor + ALL payment methods | No (soft-deleted) |
DELETE /merchants/{merchantId}/payors/{payorId}/savedPaymentMethods |
ALL payment methods only | Yes |
DELETE /merchants/{merchantId}/payors/{payorId}/savedPaymentMethods/{id} |
Single payment method | Yes |
Troubleshooting
- Some payment methods may be locked due to pending transactions - wait for transactions to complete
- Some payment methods may be associated with active recurring payments - cancel or reassign subscriptions
- Review the error details in the response to identify which payment methods failed and why
- Retry the operation after resolving the issues, or delete failed payment methods individually
- Verify the payorId exists and belongs to the specified merchant
- Check that the merchantId is correct (must be exactly 11 digits)
- The payor may have been deleted - check the payor's isDeleted status
- Verify you're using the correct environment (production vs. sandbox)
- Clear your application's cache - payment method data may be cached
- Verify the deletion was successful by making a fresh GET request
- Check if you're looking at the correct payor (verify payorId)
- Some UIs may display historical payment methods - ensure you're filtering by isDeleted status
- Wait for pending transactions to settle or complete
- Check transaction status using the transactions endpoint
- Contact support if transactions remain pending for an extended period
- Consider canceling pending transactions first (if appropriate)
Recovery from Accidental Deletion
- Contact Procare Pay support immediately
- Provide the
correlationIdfrom the delete response - Provide the
merchantIdandpayorId - Recovery is not guaranteed - payment methods may need to be re-added manually
- The customer will need to provide their payment information again
Security Considerations
- Authorization: Ensure the user has permission to delete payment methods for this payor
- Confirmation Required: Always require explicit user confirmation before bulk deletion
- Audit Logging: Log who deleted the payment methods, when, and why
- Rate Limiting: Monitor for unusual bulk deletion patterns that might indicate abuse
- Customer Notification: Consider notifying the account holder when all payment methods are removed
- Session Validation: Require recent authentication before allowing bulk deletions
- Dependent Resource Check: Verify no active subscriptions or scheduled payments depend on these payment methods
Additional Notes
- The
merchantIdmust be exactly 11 digits. Requests with invalid formats will return a 400 Bad Request error. - This operation deletes ALL payment methods - there is no way to selectively exclude certain payment methods using this endpoint.
- To delete individual payment methods, use the
DELETE /v1/rest/merchants/{merchantId}/payors/{payorId}/savedPaymentMethods/{savedPaymentMethodId}endpoint. - The payor profile remains active after deletion - the payor can still be used to create new payment methods.
- Transaction history is preserved even after payment method deletion.
- The
correlationIdin the response should be logged for troubleshooting purposes. - After deletion, the payor cannot process transactions until new payment methods are added.
- A 207 Multi-Status response is not a complete failure - some payment methods may have been deleted successfully.
- This endpoint is particularly useful for security incidents where all payment data needs to be cleared immediately.
Related Endpoints
- GET /v1/rest/merchants/{merchantId}/payors/{payorId}/savedPaymentMethods - List all payment methods (to see what will be deleted)
- DELETE /v1/rest/merchants/{merchantId}/payors/{payorId}/savedPaymentMethods/{savedPaymentMethodId} - Delete a single payment method
- DELETE /v1/rest/merchants/{merchantId}/payors/{payorId} - Delete payor and all payment methods together
- POST /v1/rest/merchants/{merchantId}/payors/{payorId}/savedPaymentMethods - Add new payment methods after deletion