Procare Pay Integration Service

Complete API Documentation for Payment Processing

Update Saved Payment Method

PUT /v1/rest/merchants/{merchantId}/payors/{payorId}/savedPaymentMethods/{savedPaymentMethodId}

Description: Updates a saved payment method for the specified merchant, payor, and payment method. This endpoint allows you to update account holder information, billing address, and other payment method details.

What can be updated: This endpoint supports updating account holder information (name, address, email, phone), card expiration dates, default payment method status, and custom metadata. You cannot change the account number itself - to use a different account number, delete this payment method and create a new one.

Path Parameters

merchantId (required)
Type: string
Pattern: Must be an 11-digit number (e.g., "12345678901")
Description: The 11-digit merchant identifier
payorId (required)
Type: string
Description: The unique payor identifier
savedPaymentMethodId (required)
Type: string
Description: The unique identifier for the saved payment method to update

Authentication

This endpoint requires bearer token authentication using the Authorization header.

Note: The bearer token must be a valid Cognito token.

Request Body Fields

Field Type Required Description
idLimitedBitFlag boolean Optional Indicates whether IDs use 64-bit integer format (true) or GUID format (false)
paymentMethodType string Optional The payment method type: "Checking", "Saving", "CreditCard", or "Null". Used when updating to specify the account type.
customerAccountType string Optional User-defined external account type (e.g., "Primary", "Backup", "Business")
customerAccountId string Optional The external customer ID for the payor profile
encryptedAccountNumber string Optional Encrypted account number (credit card or bank account). If you need to change the account number, create a new payment method instead of updating.
cardExpiry string Optional Credit card expiration in MMyy, MMyyyy, or yyyyMMdd format. Required for credit cards, not applicable for ACH.
abaRoutingNumber string Optional Bank routing (ABA) number for ACH accounts. Required for ACH, not applicable for credit cards.
accountHolderFirstName string Optional The first name of the account holder
accountHolderLastName string Optional The last name of the account holder
accountHolderStreetLine1 string Optional The first line of the billing street address
accountHolderStreetLine2 string Optional The second line of the billing street address (apartment, suite, etc.)
accountHolderCity string Optional The billing address city
accountHolderRegion string Optional The billing address region/state/province
accountHolderPostalCode string Optional The billing address postal/ZIP code
accountHolderPhoneNumber string Optional The account holder's phone number
accountHolderEmail string Optional The account holder's email address
setAsDefaultPaymentMethod boolean Optional Set to true to make this payment method the default for this payor. Default: false
customerData object Optional Key-value pairs for storing custom metadata (e.g., {"notes": "Updated card", "priority": "high"})
sponsorKey string Optional Sponsor key (max 8 characters). Must not be empty string if provided.
allowTransactionalEmails boolean Optional Whether to allow transactional emails. Automatically set to false if email is null/empty.
Important: All fields in the request body are optional, but you should include all fields you want to keep. The update operation may replace existing values, so include the current values for fields you don't want to change.

Code Examples

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

public class SavedPaymentMethodUpdateRequest
{
    [JsonProperty("cardExpiry")]
    public string CardExpiry { get; set; }

    [JsonProperty("accountHolderFirstName")]
    public string AccountHolderFirstName { get; set; }

    [JsonProperty("accountHolderLastName")]
    public string AccountHolderLastName { get; set; }

    [JsonProperty("accountHolderStreetLine1")]
    public string AccountHolderStreetLine1 { get; set; }

    [JsonProperty("accountHolderStreetLine2")]
    public string AccountHolderStreetLine2 { get; set; }

    [JsonProperty("accountHolderCity")]
    public string AccountHolderCity { get; set; }

    [JsonProperty("accountHolderRegion")]
    public string AccountHolderRegion { get; set; }

    [JsonProperty("accountHolderPostalCode")]
    public string AccountHolderPostalCode { get; set; }

    [JsonProperty("accountHolderPhoneNumber")]
    public string AccountHolderPhoneNumber { get; set; }

    [JsonProperty("accountHolderEmail")]
    public string AccountHolderEmail { get; set; }

    [JsonProperty("setAsDefaultPaymentMethod")]
    public bool SetAsDefaultPaymentMethod { get; set; }

    [JsonProperty("customerData")]
    public Dictionary<string, string> CustomerData { get; set; }

    [JsonProperty("sponsorKey")]
    public string SponsorKey { get; set; }

    [JsonProperty("allowTransactionalEmails")]
    public bool AllowTransactionalEmails { get; set; }
}

public class SavedPaymentMethodClient
{
    private readonly HttpClient _httpClient;
    private readonly string _baseUrl = "https://your-api-domain.com"; // Replace with actual base URL
    private readonly string _bearerToken;

    public SavedPaymentMethodClient(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> UpdateSavedPaymentMethodAsync(
        string merchantId,
        string payorId,
        string savedPaymentMethodId,
        SavedPaymentMethodUpdateRequest updateRequest)
    {
        try
        {
            // Construct the endpoint URL
            string endpoint = $"/v1/rest/merchants/{merchantId}/payors/{payorId}" +
                            $"/savedPaymentMethods/{savedPaymentMethodId}";

            // Serialize the request object to JSON
            string jsonContent = JsonConvert.SerializeObject(
                updateRequest,
                Formatting.None,
                new JsonSerializerSettings
                {
                    NullValueHandling = NullValueHandling.Ignore
                });

            var content = new StringContent(
                jsonContent,
                Encoding.UTF8,
                "application/json");

            // Make the PUT request
            HttpResponseMessage response = await _httpClient.PutAsync(endpoint, content);

            // 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;
        }
    }
}

// Example usage: Update credit card expiration date and billing address
var updateRequest = new SavedPaymentMethodUpdateRequest
{
    CardExpiry = "1227",  // December 2027
    AccountHolderFirstName = "John",
    AccountHolderLastName = "Doe",
    AccountHolderStreetLine1 = "456 New Address Ave",
    AccountHolderStreetLine2 = "Suite 100",
    AccountHolderCity = "Chicago",
    AccountHolderRegion = "IL",
    AccountHolderPostalCode = "60601",
    AccountHolderPhoneNumber = "555-987-6543",
    AccountHolderEmail = "john.doe@newdomain.com",
    SetAsDefaultPaymentMethod = true,
    CustomerData = new Dictionary<string, string>
    {
        { "notes", "Updated card expiration and address" },
        { "lastModifiedBy", "CustomerService" }
    },
    AllowTransactionalEmails = true
};

var client = new SavedPaymentMethodClient("your-bearer-token-here");
string result = await client.UpdateSavedPaymentMethodAsync(
    "12345678901",              // merchantId
    "5513027774438108364",      // payorId
    "5513027774438108365",      // savedPaymentMethodId
    updateRequest
);
Console.WriteLine(result);
Imports System
Imports System.Net.Http
Imports System.Net.Http.Headers
Imports System.Text
Imports System.Threading.Tasks
Imports System.Collections.Generic
Imports Newtonsoft.Json

Public Class SavedPaymentMethodUpdateRequest
    <JsonProperty("cardExpiry")>
    Public Property CardExpiry As String

    <JsonProperty("accountHolderFirstName")>
    Public Property AccountHolderFirstName As String

    <JsonProperty("accountHolderLastName")>
    Public Property AccountHolderLastName As String

    <JsonProperty("accountHolderStreetLine1")>
    Public Property AccountHolderStreetLine1 As String

    <JsonProperty("accountHolderStreetLine2")>
    Public Property AccountHolderStreetLine2 As String

    <JsonProperty("accountHolderCity")>
    Public Property AccountHolderCity As String

    <JsonProperty("accountHolderRegion")>
    Public Property AccountHolderRegion As String

    <JsonProperty("accountHolderPostalCode")>
    Public Property AccountHolderPostalCode As String

    <JsonProperty("accountHolderPhoneNumber")>
    Public Property AccountHolderPhoneNumber As String

    <JsonProperty("accountHolderEmail")>
    Public Property AccountHolderEmail As String

    <JsonProperty("setAsDefaultPaymentMethod")>
    Public Property SetAsDefaultPaymentMethod As Boolean

    <JsonProperty("customerData")>
    Public Property CustomerData As Dictionary(Of String, String)

    <JsonProperty("sponsorKey")>
    Public Property SponsorKey As String

    <JsonProperty("allowTransactionalEmails")>
    Public Property AllowTransactionalEmails As Boolean
End Class

Public Class SavedPaymentMethodClient
    Private ReadOnly _httpClient As HttpClient
    Private ReadOnly _baseUrl As String = "https://your-api-domain.com" ' Replace with actual base URL
    Private ReadOnly _bearerToken As String

    Public Sub New(bearerToken As String)
        _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"))
    End Sub

    Public Async Function UpdateSavedPaymentMethodAsync(
        merchantId As String,
        payorId As String,
        savedPaymentMethodId As String,
        updateRequest As SavedPaymentMethodUpdateRequest) As Task(Of String)

        Try
            ' Construct the endpoint URL
            Dim endpoint As String = $"/v1/rest/merchants/{merchantId}/payors/{payorId}" & _
                                    $"/savedPaymentMethods/{savedPaymentMethodId}"

            ' Serialize the request object to JSON
            Dim jsonContent As String = JsonConvert.SerializeObject(
                updateRequest,
                Formatting.None,
                New JsonSerializerSettings With {
                    .NullValueHandling = NullValueHandling.Ignore
                })

            Dim content = New StringContent(
                jsonContent,
                Encoding.UTF8,
                "application/json")

            ' Make the PUT request
            Dim response As HttpResponseMessage = Await _httpClient.PutAsync(endpoint, content)

            ' Ensure the request was successful
            response.EnsureSuccessStatusCode()

            ' Read and return the response content as a string
            Dim responseBody As String = Await response.Content.ReadAsStringAsync()
            Return responseBody

        Catch e As HttpRequestException
            Console.WriteLine($"Request error: {e.Message}")
            Throw
        End Try
    End Function
End Class

' Example usage: Update credit card expiration date and billing address
Dim updateRequest As New SavedPaymentMethodUpdateRequest With {
    .CardExpiry = "1227",
    .AccountHolderFirstName = "John",
    .AccountHolderLastName = "Doe",
    .AccountHolderStreetLine1 = "456 New Address Ave",
    .AccountHolderStreetLine2 = "Suite 100",
    .AccountHolderCity = "Chicago",
    .AccountHolderRegion = "IL",
    .AccountHolderPostalCode = "60601",
    .AccountHolderPhoneNumber = "555-987-6543",
    .AccountHolderEmail = "john.doe@newdomain.com",
    .SetAsDefaultPaymentMethod = True,
    .CustomerData = New Dictionary(Of String, String) From {
        {"notes", "Updated card expiration and address"},
        {"lastModifiedBy", "CustomerService"}
    },
    .AllowTransactionalEmails = True
}

Dim client As New SavedPaymentMethodClient("your-bearer-token-here")
Dim result As String = Await client.UpdateSavedPaymentMethodAsync(
    "12345678901",              ' merchantId
    "5513027774438108364",      ' payorId
    "5513027774438108365",      ' savedPaymentMethodId
    updateRequest
)
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;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;

class SavedPaymentMethodUpdateRequest {
    @JsonProperty("cardExpiry")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String cardExpiry;

    @JsonProperty("accountHolderFirstName")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String accountHolderFirstName;

    @JsonProperty("accountHolderLastName")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String accountHolderLastName;

    @JsonProperty("accountHolderStreetLine1")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String accountHolderStreetLine1;

    @JsonProperty("accountHolderStreetLine2")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String accountHolderStreetLine2;

    @JsonProperty("accountHolderCity")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String accountHolderCity;

    @JsonProperty("accountHolderRegion")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String accountHolderRegion;

    @JsonProperty("accountHolderPostalCode")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String accountHolderPostalCode;

    @JsonProperty("accountHolderPhoneNumber")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String accountHolderPhoneNumber;

    @JsonProperty("accountHolderEmail")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String accountHolderEmail;

    @JsonProperty("setAsDefaultPaymentMethod")
    private boolean setAsDefaultPaymentMethod;

    @JsonProperty("customerData")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private Map<String, String> customerData;

    @JsonProperty("sponsorKey")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String sponsorKey;

    @JsonProperty("allowTransactionalEmails")
    private boolean allowTransactionalEmails;

    // Getters and setters
    public void setCardExpiry(String cardExpiry) { this.cardExpiry = cardExpiry; }
    public void setAccountHolderFirstName(String name) { this.accountHolderFirstName = name; }
    public void setAccountHolderLastName(String name) { this.accountHolderLastName = name; }
    public void setAccountHolderStreetLine1(String street) { this.accountHolderStreetLine1 = street; }
    public void setAccountHolderStreetLine2(String street) { this.accountHolderStreetLine2 = street; }
    public void setAccountHolderCity(String city) { this.accountHolderCity = city; }
    public void setAccountHolderRegion(String region) { this.accountHolderRegion = region; }
    public void setAccountHolderPostalCode(String postalCode) { this.accountHolderPostalCode = postalCode; }
    public void setAccountHolderPhoneNumber(String phone) { this.accountHolderPhoneNumber = phone; }
    public void setAccountHolderEmail(String email) { this.accountHolderEmail = email; }
    public void setSetAsDefaultPaymentMethod(boolean isDefault) { this.setAsDefaultPaymentMethod = isDefault; }
    public void setCustomerData(Map<String, String> data) { this.customerData = data; }
    public void setSponsorKey(String key) { this.sponsorKey = key; }
    public void setAllowTransactionalEmails(boolean allow) { this.allowTransactionalEmails = allow; }
}

public class SavedPaymentMethodClient {
    private final HttpClient httpClient;
    private final String baseUrl;
    private final String bearerToken;
    private final ObjectMapper objectMapper;

    public SavedPaymentMethodClient(String baseUrl, String bearerToken) {
        this.baseUrl = baseUrl;
        this.bearerToken = bearerToken;
        this.httpClient = HttpClient.newHttpClient();
        this.objectMapper = new ObjectMapper();
    }

    public String updateSavedPaymentMethod(
            String merchantId,
            String payorId,
            String savedPaymentMethodId,
            SavedPaymentMethodUpdateRequest updateRequest)
            throws IOException, InterruptedException {
        try {
            // Construct the endpoint URL
            String endpoint = String.format("%s/v1/rest/merchants/%s/payors/%s/savedPaymentMethods/%s",
                baseUrl, merchantId, payorId, savedPaymentMethodId);

            // Serialize the request object to JSON
            String jsonContent = objectMapper.writeValueAsString(updateRequest);

            // Build the HTTP request
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(endpoint))
                    .header("Authorization", "Bearer " + bearerToken)
                    .header("Accept", "application/json")
                    .header("Content-Type", "application/json")
                    .PUT(HttpRequest.BodyPublishers.ofString(jsonContent))
                    .build();

            // Send the request and get response
            HttpResponse<String> response = httpClient.send(request,
                HttpResponse.BodyHandlers.ofString());

            // Check if request was successful (status code 200-299)
            if (response.statusCode() < 200 || response.statusCode() >= 300) {
                throw new RuntimeException("HTTP Error: " + response.statusCode() +
                    " - " + response.body());
            }

            // Return the response body
            return response.body();

        } catch (IOException | InterruptedException e) {
            System.err.println("Request error: " + e.getMessage());
            throw e;
        }
    }

    // Example usage
    public static void main(String[] args) {
        try {
            SavedPaymentMethodClient client = new SavedPaymentMethodClient(
                "https://your-api-domain.com",
                "your-bearer-token-here"
            );

            SavedPaymentMethodUpdateRequest updateRequest = new SavedPaymentMethodUpdateRequest();
            updateRequest.setCardExpiry("1227");
            updateRequest.setAccountHolderFirstName("John");
            updateRequest.setAccountHolderLastName("Doe");
            updateRequest.setAccountHolderStreetLine1("456 New Address Ave");
            updateRequest.setAccountHolderStreetLine2("Suite 100");
            updateRequest.setAccountHolderCity("Chicago");
            updateRequest.setAccountHolderRegion("IL");
            updateRequest.setAccountHolderPostalCode("60601");
            updateRequest.setAccountHolderPhoneNumber("555-987-6543");
            updateRequest.setAccountHolderEmail("john.doe@newdomain.com");
            updateRequest.setSetAsDefaultPaymentMethod(true);

            Map<String, String> customerData = new HashMap<>();
            customerData.put("notes", "Updated card expiration and address");
            customerData.put("lastModifiedBy", "CustomerService");
            updateRequest.setCustomerData(customerData);
            updateRequest.setAllowTransactionalEmails(true);

            String result = client.updateSavedPaymentMethod(
                "12345678901",          // merchantId
                "5513027774438108364",  // payorId
                "5513027774438108365",  // savedPaymentMethodId
                updateRequest
            );
            System.out.println(result);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
require 'net/http'
require 'uri'
require 'json'

class SavedPaymentMethodClient
  def initialize(base_url, bearer_token)
    @base_url = base_url
    @bearer_token = bearer_token
  end

  def update_saved_payment_method(merchant_id, payor_id, saved_payment_method_id, update_request)
    # Construct the endpoint URL
    endpoint = "#{@base_url}/v1/rest/merchants/#{merchant_id}/payors/#{payor_id}" \
               "/savedPaymentMethods/#{saved_payment_method_id}"
    uri = URI(endpoint)

    # Create HTTP request
    request = Net::HTTP::Put.new(uri)
    request['Authorization'] = "Bearer #{@bearer_token}"
    request['Accept'] = 'application/json'
    request['Content-Type'] = 'application/json'

    # Serialize request to JSON, removing nil values
    request.body = update_request.compact.to_json

    # Make the request
    response = Net::HTTP.start(uri.hostname, uri.port,
                               use_ssl: uri.scheme == 'https') do |http|
      http.request(request)
    end

    # Check response status
    unless response.is_a?(Net::HTTPSuccess)
      raise "HTTP Error: #{response.code} - #{response.message}\n#{response.body}"
    end

    # Return the response body
    response.body

  rescue StandardError => e
    puts "Request error: #{e.message}"
    raise
  end
end

# Example usage: Update credit card expiration date and billing address
begin
  client = SavedPaymentMethodClient.new(
    'https://your-api-domain.com',
    'your-bearer-token-here'
  )

  update_request = {
    cardExpiry: '1227',
    accountHolderFirstName: 'John',
    accountHolderLastName: 'Doe',
    accountHolderStreetLine1: '456 New Address Ave',
    accountHolderStreetLine2: 'Suite 100',
    accountHolderCity: 'Chicago',
    accountHolderRegion: 'IL',
    accountHolderPostalCode: '60601',
    accountHolderPhoneNumber: '555-987-6543',
    accountHolderEmail: 'john.doe@newdomain.com',
    setAsDefaultPaymentMethod: true,
    customerData: {
      notes: 'Updated card expiration and address',
      lastModifiedBy: 'CustomerService'
    },
    allowTransactionalEmails: true
  }

  result = client.update_saved_payment_method(
    '12345678901',          # merchantId
    '5513027774438108364',  # payorId
    '5513027774438108365',  # savedPaymentMethodId
    update_request
  )
  puts result

rescue => e
  puts "Error: #{e.message}"
end

Example Request Bodies

Example 1: Update Credit Card Expiration Date

{
  "cardExpiry": "1227",
  "accountHolderFirstName": "John",
  "accountHolderLastName": "Doe",
  "accountHolderEmail": "john.doe@example.com"
}

Example 2: Update Billing Address

{
  "accountHolderStreetLine1": "789 Oak Street",
  "accountHolderStreetLine2": "Apartment 5C",
  "accountHolderCity": "Boston",
  "accountHolderRegion": "MA",
  "accountHolderPostalCode": "02101",
  "accountHolderPhoneNumber": "555-111-2222"
}

Example 3: Set as Default Payment Method

{
  "setAsDefaultPaymentMethod": true,
  "customerData": {
    "reason": "Customer requested primary card change",
    "changedBy": "CustomerService"
  }
}

Example 4: Update Contact Information

{
  "accountHolderEmail": "newemail@example.com",
  "accountHolderPhoneNumber": "555-999-8888",
  "allowTransactionalEmails": true,
  "customerData": {
    "contactPreference": "email",
    "timezone": "America/Chicago"
  }
}

Example 5: Update ACH Account Holder Name

{
  "accountHolderFirstName": "Jane",
  "accountHolderLastName": "Smith-Johnson",
  "customerAccountType": "Joint Account",
  "customerData": {
    "accountOwnership": "joint",
    "secondaryHolder": "John Johnson"
  }
}

Response Format

The response follows the same format as the GET endpoint, returning the complete updated payment method details. See the Get Saved Payment Method documentation for full response field descriptions.

Success Response (HTTP 200)

{
  "responseStatus": "SavedPaymentMethodUpdated",
  "responseMessage": "Payment method updated successfully",
  "responseCode": "200",
  "responseReason": null,
  "responseResult": "success",
  "legacyResponseCode": "A",
  "correlationId": "xyz789-abc123-def456",
  "payorId": "5513027774438108364",
  "savedPaymentMethodId": "5513027774438108365",
  "savedPaymentMethodIdLimitedBitFlag": true,
  "createdDate": "2024-01-15T10:30:00Z",
  "accountType": "VISA",
  "customerAccountId": "CUST-12345",
  "customerAccountType": "Primary",
  "binId": "dGVzdC1iaW4taWQ",
  "maskedAccountNumber": "************1234",
  "lastFour": "1234",
  "cardExpiry": "1227",
  "abaRoutingNumber": null,
  "accountHolderFirstName": "John",
  "accountHolderLastName": "Doe",
  "accountHolderStreetLine1": "456 New Address Ave",
  "accountHolderStreetLine2": "Suite 100",
  "accountHolderCity": "Chicago",
  "accountHolderRegion": "IL",
  "accountHolderPostalCode": "60601",
  "accountHolderPhoneNumber": "555-987-6543",
  "accountHolderEmail": "john.doe@newdomain.com",
  "binInformation": {
    "binId": "dGVzdC1iaW4taWQ",
    "cardType": "Credit",
    "brandName": "Visa",
    "fundingSource": "Credit",
    "bin": "45678901",
    "issuerInformation": {
      "name": "Example Bank",
      "country": "US",
      "phoneNumber": "1-800-555-0100"
    },
    "surcharge": "Allowed"
  },
  "isDeleted": false,
  "deletedDate": null,
  "customerData": {
    "notes": "Updated card expiration and address",
    "lastModifiedBy": "CustomerService"
  },
  "isDefaultAccount": true,
  "sponsorKey": "SPONSOR1",
  "allowTransactionalEmails": true
}

HTTP Status Codes

Status Code Description
200 Success - Saved payment method updated successfully
400 Bad Request - Validation error (invalid data format, missing required fields, or invalid parameter values)
401 Unauthorized - Invalid or expired bearer token
404 Not Found - Saved payment method with the specified ID does not exist for this payor and merchant
500 Internal Server Error - Server encountered an unexpected error

Common Error Scenarios

Validation Error (HTTP 400)

{
  "responseStatus": "SavedPaymentValidationError",
  "responseMessage": "Validation failed",
  "responseCode": "400",
  "responseReason": "Card expiry must be in MMyy, MMyyyy, or yyyyMMdd format",
  "responseResult": "failure",
  "correlationId": "error-123-456-789"
}

Not Found Error (HTTP 404)

{
  "responseStatus": "NotFound",
  "responseMessage": "Saved payment method not found",
  "responseCode": "404",
  "responseReason": "No saved payment method exists with the specified ID for this payor",
  "responseResult": "failure",
  "correlationId": "error-987-654-321"
}

Data Encryption Requirements

Sensitive Data Encryption:

If you need to update the account number itself (which is rare), you must encrypt it before sending:

  • Credit Card Numbers (PAN): Must be encrypted using the public key obtained from the /keys/pan endpoint
  • Bank Account Numbers: Must be encrypted using the public key obtained from the /keys/sad endpoint
  • The encrypted value should be placed in the encryptedAccountNumber field
  • In most update scenarios, you should NOT send the account number - only update other fields like expiration, name, or address

Best Practices

1. Partial Updates

Only include fields you want to update in the request body. However, be cautious as some implementations may treat missing fields as "clear this field". It's safest to include all current values and only change the specific fields you need to update.

2. Update Card Expiration Dates Proactively

Monitor card expiration dates and prompt customers to update expiring cards before they expire. This prevents transaction failures and improves customer experience.

3. Verify Updates

After updating a payment method, consider making a GET request to verify the changes were applied correctly.

// After updating, verify the changes
var verifyResult = await client.GetSavedPaymentMethodByIdAsync(
    merchantId,
    payorId,
    savedPaymentMethodId
);

4. Handle Default Payment Method Changes

When setting setAsDefaultPaymentMethod: true, the system will automatically unset the previous default payment method. Only one payment method can be the default at a time.

5. Preserve Custom Data

If you have existing customerData, merge new values with existing ones rather than replacing the entire object, unless you intentionally want to clear old custom data.

6. Email Validation

If you set allowTransactionalEmails: true, ensure the accountHolderEmail field contains a valid email address. The system will automatically set allowTransactionalEmails to false if the email is null or empty.

Common Use Cases

1. Update Expiring Credit Card

When a customer receives a new card with a new expiration date but the same account number:

{
  "cardExpiry": "0328"  // March 2028
}

2. Update Billing Address After Move

When a customer moves to a new address:

{
  "accountHolderStreetLine1": "123 New Street",
  "accountHolderStreetLine2": null,
  "accountHolderCity": "New City",
  "accountHolderRegion": "NY",
  "accountHolderPostalCode": "10001"
}

3. Update Contact Information

When a customer changes their email or phone number:

{
  "accountHolderEmail": "newemail@example.com",
  "accountHolderPhoneNumber": "555-123-9999",
  "allowTransactionalEmails": true
}

4. Mark as Default Payment Method

When a customer wants to change their default payment method:

{
  "setAsDefaultPaymentMethod": true
}

5. Update After Name Change

When a customer legally changes their name (marriage, etc.):

{
  "accountHolderFirstName": "Jane",
  "accountHolderLastName": "NewLastName"
}

Troubleshooting

Issue: Getting 400 error "Validation failed"
  • Check that cardExpiry is in the correct format (MMyy, MMyyyy, or yyyyMMdd)
  • Verify that sponsorKey is not an empty string and does not exceed 8 characters
  • Ensure email addresses are in valid format if provided
  • Check that all required fields for the payment method type are included
Issue: Update appears successful but changes aren't reflected
  • Verify the response body to confirm the changes were applied
  • Some fields may have validation rules that prevent certain values
  • Check if you have proper permissions to update the payment method
  • Ensure you're updating the correct savedPaymentMethodId
Issue: Getting 404 error
  • Verify the savedPaymentMethodId exists and belongs to the specified payorId
  • Check that the merchantId is correct and matches the payor's merchant
  • The payment method may have been deleted (check isDeleted status)

Additional Notes

  • The merchantId must be exactly 11 digits. Requests with invalid formats will return a 400 Bad Request error.
  • You cannot change the account number through an update - to use a different account number, delete the old payment method and create a new one.
  • Setting a payment method as default will automatically unset any previous default payment method for that payor.
  • The correlationId in the response is useful for troubleshooting and should be provided when contacting support.
  • All timestamps in the response are in UTC format.
  • The response includes the complete updated payment method details, including any fields that weren't changed.
  • Custom attributes in customerData are merged with existing data unless you explicitly overwrite the entire object.
  • Changes take effect immediately and will be used for subsequent transactions.

Security Considerations

  • Always use HTTPS for API requests containing sensitive payment information
  • Never log or store the full account number in plain text
  • Implement proper access controls to ensure only authorized users can update payment methods
  • Consider implementing an audit log to track payment method changes
  • Validate all input data before sending to the API
  • Use the correlationId for tracking and debugging without exposing sensitive data