MAC Control

Last updated: 2025-12-24

This section helps you learn about real-world decline scenarios and observe how MAC Control enforces issuer guidance automatically and decisively.

When a transaction is declined, the issuer sends a Merchant Advice Code (MAC) to guide the next move: retry, wait, or stop. MAC Control reads that advice and either allows or blocks the retry attempt. This section shows various scenarios, including:

  • Trigger declines with specific MACs
  • Attempt retries and see whether MAC Control allows or blocks them

All examples use the DB (debit) payment type for simplicity. MAC Control also supports pre-authorisations, rebills, refunds, reversals, and credits. MAC Control applies only when MACs are exposed by the acquirer and present in the issuer response. MAC Control works across PANs, wallet DPANs, and network tokens.

Use cases

ScenarioMACSummaryGet started
🔴 Account closed03The account is permanently closed and retrying will not help.Account closed
🔴 Recurring cancelled21The cardholder cancelled the recurring mandate and no further charges are allowed.Recurring cancelled
🟡 Insufficient funds02, 24-30The account does not have enough funds and retrying can succeed after the advised delay.Insufficient funds
🟠 Update account info01Credentials are outdated and the account needs an update before retrying.Update account info
🟠 SCA required01Strong Customer Authentication is required before retrying.SCA required
🟠 Not eligible for instalment22The merchant is not enrolled in the scheme instalment programme.Not eligible for instalment

Account closed (MAC 03)

The merchant initiates a transaction, but the issuer responds with MAC 🔴 03 (Account Closed). This is a hard decline. Retrying does not work and may lead to higher costs. MAC Control blocks the retry for 30 days to prevent unnecessary costs and ensure compliance.

How it works

  1. The merchant initiates a payment. The transaction gets declined with MAC 🔴 03 (Account Closed).
  2. The merchant attempts a retry. MAC Control blocks the retry for 30 days.

1. The merchant initiates a payment

Initiate a server-to-server POST request with the required payment data. Use an amount ending in .03 to simulate MAC 03.

Sample request:

curl https://sandbox-card.peachpayments.com/v1/payments \
 -d "entityId=YOUR_ENTITY_ID" \
 -d "amount=10.03" \
 -d "currency=ZAR" \
 -d "paymentBrand=VISA" \
 -d "paymentType=DB" \
 -d "card.number=4200000000000000" \
 -d "card.holder=Jane Jones" \
 -d "card.expiryMonth=05" \
 -d "card.expiryYear=2034" \
 -d "card.cvv=123" \
 -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
using System.Net.Http;
using System.Net.Http.Headers;

var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox-card.peachpayments.com/v1/payments");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_ACCESS_TOKEN");
request.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
  ["entityId"] = "YOUR_ENTITY_ID",
  ["amount"] = "10.03",
  ["currency"] = "ZAR",
  ["paymentBrand"] = "VISA",
  ["paymentType"] = "DB",
  ["card.number"] = "4200000000000000",
  ["card.holder"] = "Jane Jones",
  ["card.expiryMonth"] = "05",
  ["card.expiryYear"] = "2034",
  ["card.cvv"] = "123"
});
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
def url = "https://sandbox-card.peachpayments.com/v1/payments"
def body = [
  entityId: "YOUR_ENTITY_ID",
  amount: "10.03",
  currency: "ZAR",
  paymentBrand: "VISA",
  paymentType: "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
]
def connection = new URL(url).openConnection()
connection.setRequestMethod("POST")
connection.setRequestProperty("Authorization", "Bearer YOUR_ACCESS_TOKEN")
connection.doOutput = true
connection.outputStream.withWriter { it << body.collect { k, v -> "$k=$v" }.join("&") }
def response = connection.inputStream.text
HttpClient client = HttpClient.newHttpClient();
String body = "entityId=YOUR_ENTITY_ID" +
  "&amount=10.03" +
  "&currency=ZAR" +
  "&paymentBrand=VISA" +
  "&paymentType=DB" +
  "&card.number=4200000000000000" +
  "&card.holder=Jane Jones" +
  "&card.expiryMonth=05" +
  "&card.expiryYear=2034" +
  "&card.cvv=123";
HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create("https://sandbox-card.peachpayments.com/v1/payments"))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .header("Content-Type", "application/x-www-form-urlencoded")
  .POST(HttpRequest.BodyPublishers.ofString(body))
  .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
const fetch = require("node-fetch");

const body = new URLSearchParams({
  entityId: "YOUR_ENTITY_ID",
  amount: "10.03",
  currency: "ZAR",
  paymentBrand: "VISA",
  paymentType: "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
});

const response = await fetch("https://sandbox-card.peachpayments.com/v1/payments", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_ACCESS_TOKEN" },
  body
});
const data = await response.text();
$url = "https://sandbox-card.peachpayments.com/v1/payments";
$data = http_build_query([
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "10.03",
  "currency" => "ZAR",
  "paymentBrand" => "VISA",
  "paymentType" => "DB",
  "card.number" => "4200000000000000",
  "card.holder" => "Jane Jones",
  "card.expiryMonth" => "05",
  "card.expiryYear" => "2034",
  "card.cvv" => "123"
]);

$options = [
  "http" => [
    "method" => "POST",
    "header" => "Authorization: Bearer YOUR_ACCESS_TOKEN\r\n" .
                "Content-Type: application/x-www-form-urlencoded\r\n",
    "content" => $data
  ]
];

$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
import requests

payload = {
  "entityId": "YOUR_ENTITY_ID",
  "amount": "10.03",
  "currency": "ZAR",
  "paymentBrand": "VISA",
  "paymentType": "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
}

response = requests.post(
  "https://sandbox-card.peachpayments.com/v1/payments",
  headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN"},
  data=payload
)
require "net/http"

uri = URI("https://sandbox-card.peachpayments.com/v1/payments")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_ACCESS_TOKEN"
request.set_form_data(
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "10.03",
  "currency" => "ZAR",
  "paymentBrand" => "VISA",
  "paymentType" => "DB",
  "card.number" => "4200000000000000",
  "card.holder" => "Jane Jones",
  "card.expiryMonth" => "05",
  "card.expiryYear" => "2034",
  "card.cvv" => "123"
)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
import scalaj.http._

val response = Http("https://sandbox-card.peachpayments.com/v1/payments")
  .postForm(Seq(
    "entityId" -> "YOUR_ENTITY_ID",
    "amount" -> "10.03",
    "currency" -> "ZAR",
    "paymentBrand" -> "VISA",
    "paymentType" -> "DB",
    "card.number" -> "4200000000000000",
    "card.holder" -> "Jane Jones",
    "card.expiryMonth" -> "05",
    "card.expiryYear" -> "2034",
    "card.cvv" -> "123"
  ))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .asString
Imports System.Net
Imports System.Text

Dim url = "https://sandbox-card.peachpayments.com/v1/payments"
Dim data = "entityId=YOUR_ENTITY_ID&amount=10.03&currency=ZAR&paymentBrand=VISA&paymentType=DB&card.number=4200000000000000&card.holder=Jane Jones&card.expiryMonth=05&card.expiryYear=2034&card.cvv=123"
Dim request = CType(WebRequest.Create(url), HttpWebRequest)
request.Method = "POST"
request.Headers.Add("Authorization", "Bearer YOUR_ACCESS_TOKEN")
request.ContentType = "application/x-www-form-urlencoded"
Dim bytes = Encoding.UTF8.GetBytes(data)
request.ContentLength = bytes.Length
Using stream = request.GetRequestStream()
  stream.Write(bytes, 0, bytes.Length)
End Using
Dim response = CType(request.GetResponse(), HttpWebResponse)

2. The merchant attempts a retry

Retry the same transaction using the same account. Changing the amount, currency, or merchant transaction ID does not help because the issue is structural, not transactional. MAC Control blocks the retry for 30 days.

Merchant recommendation:

  • Do not retry with the same account
  • Prompt the customer to provide a new payment method

Sample request:

curl https://sandbox-card.peachpayments.com/v1/payments \
 -d "entityId=YOUR_ENTITY_ID" \
 -d "amount=10.03" \
 -d "currency=ZAR" \
 -d "paymentBrand=VISA" \
 -d "paymentType=DB" \
 -d "card.number=4200000000000000" \
 -d "card.holder=Jane Jones" \
 -d "card.expiryMonth=05" \
 -d "card.expiryYear=2034" \
 -d "card.cvv=123" \
 -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
using System.Net.Http;
using System.Net.Http.Headers;

var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox-card.peachpayments.com/v1/payments");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_ACCESS_TOKEN");
request.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
  ["entityId"] = "YOUR_ENTITY_ID",
  ["amount"] = "10.03",
  ["currency"] = "ZAR",
  ["paymentBrand"] = "VISA",
  ["paymentType"] = "DB",
  ["card.number"] = "4200000000000000",
  ["card.holder"] = "Jane Jones",
  ["card.expiryMonth"] = "05",
  ["card.expiryYear"] = "2034",
  ["card.cvv"] = "123"
});
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
def url = "https://sandbox-card.peachpayments.com/v1/payments"
def body = [
  entityId: "YOUR_ENTITY_ID",
  amount: "10.03",
  currency: "ZAR",
  paymentBrand: "VISA",
  paymentType: "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
]
def connection = new URL(url).openConnection()
connection.setRequestMethod("POST")
connection.setRequestProperty("Authorization", "Bearer YOUR_ACCESS_TOKEN")
connection.doOutput = true
connection.outputStream.withWriter { it << body.collect { k, v -> "$k=$v" }.join("&") }
def response = connection.inputStream.text
HttpClient client = HttpClient.newHttpClient();
String body = "entityId=YOUR_ENTITY_ID" +
  "&amount=10.03" +
  "&currency=ZAR" +
  "&paymentBrand=VISA" +
  "&paymentType=DB" +
  "&card.number=4200000000000000" +
  "&card.holder=Jane Jones" +
  "&card.expiryMonth=05" +
  "&card.expiryYear=2034" +
  "&card.cvv=123";
HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create("https://sandbox-card.peachpayments.com/v1/payments"))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .header("Content-Type", "application/x-www-form-urlencoded")
  .POST(HttpRequest.BodyPublishers.ofString(body))
  .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
const fetch = require("node-fetch");

const body = new URLSearchParams({
  entityId: "YOUR_ENTITY_ID",
  amount: "10.03",
  currency: "ZAR",
  paymentBrand: "VISA",
  paymentType: "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
});

const response = await fetch("https://sandbox-card.peachpayments.com/v1/payments", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_ACCESS_TOKEN" },
  body
});
const data = await response.text();
$url = "https://sandbox-card.peachpayments.com/v1/payments";
$data = http_build_query([
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "10.03",
  "currency" => "ZAR",
  "paymentBrand" => "VISA",
  "paymentType" => "DB",
  "card.number" => "4200000000000000",
  "card.holder" => "Jane Jones",
  "card.expiryMonth" => "05",
  "card.expiryYear" => "2034",
  "card.cvv" => "123"
]);

$options = [
  "http" => [
    "method" => "POST",
    "header" => "Authorization: Bearer YOUR_ACCESS_TOKEN\r\n" .
                "Content-Type: application/x-www-form-urlencoded\r\n",
    "content" => $data
  ]
];

$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
import requests

payload = {
  "entityId": "YOUR_ENTITY_ID",
  "amount": "10.03",
  "currency": "ZAR",
  "paymentBrand": "VISA",
  "paymentType": "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
}

response = requests.post(
  "https://sandbox-card.peachpayments.com/v1/payments",
  headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN"},
  data=payload
)
require "net/http"

uri = URI("https://sandbox-card.peachpayments.com/v1/payments")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_ACCESS_TOKEN"
request.set_form_data(
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "10.03",
  "currency" => "ZAR",
  "paymentBrand" => "VISA",
  "paymentType" => "DB",
  "card.number" => "4200000000000000",
  "card.holder" => "Jane Jones",
  "card.expiryMonth" => "05",
  "card.expiryYear" => "2034",
  "card.cvv" => "123"
)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
import scalaj.http._

val response = Http("https://sandbox-card.peachpayments.com/v1/payments")
  .postForm(Seq(
    "entityId" -> "YOUR_ENTITY_ID",
    "amount" -> "10.03",
    "currency" -> "ZAR",
    "paymentBrand" -> "VISA",
    "paymentType" -> "DB",
    "card.number" -> "4200000000000000",
    "card.holder" -> "Jane Jones",
    "card.expiryMonth" -> "05",
    "card.expiryYear" -> "2034",
    "card.cvv" -> "123"
  ))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .asString
Imports System.Net
Imports System.Text

Dim url = "https://sandbox-card.peachpayments.com/v1/payments"
Dim data = "entityId=YOUR_ENTITY_ID&amount=10.03&currency=ZAR&paymentBrand=VISA&paymentType=DB&card.number=4200000000000000&card.holder=Jane Jones&card.expiryMonth=05&card.expiryYear=2034&card.cvv=123"
Dim request = CType(WebRequest.Create(url), HttpWebRequest)
request.Method = "POST"
request.Headers.Add("Authorization", "Bearer YOUR_ACCESS_TOKEN")
request.ContentType = "application/x-www-form-urlencoded"
Dim bytes = Encoding.UTF8.GetBytes(data)
request.ContentLength = bytes.Length
Using stream = request.GetRequestStream()
  stream.Write(bytes, 0, bytes.Length)
End Using
Dim response = CType(request.GetResponse(), HttpWebResponse)

Recurring cancelled (MAC 21)

The merchant initiates a recurring payment, but the issuer responds with MAC 🔴 21 (Recurring Cancelled). This indicates that the cardholder cancelled their recurring agreement, such as a subscription or mandate. Retrying the same transaction violates issuer intent. MAC Control blocks the retry for 30 days to enforce compliance and prevent unnecessary costs.

How it works

  1. The merchant initiates a recurring payment. The transaction gets declined with MAC 🔴 21 (Customer cancelled recurring agreement).
  2. The merchant attempts a retry. MAC Control blocks the retry for 30 days.

1. The merchant initiates a payment

Initiate a server-to-server POST request simulating a recurring payment. Use an amount ending in .21 to simulate MAC 🔴 21.

Sample request:

curl https://sandbox-card.peachpayments.com/v1/payments \
 -d "entityId=YOUR_ENTITY_ID" \
 -d "amount=1234.21" \
 -d "paymentType=DB" \
 -d "currency=EUR" \
 -d "merchantTransactionId=OrderTQMX4ZV34V-MAC21" \
 -d "paymentBrand=MASTER" \
 -d "card.holder=John Smith" \
 -d "card.number=5555555676186886" \
 -d "card.expiryMonth=12" \
 -d "card.expiryYear=2027" \
 -d "card.cvv=123" \
 -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
using System.Net.Http;
using System.Net.Http.Headers;

var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox-card.peachpayments.com/v1/payments");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_ACCESS_TOKEN");
request.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
  ["entityId"] = "YOUR_ENTITY_ID",
  ["amount"] = "1234.21",
  ["paymentType"] = "DB",
  ["currency"] = "EUR",
  ["merchantTransactionId"] = "OrderTQMX4ZV34V-MAC21",
  ["paymentBrand"] = "MASTER",
  ["card.holder"] = "John Smith",
  ["card.number"] = "5555555676186886",
  ["card.expiryMonth"] = "12",
  ["card.expiryYear"] = "2027",
  ["card.cvv"] = "123"
});
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
def url = "https://sandbox-card.peachpayments.com/v1/payments"
def body = [
  entityId: "YOUR_ENTITY_ID",
  amount: "1234.21",
  paymentType: "DB",
  currency: "EUR",
  merchantTransactionId: "OrderTQMX4ZV34V-MAC21",
  paymentBrand: "MASTER",
  "card.holder": "John Smith",
  "card.number": "5555555676186886",
  "card.expiryMonth": "12",
  "card.expiryYear": "2027",
  "card.cvv": "123"
]
def connection = new URL(url).openConnection()
connection.setRequestMethod("POST")
connection.setRequestProperty("Authorization", "Bearer YOUR_ACCESS_TOKEN")
connection.doOutput = true
connection.outputStream.withWriter { it << body.collect { k, v -> "$k=$v" }.join("&") }
def response = connection.inputStream.text
HttpClient client = HttpClient.newHttpClient();
String body = "entityId=YOUR_ENTITY_ID" +
  "&amount=1234.21" +
  "&paymentType=DB" +
  "&currency=EUR" +
  "&merchantTransactionId=OrderTQMX4ZV34V-MAC21" +
  "&paymentBrand=MASTER" +
  "&card.holder=John Smith" +
  "&card.number=5555555676186886" +
  "&card.expiryMonth=12" +
  "&card.expiryYear=2027" +
  "&card.cvv=123";
HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create("https://sandbox-card.peachpayments.com/v1/payments"))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .header("Content-Type", "application/x-www-form-urlencoded")
  .POST(HttpRequest.BodyPublishers.ofString(body))
  .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
const fetch = require("node-fetch");

const body = new URLSearchParams({
  entityId: "YOUR_ENTITY_ID",
  amount: "1234.21",
  paymentType: "DB",
  currency: "EUR",
  merchantTransactionId: "OrderTQMX4ZV34V-MAC21",
  paymentBrand: "MASTER",
  "card.holder": "John Smith",
  "card.number": "5555555676186886",
  "card.expiryMonth": "12",
  "card.expiryYear": "2027",
  "card.cvv": "123"
});

const response = await fetch("https://sandbox-card.peachpayments.com/v1/payments", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_ACCESS_TOKEN" },
  body
});
const data = await response.text();
$url = "https://sandbox-card.peachpayments.com/v1/payments";
$data = http_build_query([
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "1234.21",
  "paymentType" => "DB",
  "currency" => "EUR",
  "merchantTransactionId" => "OrderTQMX4ZV34V-MAC21",
  "paymentBrand" => "MASTER",
  "card.holder" => "John Smith",
  "card.number" => "5555555676186886",
  "card.expiryMonth" => "12",
  "card.expiryYear" => "2027",
  "card.cvv" => "123"
]);

$options = [
  "http" => [
    "method" => "POST",
    "header" => "Authorization: Bearer YOUR_ACCESS_TOKEN\r\n" .
                "Content-Type: application/x-www-form-urlencoded\r\n",
    "content" => $data
  ]
];

$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
import requests

payload = {
  "entityId": "YOUR_ENTITY_ID",
  "amount": "1234.21",
  "paymentType": "DB",
  "currency": "EUR",
  "merchantTransactionId": "OrderTQMX4ZV34V-MAC21",
  "paymentBrand": "MASTER",
  "card.holder": "John Smith",
  "card.number": "5555555676186886",
  "card.expiryMonth": "12",
  "card.expiryYear": "2027",
  "card.cvv": "123"
}

response = requests.post(
  "https://sandbox-card.peachpayments.com/v1/payments",
  headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN"},
  data=payload
)
require "net/http"

uri = URI("https://sandbox-card.peachpayments.com/v1/payments")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_ACCESS_TOKEN"
request.set_form_data(
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "1234.21",
  "paymentType" => "DB",
  "currency" => "EUR",
  "merchantTransactionId" => "OrderTQMX4ZV34V-MAC21",
  "paymentBrand" => "MASTER",
  "card.holder" => "John Smith",
  "card.number" => "5555555676186886",
  "card.expiryMonth" => "12",
  "card.expiryYear" => "2027",
  "card.cvv" => "123"
)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
import scalaj.http._

val response = Http("https://sandbox-card.peachpayments.com/v1/payments")
  .postForm(Seq(
    "entityId" -> "YOUR_ENTITY_ID",
    "amount" -> "1234.21",
    "paymentType" -> "DB",
    "currency" -> "EUR",
    "merchantTransactionId" -> "OrderTQMX4ZV34V-MAC21",
    "paymentBrand" -> "MASTER",
    "card.holder" -> "John Smith",
    "card.number" -> "5555555676186886",
    "card.expiryMonth" -> "12",
    "card.expiryYear" -> "2027",
    "card.cvv" -> "123"
  ))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .asString
Imports System.Net
Imports System.Text

Dim url = "https://sandbox-card.peachpayments.com/v1/payments"
Dim data = "entityId=YOUR_ENTITY_ID&amount=1234.21&paymentType=DB&currency=EUR&merchantTransactionId=OrderTQMX4ZV34V-MAC21&paymentBrand=MASTER&card.holder=John Smith&card.number=5555555676186886&card.expiryMonth=12&card.expiryYear=2027&card.cvv=123"
Dim request = CType(WebRequest.Create(url), HttpWebRequest)
request.Method = "POST"
request.Headers.Add("Authorization", "Bearer YOUR_ACCESS_TOKEN")
request.ContentType = "application/x-www-form-urlencoded"
Dim bytes = Encoding.UTF8.GetBytes(data)
request.ContentLength = bytes.Length
Using stream = request.GetRequestStream()
  stream.Write(bytes, 0, bytes.Length)
End Using
Dim response = CType(request.GetResponse(), HttpWebResponse)

2. The merchant attempts a retry

Retry the same transaction using the same account, amount, currency, and merchantTransactionId. MAC Control blocks the retry for 30 days.

Merchant recommendation:

  • Do not retry the same recurring transaction
  • Notify the customer that their recurring agreement has been cancelled
  • Offer reactivation options, such as opt in again or re-subscribe
  • Consider switching to a one-time payment if the customer still wants to complete the transaction

Sample request:

curl https://sandbox-card.peachpayments.com/v1/payments \
 -d "entityId=YOUR_ENTITY_ID" \
 -d "amount=1234.21" \
 -d "paymentType=DB" \
 -d "currency=EUR" \
 -d "merchantTransactionId=OrderTQMX4ZV34V-MAC21" \
 -d "paymentBrand=MASTER" \
 -d "card.holder=John Smith" \
 -d "card.number=5555555676186886" \
 -d "card.expiryMonth=12" \
 -d "card.expiryYear=2027" \
 -d "card.cvv=123" \
 -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
using System.Net.Http;
using System.Net.Http.Headers;

var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox-card.peachpayments.com/v1/payments");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_ACCESS_TOKEN");
request.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
  ["entityId"] = "YOUR_ENTITY_ID",
  ["amount"] = "1234.21",
  ["paymentType"] = "DB",
  ["currency"] = "EUR",
  ["merchantTransactionId"] = "OrderTQMX4ZV34V-MAC21",
  ["paymentBrand"] = "MASTER",
  ["card.holder"] = "John Smith",
  ["card.number"] = "5555555676186886",
  ["card.expiryMonth"] = "12",
  ["card.expiryYear"] = "2027",
  ["card.cvv"] = "123"
});
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
def url = "https://sandbox-card.peachpayments.com/v1/payments"
def body = [
  entityId: "YOUR_ENTITY_ID",
  amount: "1234.21",
  paymentType: "DB",
  currency: "EUR",
  merchantTransactionId: "OrderTQMX4ZV34V-MAC21",
  paymentBrand: "MASTER",
  "card.holder": "John Smith",
  "card.number": "5555555676186886",
  "card.expiryMonth": "12",
  "card.expiryYear": "2027",
  "card.cvv": "123"
]
def connection = new URL(url).openConnection()
connection.setRequestMethod("POST")
connection.setRequestProperty("Authorization", "Bearer YOUR_ACCESS_TOKEN")
connection.doOutput = true
connection.outputStream.withWriter { it << body.collect { k, v -> "$k=$v" }.join("&") }
def response = connection.inputStream.text
HttpClient client = HttpClient.newHttpClient();
String body = "entityId=YOUR_ENTITY_ID" +
  "&amount=1234.21" +
  "&paymentType=DB" +
  "&currency=EUR" +
  "&merchantTransactionId=OrderTQMX4ZV34V-MAC21" +
  "&paymentBrand=MASTER" +
  "&card.holder=John Smith" +
  "&card.number=5555555676186886" +
  "&card.expiryMonth=12" +
  "&card.expiryYear=2027" +
  "&card.cvv=123";
HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create("https://sandbox-card.peachpayments.com/v1/payments"))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .header("Content-Type", "application/x-www-form-urlencoded")
  .POST(HttpRequest.BodyPublishers.ofString(body))
  .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
const fetch = require("node-fetch");

const body = new URLSearchParams({
  entityId: "YOUR_ENTITY_ID",
  amount: "1234.21",
  paymentType: "DB",
  currency: "EUR",
  merchantTransactionId: "OrderTQMX4ZV34V-MAC21",
  paymentBrand: "MASTER",
  "card.holder": "John Smith",
  "card.number": "5555555676186886",
  "card.expiryMonth": "12",
  "card.expiryYear": "2027",
  "card.cvv": "123"
});

const response = await fetch("https://sandbox-card.peachpayments.com/v1/payments", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_ACCESS_TOKEN" },
  body
});
const data = await response.text();
$url = "https://sandbox-card.peachpayments.com/v1/payments";
$data = http_build_query([
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "1234.21",
  "paymentType" => "DB",
  "currency" => "EUR",
  "merchantTransactionId" => "OrderTQMX4ZV34V-MAC21",
  "paymentBrand" => "MASTER",
  "card.holder" => "John Smith",
  "card.number" => "5555555676186886",
  "card.expiryMonth" => "12",
  "card.expiryYear" => "2027",
  "card.cvv" => "123"
]);

$options = [
  "http" => [
    "method" => "POST",
    "header" => "Authorization: Bearer YOUR_ACCESS_TOKEN\r\n" .
                "Content-Type: application/x-www-form-urlencoded\r\n",
    "content" => $data
  ]
];

$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
import requests

payload = {
  "entityId": "YOUR_ENTITY_ID",
  "amount": "1234.21",
  "paymentType": "DB",
  "currency": "EUR",
  "merchantTransactionId": "OrderTQMX4ZV34V-MAC21",
  "paymentBrand": "MASTER",
  "card.holder": "John Smith",
  "card.number": "5555555676186886",
  "card.expiryMonth": "12",
  "card.expiryYear": "2027",
  "card.cvv": "123"
}

response = requests.post(
  "https://sandbox-card.peachpayments.com/v1/payments",
  headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN"},
  data=payload
)
require "net/http"

uri = URI("https://sandbox-card.peachpayments.com/v1/payments")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_ACCESS_TOKEN"
request.set_form_data(
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "1234.21",
  "paymentType" => "DB",
  "currency" => "EUR",
  "merchantTransactionId" => "OrderTQMX4ZV34V-MAC21",
  "paymentBrand" => "MASTER",
  "card.holder" => "John Smith",
  "card.number" => "5555555676186886",
  "card.expiryMonth" => "12",
  "card.expiryYear" => "2027",
  "card.cvv" => "123"
)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
import scalaj.http._

val response = Http("https://sandbox-card.peachpayments.com/v1/payments")
  .postForm(Seq(
    "entityId" -> "YOUR_ENTITY_ID",
    "amount" -> "1234.21",
    "paymentType" -> "DB",
    "currency" -> "EUR",
    "merchantTransactionId" -> "OrderTQMX4ZV34V-MAC21",
    "paymentBrand" -> "MASTER",
    "card.holder" -> "John Smith",
    "card.number" -> "5555555676186886",
    "card.expiryMonth" -> "12",
    "card.expiryYear" -> "2027",
    "card.cvv" -> "123"
  ))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .asString
Imports System.Net
Imports System.Text

Dim url = "https://sandbox-card.peachpayments.com/v1/payments"
Dim data = "entityId=YOUR_ENTITY_ID&amount=1234.21&paymentType=DB&currency=EUR&merchantTransactionId=OrderTQMX4ZV34V-MAC21&paymentBrand=MASTER&card.holder=John Smith&card.number=5555555676186886&card.expiryMonth=12&card.expiryYear=2027&card.cvv=123"
Dim request = CType(WebRequest.Create(url), HttpWebRequest)
request.Method = "POST"
request.Headers.Add("Authorization", "Bearer YOUR_ACCESS_TOKEN")
request.ContentType = "application/x-www-form-urlencoded"
Dim bytes = Encoding.UTF8.GetBytes(data)
request.ContentLength = bytes.Length
Using stream = request.GetRequestStream()
  stream.Write(bytes, 0, bytes.Length)
End Using
Dim response = CType(request.GetResponse(), HttpWebResponse)

Insufficient funds (MAC 02, MAC 24-30)

The merchant initiates a transaction, but the issuer responds with MAC 🟠 02 or 24-30 (Insufficient funds or credit limit reached). These are transaction-level issues. The cardholder may resolve them, so retrying can succeed, but only after the issuer-advised delay. MAC Control blocks identical retries during this window to avoid unnecessary costs.

How it works

  1. The merchant initiates a payment. The transaction gets declined with MAC 🟠 02 or 24-30 (Credit limits or insufficient funds).
  2. The merchant attempts a retry. MAC Control blocks the retry for the advised delay.

1. The merchant initiates a payment

Initiate a server-to-server POST request simulating a payment. Use an amount ending in .02, .24, or .25 to simulate MAC 🟠 02 or 24-30.

Sample request:

curl https://sandbox-card.peachpayments.com/v1/payments \
 -d "entityId=YOUR_ENTITY_ID" \
 -d "amount=1234.24" \
 -d "paymentType=DB" \
 -d "currency=EUR" \
 -d "merchantTransactionId=OrderUJ6VCXV5PN-MAC24" \
 -d "paymentBrand=MASTER" \
 -d "card.holder=John Smith" \
 -d "card.number=5555553987291859" \
 -d "card.expiryMonth=12" \
 -d "card.expiryYear=2027" \
 -d "card.cvv=123" \
 -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
using System.Net.Http;
using System.Net.Http.Headers;

var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox-card.peachpayments.com/v1/payments");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_ACCESS_TOKEN");
request.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
  ["entityId"] = "YOUR_ENTITY_ID",
  ["amount"] = "1234.24",
  ["paymentType"] = "DB",
  ["currency"] = "EUR",
  ["merchantTransactionId"] = "OrderUJ6VCXV5PN-MAC24",
  ["paymentBrand"] = "MASTER",
  ["card.holder"] = "John Smith",
  ["card.number"] = "5555553987291859",
  ["card.expiryMonth"] = "12",
  ["card.expiryYear"] = "2027",
  ["card.cvv"] = "123"
});
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
def url = "https://sandbox-card.peachpayments.com/v1/payments"
def body = [
  entityId: "YOUR_ENTITY_ID",
  amount: "1234.24",
  paymentType: "DB",
  currency: "EUR",
  merchantTransactionId: "OrderUJ6VCXV5PN-MAC24",
  paymentBrand: "MASTER",
  "card.holder": "John Smith",
  "card.number": "5555553987291859",
  "card.expiryMonth": "12",
  "card.expiryYear": "2027",
  "card.cvv": "123"
]
def connection = new URL(url).openConnection()
connection.setRequestMethod("POST")
connection.setRequestProperty("Authorization", "Bearer YOUR_ACCESS_TOKEN")
connection.doOutput = true
connection.outputStream.withWriter { it << body.collect { k, v -> "$k=$v" }.join("&") }
def response = connection.inputStream.text
HttpClient client = HttpClient.newHttpClient();
String body = "entityId=YOUR_ENTITY_ID" +
  "&amount=1234.24" +
  "&paymentType=DB" +
  "&currency=EUR" +
  "&merchantTransactionId=OrderUJ6VCXV5PN-MAC24" +
  "&paymentBrand=MASTER" +
  "&card.holder=John Smith" +
  "&card.number=5555553987291859" +
  "&card.expiryMonth=12" +
  "&card.expiryYear=2027" +
  "&card.cvv=123";
HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create("https://sandbox-card.peachpayments.com/v1/payments"))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .header("Content-Type", "application/x-www-form-urlencoded")
  .POST(HttpRequest.BodyPublishers.ofString(body))
  .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
const fetch = require("node-fetch");

const body = new URLSearchParams({
  entityId: "YOUR_ENTITY_ID",
  amount: "1234.24",
  paymentType: "DB",
  currency: "EUR",
  merchantTransactionId: "OrderUJ6VCXV5PN-MAC24",
  paymentBrand: "MASTER",
  "card.holder": "John Smith",
  "card.number": "5555553987291859",
  "card.expiryMonth": "12",
  "card.expiryYear": "2027",
  "card.cvv": "123"
});

const response = await fetch("https://sandbox-card.peachpayments.com/v1/payments", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_ACCESS_TOKEN" },
  body
});
const data = await response.text();
$url = "https://sandbox-card.peachpayments.com/v1/payments";
$data = http_build_query([
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "1234.24",
  "paymentType" => "DB",
  "currency" => "EUR",
  "merchantTransactionId" => "OrderUJ6VCXV5PN-MAC24",
  "paymentBrand" => "MASTER",
  "card.holder" => "John Smith",
  "card.number" => "5555553987291859",
  "card.expiryMonth" => "12",
  "card.expiryYear" => "2027",
  "card.cvv" => "123"
]);

$options = [
  "http" => [
    "method" => "POST",
    "header" => "Authorization: Bearer YOUR_ACCESS_TOKEN\r\n" .
                "Content-Type: application/x-www-form-urlencoded\r\n",
    "content" => $data
  ]
];

$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
import requests

payload = {
  "entityId": "YOUR_ENTITY_ID",
  "amount": "1234.24",
  "paymentType": "DB",
  "currency": "EUR",
  "merchantTransactionId": "OrderUJ6VCXV5PN-MAC24",
  "paymentBrand": "MASTER",
  "card.holder": "John Smith",
  "card.number": "5555553987291859",
  "card.expiryMonth": "12",
  "card.expiryYear": "2027",
  "card.cvv": "123"
}

response = requests.post(
  "https://sandbox-card.peachpayments.com/v1/payments",
  headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN"},
  data=payload
)
require "net/http"

uri = URI("https://sandbox-card.peachpayments.com/v1/payments")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_ACCESS_TOKEN"
request.set_form_data(
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "1234.24",
  "paymentType" => "DB",
  "currency" => "EUR",
  "merchantTransactionId" => "OrderUJ6VCXV5PN-MAC24",
  "paymentBrand" => "MASTER",
  "card.holder" => "John Smith",
  "card.number" => "5555553987291859",
  "card.expiryMonth" => "12",
  "card.expiryYear" => "2027",
  "card.cvv" => "123"
)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
import scalaj.http._

val response = Http("https://sandbox-card.peachpayments.com/v1/payments")
  .postForm(Seq(
    "entityId" -> "YOUR_ENTITY_ID",
    "amount" -> "1234.24",
    "paymentType" -> "DB",
    "currency" -> "EUR",
    "merchantTransactionId" -> "OrderUJ6VCXV5PN-MAC24",
    "paymentBrand" -> "MASTER",
    "card.holder" -> "John Smith",
    "card.number" -> "5555553987291859",
    "card.expiryMonth" -> "12",
    "card.expiryYear" -> "2027",
    "card.cvv" -> "123"
  ))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .asString
Imports System.Net
Imports System.Text

Dim url = "https://sandbox-card.peachpayments.com/v1/payments"
Dim data = "entityId=YOUR_ENTITY_ID&amount=1234.24&paymentType=DB&currency=EUR&merchantTransactionId=OrderUJ6VCXV5PN-MAC24&paymentBrand=MASTER&card.holder=John Smith&card.number=5555553987291859&card.expiryMonth=12&card.expiryYear=2027&card.cvv=123"
Dim request = CType(WebRequest.Create(url), HttpWebRequest)
request.Method = "POST"
request.Headers.Add("Authorization", "Bearer YOUR_ACCESS_TOKEN")
request.ContentType = "application/x-www-form-urlencoded"
Dim bytes = Encoding.UTF8.GetBytes(data)
request.ContentLength = bytes.Length
Using stream = request.GetRequestStream()
  stream.Write(bytes, 0, bytes.Length)
End Using
Dim response = CType(request.GetResponse(), HttpWebResponse)

2. The merchant attempts a retry

Retry the same transaction using the same account, amount, currency, and merchantTransactionId. MAC Control blocks it for the advised delay.

Merchant recommendation:

  • Do not retry immediately and respect the issuer-advised delay
  • Wait for the delay window before retrying the same transaction
  • Optionally retry with a modified transaction, such as a lower amount
  • Notify the customer about the failed payment and offer alternative payment methods

Sample request:

curl https://sandbox-card.peachpayments.com/v1/payments \
 -d "entityId=YOUR_ENTITY_ID" \
 -d "amount=1234.24" \
 -d "paymentType=DB" \
 -d "currency=EUR" \
 -d "merchantTransactionId=OrderUJ6VCXV5PN-MAC24" \
 -d "paymentBrand=MASTER" \
 -d "card.holder=John Smith" \
 -d "card.number=5555553987291859" \
 -d "card.expiryMonth=12" \
 -d "card.expiryYear=2027" \
 -d "card.cvv=123" \
 -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
using System.Net.Http;
using System.Net.Http.Headers;

var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox-card.peachpayments.com/v1/payments");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_ACCESS_TOKEN");
request.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
  ["entityId"] = "YOUR_ENTITY_ID",
  ["amount"] = "1234.24",
  ["paymentType"] = "DB",
  ["currency"] = "EUR",
  ["merchantTransactionId"] = "OrderUJ6VCXV5PN-MAC24",
  ["paymentBrand"] = "MASTER",
  ["card.holder"] = "John Smith",
  ["card.number"] = "5555553987291859",
  ["card.expiryMonth"] = "12",
  ["card.expiryYear"] = "2027",
  ["card.cvv"] = "123"
});
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
def url = "https://sandbox-card.peachpayments.com/v1/payments"
def body = [
  entityId: "YOUR_ENTITY_ID",
  amount: "1234.24",
  paymentType: "DB",
  currency: "EUR",
  merchantTransactionId: "OrderUJ6VCXV5PN-MAC24",
  paymentBrand: "MASTER",
  "card.holder": "John Smith",
  "card.number": "5555553987291859",
  "card.expiryMonth": "12",
  "card.expiryYear": "2027",
  "card.cvv": "123"
]
def connection = new URL(url).openConnection()
connection.setRequestMethod("POST")
connection.setRequestProperty("Authorization", "Bearer YOUR_ACCESS_TOKEN")
connection.doOutput = true
connection.outputStream.withWriter { it << body.collect { k, v -> "$k=$v" }.join("&") }
def response = connection.inputStream.text
HttpClient client = HttpClient.newHttpClient();
String body = "entityId=YOUR_ENTITY_ID" +
  "&amount=1234.24" +
  "&paymentType=DB" +
  "&currency=EUR" +
  "&merchantTransactionId=OrderUJ6VCXV5PN-MAC24" +
  "&paymentBrand=MASTER" +
  "&card.holder=John Smith" +
  "&card.number=5555553987291859" +
  "&card.expiryMonth=12" +
  "&card.expiryYear=2027" +
  "&card.cvv=123";
HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create("https://sandbox-card.peachpayments.com/v1/payments"))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .header("Content-Type", "application/x-www-form-urlencoded")
  .POST(HttpRequest.BodyPublishers.ofString(body))
  .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
const fetch = require("node-fetch");

const body = new URLSearchParams({
  entityId: "YOUR_ENTITY_ID",
  amount: "1234.24",
  paymentType: "DB",
  currency: "EUR",
  merchantTransactionId: "OrderUJ6VCXV5PN-MAC24",
  paymentBrand: "MASTER",
  "card.holder": "John Smith",
  "card.number": "5555553987291859",
  "card.expiryMonth": "12",
  "card.expiryYear": "2027",
  "card.cvv": "123"
});

const response = await fetch("https://sandbox-card.peachpayments.com/v1/payments", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_ACCESS_TOKEN" },
  body
});
const data = await response.text();
$url = "https://sandbox-card.peachpayments.com/v1/payments";
$data = http_build_query([
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "1234.24",
  "paymentType" => "DB",
  "currency" => "EUR",
  "merchantTransactionId" => "OrderUJ6VCXV5PN-MAC24",
  "paymentBrand" => "MASTER",
  "card.holder" => "John Smith",
  "card.number" => "5555553987291859",
  "card.expiryMonth" => "12",
  "card.expiryYear" => "2027",
  "card.cvv" => "123"
]);

$options = [
  "http" => [
    "method" => "POST",
    "header" => "Authorization: Bearer YOUR_ACCESS_TOKEN\r\n" .
                "Content-Type: application/x-www-form-urlencoded\r\n",
    "content" => $data
  ]
];

$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
import requests

payload = {
  "entityId": "YOUR_ENTITY_ID",
  "amount": "1234.24",
  "paymentType": "DB",
  "currency": "EUR",
  "merchantTransactionId": "OrderUJ6VCXV5PN-MAC24",
  "paymentBrand": "MASTER",
  "card.holder": "John Smith",
  "card.number": "5555553987291859",
  "card.expiryMonth": "12",
  "card.expiryYear": "2027",
  "card.cvv": "123"
}

response = requests.post(
  "https://sandbox-card.peachpayments.com/v1/payments",
  headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN"},
  data=payload
)
require "net/http"

uri = URI("https://sandbox-card.peachpayments.com/v1/payments")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_ACCESS_TOKEN"
request.set_form_data(
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "1234.24",
  "paymentType" => "DB",
  "currency" => "EUR",
  "merchantTransactionId" => "OrderUJ6VCXV5PN-MAC24",
  "paymentBrand" => "MASTER",
  "card.holder" => "John Smith",
  "card.number" => "5555553987291859",
  "card.expiryMonth" => "12",
  "card.expiryYear" => "2027",
  "card.cvv" => "123"
)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
import scalaj.http._

val response = Http("https://sandbox-card.peachpayments.com/v1/payments")
  .postForm(Seq(
    "entityId" -> "YOUR_ENTITY_ID",
    "amount" -> "1234.24",
    "paymentType" -> "DB",
    "currency" -> "EUR",
    "merchantTransactionId" -> "OrderUJ6VCXV5PN-MAC24",
    "paymentBrand" -> "MASTER",
    "card.holder" -> "John Smith",
    "card.number" -> "5555553987291859",
    "card.expiryMonth" -> "12",
    "card.expiryYear" -> "2027",
    "card.cvv" -> "123"
  ))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .asString
Imports System.Net
Imports System.Text

Dim url = "https://sandbox-card.peachpayments.com/v1/payments"
Dim data = "entityId=YOUR_ENTITY_ID&amount=1234.24&paymentType=DB&currency=EUR&merchantTransactionId=OrderUJ6VCXV5PN-MAC24&paymentBrand=MASTER&card.holder=John Smith&card.number=5555553987291859&card.expiryMonth=12&card.expiryYear=2027&card.cvv=123"
Dim request = CType(WebRequest.Create(url), HttpWebRequest)
request.Method = "POST"
request.Headers.Add("Authorization", "Bearer YOUR_ACCESS_TOKEN")
request.ContentType = "application/x-www-form-urlencoded"
Dim bytes = Encoding.UTF8.GetBytes(data)
request.ContentLength = bytes.Length
Using stream = request.GetRequestStream()
  stream.Write(bytes, 0, bytes.Length)
End Using
Dim response = CType(request.GetResponse(), HttpWebResponse)

Update account info (MAC 01)

The merchant initiates a transaction, but the issuer responds with MAC 🟠 01 (Cardholder account needs update). This typically means the card is expired, replaced, or otherwise outdated. Retrying with the same credentials fails. MAC Control blocks the retry for 7 days, unless updated credentials are received via Real Time Account Updater or Network Token lifecycle events.

How it works

  1. The merchant initiates a payment. The transaction gets declined with MAC 🟠 01 (Cardholder account needs update).
  2. The merchant attempts a retry. MAC Control blocks the retry for 7 days unless credentials are refreshed.

1. The merchant initiates a payment

Initiate a server-to-server POST request simulating a payment. Use an amount ending in .01 to simulate MAC 01.

Sample request:

curl https://sandbox-card.peachpayments.com/v1/payments \
 -d "entityId=YOUR_ENTITY_ID" \
 -d "amount=10.01" \
 -d "currency=ZAR" \
 -d "paymentBrand=VISA" \
 -d "paymentType=DB" \
 -d "card.number=4200000000000000" \
 -d "card.holder=Jane Jones" \
 -d "card.expiryMonth=05" \
 -d "card.expiryYear=2034" \
 -d "card.cvv=123" \
 -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
using System.Net.Http;
using System.Net.Http.Headers;

var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox-card.peachpayments.com/v1/payments");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_ACCESS_TOKEN");
request.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
  ["entityId"] = "YOUR_ENTITY_ID",
  ["amount"] = "10.01",
  ["currency"] = "ZAR",
  ["paymentBrand"] = "VISA",
  ["paymentType"] = "DB",
  ["card.number"] = "4200000000000000",
  ["card.holder"] = "Jane Jones",
  ["card.expiryMonth"] = "05",
  ["card.expiryYear"] = "2034",
  ["card.cvv"] = "123"
});
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
def url = "https://sandbox-card.peachpayments.com/v1/payments"
def body = [
  entityId: "YOUR_ENTITY_ID",
  amount: "10.01",
  currency: "ZAR",
  paymentBrand: "VISA",
  paymentType: "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
]
def connection = new URL(url).openConnection()
connection.setRequestMethod("POST")
connection.setRequestProperty("Authorization", "Bearer YOUR_ACCESS_TOKEN")
connection.doOutput = true
connection.outputStream.withWriter { it << body.collect { k, v -> "$k=$v" }.join("&") }
def response = connection.inputStream.text
HttpClient client = HttpClient.newHttpClient();
String body = "entityId=YOUR_ENTITY_ID" +
  "&amount=10.01" +
  "&currency=ZAR" +
  "&paymentBrand=VISA" +
  "&paymentType=DB" +
  "&card.number=4200000000000000" +
  "&card.holder=Jane Jones" +
  "&card.expiryMonth=05" +
  "&card.expiryYear=2034" +
  "&card.cvv=123";
HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create("https://sandbox-card.peachpayments.com/v1/payments"))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .header("Content-Type", "application/x-www-form-urlencoded")
  .POST(HttpRequest.BodyPublishers.ofString(body))
  .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
const fetch = require("node-fetch");

const body = new URLSearchParams({
  entityId: "YOUR_ENTITY_ID",
  amount: "10.01",
  currency: "ZAR",
  paymentBrand: "VISA",
  paymentType: "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
});

const response = await fetch("https://sandbox-card.peachpayments.com/v1/payments", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_ACCESS_TOKEN" },
  body
});
const data = await response.text();
$url = "https://sandbox-card.peachpayments.com/v1/payments";
$data = http_build_query([
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "10.01",
  "currency" => "ZAR",
  "paymentBrand" => "VISA",
  "paymentType" => "DB",
  "card.number" => "4200000000000000",
  "card.holder" => "Jane Jones",
  "card.expiryMonth" => "05",
  "card.expiryYear" => "2034",
  "card.cvv" => "123"
]);

$options = [
  "http" => [
    "method" => "POST",
    "header" => "Authorization: Bearer YOUR_ACCESS_TOKEN\r\n" .
                "Content-Type: application/x-www-form-urlencoded\r\n",
    "content" => $data
  ]
];

$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
import requests

payload = {
  "entityId": "YOUR_ENTITY_ID",
  "amount": "10.01",
  "currency": "ZAR",
  "paymentBrand": "VISA",
  "paymentType": "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
}

response = requests.post(
  "https://sandbox-card.peachpayments.com/v1/payments",
  headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN"},
  data=payload
)
require "net/http"

uri = URI("https://sandbox-card.peachpayments.com/v1/payments")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_ACCESS_TOKEN"
request.set_form_data(
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "10.01",
  "currency" => "ZAR",
  "paymentBrand" => "VISA",
  "paymentType" => "DB",
  "card.number" => "4200000000000000",
  "card.holder" => "Jane Jones",
  "card.expiryMonth" => "05",
  "card.expiryYear" => "2034",
  "card.cvv" => "123"
)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
import scalaj.http._

val response = Http("https://sandbox-card.peachpayments.com/v1/payments")
  .postForm(Seq(
    "entityId" -> "YOUR_ENTITY_ID",
    "amount" -> "10.01",
    "currency" -> "ZAR",
    "paymentBrand" -> "VISA",
    "paymentType" -> "DB",
    "card.number" -> "4200000000000000",
    "card.holder" -> "Jane Jones",
    "card.expiryMonth" -> "05",
    "card.expiryYear" -> "2034",
    "card.cvv" -> "123"
  ))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .asString
Imports System.Net
Imports System.Text

Dim url = "https://sandbox-card.peachpayments.com/v1/payments"
Dim data = "entityId=YOUR_ENTITY_ID&amount=10.01&currency=ZAR&paymentBrand=VISA&paymentType=DB&card.number=4200000000000000&card.holder=Jane Jones&card.expiryMonth=05&card.expiryYear=2034&card.cvv=123"
Dim request = CType(WebRequest.Create(url), HttpWebRequest)
request.Method = "POST"
request.Headers.Add("Authorization", "Bearer YOUR_ACCESS_TOKEN")
request.ContentType = "application/x-www-form-urlencoded"
Dim bytes = Encoding.UTF8.GetBytes(data)
request.ContentLength = bytes.Length
Using stream = request.GetRequestStream()
  stream.Write(bytes, 0, bytes.Length)
End Using
Dim response = CType(request.GetResponse(), HttpWebResponse)

2. The merchant attempts a retry

Retry the same transaction using the same account. Changing the amount, currency, or merchant transaction ID does not help because the issue is structural, not transactional. MAC Control blocks it for 7 days unless credentials are refreshed.

Merchant recommendation:

  • Do not retry with the same outdated credentials
  • Wait for credential refresh via Real Time Account Updater or Network Token lifecycle events
  • Prompt the customer to update their card details if no automatic update is available
  • Consider offering alternative payment methods

Sample request:

curl https://sandbox-card.peachpayments.com/v1/payments \
 -d "entityId=YOUR_ENTITY_ID" \
 -d "amount=10.01" \
 -d "currency=ZAR" \
 -d "paymentBrand=VISA" \
 -d "paymentType=DB" \
 -d "card.number=4200000000000000" \
 -d "card.holder=Jane Jones" \
 -d "card.expiryMonth=05" \
 -d "card.expiryYear=2034" \
 -d "card.cvv=123" \
 -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
using System.Net.Http;
using System.Net.Http.Headers;

var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox-card.peachpayments.com/v1/payments");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_ACCESS_TOKEN");
request.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
  ["entityId"] = "YOUR_ENTITY_ID",
  ["amount"] = "10.01",
  ["currency"] = "ZAR",
  ["paymentBrand"] = "VISA",
  ["paymentType"] = "DB",
  ["card.number"] = "4200000000000000",
  ["card.holder"] = "Jane Jones",
  ["card.expiryMonth"] = "05",
  ["card.expiryYear"] = "2034",
  ["card.cvv"] = "123"
});
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
def url = "https://sandbox-card.peachpayments.com/v1/payments"
def body = [
  entityId: "YOUR_ENTITY_ID",
  amount: "10.01",
  currency: "ZAR",
  paymentBrand: "VISA",
  paymentType: "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
]
def connection = new URL(url).openConnection()
connection.setRequestMethod("POST")
connection.setRequestProperty("Authorization", "Bearer YOUR_ACCESS_TOKEN")
connection.doOutput = true
connection.outputStream.withWriter { it << body.collect { k, v -> "$k=$v" }.join("&") }
def response = connection.inputStream.text
HttpClient client = HttpClient.newHttpClient();
String body = "entityId=YOUR_ENTITY_ID" +
  "&amount=10.01" +
  "&currency=ZAR" +
  "&paymentBrand=VISA" +
  "&paymentType=DB" +
  "&card.number=4200000000000000" +
  "&card.holder=Jane Jones" +
  "&card.expiryMonth=05" +
  "&card.expiryYear=2034" +
  "&card.cvv=123";
HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create("https://sandbox-card.peachpayments.com/v1/payments"))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .header("Content-Type", "application/x-www-form-urlencoded")
  .POST(HttpRequest.BodyPublishers.ofString(body))
  .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
const fetch = require("node-fetch");

const body = new URLSearchParams({
  entityId: "YOUR_ENTITY_ID",
  amount: "10.01",
  currency: "ZAR",
  paymentBrand: "VISA",
  paymentType: "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
});

const response = await fetch("https://sandbox-card.peachpayments.com/v1/payments", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_ACCESS_TOKEN" },
  body
});
const data = await response.text();
$url = "https://sandbox-card.peachpayments.com/v1/payments";
$data = http_build_query([
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "10.01",
  "currency" => "ZAR",
  "paymentBrand" => "VISA",
  "paymentType" => "DB",
  "card.number" => "4200000000000000",
  "card.holder" => "Jane Jones",
  "card.expiryMonth" => "05",
  "card.expiryYear" => "2034",
  "card.cvv" => "123"
]);

$options = [
  "http" => [
    "method" => "POST",
    "header" => "Authorization: Bearer YOUR_ACCESS_TOKEN\r\n" .
                "Content-Type: application/x-www-form-urlencoded\r\n",
    "content" => $data
  ]
];

$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
import requests

payload = {
  "entityId": "YOUR_ENTITY_ID",
  "amount": "10.01",
  "currency": "ZAR",
  "paymentBrand": "VISA",
  "paymentType": "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
}

response = requests.post(
  "https://sandbox-card.peachpayments.com/v1/payments",
  headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN"},
  data=payload
)
require "net/http"

uri = URI("https://sandbox-card.peachpayments.com/v1/payments")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_ACCESS_TOKEN"
request.set_form_data(
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "10.01",
  "currency" => "ZAR",
  "paymentBrand" => "VISA",
  "paymentType" => "DB",
  "card.number" => "4200000000000000",
  "card.holder" => "Jane Jones",
  "card.expiryMonth" => "05",
  "card.expiryYear" => "2034",
  "card.cvv" => "123"
)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
import scalaj.http._

val response = Http("https://sandbox-card.peachpayments.com/v1/payments")
  .postForm(Seq(
    "entityId" -> "YOUR_ENTITY_ID",
    "amount" -> "10.01",
    "currency" -> "ZAR",
    "paymentBrand" -> "VISA",
    "paymentType" -> "DB",
    "card.number" -> "4200000000000000",
    "card.holder" -> "Jane Jones",
    "card.expiryMonth" -> "05",
    "card.expiryYear" -> "2034",
    "card.cvv" -> "123"
  ))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .asString
Imports System.Net
Imports System.Text

Dim url = "https://sandbox-card.peachpayments.com/v1/payments"
Dim data = "entityId=YOUR_ENTITY_ID&amount=10.01&currency=ZAR&paymentBrand=VISA&paymentType=DB&card.number=4200000000000000&card.holder=Jane Jones&card.expiryMonth=05&card.expiryYear=2034&card.cvv=123"
Dim request = CType(WebRequest.Create(url), HttpWebRequest)
request.Method = "POST"
request.Headers.Add("Authorization", "Bearer YOUR_ACCESS_TOKEN")
request.ContentType = "application/x-www-form-urlencoded"
Dim bytes = Encoding.UTF8.GetBytes(data)
request.ContentLength = bytes.Length
Using stream = request.GetRequestStream()
  stream.Write(bytes, 0, bytes.Length)
End Using
Dim response = CType(request.GetResponse(), HttpWebResponse)

SCA required (MAC 01)

The merchant initiates a transaction, but the issuer responds with MAC 🟠 01 (Strong Customer Authentication required). This means the transaction must be authenticated using EMV 3DS or another SCA-compliant method. Retrying without authentication fails. MAC Control blocks the retry for 7 days, giving time to enable 3DS and meet issuer requirements.

How it works

  1. The merchant initiates a payment. The transaction gets declined with MAC 🟠 01 (Strong Customer Authentication required).
  2. The merchant attempts a retry. MAC Control blocks it for 7 days.

1. The merchant initiates a payment

Initiate a server-to-server POST request simulating a payment. Use an amount ending in .11 to simulate MAC 01.

Sample request:

curl https://sandbox-card.peachpayments.com/v1/payments \
 -d "entityId=YOUR_ENTITY_ID" \
 -d "amount=10.11" \
 -d "currency=ZAR" \
 -d "paymentBrand=VISA" \
 -d "paymentType=DB" \
 -d "card.number=4200000000000000" \
 -d "card.holder=Jane Jones" \
 -d "card.expiryMonth=05" \
 -d "card.expiryYear=2034" \
 -d "card.cvv=123" \
 -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
using System.Net.Http;
using System.Net.Http.Headers;

var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox-card.peachpayments.com/v1/payments");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_ACCESS_TOKEN");
request.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
  ["entityId"] = "YOUR_ENTITY_ID",
  ["amount"] = "10.11",
  ["currency"] = "ZAR",
  ["paymentBrand"] = "VISA",
  ["paymentType"] = "DB",
  ["card.number"] = "4200000000000000",
  ["card.holder"] = "Jane Jones",
  ["card.expiryMonth"] = "05",
  ["card.expiryYear"] = "2034",
  ["card.cvv"] = "123"
});
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
def url = "https://sandbox-card.peachpayments.com/v1/payments"
def body = [
  entityId: "YOUR_ENTITY_ID",
  amount: "10.11",
  currency: "ZAR",
  paymentBrand: "VISA",
  paymentType: "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
]
def connection = new URL(url).openConnection()
connection.setRequestMethod("POST")
connection.setRequestProperty("Authorization", "Bearer YOUR_ACCESS_TOKEN")
connection.doOutput = true
connection.outputStream.withWriter { it << body.collect { k, v -> "$k=$v" }.join("&") }
def response = connection.inputStream.text
HttpClient client = HttpClient.newHttpClient();
String body = "entityId=YOUR_ENTITY_ID" +
  "&amount=10.11" +
  "&currency=ZAR" +
  "&paymentBrand=VISA" +
  "&paymentType=DB" +
  "&card.number=4200000000000000" +
  "&card.holder=Jane Jones" +
  "&card.expiryMonth=05" +
  "&card.expiryYear=2034" +
  "&card.cvv=123";
HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create("https://sandbox-card.peachpayments.com/v1/payments"))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .header("Content-Type", "application/x-www-form-urlencoded")
  .POST(HttpRequest.BodyPublishers.ofString(body))
  .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
const fetch = require("node-fetch");

const body = new URLSearchParams({
  entityId: "YOUR_ENTITY_ID",
  amount: "10.11",
  currency: "ZAR",
  paymentBrand: "VISA",
  paymentType: "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
});

const response = await fetch("https://sandbox-card.peachpayments.com/v1/payments", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_ACCESS_TOKEN" },
  body
});
const data = await response.text();
$url = "https://sandbox-card.peachpayments.com/v1/payments";
$data = http_build_query([
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "10.11",
  "currency" => "ZAR",
  "paymentBrand" => "VISA",
  "paymentType" => "DB",
  "card.number" => "4200000000000000",
  "card.holder" => "Jane Jones",
  "card.expiryMonth" => "05",
  "card.expiryYear" => "2034",
  "card.cvv" => "123"
]);

$options = [
  "http" => [
    "method" => "POST",
    "header" => "Authorization: Bearer YOUR_ACCESS_TOKEN\r\n" .
                "Content-Type: application/x-www-form-urlencoded\r\n",
    "content" => $data
  ]
];

$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
import requests

payload = {
  "entityId": "YOUR_ENTITY_ID",
  "amount": "10.11",
  "currency": "ZAR",
  "paymentBrand": "VISA",
  "paymentType": "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
}

response = requests.post(
  "https://sandbox-card.peachpayments.com/v1/payments",
  headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN"},
  data=payload
)
require "net/http"

uri = URI("https://sandbox-card.peachpayments.com/v1/payments")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_ACCESS_TOKEN"
request.set_form_data(
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "10.11",
  "currency" => "ZAR",
  "paymentBrand" => "VISA",
  "paymentType" => "DB",
  "card.number" => "4200000000000000",
  "card.holder" => "Jane Jones",
  "card.expiryMonth" => "05",
  "card.expiryYear" => "2034",
  "card.cvv" => "123"
)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
import scalaj.http._

val response = Http("https://sandbox-card.peachpayments.com/v1/payments")
  .postForm(Seq(
    "entityId" -> "YOUR_ENTITY_ID",
    "amount" -> "10.11",
    "currency" -> "ZAR",
    "paymentBrand" -> "VISA",
    "paymentType" -> "DB",
    "card.number" -> "4200000000000000",
    "card.holder" -> "Jane Jones",
    "card.expiryMonth" -> "05",
    "card.expiryYear" -> "2034",
    "card.cvv" -> "123"
  ))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .asString
Imports System.Net
Imports System.Text

Dim url = "https://sandbox-card.peachpayments.com/v1/payments"
Dim data = "entityId=YOUR_ENTITY_ID&amount=10.11&currency=ZAR&paymentBrand=VISA&paymentType=DB&card.number=4200000000000000&card.holder=Jane Jones&card.expiryMonth=05&card.expiryYear=2034&card.cvv=123"
Dim request = CType(WebRequest.Create(url), HttpWebRequest)
request.Method = "POST"
request.Headers.Add("Authorization", "Bearer YOUR_ACCESS_TOKEN")
request.ContentType = "application/x-www-form-urlencoded"
Dim bytes = Encoding.UTF8.GetBytes(data)
request.ContentLength = bytes.Length
Using stream = request.GetRequestStream()
  stream.Write(bytes, 0, bytes.Length)
End Using
Dim response = CType(request.GetResponse(), HttpWebResponse)

2. The merchant attempts a retry

Retry the same transaction using the same account. Changing the amount, currency, or merchant transaction ID does not help because the issue is structural, not transactional. MAC Control blocks it for 7 days.

Merchant recommendation:

  • Do not retry without authentication
  • Enable EMV 3DS on the merchant channel and account

Sample request:

curl https://sandbox-card.peachpayments.com/v1/payments \
 -d "entityId=YOUR_ENTITY_ID" \
 -d "amount=10.11" \
 -d "currency=ZAR" \
 -d "paymentBrand=VISA" \
 -d "paymentType=DB" \
 -d "card.number=4200000000000000" \
 -d "card.holder=Jane Jones" \
 -d "card.expiryMonth=05" \
 -d "card.expiryYear=2034" \
 -d "card.cvv=123" \
 -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
using System.Net.Http;
using System.Net.Http.Headers;

var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox-card.peachpayments.com/v1/payments");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_ACCESS_TOKEN");
request.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
  ["entityId"] = "YOUR_ENTITY_ID",
  ["amount"] = "10.11",
  ["currency"] = "ZAR",
  ["paymentBrand"] = "VISA",
  ["paymentType"] = "DB",
  ["card.number"] = "4200000000000000",
  ["card.holder"] = "Jane Jones",
  ["card.expiryMonth"] = "05",
  ["card.expiryYear"] = "2034",
  ["card.cvv"] = "123"
});
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
def url = "https://sandbox-card.peachpayments.com/v1/payments"
def body = [
  entityId: "YOUR_ENTITY_ID",
  amount: "10.11",
  currency: "ZAR",
  paymentBrand: "VISA",
  paymentType: "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
]
def connection = new URL(url).openConnection()
connection.setRequestMethod("POST")
connection.setRequestProperty("Authorization", "Bearer YOUR_ACCESS_TOKEN")
connection.doOutput = true
connection.outputStream.withWriter { it << body.collect { k, v -> "$k=$v" }.join("&") }
def response = connection.inputStream.text
HttpClient client = HttpClient.newHttpClient();
String body = "entityId=YOUR_ENTITY_ID" +
  "&amount=10.11" +
  "&currency=ZAR" +
  "&paymentBrand=VISA" +
  "&paymentType=DB" +
  "&card.number=4200000000000000" +
  "&card.holder=Jane Jones" +
  "&card.expiryMonth=05" +
  "&card.expiryYear=2034" +
  "&card.cvv=123";
HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create("https://sandbox-card.peachpayments.com/v1/payments"))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .header("Content-Type", "application/x-www-form-urlencoded")
  .POST(HttpRequest.BodyPublishers.ofString(body))
  .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
const fetch = require("node-fetch");

const body = new URLSearchParams({
  entityId: "YOUR_ENTITY_ID",
  amount: "10.11",
  currency: "ZAR",
  paymentBrand: "VISA",
  paymentType: "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
});

const response = await fetch("https://sandbox-card.peachpayments.com/v1/payments", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_ACCESS_TOKEN" },
  body
});
const data = await response.text();
$url = "https://sandbox-card.peachpayments.com/v1/payments";
$data = http_build_query([
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "10.11",
  "currency" => "ZAR",
  "paymentBrand" => "VISA",
  "paymentType" => "DB",
  "card.number" => "4200000000000000",
  "card.holder" => "Jane Jones",
  "card.expiryMonth" => "05",
  "card.expiryYear" => "2034",
  "card.cvv" => "123"
]);

$options = [
  "http" => [
    "method" => "POST",
    "header" => "Authorization: Bearer YOUR_ACCESS_TOKEN\r\n" .
                "Content-Type: application/x-www-form-urlencoded\r\n",
    "content" => $data
  ]
];

$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
import requests

payload = {
  "entityId": "YOUR_ENTITY_ID",
  "amount": "10.11",
  "currency": "ZAR",
  "paymentBrand": "VISA",
  "paymentType": "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
}

response = requests.post(
  "https://sandbox-card.peachpayments.com/v1/payments",
  headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN"},
  data=payload
)
require "net/http"

uri = URI("https://sandbox-card.peachpayments.com/v1/payments")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_ACCESS_TOKEN"
request.set_form_data(
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "10.11",
  "currency" => "ZAR",
  "paymentBrand" => "VISA",
  "paymentType" => "DB",
  "card.number" => "4200000000000000",
  "card.holder" => "Jane Jones",
  "card.expiryMonth" => "05",
  "card.expiryYear" => "2034",
  "card.cvv" => "123"
)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
import scalaj.http._

val response = Http("https://sandbox-card.peachpayments.com/v1/payments")
  .postForm(Seq(
    "entityId" -> "YOUR_ENTITY_ID",
    "amount" -> "10.11",
    "currency" -> "ZAR",
    "paymentBrand" -> "VISA",
    "paymentType" -> "DB",
    "card.number" -> "4200000000000000",
    "card.holder" -> "Jane Jones",
    "card.expiryMonth" -> "05",
    "card.expiryYear" -> "2034",
    "card.cvv" -> "123"
  ))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .asString
Imports System.Net
Imports System.Text

Dim url = "https://sandbox-card.peachpayments.com/v1/payments"
Dim data = "entityId=YOUR_ENTITY_ID&amount=10.11&currency=ZAR&paymentBrand=VISA&paymentType=DB&card.number=4200000000000000&card.holder=Jane Jones&card.expiryMonth=05&card.expiryYear=2034&card.cvv=123"
Dim request = CType(WebRequest.Create(url), HttpWebRequest)
request.Method = "POST"
request.Headers.Add("Authorization", "Bearer YOUR_ACCESS_TOKEN")
request.ContentType = "application/x-www-form-urlencoded"
Dim bytes = Encoding.UTF8.GetBytes(data)
request.ContentLength = bytes.Length
Using stream = request.GetRequestStream()
  stream.Write(bytes, 0, bytes.Length)
End Using
Dim response = CType(request.GetResponse(), HttpWebResponse)

Not eligible for instalment (MAC 22)

The merchant initiates a transaction using an instalment product, but the issuer responds with MAC 🟠 22 (Not Eligible for Product). This means the merchant is not enrolled in the scheme instalment programme or the product is not supported for the cardholder. Retrying with the same account and product fails. MAC Control blocks the retry for 30 days, allowing time to review eligibility and avoid repeated declines.

How it works

  1. The merchant initiates a payment. The transaction gets declined with MAC 🟠 22 (Merchant not eligible for instalment product).
  2. The merchant attempts a retry. MAC Control blocks it for 30 days.

1. The merchant initiates a payment

Initiate a server-to-server POST request simulating a payment. Use an amount ending in .22 to simulate MAC 🟠 22.

Sample request:

curl https://sandbox-card.peachpayments.com/v1/payments \
 -d "entityId=YOUR_ENTITY_ID" \
 -d "amount=10.22" \
 -d "currency=ZAR" \
 -d "paymentBrand=VISA" \
 -d "paymentType=DB" \
 -d "card.number=4200000000000000" \
 -d "card.holder=Jane Jones" \
 -d "card.expiryMonth=05" \
 -d "card.expiryYear=2034" \
 -d "card.cvv=123" \
 -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
using System.Net.Http;
using System.Net.Http.Headers;

var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox-card.peachpayments.com/v1/payments");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_ACCESS_TOKEN");
request.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
  ["entityId"] = "YOUR_ENTITY_ID",
  ["amount"] = "10.22",
  ["currency"] = "ZAR",
  ["paymentBrand"] = "VISA",
  ["paymentType"] = "DB",
  ["card.number"] = "4200000000000000",
  ["card.holder"] = "Jane Jones",
  ["card.expiryMonth"] = "05",
  ["card.expiryYear"] = "2034",
  ["card.cvv"] = "123"
});
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
def url = "https://sandbox-card.peachpayments.com/v1/payments"
def body = [
  entityId: "YOUR_ENTITY_ID",
  amount: "10.22",
  currency: "ZAR",
  paymentBrand: "VISA",
  paymentType: "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
]
def connection = new URL(url).openConnection()
connection.setRequestMethod("POST")
connection.setRequestProperty("Authorization", "Bearer YOUR_ACCESS_TOKEN")
connection.doOutput = true
connection.outputStream.withWriter { it << body.collect { k, v -> "$k=$v" }.join("&") }
def response = connection.inputStream.text
HttpClient client = HttpClient.newHttpClient();
String body = "entityId=YOUR_ENTITY_ID" +
  "&amount=10.22" +
  "&currency=ZAR" +
  "&paymentBrand=VISA" +
  "&paymentType=DB" +
  "&card.number=4200000000000000" +
  "&card.holder=Jane Jones" +
  "&card.expiryMonth=05" +
  "&card.expiryYear=2034" +
  "&card.cvv=123";
HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create("https://sandbox-card.peachpayments.com/v1/payments"))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .header("Content-Type", "application/x-www-form-urlencoded")
  .POST(HttpRequest.BodyPublishers.ofString(body))
  .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
const fetch = require("node-fetch");

const body = new URLSearchParams({
  entityId: "YOUR_ENTITY_ID",
  amount: "10.22",
  currency: "ZAR",
  paymentBrand: "VISA",
  paymentType: "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
});

const response = await fetch("https://sandbox-card.peachpayments.com/v1/payments", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_ACCESS_TOKEN" },
  body
});
const data = await response.text();
$url = "https://sandbox-card.peachpayments.com/v1/payments";
$data = http_build_query([
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "10.22",
  "currency" => "ZAR",
  "paymentBrand" => "VISA",
  "paymentType" => "DB",
  "card.number" => "4200000000000000",
  "card.holder" => "Jane Jones",
  "card.expiryMonth" => "05",
  "card.expiryYear" => "2034",
  "card.cvv" => "123"
]);

$options = [
  "http" => [
    "method" => "POST",
    "header" => "Authorization: Bearer YOUR_ACCESS_TOKEN\r\n" .
                "Content-Type: application/x-www-form-urlencoded\r\n",
    "content" => $data
  ]
];

$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
import requests

payload = {
  "entityId": "YOUR_ENTITY_ID",
  "amount": "10.22",
  "currency": "ZAR",
  "paymentBrand": "VISA",
  "paymentType": "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
}

response = requests.post(
  "https://sandbox-card.peachpayments.com/v1/payments",
  headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN"},
  data=payload
)
require "net/http"

uri = URI("https://sandbox-card.peachpayments.com/v1/payments")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_ACCESS_TOKEN"
request.set_form_data(
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "10.22",
  "currency" => "ZAR",
  "paymentBrand" => "VISA",
  "paymentType" => "DB",
  "card.number" => "4200000000000000",
  "card.holder" => "Jane Jones",
  "card.expiryMonth" => "05",
  "card.expiryYear" => "2034",
  "card.cvv" => "123"
)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
import scalaj.http._

val response = Http("https://sandbox-card.peachpayments.com/v1/payments")
  .postForm(Seq(
    "entityId" -> "YOUR_ENTITY_ID",
    "amount" -> "10.22",
    "currency" -> "ZAR",
    "paymentBrand" -> "VISA",
    "paymentType" -> "DB",
    "card.number" -> "4200000000000000",
    "card.holder" -> "Jane Jones",
    "card.expiryMonth" -> "05",
    "card.expiryYear" -> "2034",
    "card.cvv" -> "123"
  ))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .asString
Imports System.Net
Imports System.Text

Dim url = "https://sandbox-card.peachpayments.com/v1/payments"
Dim data = "entityId=YOUR_ENTITY_ID&amount=10.22&currency=ZAR&paymentBrand=VISA&paymentType=DB&card.number=4200000000000000&card.holder=Jane Jones&card.expiryMonth=05&card.expiryYear=2034&card.cvv=123"
Dim request = CType(WebRequest.Create(url), HttpWebRequest)
request.Method = "POST"
request.Headers.Add("Authorization", "Bearer YOUR_ACCESS_TOKEN")
request.ContentType = "application/x-www-form-urlencoded"
Dim bytes = Encoding.UTF8.GetBytes(data)
request.ContentLength = bytes.Length
Using stream = request.GetRequestStream()
  stream.Write(bytes, 0, bytes.Length)
End Using
Dim response = CType(request.GetResponse(), HttpWebResponse)

2. The merchant attempts a retry

Retry the same transaction using the same account. Changing the amount, currency, or merchant transaction ID does not help because the issue is structural, not transactional. MAC Control blocks it for 30 days.

Merchant recommendation:

  • Do not retry with the same product and account
  • Review eligibility for the instalment programme with the acquirer or scheme
  • Switch to a standard payment product if instalment is not supported
  • Notify the customer and offer alternative payment options, such as pay in full or use a wallet

Sample request:

curl https://sandbox-card.peachpayments.com/v1/payments \
 -d "entityId=YOUR_ENTITY_ID" \
 -d "amount=10.22" \
 -d "currency=ZAR" \
 -d "paymentBrand=VISA" \
 -d "paymentType=DB" \
 -d "card.number=4200000000000000" \
 -d "card.holder=Jane Jones" \
 -d "card.expiryMonth=05" \
 -d "card.expiryYear=2034" \
 -d "card.cvv=123" \
 -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
using System.Net.Http;
using System.Net.Http.Headers;

var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox-card.peachpayments.com/v1/payments");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_ACCESS_TOKEN");
request.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
  ["entityId"] = "YOUR_ENTITY_ID",
  ["amount"] = "10.22",
  ["currency"] = "ZAR",
  ["paymentBrand"] = "VISA",
  ["paymentType"] = "DB",
  ["card.number"] = "4200000000000000",
  ["card.holder"] = "Jane Jones",
  ["card.expiryMonth"] = "05",
  ["card.expiryYear"] = "2034",
  ["card.cvv"] = "123"
});
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
def url = "https://sandbox-card.peachpayments.com/v1/payments"
def body = [
  entityId: "YOUR_ENTITY_ID",
  amount: "10.22",
  currency: "ZAR",
  paymentBrand: "VISA",
  paymentType: "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
]
def connection = new URL(url).openConnection()
connection.setRequestMethod("POST")
connection.setRequestProperty("Authorization", "Bearer YOUR_ACCESS_TOKEN")
connection.doOutput = true
connection.outputStream.withWriter { it << body.collect { k, v -> "$k=$v" }.join("&") }
def response = connection.inputStream.text
HttpClient client = HttpClient.newHttpClient();
String body = "entityId=YOUR_ENTITY_ID" +
  "&amount=10.22" +
  "&currency=ZAR" +
  "&paymentBrand=VISA" +
  "&paymentType=DB" +
  "&card.number=4200000000000000" +
  "&card.holder=Jane Jones" +
  "&card.expiryMonth=05" +
  "&card.expiryYear=2034" +
  "&card.cvv=123";
HttpRequest request = HttpRequest.newBuilder()
  .uri(URI.create("https://sandbox-card.peachpayments.com/v1/payments"))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .header("Content-Type", "application/x-www-form-urlencoded")
  .POST(HttpRequest.BodyPublishers.ofString(body))
  .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
const fetch = require("node-fetch");

const body = new URLSearchParams({
  entityId: "YOUR_ENTITY_ID",
  amount: "10.22",
  currency: "ZAR",
  paymentBrand: "VISA",
  paymentType: "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
});

const response = await fetch("https://sandbox-card.peachpayments.com/v1/payments", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_ACCESS_TOKEN" },
  body
});
const data = await response.text();
$url = "https://sandbox-card.peachpayments.com/v1/payments";
$data = http_build_query([
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "10.22",
  "currency" => "ZAR",
  "paymentBrand" => "VISA",
  "paymentType" => "DB",
  "card.number" => "4200000000000000",
  "card.holder" => "Jane Jones",
  "card.expiryMonth" => "05",
  "card.expiryYear" => "2034",
  "card.cvv" => "123"
]);

$options = [
  "http" => [
    "method" => "POST",
    "header" => "Authorization: Bearer YOUR_ACCESS_TOKEN\r\n" .
                "Content-Type: application/x-www-form-urlencoded\r\n",
    "content" => $data
  ]
];

$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
import requests

payload = {
  "entityId": "YOUR_ENTITY_ID",
  "amount": "10.22",
  "currency": "ZAR",
  "paymentBrand": "VISA",
  "paymentType": "DB",
  "card.number": "4200000000000000",
  "card.holder": "Jane Jones",
  "card.expiryMonth": "05",
  "card.expiryYear": "2034",
  "card.cvv": "123"
}

response = requests.post(
  "https://sandbox-card.peachpayments.com/v1/payments",
  headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN"},
  data=payload
)
require "net/http"

uri = URI("https://sandbox-card.peachpayments.com/v1/payments")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_ACCESS_TOKEN"
request.set_form_data(
  "entityId" => "YOUR_ENTITY_ID",
  "amount" => "10.22",
  "currency" => "ZAR",
  "paymentBrand" => "VISA",
  "paymentType" => "DB",
  "card.number" => "4200000000000000",
  "card.holder" => "Jane Jones",
  "card.expiryMonth" => "05",
  "card.expiryYear" => "2034",
  "card.cvv" => "123"
)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
import scalaj.http._

val response = Http("https://sandbox-card.peachpayments.com/v1/payments")
  .postForm(Seq(
    "entityId" -> "YOUR_ENTITY_ID",
    "amount" -> "10.22",
    "currency" -> "ZAR",
    "paymentBrand" -> "VISA",
    "paymentType" -> "DB",
    "card.number" -> "4200000000000000",
    "card.holder" -> "Jane Jones",
    "card.expiryMonth" -> "05",
    "card.expiryYear" -> "2034",
    "card.cvv" -> "123"
  ))
  .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
  .asString
Imports System.Net
Imports System.Text

Dim url = "https://sandbox-card.peachpayments.com/v1/payments"
Dim data = "entityId=YOUR_ENTITY_ID&amount=10.22&currency=ZAR&paymentBrand=VISA&paymentType=DB&card.number=4200000000000000&card.holder=Jane Jones&card.expiryMonth=05&card.expiryYear=2034&card.cvv=123"
Dim request = CType(WebRequest.Create(url), HttpWebRequest)
request.Method = "POST"
request.Headers.Add("Authorization", "Bearer YOUR_ACCESS_TOKEN")
request.ContentType = "application/x-www-form-urlencoded"
Dim bytes = Encoding.UTF8.GetBytes(data)
request.ContentLength = bytes.Length
Using stream = request.GetRequestStream()
  stream.Write(bytes, 0, bytes.Length)
End Using
Dim response = CType(request.GetResponse(), HttpWebResponse)

Configuration

MAC Control requires a commercial agreement and requires support team assistance to activate.