3D Secure
Layer 3D Secure 2 authentication on top of card transactions. Reduces chargeback liability and is required under PSD2 SCA for European merchants.
3D Secure (3DS) is a card network protocol that adds an issuer-driven authentication step to card-not-present transactions. When it succeeds, liability for fraud chargebacks shifts from the merchant to the issuer. moat supports 3DS 2.1 and 2.2 via the paay endpoints.
3DS 2 is the current standard. It is frictionless for most transactions — the issuer's risk engine silently approves without prompting the customer. Challenges (OTP codes, banking-app approvals) only happen when the issuer is not confident from passive signals.
When to use 3DS
- Europe / UK — PSD2 SCA requires strong customer authentication on most transactions. 3DS 2 is how you satisfy it.
- High-risk categories — digital goods, travel, high ticket, or any segment with elevated chargeback rates.
- Selective step-up — pair with Fraud Protection rules to trigger 3DS only when risk warrants it.
Integration pattern
3DS is a three-party dance: your site, the issuer, and moat. The basic flow:
- Create a 3DS session on moat. Moat returns a session ID and the data needed to launch the challenge.
- If a challenge is needed, redirect or embed the issuer's challenge UI.
- After the challenge, moat returns an authentication result (
authenticated,failed, ornot_enrolled). - Pass the authentication result into the transaction's
payment_method.card.three_d_secureobject when charging.
Create a 3DS session
{
"amount": 12500,
"currency": "USD",
"card": {
"number": "4111111111111111",
"expiration_date": "12/30"
},
"billing_address": {
"address_line_1": "123 Main St",
"city": "London",
"postal_code": "EC1A 1AA",
"country": "GB"
},
"browser_info": {
"accept_header": "text/html,application/xhtml+xml",
"user_agent": "Mozilla/5.0 ...",
"language": "en-GB",
"screen_width": 1440,
"screen_height": 900,
"timezone_offset": 0
}
}
Response
{
"status": "success",
"data": {
"session_id": "3ds_01H9XK...",
"authentication_status": "challenge_required",
"challenge_url": "https://...",
"cavv": null,
"eci": null,
"ds_trans_id": null
}
}
Possible authentication_status values
| Status | Meaning |
|---|---|
authenticated | Frictionless success. Proceed directly to authorization. |
challenge_required | Present the challenge at challenge_url. Complete, then poll or listen for the final result. |
not_enrolled | Card is not enrolled in 3DS. You may still authorize; liability remains with you. |
failed | Authentication failed. Do not authorize, or authorize at your own risk. |
Pass results to transaction
After a successful authentication, pass the resulting values on the transaction:
{
"type": "sale",
"amount": 12500,
"payment_method": {
"card": {
"number": "4111111111111111",
"expiration_date": "12/30",
"cvc": "123",
"three_d_secure": {
"cavv": "AAABB0...",
"eci": "05",
"ds_trans_id": "...",
"version": "2.2.0"
}
}
}
}
Liability shift
When 3DS authenticates successfully, the resulting transaction carries a liability shift — fraud chargebacks are pushed back to the issuer rather than borne by you. This is visible in the transaction response as three_d_secure.liability_shifted: true.
See also
- 3D Secure with Tokenizer — combined flow that runs 3DS during tokenization, so you get a token with 3DS results already attached.