Standalone exemption
Send a standalone server-to-server request to determine whether a transaction qualifies for an exemption.
You must be fully PCI compliant to perform a standalone exemption request, as it requires collecting card data.
1. Send the standalone exemption request
Use the standalone endpoint to send requests to the exemption engine: https://sandbox-card.peachpayments.com/v1/exemption
curl https://sandbox-card.peachpayments.com/v1/exemption \
-d "entityId=8a8294174e735d0c014e78cf26461790" \
-d "amount=12.50" \
-d "currency=EUR" \
-d "paymentBrand=VISA" \
-d "card.number=4200000000000042" \
-d "card.holder=John Smith" \
-d "card.expiryMonth=12" \
-d "card.expiryYear=2026" \
-d "card.cvv=123" \
-d "risk.parameters[EX_merchant.mcc]=3000" \
-d "risk.parameters[EX_merchant.postcode]=0125EH" \
-d "risk.parameters[EX_channelId]=000503000001" \
-d "risk.parameters[EX_serviceId]=I" \
-d "[email protected]" \
-d "testMode=EXTERNAL" \
-H "Authorization: Bearer OGE4Mjk0MTc0ZTczNWQwYzAxNGU3OGNmMjY2YjE3OTR8SFV3I3JGQTQ9bWpxaWYrPz9OWVQ="public Dictionary<string, dynamic> Request() {
Dictionary<string, dynamic> responseData;
string data="entityId=8a8294174e735d0c014e78cf26461790" +
"&amount=12.50" +
"¤cy=EUR" +
"&paymentBrand=VISA" +
"&card.number=4200000000000042" +
"&card.holder=John Smith" +
"&card.expiryMonth=12" +
"&card.expiryYear=2026" +
"&card.cvv=123" +
"&risk.parameters[EX_merchant.mcc]=3000" +
"&risk.parameters[EX_merchant.postcode]=0125EH" +
"&risk.parameters[EX_channelId]=000503000001" +
"&risk.parameters[EX_serviceId]=I" +
"&[email protected]" +
"&testMode=EXTERNAL";
string url = "https://sandbox-card.peachpayments.com/v1/exemption";
byte[] buffer = Encoding.ASCII.GetBytes(data);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
request.Method = "POST";
request.Headers["Authorization"] = "Bearer OGE4Mjk0MTc0ZTczNWQwYzAxNGU3OGNmMjY2YjE3OTR8SFV3I3JGQTQ9bWpxaWYrPz9OWVQ=";
request.ContentType = "application/x-www-form-urlencoded";
Stream PostData = request.GetRequestStream();
PostData.Write(buffer, 0, buffer.Length);
PostData.Close();
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
var s = new JavaScriptSerializer();
responseData = s.Deserialize<Dictionary<string, dynamic>>(reader.ReadToEnd());
reader.Close();
dataStream.Close();
}
return responseData;
}
responseData = Request()["result"]["description"];import groovy.json.JsonSlurper
public static String request() {
def data = "entityId=8a8294174e735d0c014e78cf26461790" +
"&amount=12.50" +
"¤cy=EUR" +
"&paymentBrand=VISA" +
"&card.number=4200000000000042" +
"&card.holder=John Smith" +
"&card.expiryMonth=12" +
"&card.expiryYear=2026" +
"&card.cvv=123" +
"&risk.parameters[EX_merchant.mcc]=3000" +
"&risk.parameters[EX_merchant.postcode]=0125EH" +
"&risk.parameters[EX_channelId]=000503000001" +
"&risk.parameters[EX_serviceId]=I" +
"&[email protected]" +
"&testMode=EXTERNAL"
def url = "https://sandbox-card.peachpayments.com/v1/exemption".toURL()
def connection = url.openConnection()
connection.setRequestMethod("POST")
connection.setRequestProperty("Authorization", "Bearer OGE4Mjk0MTc0ZTczNWQwYzAxNGU3OGNmMjY2YjE3OTR8SFV3I3JGQTQ9bWpxaWYrPz9OWVQ=")
connection.doOutput = true
connection.outputStream << data
def json = new JsonSlurper().parseText(connection.inputStream.text)
json
}
println request()private String request() throws IOException {
URL url = new URL("https://sandbox-card.peachpayments.com/v1/exemption");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Authorization", "Bearer OGE4Mjk0MTc0ZTczNWQwYzAxNGU3OGNmMjY2YjE3OTR8SFV3I3JGQTQ9bWpxaWYrPz9OWVQ=");
conn.setDoInput(true);
conn.setDoOutput(true);
String data = ""
+ "entityId=8a8294174e735d0c014e78cf26461790"
+ "&amount=12.50"
+ "¤cy=EUR"
+ "&paymentBrand=VISA"
+ "&card.number=4200000000000042"
+ "&card.holder=John Smith"
+ "&card.expiryMonth=12"
+ "&card.expiryYear=2026"
+ "&card.cvv=123"
+ "&risk.parameters[EX_merchant.mcc]=3000"
+ "&risk.parameters[EX_merchant.postcode]=0125EH"
+ "&risk.parameters[EX_channelId]=000503000001"
+ "&risk.parameters[EX_serviceId]=I"
+ "&[email protected]"
+ "&testMode=EXTERNAL";
DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
wr.writeBytes(data);
wr.flush();
wr.close();
int responseCode = conn.getResponseCode();
InputStream is;
if (responseCode >= 400) {
is = conn.getErrorStream();
} else {
is = conn.getInputStream();
}
return IOUtils.toString(is);
}const https = require('https');
const querystring = require('querystring');
const request = async () => {
const path = '/v1/exemption';
const data = querystring.stringify({
'entityId': '8a8294174e735d0c014e78cf26461790',
'amount': '12.50',
'currency': 'EUR',
'paymentBrand': 'VISA',
'card.number': '4200000000000042',
'card.holder': 'John Smith',
'card.expiryMonth': '12',
'card.expiryYear': '2026',
'card.cvv': '123',
'risk.parameters[EX_merchant.mcc]': '3000',
'risk.parameters[EX_merchant.postcode]': '0125EH',
'risk.parameters[EX_channelId]': '000503000001',
'risk.parameters[EX_serviceId]': 'I',
'customer.email': '[email protected]',
'testMode': 'EXTERNAL'
});
const options = {
port: 443,
host: 'sandbox-card.peachpayments.com',
path: path,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': data.length,
'Authorization': 'Bearer OGE4Mjk0MTc0ZTczNWQwYzAxNGU3OGNmMjY2YjE3OTR8SFV3I3JGQTQ9bWpxaWYrPz9OWVQ='
}
};
return new Promise((resolve, reject) => {
const postRequest = https.request(options, function (res) {
const buf = [];
res.on('data', chunk => {
buf.push(Buffer.from(chunk));
});
res.on('end', () => {
const jsonString = Buffer.concat(buf).toString('utf8');
try {
resolve(JSON.parse(jsonString));
} catch (error) {
reject(error);
}
});
});
postRequest.on('error', reject);
postRequest.write(data);
postRequest.end();
});
};
request().then(console.log).catch(console.error);function request() {
$url = "https://sandbox-card.peachpayments.com/v1/exemption";
$data = "entityId=8a8294174e735d0c014e78cf26461790" .
"&amount=12.50" .
"¤cy=EUR" .
"&paymentBrand=VISA" .
"&card.number=4200000000000042" .
"&card.holder=John Smith" .
"&card.expiryMonth=12" .
"&card.expiryYear=2026" .
"&card.cvv=123" .
"&risk.parameters[EX_merchant.mcc]=3000" .
"&risk.parameters[EX_merchant.postcode]=0125EH" .
"&risk.parameters[EX_channelId]=000503000001" .
"&risk.parameters[EX_serviceId]=I" .
"&[email protected]" .
"&testMode=EXTERNAL";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Authorization:Bearer OGE4Mjk0MTc0ZTczNWQwYzAxNGU3OGNmMjY2YjE3OTR8SFV3I3JGQTQ9bWpxaWYrPz9OWVQ='
));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // this should be set to true in production
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$responseData = curl_exec($ch);
if (curl_errno($ch)) {
return curl_error($ch);
}
curl_close($ch);
return $responseData;
}
$responseData = request();try:
from urllib.parse import urlencode
from urllib.request import build_opener, Request, HTTPHandler
from urllib.error import HTTPError, URLError
except ImportError:
from urllib import urlencode
from urllib2 import build_opener, Request, HTTPHandler, HTTPError, URLError
import json
def request():
url = "https://sandbox-card.peachpayments.com/v1/exemption"
data = {
'entityId': '8a8294174e735d0c014e78cf26461790',
'amount': '12.50',
'currency': 'EUR',
'paymentBrand': 'VISA',
'card.number': '4200000000000042',
'card.holder': 'John Smith',
'card.expiryMonth': '12',
'card.expiryYear': '2026',
'card.cvv': '123',
'risk.parameters[EX_merchant.mcc]': '3000',
'risk.parameters[EX_merchant.postcode]': '0125EH',
'risk.parameters[EX_channelId]': '000503000001',
'risk.parameters[EX_serviceId]': 'I',
'customer.email': '[email protected]',
'testMode': 'EXTERNAL'
}
try:
opener = build_opener(HTTPHandler)
request = Request(url, data=urlencode(data).encode('utf-8'))
request.add_header('Authorization', 'Bearer OGE4Mjk0MTc0ZTczNWQwYzAxNGU3OGNmMjY2YjE3OTR8SFV3I3JGQTQ9bWpxaWYrPz9OWVQ=')
request.get_method = lambda: 'POST'
response = opener.open(request)
return json.loads(response.read())
except HTTPError as e:
return json.loads(e.read())
except URLError as e:
return e.reason
responseData = request()
print(responseData)require 'net/https'
require 'uri'
require 'json'
def request()
uri = URI('https://sandbox-card.peachpayments.com/v1/exemption')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri.path)
req.set_form_data({
'entityId' => '8a8294174e735d0c014e78cf26461790',
'amount' => '12.50',
'currency' => 'EUR',
'paymentBrand' => 'VISA',
'card.number' => '4200000000000042',
'card.holder' => 'John Smith',
'card.expiryMonth' => '12',
'card.expiryYear' => '2026',
'card.cvv' => '123',
'risk.parameters[EX_merchant.mcc]' => '3000',
'risk.parameters[EX_merchant.postcode]' => '0125EH',
'risk.parameters[EX_channelId]' => '000503000001',
'risk.parameters[EX_serviceId]' => 'I',
'customer.email' => '[email protected]',
'testMode' => 'EXTERNAL'
})
res = http.request(req)
return JSON.parse(res.body)
end
puts request()def initialPayment: String = {
val url = "https://sandbox-card.peachpayments.com/v1/exemption"
val data = ("" +
"entityId=8a8294174e735d0c014e78cf26461790" +
"&amount=12.50" +
"¤cy=EUR" +
"&paymentBrand=VISA" +
"&card.number=4200000000000042" +
"&card.holder=John Smith" +
"&card.expiryMonth=12" +
"&card.expiryYear=2026" +
"&card.cvv=123" +
"&risk.parameters[EX_merchant.mcc]=3000" +
"&risk.parameters[EX_merchant.postcode]=0125EH" +
"&risk.parameters[EX_channelId]=000503000001" +
"&risk.parameters[EX_serviceId]=I" +
"&[email protected]" +
"&testMode=EXTERNAL"
)
val conn = new URL(url).openConnection()
conn match {
case secureConn: HttpsURLConnection => secureConn.setRequestMethod("POST")
case _ => throw new ClassCastException
}
conn.setDoInput(true)
conn.setDoOutput(true)
IOUtils.write(data, conn.getOutputStream())
conn.setRequestProperty("Authorization", "Bearer OGE4Mjk0MTc0ZTczNWQwYzAxNGU3OGNmMjY2YjE3OTR8SFV3I3JGQTQ9bWpxaWYrPz9OWVQ=")
conn.connect()
if (conn.getResponseCode() >= 400) {
return IOUtils.toString(conn.getErrorStream())
} else {
return IOUtils.toString(conn.getInputStream())
}
}Public Function Request() As Dictionary(Of String, Object)
Dim url As String = "https://sandbox-card.peachpayments.com/v1/exemption"
Dim data As String = "" +
"entityId=8a8294174e735d0c014e78cf26461790" +
"&amount=12.50" +
"¤cy=EUR" +
"&paymentBrand=VISA" +
"&card.number=4200000000000042" +
"&card.holder=John Smith" +
"&card.expiryMonth=12" +
"&card.expiryYear=2026" +
"&card.cvv=123" +
"&risk.parameters[EX_merchant.mcc]=3000" +
"&risk.parameters[EX_merchant.postcode]=0125EH" +
"&risk.parameters[EX_channelId]=000503000001" +
"&risk.parameters[EX_serviceId]=I" +
"&[email protected]" +
"&testMode=EXTERNAL"
Dim req As WebRequest = WebRequest.Create(url)
req.Method = "POST"
req.Headers.Add("Authorization", "Bearer OGE4Mjk0MTc0ZTczNWQwYzAxNGU3OGNmMjY2YjE3OTR8SFV3I3JGQTQ9bWpxaWYrPz9OWVQ=")
req.ContentType = "application/x-www-form-urlencoded"
Dim byteArray As Byte() = Encoding.UTF8.GetBytes(data)
req.ContentLength = byteArray.Length
Dim dataStream As Stream = req.GetRequestStream()
dataStream.Write(byteArray, 0, byteArray.Length)
dataStream.Close()
Dim res As WebResponse = req.GetResponse()
Dim resStream = res.GetResponseStream()
Dim reader As New StreamReader(resStream)
Dim response As String = reader.ReadToEnd()
reader.Close()
resStream.Close()
res.Close()
Dim jss As New System.Web.Script.Serialization.JavaScriptSerializer()
Dim dict As Dictionary(Of String, Object) = jss.Deserialize(Of Dictionary(Of String, Object))(response)
Return dict
End Function
responseData = Request()("result")("description"){
"id":"8ac7a4a19d29e143019d29e9df7a1835",
"paymentBrand":"VISA",
"amount":"12.50",
"currency":"EUR",
"result":{
"code":"000.300.103",
"description":"Exemption check successful"
},
"resultDetails":{
"RiskFraudTSWHitFlag":"N",
"IovationAccountCode":"[email protected]",
"RiskFraudTREHitFlag":"Y",
"EXTERNAL_SYSTEM_LINK":"https://csi-stage.aciondemand.com/mars/en-US/search/transaction/000503000001ACQ20260326073126518",
"RiskFraudCNBNumHits":"0",
"RiskReport":"0330",
"RiskRuleCategory":"SCAEX_01",
"RiskFraudMaxTof":"1757",
"TransactionId":"3839.0943.1332",
"RiskFraudMinTof":"1",
"RiskFraudCNBHitFlag":"N",
"RiskFraudSDSNumHits":"0",
"RiskFraudVirtualBin":"840",
"RiskFraudTRENumHits":"1",
"action":"created",
"RiskOrderId":"000503000001ACQ20260326073126518",
"RiskFraudSDSHitFlag":"N",
"RiskFraudCardClass":"VIS",
"RiskFraudTSWNumHits":"0"
},
"card":{
"bin":"420000",
"last4Digits":"0042",
"holder":"John Smith",
"expiryMonth":"12",
"expiryYear":"2027"
},
"customer":{
"email":"[email protected]"
},
"risk":{
"parameters":{
"EX_channelId":"000503000001",
"EX_merchant.mcc":"3000",
"EX_merchant.postcode":"0125EH",
"EX_serviceId":"I"
}
},
"buildNumber":"9092e7a6af8301accda2f9a3a38f743f907dadd5@2026-03-23 16:50:06 +0000",
"timestamp":"2026-03-26 11:31:26+0000",
"ndc":"8a8294174e735d0c014e78cf26461790_8a8c4451de474e93a1be6849f8aa87e8"
}2. Handle the response
To determine which exemption applies, check the value in the resultDetails.RiskRuleCategory field. This value is always prefixed with SCAEX_. The two-digit value after the prefix indicates the applicable exemption:
- 00: Exemption is not applicable
- 01: Low-value exemption is applicable
- 02: TRA exemption is applicable
- 03: Trusted beneficiary exemption is applicable
- 04: Corporate card exemption is applicable
To use an exemption during payment, include threeDSecure.exemptionFlag in the payment request with the applicable two-digit value.
Updated about 7 hours ago