Update Transaction Custom Attributes
Description: Updates the custom attributes for a given transaction. Custom attributes are key-value pairs that you can use to store additional metadata about a transaction such as internal tracking numbers, department codes, customer notes, or any other business-specific information.
Custom attributes are like sticky notes you can attach to a transaction. They allow you to:
- Track internal data: Associate your internal reference numbers with transactions
- Categorize transactions: Tag transactions by department, project, or category
- Add context: Store notes, reasons, or additional details about a transaction
- Enable reporting: Filter and report on transactions using your custom data
Important: This endpoint only updates custom attributes - it cannot change the transaction amount, status, or payment details.
Path Parameters
Request Body
{
"customAttributes": {
"invoiceNumber": "INV-2026-001",
"department": "Sales",
"notes": "Rush order - expedited shipping",
"customerRef": "CUST-12345"
}
}
- New keys will be added to the transaction's custom attributes
- Existing keys will be updated with new values
- Keys not included in the request remain unchanged
- To remove a custom attribute, set its value to an empty string or null
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.Text;
using System.Threading.Tasks;
using System.Collections.Generic;
using Newtonsoft.Json;
public class UpdateCustomAttributesRequest
{
[JsonProperty("customAttributes")]
public Dictionary<string, string> CustomAttributes { get; set; }
}
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> UpdateCustomAttributesAsync(
string merchantId,
string transactionId,
Dictionary<string, string> customAttributes)
{
try
{
string endpoint = $"/v1/rest/merchants/{merchantId}/transactions/{transactionId}";
var request = new UpdateCustomAttributesRequest
{
CustomAttributes = customAttributes
};
string jsonContent = JsonConvert.SerializeObject(request);
var content = new StringContent(
jsonContent,
Encoding.UTF8,
"application/json");
HttpResponseMessage response = await _httpClient.PutAsync(endpoint, content);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
catch (HttpRequestException e)
{
Console.WriteLine($"Request error: {e.Message}");
throw;
}
}
}
// Example usage: Add tracking information
var client = new TransactionClient("your-bearer-token-here");
var attributes = new Dictionary<string, string>
{
{ "invoiceNumber", "INV-2026-001" },
{ "department", "Sales" },
{ "notes", "Rush order - expedited shipping" },
{ "processedBy", "John Doe" }
};
string result = await client.UpdateCustomAttributesAsync(
"12345678901", // merchantId
"a1b2c3d4-e5f6-7890-abcd-ef1234567890", // transactionId
attributes
);
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 UpdateCustomAttributesRequest
<JsonProperty("customAttributes")>
Public Property CustomAttributes As Dictionary(Of String, String)
End Class
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 UpdateCustomAttributesAsync(
merchantId As String,
transactionId As String,
customAttributes As Dictionary(Of String, String)) As Task(Of String)
Try
Dim endpoint As String = $"/v1/rest/merchants/{merchantId}/transactions/{transactionId}"
Dim request As New UpdateCustomAttributesRequest With {
.CustomAttributes = customAttributes
}
Dim jsonContent As String = JsonConvert.SerializeObject(request)
Dim content As New StringContent(
jsonContent,
Encoding.UTF8,
"application/json")
Dim response As HttpResponseMessage = Await _httpClient.PutAsync(endpoint, content)
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 attributes As New Dictionary(Of String, String) From {
{"invoiceNumber", "INV-2026-001"},
{"department", "Sales"},
{"notes", "Rush order - expedited shipping"}
}
Dim result As String = Await client.UpdateCustomAttributesAsync(
"12345678901",
"a1b2c3d4-e5f6-7890-abcd-ef1234567890",
attributes
)
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 com.google.gson.Gson;
import java.util.HashMap;
import java.util.Map;
class UpdateCustomAttributesRequest {
private Map<String, String> customAttributes;
public UpdateCustomAttributesRequest(Map<String, String> customAttributes) {
this.customAttributes = customAttributes;
}
public Map<String, String> getCustomAttributes() {
return customAttributes;
}
}
public class TransactionClient {
private final String baseUrl;
private final String bearerToken;
private final HttpClient httpClient;
private final Gson gson;
public TransactionClient(String baseUrl, String bearerToken) {
this.baseUrl = baseUrl;
this.bearerToken = bearerToken;
this.httpClient = HttpClient.newHttpClient();
this.gson = new Gson();
}
public String updateCustomAttributes(
String merchantId,
String transactionId,
Map<String, String> customAttributes)
throws IOException, InterruptedException {
String endpoint = baseUrl + "/v1/rest/merchants/" + merchantId +
"/transactions/" + transactionId;
UpdateCustomAttributesRequest request =
new UpdateCustomAttributesRequest(customAttributes);
String jsonBody = gson.toJson(request);
HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(URI.create(endpoint))
.header("Authorization", "Bearer " + bearerToken)
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.PUT(HttpRequest.BodyPublishers.ofString(jsonBody))
.build();
HttpResponse<String> response = httpClient.send(
httpRequest,
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() != 200) {
throw new IOException("HTTP Error: " + response.statusCode());
}
return response.body();
}
}
// Example usage
TransactionClient client = new TransactionClient(
"https://your-api-domain.com",
"your-bearer-token-here"
);
Map<String, String> attributes = new HashMap<>();
attributes.put("invoiceNumber", "INV-2026-001");
attributes.put("department", "Sales");
attributes.put("notes", "Rush order - expedited shipping");
String result = client.updateCustomAttributes(
"12345678901",
"a1b2c3d4-e5f6-7890-abcd-ef1234567890",
attributes
);
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 update_custom_attributes(merchant_id, transaction_id, custom_attributes)
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::Put.new(uri.path)
request['Authorization'] = "Bearer #{@bearer_token}"
request['Content-Type'] = 'application/json'
request['Accept'] = 'application/json'
request.body = {
customAttributes: custom_attributes
}.to_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'
)
attributes = {
invoiceNumber: 'INV-2026-001',
department: 'Sales',
notes: 'Rush order - expedited shipping'
}
result = client.update_custom_attributes(
'12345678901',
'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
attributes
)
puts result
Example Request Bodies
Example 1: Add Invoice and Department Tracking
{
"customAttributes": {
"invoiceNumber": "INV-2026-001",
"department": "Sales",
"costCenter": "CC-100"
}
}
Example 2: Add Customer Notes
{
"customAttributes": {
"customerNote": "Customer requested expedited processing",
"priority": "high",
"notifiedBy": "John Doe"
}
}
Example 3: Update Tracking Status
{
"customAttributes": {
"fulfillmentStatus": "shipped",
"trackingNumber": "1Z999AA10123456784",
"shippedDate": "2026-04-02",
"carrier": "UPS"
}
}
Example 4: Add Project/Campaign Information
{
"customAttributes": {
"projectId": "PROJ-2026-Q1",
"campaignCode": "SPRING2026",
"referralSource": "Email Campaign"
}
}
Response Format
Success Response (HTTP 200)
{
"responseStatus": "TransactionUpdated",
"responseMessage": "Custom attributes updated successfully",
"responseCode": "200",
"responseReason": null,
"responseResult": "success",
"legacyResponseCode": "A",
"correlationId": "update-123-456-789",
"customAttributes": {
"invoiceNumber": "INV-2026-001",
"department": "Sales",
"notes": "Rush order - expedited shipping",
"processedBy": "John Doe"
}
}
HTTP Status Codes
| Status Code | Description |
|---|---|
| 200 | Success - Custom attributes updated successfully |
| 400 | Bad Request - Validation error (invalid data format or missing customAttributes) |
| 401 | Unauthorized - Invalid or expired bearer token |
| 404 | Not Found - Transaction with specified ID does not exist |
| 500 | Internal Server Error - Server error processing update |
Best Practices
1. Use Descriptive Key Names
Use clear, descriptive names for your custom attribute keys. This makes it easier to understand what the data represents months or years later.
// Good - clear and descriptive
{ "invoiceNumber": "INV-001", "shippingMethod": "Express" }
// Bad - cryptic abbreviations
{ "inv": "INV-001", "sm": "Exp" }
2. Establish Naming Conventions
Use consistent naming conventions across all transactions. Consider using camelCase or snake_case consistently throughout your application.
// Consistent camelCase
{ "invoiceNumber": "INV-001", "orderDate": "2026-04-02" }
// Or consistent snake_case
{ "invoice_number": "INV-001", "order_date": "2026-04-02" }
3. Update Immediately After Events
Update custom attributes as soon as relevant events occur (order shipped, status changed, etc.) to keep data current and accurate.
4. Store Searchable Data
Use custom attributes to store data you'll want to search or filter by later. This makes reporting and analysis much easier.
5. Don't Store Sensitive Data
Avoid storing sensitive information like full credit card numbers, SSNs, or passwords in custom attributes. Use them for tracking and metadata only.
6. Keep Values as Strings
All values must be strings. If you need to store numbers or dates, convert them to string format:
{
"customAttributes": {
"quantity": "5", // Number as string
"orderDate": "2026-04-02", // Date as string
"isRushOrder": "true" // Boolean as string
}
}
Common Use Cases
1. Link to Internal Order System
// Link payment transaction to your order management system
var attributes = new Dictionary<string, string>
{
{ "internalOrderId", "ORD-12345" },
{ "orderSystem", "Magento" },
{ "orderUrl", "https://admin.example.com/orders/12345" }
};
await client.UpdateCustomAttributesAsync(merchantId, transactionId, attributes);
2. Track Fulfillment Status
// Update when order ships
var attributes = new Dictionary<string, string>
{
{ "fulfillmentStatus", "shipped" },
{ "shippedDate", DateTime.Now.ToString("yyyy-MM-dd") },
{ "trackingNumber", "1Z999AA10123456784" },
{ "carrier", "UPS" },
{ "estimatedDelivery", "2026-04-05" }
};
await client.UpdateCustomAttributesAsync(merchantId, transactionId, attributes);
3. Department/Project Allocation
// Allocate transaction to department for accounting
var attributes = new Dictionary<string, string>
{
{ "department": "Marketing" },
{ "costCenter": "CC-200" },
{ "projectCode": "PROJ-2026-Q1" },
{ "budgetCategory": "Advertising" }
};
await client.UpdateCustomAttributesAsync(merchantId, transactionId, attributes);
4. Customer Service Notes
// Add notes from customer service interaction
var attributes = new Dictionary<string, string>
{
{ "supportTicket": "TICKET-789" },
{ "customerIssue": "Requested refund - product damaged" },
{ "handledBy", "Jane Smith" },
{ "resolutionDate": DateTime.Now.ToString("yyyy-MM-dd") }
};
await client.UpdateCustomAttributesAsync(merchantId, transactionId, attributes);
5. Marketing Campaign Tracking
// Track which marketing campaign generated the sale
var attributes = new Dictionary<string, string>
{
{ "campaignId": "SPRING2026" },
{ "adSource": "Google Ads" },
{ "keyword": "buy widgets online" },
{ "landingPage": "/products/widgets" }
};
await client.UpdateCustomAttributesAsync(merchantId, transactionId, attributes);
Merging vs Replacing Custom Attributes
This endpoint merges the new custom attributes with existing ones. It does NOT replace all custom attributes.
- New keys are added
- Existing keys are updated with new values
- Keys not mentioned in the request remain unchanged
Example:
// Original custom attributes on transaction:
{
"invoiceNumber": "INV-001",
"department": "Sales",
"priority": "normal"
}
// Update request:
{
"customAttributes": {
"department": "Marketing", // Updates existing key
"trackingNumber": "1Z999AA" // Adds new key
}
}
// Result after update:
{
"invoiceNumber": "INV-001", // Unchanged
"department": "Marketing", // Updated
"priority": "normal", // Unchanged
"trackingNumber": "1Z999AA" // Added
}
Troubleshooting
- Verify the
customAttributesfield is included in the request body - Ensure all keys and values are strings
- Check that the JSON is properly formatted
- Verify you're not exceeding any size limits for custom attributes
- Verify the transaction ID is correct
- Ensure the transaction belongs to the specified merchant
- Check that you're using the correct merchant ID
- Verify the update was successful (check the response)
- Ensure you're using the correct attribute names when searching
- Check that the search endpoint supports filtering by custom attributes
- Allow time for data to propagate (may take a few moments)
Additional Notes
- You can update custom attributes at any time after the transaction is created
- Updates are immediate and reflected in subsequent API calls
- There may be limits on the number of custom attributes or size of values (check with your account settings)
- Custom attributes are included when you retrieve the transaction via GET endpoint
- You can use custom attributes to filter transactions in the search endpoint
- To remove a custom attribute, set its value to an empty string
- Custom attributes are stored permanently with the transaction
- This operation does not affect the transaction amount, status, or settlement