Docs/Services/3D Secure

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 vs. 3DS 1

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:

  1. Create a 3DS session on moat. Moat returns a session ID and the data needed to launch the challenge.
  2. If a challenge is needed, redirect or embed the issuer's challenge UI.
  3. After the challenge, moat returns an authentication result (authenticated, failed, or not_enrolled).
  4. Pass the authentication result into the transaction's payment_method.card.three_d_secure object when charging.

Create a 3DS session

POST /api/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

StatusMeaning
authenticatedFrictionless success. Proceed directly to authorization.
challenge_requiredPresent the challenge at challenge_url. Complete, then poll or listen for the final result.
not_enrolledCard is not enrolled in 3DS. You may still authorize; liability remains with you.
failedAuthentication 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.