Simulate a card decline
Send a card sale the sandbox always refuses, and handle the refusal where it actually arrives: in the response body, not as a transport error.
Signed in, you can run this blueprint against your own sandbox merchant one call at a time, with the values from each call threaded into the next. Sign in to run it.
2 steps, 1 API callPaymentsTransactions
Samples use {{API_KEY}} for your API key and {{BASE_URL}} for this instance's API address. Anything else in double braces is a value an earlier step gave you.
Reproduce it in the sandbox
1. Send the sale at the declining amount
API call
POST /api/transactions
The cents of the amount pick the outcome, and the rest of the amount is ignored, so this is the same sale request as any other with one number changed.
Values this step gives you
curl -X POST "{{BASE_URL}}/api/transactions" \
-H "api-key: {{API_KEY}}" \
-H "Content-Type: application/json" \
-d '{
"transactionType": "Sale",
"cardData": {
"cardNumber": "4111111111111111",
"nameOnCard": "Jane Doe",
"expirationMonth": 12,
"expirationYear": 2030,
"cvv": 123
},
"invoiceData": {
"amounts": { "base": 10.01, "total": 10.01 }
}
}'using var http = new HttpClient { BaseAddress = new Uri("{{BASE_URL}}") };
http.DefaultRequestHeaders.Add("api-key", "{{API_KEY}}");
var response = await http.PostAsJsonAsync("/api/transactions", new
{
transactionType = "Sale",
cardData = new
{
cardNumber = "4111111111111111",
nameOnCard = "Jane Doe",
expirationMonth = 12,
expirationYear = 2030,
cvv = 123
},
invoiceData = new
{
amounts = new { @base = 10.01m, total = 10.01m }
}
});
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
var resultCode = result.GetProperty("responseData").GetProperty("resultCode").GetString();2. Read the outcome off the response
On your side
The sandbox answers with the result code "Decline" and the message "AUTH DECLINED" in the response body. The platform files that result under the "Declined" outcome. The response carries host error 200. The refusal arrives on a successful HTTP response, because the request itself worked: a refused card is a business outcome, not a transport failure. An integration that decides on the status code alone reads this as a completed payment, which is the mistake this scenario exists to find.
Values this step gives you
What this step answers with
Abridged to the properties this step depends on. A real response carries more.
{
"id": "9f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"merchantId": "3a7b1c9d-2e4f-4a6b-8c8d-9e0f1a2b3c4d",
"resultCode": "Decline",
"responseData": {
"resultCode": "Decline",
"resultMessage": "AUTH DECLINED"
}
}