Start 3D Secure authentication
- Sandbox:
POST https://sandbox.payme.io/api/sales/{payme_sale_id}/3ds
- Production:
POST https://live.payme.io/api/sales/{payme_sale_id}/3ds
Credentials
- Header
PayMe-Public-Key (API key)
Overview
Starts 3D Secure 2 authentication for a card on an existing sale, without charging it. Use it when another gateway processes the payment and you need the 3DS values (eci, cavv, xid) from PayMe's MPI. The whole flow: Standalone 3D Secure: process flow.
Call it from the buyer's browser with the seller's public key in the PayMe-Public-Key header. The sale must belong to that seller. Send the browser data that PayMe's JS library collected (meta_data_jwt); see 3DS integration using JS API.
The response has one of two outcomes:
status_code 0: frictionless approval. Pass hash_3dsecure to your server and resolve it with Resolve a 3D Secure hash.
status_code 5: the issuer wants a challenge. Send the buyer to redirect_url (a GET request). After the challenge, the hash comes back to the page that opened it.
The seller must have the 3D Secure service active.
Errors
| HTTP |
Code |
When |
| 400 |
670 |
meta_data_jwt (or meta_data) is missing or can't be read. |
| 400 |
4 |
The sale uses another payment method. |
| 400 |
720 |
3D Secure was blocked for this card. |
| 500 |
720 |
3D Secure isn't available for this card, or the seller has no 3D Secure service. |
| 500 |
350 |
No sale has this ID. |
| 500 |
Card error code |
The card number or expiry is invalid, for example 356 for the expiry. |
| 401 |
— |
The PayMe-Public-Key header is missing or unknown. |
| 403 |
163 |
The seller isn't active. |
Parameters
| Name |
In |
Type |
Required |
Description |
payme_sale_id |
path |
string |
yes |
The sale to authenticate (payme_sale_id). It must belong to the seller of the public key. |
PayMe-Public-Key |
header |
string |
yes |
The seller's public key. Safe to use in the browser. |
Request body
Content type: application/json
| Field |
Type |
Required |
Description |
payment |
object |
yes |
The card to authenticate. |
payment.method |
string |
yes |
credit-card. |
payment.card_number |
string |
no |
Card number. Required unless you send buyer_key. |
payment.card_expiry |
string |
no |
Card expiry, MMYY. Required unless you send buyer_key. |
payment.buyer_key |
string |
no |
A saved buyer token of this seller, instead of card_number and card_expiry. |
customer |
object |
no |
Card holder details. Ignored when you send payment.buyer_key. |
customer.name |
string |
no |
Card holder's name. |
customer.email |
string |
no |
Card holder's email. |
customer.phone |
string |
no |
Card holder's mobile number. |
customer.social_id |
string |
no |
Card holder's national ID. |
customer.zip_code |
string |
no |
Zip code. |
customer.country |
string |
no |
Two-letter ISO country code. |
customer.state |
string |
no |
State or region. |
customer.city |
string |
no |
City. |
customer.line1 |
string |
no |
Address line 1. |
customer.line2 |
string |
no |
Address line 2. |
meta_data_jwt |
string |
no |
The browser data from PayMe's JS library. Send this or meta_data; without either, the call fails with error 670. |
meta_data |
object |
no |
The browser data as a plain object, instead of meta_data_jwt. PayMe adds the buyer's IP and Accept header from the request, so send it from the buyer's browser. |
meta_data.browser |
object |
yes |
Browser details: userAgent, language, colorDepth, screen (height, width), timezone, javaEnabled and javaScriptEnabled. |
language |
string |
no |
Language of error messages: he (default), en, es, ru or ar. |
Request example
{
"payment": {
"method": "credit-card",
"card_number": "4111111111111111",
"card_expiry": "1230"
},
"customer": {
"name": "Israel Israeli",
"email": "buyer@example.com",
"phone": "0500000000"
},
"meta_data_jwt": "META_DATA_JWT_FROM_THE_LIBRARY"
}
Code samples
curl
curl -X POST 'https://sandbox.payme.io/api/sales/<payme_sale_id>/3ds' \
-H 'Content-Type: application/json' \
-H 'PayMe-Public-Key: <PayMe-Public-Key>' \
--data-raw '{
"payment": {
"method": "credit-card",
"card_number": "4111111111111111",
"card_expiry": "1230"
},
"customer": {
"name": "Israel Israeli",
"email": "buyer@example.com",
"phone": "0500000000"
},
"meta_data_jwt": "META_DATA_JWT_FROM_THE_LIBRARY"
}'
Node.js
const response = await fetch("https://sandbox.payme.io/api/sales/<payme_sale_id>/3ds", {
method: "POST",
headers: {
"Content-Type": "application/json",
"PayMe-Public-Key": "<PayMe-Public-Key>",
},
body: JSON.stringify({
"payment": {
"method": "credit-card",
"card_number": "4111111111111111",
"card_expiry": "1230"
},
"customer": {
"name": "Israel Israeli",
"email": "buyer@example.com",
"phone": "0500000000"
},
"meta_data_jwt": "META_DATA_JWT_FROM_THE_LIBRARY"
}),
});
console.log(await response.text());
Python
import requests
response = requests.post(
"https://sandbox.payme.io/api/sales/<payme_sale_id>/3ds",
headers={
"PayMe-Public-Key": "<PayMe-Public-Key>",
},
json={
"payment": {
"method": "credit-card",
"card_number": "4111111111111111",
"card_expiry": "1230",
},
"customer": {
"name": "Israel Israeli",
"email": "buyer@example.com",
"phone": "0500000000",
},
"meta_data_jwt": "META_DATA_JWT_FROM_THE_LIBRARY",
},
)
print(response.text)
PHP
<?php
$body = <<<'BODY'
{
"payment": {
"method": "credit-card",
"card_number": "4111111111111111",
"card_expiry": "1230"
},
"customer": {
"name": "Israel Israeli",
"email": "buyer@example.com",
"phone": "0500000000"
},
"meta_data_jwt": "META_DATA_JWT_FROM_THE_LIBRARY"
}
BODY;
$ch = curl_init('https://sandbox.payme.io/api/sales/<payme_sale_id>/3ds');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'PayMe-Public-Key: <PayMe-Public-Key>',
],
CURLOPT_POSTFIELDS => $body,
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
Responses
200 — Frictionless approval (0) or a challenge (5). (success)
| Field |
Type |
Description |
status_code |
integer |
0 frictionless approval: hash_3dsecure is returned. 5 challenge: send the buyer to redirect_url. |
hash_3dsecure |
string |
The encrypted 3DS result, when status_code is 0. Resolve it with Resolve a 3D Secure hash. |
status_message |
string |
A message you can show the buyer while redirecting, when status_code is 5. |
redirect_url |
string |
The issuer's challenge page, when status_code is 5. Open it with GET in the buyer's browser. |
{
"status_code": 5,
"status_message": "Generating validation page, please wait",
"redirect_url": "https://sandbox.payme.io/3ds/redirect/SALE1700-000000AA-EXAMPLE1-SALE0001?pa=REDACTED"
}
400 — Browser data is missing, the sale uses another payment method, or 3D Secure was blocked. Codes: 4, 670, 720. (error)
| Field |
Type |
Description |
status_code |
integer |
1 on failure. |
status_error_details |
string |
What went wrong, in the language you asked for (Hebrew by default). |
status_additional_info |
string |
The field or value concerned. Can be null. |
status_error_code |
integer |
PayMe error code. See the error table above and Errors. |
session |
string |
PayMe session ID. Quote it when you contact support. |
{
"status_code": 1,
"status_error_details": "Meta data details are missing",
"status_additional_info": null,
"status_error_code": 670,
"session": "a1B2c3D4"
}
500 — 3D Secure isn't available, the sale wasn't found, or the card data is invalid. See the error table. (error)
| Field |
Type |
Description |
status_code |
integer |
1 on failure. |
status_error_details |
string |
What went wrong, in the language you asked for (Hebrew by default). |
status_additional_info |
string |
The field or value concerned. Can be null. |
status_error_code |
integer |
PayMe error code. See the error table above and Errors. |
session |
string |
PayMe session ID. Quote it when you contact support. |
{
"status_code": 1,
"status_error_details": "Invalid credit card expiry",
"status_additional_info": "1221f",
"status_error_code": 356,
"session": "a1B2c3D4"
}