Test AVS responses
Drive an address match, a mismatch and an unavailable result through the sandbox, so your integration reads the AVS code off the response instead of assuming the address was checked.
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.
4 steps, 3 API callsPaymentsTransactions
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.
Drive each response in the sandbox
1. Send a sale whose address verifies
API call
POST /api/transactions
Sending the billing ZIP 66666 makes the sandbox answer with the AVS response code "Y" and report it as "Address and ZIP match" in the response. This is the baseline. Run it first so the two below are a comparison rather than a single result you have nothing to weigh against.
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,
"billingAddress": { "zip": "66666" }
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
}'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,
billingAddress = new { zip = "66666" }
},
invoiceData = new
{
amounts = new { @base = 10.00m, total = 10.00m }
}
});
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
var validation = result.GetProperty("responseData").GetProperty("cardValidationData");
var avs = validation.GetProperty("avsResponse").GetString();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": "Ok",
"authorizedAmount": 10.00,
"responseData": {
"resultCode": "Ok",
"resultMessage": "Approved",
"cardValidationData": {
"avsResponse": "Y",
"avsResponseText": "Address and ZIP match"
}
}
}2. Send a sale whose address fails to verify
API call
POST /api/transactions
Sending the billing ZIP 33333 makes the sandbox answer with the AVS response code "N" and report it as "Address and ZIP do not match" in the response. The transaction still approves. AVS doesn't refuse anything on its own, so an integration that reads only the result code can't tell this response apart from the one above.
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,
"billingAddress": { "zip": "33333" }
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
}'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,
billingAddress = new { zip = "33333" }
},
invoiceData = new
{
amounts = new { @base = 10.00m, total = 10.00m }
}
});
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
var validation = result.GetProperty("responseData").GetProperty("cardValidationData");
var avs = validation.GetProperty("avsResponse").GetString();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": "Ok",
"authorizedAmount": 10.00,
"responseData": {
"resultCode": "Ok",
"resultMessage": "Approved",
"cardValidationData": {
"avsResponse": "N",
"avsResponseText": "Address and ZIP do not match"
}
}
}3. Send a sale the issuer can't verify
API call
POST /api/transactions
Sending the billing ZIP 55555 makes the sandbox answer with the AVS response code "U" and report it as "Address information unavailable" in the response. The third state, and the one most often missed. No answer isn't the same as a mismatch, and a rule that treats it as one refuses good cardholders whose issuer doesn't participate.
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,
"billingAddress": { "zip": "55555" }
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
}'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,
billingAddress = new { zip = "55555" }
},
invoiceData = new
{
amounts = new { @base = 10.00m, total = 10.00m }
}
});
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
var validation = result.GetProperty("responseData").GetProperty("cardValidationData");
var avs = validation.GetProperty("avsResponse").GetString();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": "Ok",
"authorizedAmount": 10.00,
"responseData": {
"resultCode": "Ok",
"resultMessage": "Approved",
"cardValidationData": {
"avsResponse": "U",
"avsResponseText": "Address information unavailable"
}
}
}Read the verification codes
4. Compare the three responses
On your side
The code is on responseData.cardValidationData.avsResponse and the text the simulator reported it with is on responseData.cardValidationData.avsResponseText. Every call above sent the sandbox's guaranteed-approval amount, so the result code was the same on all three and only the verification code moved. The sandbox honours 17 billing ZIP triggers in total. The full table is on the testing page rather than repeated here. The verification code never changes the result code, so all three of these approve. Whether a mismatch should refuse the payment is your merchant's policy, configured on the merchant's card verification settings and applied after the processor answers. What your integration owes the payer is a decision it can explain. Read the code, make the call on purpose, and treat an unavailable answer as its own case rather than folding it into the mismatch branch.