No such blueprint
This instance publishes no blueprint at that address. The catalog lists every one it does publish.
Back to the blueprints
Blueprints
/
Testing scenarios
Handle a CVV mismatch
Drive a CVV match, a no-match, and an issuer that can't check, so your integration handles the security code the payer typed rather than assuming it was verified.
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 .
On this page
4 steps, 3 API calls Payments Transactions
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 security code matches API call
POST
/api/transactions
Sending the CVV 111 makes the sandbox answer with the cardholder-verification response code "M" and report it as "CVV match" in the response. The baseline again. Everything below is only meaningful next to this one.
Reference for this operation
Values this step gives you
cURL CopycURL
Copied
Copy failed
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": 111
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
}'.NET Copy.NET
Copied
Copy failed
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 = 111
},
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 cv = validation.GetProperty("cvResponse").GetString();What this step answers with
Abridged to the properties this step depends on. A real response carries more.
HTTP 200 CopyHTTP 200
Copied
Copy failed
{
"id": "9f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"merchantId": "3a7b1c9d-2e4f-4a6b-8c8d-9e0f1a2b3c4d",
"resultCode": "Ok",
"authorizedAmount": 10.00,
"responseData": {
"resultCode": "Ok",
"resultMessage": "Approved",
"cardValidationData": {
"cvResponse": "M",
"cvResultText": "CVV match"
}
}
}2. Send a sale whose security code fails to match API call
POST
/api/transactions
Sending the CVV 222 makes the sandbox answer with the cardholder-verification response code "N" and report it as "CVV no match" in the response. The transaction approves anyway. This is the case that surprises people. The platform reports a wrong security code rather than refusing it, and an integration that stores the card on this response has stored one the payer may not hold.
Reference for this operation
Values this step gives you
cURL CopycURL
Copied
Copy failed
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": 222
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
}'.NET Copy.NET
Copied
Copy failed
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 = 222
},
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 cv = validation.GetProperty("cvResponse").GetString();What this step answers with
Abridged to the properties this step depends on. A real response carries more.
HTTP 200 CopyHTTP 200
Copied
Copy failed
{
"id": "9f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"merchantId": "3a7b1c9d-2e4f-4a6b-8c8d-9e0f1a2b3c4d",
"resultCode": "Ok",
"authorizedAmount": 10.00,
"responseData": {
"resultCode": "Ok",
"resultMessage": "Approved",
"cardValidationData": {
"cvResponse": "N",
"cvResultText": "CVV no match"
}
}
}3. Send a sale the issuer can't check API call
POST
/api/transactions
Sending the CVV 555 makes the sandbox answer with the cardholder-verification response code "U" and report it as "Issuer unable to process CVV" in the response. The third state. The code went out and no answer came back, which is evidence of nothing either way and shouldn't score as a match.
Reference for this operation
Values this step gives you
cURL CopycURL
Copied
Copy failed
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": 555
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
}'.NET Copy.NET
Copied
Copy failed
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 = 555
},
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 cv = validation.GetProperty("cvResponse").GetString();What this step answers with
Abridged to the properties this step depends on. A real response carries more.
HTTP 200 CopyHTTP 200
Copied
Copy failed
{
"id": "9f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
"merchantId": "3a7b1c9d-2e4f-4a6b-8c8d-9e0f1a2b3c4d",
"resultCode": "Ok",
"authorizedAmount": 10.00,
"responseData": {
"resultCode": "Ok",
"resultMessage": "Approved",
"cardValidationData": {
"cvResponse": "U",
"cvResultText": "Issuer unable to process CVV"
}
}
}Read the verification codes 4. Compare the three responses On your side
The code is on responseData.cardValidationData.cvResponse and the text the simulator reported it with is on responseData.cardValidationData.cvResultText. 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 10 CVV triggers in total. The full table is on the testing page rather than repeated here. As with AVS, none of these change the result code, and the merchant's card verification settings decide whether a no-match refuses the payment. The one to get right in your own code is the difference between a code that was checked and wrong and one that was never checked at all. Collapsing them into a single failure branch refuses payers whose issuer never answered.
Reference for this operation
Testing your integration
Values this step gives you
Run the whole flow as one script
Every step above in one script you can copy and run. Replace {{API_KEY}} with your own API key and {{BASE_URL}} with this instance's API address, and set any value the script asks you for at the top. A step that happens outside the API stays a comment.
Code sample language >_
cURL PS
PowerShell TS
TypeScript C#
C# Py
Python
brew install jq
Copythe install command for cURL
Copied
Copy failed
cURL CopycURL
Copied
Copy failed
#!/usr/bin/env bash
# Handle a CVV mismatch
#
# Drive a CVV match, a no-match, and an issuer that can't check, so your integration handles the
# security code the payer typed rather than assuming it was verified.
#
# Every API call in this blueprint, in order. Each value a call returns is passed to the calls after
# it. A step that happens outside the API is a comment, and any failed call stops the script.
set -euo pipefail
BASE_URL="{{BASE_URL}}"
API_KEY="{{API_KEY}}"
# Sends one request and prints the response body. A failed call prints the API's answer and stops
# the script.
call() {
local method="$1" path="$2" body="${3:-}" out
local args=(-sS --fail-with-body -X "$method" "$BASE_URL$path" -H "api-key: $API_KEY")
if [ -n "$body" ]; then
args+=(-H "Content-Type: application/json" -d "$body")
fi
if ! out=$(curl "${args[@]}"); then
printf '%s\n' "$out" >&2
return 1
fi
printf '%s' "$out"
}
# Phase 1: Drive each response in the sandbox
# Step 1: Send a sale whose security code matches
call POST "/api/transactions" '{
"transactionType": "Sale",
"cardData": {
"cardNumber": "4111111111111111",
"nameOnCard": "Jane Doe",
"expirationMonth": 12,
"expirationYear": 2030,
"cvv": 111
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
}' > /dev/null
# Step 2: Send a sale whose security code fails to match
call POST "/api/transactions" '{
"transactionType": "Sale",
"cardData": {
"cardNumber": "4111111111111111",
"nameOnCard": "Jane Doe",
"expirationMonth": 12,
"expirationYear": 2030,
"cvv": 222
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
}' > /dev/null
# Step 3: Send a sale the issuer can't check
call POST "/api/transactions" '{
"transactionType": "Sale",
"cardData": {
"cardNumber": "4111111111111111",
"nameOnCard": "Jane Doe",
"expirationMonth": 12,
"expirationYear": 2030,
"cvv": 555
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
}' > /dev/null
# Phase 2: Read the verification codes
# Step 4: Compare the three responses
# The code is on responseData.cardValidationData.cvResponse and the text the simulator reported it
# with is on responseData.cardValidationData.cvResultText. 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 10 CVV triggers in total. The full table is on the testing page
# rather than repeated here. As with AVS, none of these change the result code, and the merchant's
# card verification settings decide whether a no-match refuses the payment. The one to get right in
# your own code is the difference between a code that was checked and wrong and one that was never
# checked at all. Collapsing them into a single failure branch refuses payers whose issuer never
# answered.
Copythe install command for PowerShell
Copied
Copy failed
PowerShell CopyPowerShell
Copied
Copy failed
# Handle a CVV mismatch
#
# Drive a CVV match, a no-match, and an issuer that can't check, so your integration handles the
# security code the payer typed rather than assuming it was verified.
#
# Every API call in this blueprint, in order. Each value a call returns is passed to the calls after
# it. A step that happens outside the API is a comment, and any failed call stops the script.
$ErrorActionPreference = 'Stop'
$baseUrl = '{{BASE_URL}}'
$apiKey = '{{API_KEY}}'
# Sends one request and returns the parsed response body. A failed call stops the script.
function Invoke-BlueprintCall([string] $Method, [string] $Path, [string] $Body) {
$arguments = @{
Method = $Method
Uri = $baseUrl + $Path
Headers = @{ 'api-key' = $apiKey }
}
if ($Body) {
$arguments.ContentType = 'application/json'
$arguments.Body = [System.Text.Encoding]::UTF8.GetBytes($Body)
}
Invoke-RestMethod @arguments
}
# Phase 1: Drive each response in the sandbox
# Step 1: Send a sale whose security code matches
$body = @'
{
"transactionType": "Sale",
"cardData": {
"cardNumber": "4111111111111111",
"nameOnCard": "Jane Doe",
"expirationMonth": 12,
"expirationYear": 2030,
"cvv": 111
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
}
'@
$null = Invoke-BlueprintCall -Method 'POST' -Path '/api/transactions' -Body $body
# Step 2: Send a sale whose security code fails to match
$body = @'
{
"transactionType": "Sale",
"cardData": {
"cardNumber": "4111111111111111",
"nameOnCard": "Jane Doe",
"expirationMonth": 12,
"expirationYear": 2030,
"cvv": 222
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
}
'@
$null = Invoke-BlueprintCall -Method 'POST' -Path '/api/transactions' -Body $body
# Step 3: Send a sale the issuer can't check
$body = @'
{
"transactionType": "Sale",
"cardData": {
"cardNumber": "4111111111111111",
"nameOnCard": "Jane Doe",
"expirationMonth": 12,
"expirationYear": 2030,
"cvv": 555
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
}
'@
$null = Invoke-BlueprintCall -Method 'POST' -Path '/api/transactions' -Body $body
# Phase 2: Read the verification codes
# Step 4: Compare the three responses
# The code is on responseData.cardValidationData.cvResponse and the text the simulator reported it
# with is on responseData.cardValidationData.cvResultText. 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 10 CVV triggers in total. The full table is on the testing page
# rather than repeated here. As with AVS, none of these change the result code, and the merchant's
# card verification settings decide whether a no-match refuses the payment. The one to get right in
# your own code is the difference between a code that was checked and wrong and one that was never
# checked at all. Collapsing them into a single failure branch refuses payers whose issuer never
# answered.
Copythe install command for TypeScript
Copied
Copy failed
TypeScript CopyTypeScript
Copied
Copy failed
// Handle a CVV mismatch
//
// Drive a CVV match, a no-match, and an issuer that can't check, so your integration handles the
// security code the payer typed rather than assuming it was verified.
//
// Every API call in this blueprint, in order. Each value a call returns is passed to the calls
// after it. A step that happens outside the API is a comment, and any failed call stops the script.
export {};
const baseUrl = '{{BASE_URL}}';
const apiKey = '{{API_KEY}}';
// Sends one request and returns the parsed response body. A failed call throws.
async function call(method: string, path: string, body?: unknown): Promise<any> {
const headers: Record<string, string> = { 'api-key': apiKey };
if (body !== undefined) {
headers['Content-Type'] = 'application/json';
}
const response = await fetch(baseUrl + path, {
method,
headers,
body: body === undefined ? undefined : JSON.stringify(body),
});
const text = await response.text();
if (!response.ok) {
throw new Error(`${method} ${path} answered ${response.status}: ${text}`);
}
return text ? JSON.parse(text) : null;
}
// Phase 1: Drive each response in the sandbox
// Step 1: Send a sale whose security code matches
await call('POST', '/api/transactions', {
"transactionType": "Sale",
"cardData": {
"cardNumber": "4111111111111111",
"nameOnCard": "Jane Doe",
"expirationMonth": 12,
"expirationYear": 2030,
"cvv": 111
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
});
// Step 2: Send a sale whose security code fails to match
await call('POST', '/api/transactions', {
"transactionType": "Sale",
"cardData": {
"cardNumber": "4111111111111111",
"nameOnCard": "Jane Doe",
"expirationMonth": 12,
"expirationYear": 2030,
"cvv": 222
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
});
// Step 3: Send a sale the issuer can't check
await call('POST', '/api/transactions', {
"transactionType": "Sale",
"cardData": {
"cardNumber": "4111111111111111",
"nameOnCard": "Jane Doe",
"expirationMonth": 12,
"expirationYear": 2030,
"cvv": 555
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
});
// Phase 2: Read the verification codes
// Step 4: Compare the three responses
// The code is on responseData.cardValidationData.cvResponse and the text the simulator reported it
// with is on responseData.cardValidationData.cvResultText. 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 10 CVV triggers in total. The full table is on the
// testing page rather than repeated here. As with AVS, none of these change the result code, and
// the merchant's card verification settings decide whether a no-match refuses the payment. The one
// to get right in your own code is the difference between a code that was checked and wrong and one
// that was never checked at all. Collapsing them into a single failure branch refuses payers whose
// issuer never answered.
Copythe install command for C#
Copied
Copy failed
C# CopyC#
Copied
Copy failed
// Handle a CVV mismatch
//
// Drive a CVV match, a no-match, and an issuer that can't check, so your integration handles the
// security code the payer typed rather than assuming it was verified.
//
// Every API call in this blueprint, in order. Each value a call returns is passed to the calls
// after it. A step that happens outside the API is a comment, and any failed call stops the script.
using System.Text;
using System.Text.Json;
var baseUrl = "{{BASE_URL}}";
var apiKey = "{{API_KEY}}";
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("api-key", apiKey);
// Sends one request and returns the parsed response body. A failed call throws.
async Task<JsonElement> CallAsync(string method, string path, string? body = null)
{
using var request = new HttpRequestMessage(new HttpMethod(method), baseUrl + path);
if (body is not null)
{
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
}
using var response = await http.SendAsync(request);
var json = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException($"{method} {path} answered {(int)response.StatusCode}: {json}");
}
return json.Length == 0 ? default : JsonSerializer.Deserialize<JsonElement>(json);
}
// Phase 1: Drive each response in the sandbox
// Step 1: Send a sale whose security code matches
await CallAsync("POST", "/api/transactions", """
{
"transactionType": "Sale",
"cardData": {
"cardNumber": "4111111111111111",
"nameOnCard": "Jane Doe",
"expirationMonth": 12,
"expirationYear": 2030,
"cvv": 111
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
}
""");
// Step 2: Send a sale whose security code fails to match
await CallAsync("POST", "/api/transactions", """
{
"transactionType": "Sale",
"cardData": {
"cardNumber": "4111111111111111",
"nameOnCard": "Jane Doe",
"expirationMonth": 12,
"expirationYear": 2030,
"cvv": 222
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
}
""");
// Step 3: Send a sale the issuer can't check
await CallAsync("POST", "/api/transactions", """
{
"transactionType": "Sale",
"cardData": {
"cardNumber": "4111111111111111",
"nameOnCard": "Jane Doe",
"expirationMonth": 12,
"expirationYear": 2030,
"cvv": 555
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
}
""");
// Phase 2: Read the verification codes
// Step 4: Compare the three responses
// The code is on responseData.cardValidationData.cvResponse and the text the simulator reported it
// with is on responseData.cardValidationData.cvResultText. 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 10 CVV triggers in total. The full table is on the
// testing page rather than repeated here. As with AVS, none of these change the result code, and
// the merchant's card verification settings decide whether a no-match refuses the payment. The one
// to get right in your own code is the difference between a code that was checked and wrong and one
// that was never checked at all. Collapsing them into a single failure branch refuses payers whose
// issuer never answered.
pip install requests
Copythe install command for Python
Copied
Copy failed
Python CopyPython
Copied
Copy failed
# Handle a CVV mismatch
#
# Drive a CVV match, a no-match, and an issuer that can't check, so your integration handles the
# security code the payer typed rather than assuming it was verified.
#
# Every API call in this blueprint, in order. Each value a call returns is passed to the calls after
# it. A step that happens outside the API is a comment, and any failed call stops the script.
import requests
BASE_URL = "{{BASE_URL}}"
API_KEY = "{{API_KEY}}"
# Sends one request and returns the parsed response body. A failed call raises.
def call(method, path, body=None):
response = requests.request(
method,
BASE_URL + path,
headers={"api-key": API_KEY},
json=body,
)
response.raise_for_status()
return response.json() if response.content else None
# Phase 1: Drive each response in the sandbox
# Step 1: Send a sale whose security code matches
call("POST", "/api/transactions", {
"transactionType": "Sale",
"cardData": {
"cardNumber": "4111111111111111",
"nameOnCard": "Jane Doe",
"expirationMonth": 12,
"expirationYear": 2030,
"cvv": 111
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
})
# Step 2: Send a sale whose security code fails to match
call("POST", "/api/transactions", {
"transactionType": "Sale",
"cardData": {
"cardNumber": "4111111111111111",
"nameOnCard": "Jane Doe",
"expirationMonth": 12,
"expirationYear": 2030,
"cvv": 222
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
})
# Step 3: Send a sale the issuer can't check
call("POST", "/api/transactions", {
"transactionType": "Sale",
"cardData": {
"cardNumber": "4111111111111111",
"nameOnCard": "Jane Doe",
"expirationMonth": 12,
"expirationYear": 2030,
"cvv": 555
},
"invoiceData": {
"amounts": { "base": 10.00, "total": 10.00 }
}
})
# Phase 2: Read the verification codes
# Step 4: Compare the three responses
# The code is on responseData.cardValidationData.cvResponse and the text the simulator reported it
# with is on responseData.cardValidationData.cvResultText. 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 10 CVV triggers in total. The full table is on the testing page
# rather than repeated here. As with AVS, none of these change the result code, and the merchant's
# card verification settings decide whether a no-match refuses the payment. The one to get right in
# your own code is the difference between a code that was checked and wrong and one that was never
# checked at all. Collapsing them into a single failure branch refuses payers whose issuer never
# answered.
Next steps