3D Secure — Increase

3D Secure

3D Secure (3DS) is a protocol governed by EMVCo that lets you verify a cardholder’s identity before a card payment is authorized. Unlike card authorizations, 3DS follows a strict state machine with well-defined stages. When a merchant initiates a 3DS authentication attempt, Increase creates a card_authentication entry on the Card Payment.

The 3DS API is composed of a few parts:

Authentication lifecycle

A card_authentication progresses through a series of statuses as the authentication attempt is processed. Here is a typical challenge-based flow:

  1. We receive an authentication request from Visa with metadata about the purchase. You receive a card_authentication_requested real-time decision and decide to request a challenge. The authentication moves to awaiting_challenge.
  2. The cardholder’s client (a browser or app) connects to Increase to initiate the challenge. We generate a one-time code and send you a card_authentication_challenge_requested real-time decision containing the code. You deliver it to your cardholder via text message or email. The authentication moves to validating_challenge.
  3. The cardholder enters the one-time code. If correct, the authentication moves to authenticated_with_challenge. We generate a cryptographic Cardholder Authentication Verification Value (CAVV) that is sent to the acquirer through Visa.
  4. The acquirer kicks off the card authorization, including the CAVV in the authorization message to tie it to the successful authentication. The Card Payment now has both a card_authentication and a card_authorization element.

If at step 1 you are confident in the transaction, you can approve the authentication directly. This results in a status of authenticated_without_challenge and skips the challenge steps entirely.

Statuses

Status Description
authenticated_without_challenge Approved without requiring a challenge.
awaiting_challenge A challenge has been requested and we are waiting for the cardholder’s client to initiate it.
validating_challenge The challenge is in progress and the cardholder is entering their one-time code.
authenticated_with_challenge The cardholder successfully completed the challenge.
denied The authentication attempt was denied.
canceled The authentication was canceled.
timed_out_awaiting_challenge The cardholder’s client did not initiate the challenge in time.
exceeded_attempt_threshold The cardholder exceeded the maximum number of challenge attempts.
errored An error occurred during the authentication.

Real-time decisions

We recommend first reading our Real-Time Decisions guide for background on how real-time webhooks work.

Responding to authentication requests

When a merchant attempts to authenticate a purchase, Increase creates a Real-Time Decision with category: card_authentication_requested. This comes with metadata about the purchase including merchant details and the purchase amount. Your application decides how to proceed:

To action the decision, POST to the Real-Time Decision action endpoint:

curl -X "POST" \
  --url "https://api.increase.com/real_time_decisions/${REAL_TIME_DECISION_ID}/action" \
  -H "Authorization: Bearer ${INCREASE_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "card_authentication": {
      "decision": "challenge"
    }
  }'

Delivering the challenge

If you request a challenge, the cardholder’s client (browser or app) will connect to Increase to start the challenge process. Increase creates a second Real-Time Decision with category: card_authentication_challenge_requested. This decision includes a one_time_code that you must deliver to your cardholder via text message or email.

Once you’ve delivered the code, action the decision with the result:

curl -X "POST" \
  --url "https://api.increase.com/real_time_decisions/${REAL_TIME_DECISION_ID}/action" \
  -H "Authorization: Bearer ${INCREASE_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "card_authentication_challenge": {
      "result": "success"
    }
  }'

If your application is unable to deliver the one-time code, respond with "result": "failure".

After the challenge is delivered, Increase renders an interface to the cardholder where they enter the one-time code. We validate their attempts and update the card_authentication status accordingly.

Testing in sandbox

You can simulate the end-to-end authentication flow using three sandbox endpoints.

1. Simulate an authentication attempt

Create a simulated 3DS authentication request for a card:

curl -X "POST" \
  --url "${INCREASE_URL}/simulations/card_authentications" \
  -H "Authorization: Bearer ${INCREASE_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "card_id": "card_oubs0hwk5rn6knuecxg2"
  }'

This returns a Card Payment with a card_authentication element. If you have a card_authentication_requested real-time decision subscription, you’ll receive the webhook and can action the decision.

2. Simulate initiating a challenge

After requesting a challenge, simulate the cardholder’s client connecting to start the challenge:

curl -X "POST" \
  --url "${INCREASE_URL}/simulations/card_authentications/${CARD_PAYMENT_ID}/challenges" \
  -H "Authorization: Bearer ${INCREASE_API_KEY}"

This triggers the card_authentication_challenge_requested real-time decision with the one-time code.

3. Simulate a challenge attempt

Simulate the cardholder entering the one-time code:

curl -X "POST" \
  --url "${INCREASE_URL}/simulations/card_authentications/${CARD_PAYMENT_ID}/challenge_attempts" \
  -H "Authorization: Bearer ${INCREASE_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "one_time_code": "123456"
  }'

Alternatively, you can navigate to https://dashboard.increase.com/card_authentication_simulation/${CARD_PAYMENT_ID} and enter the one-time code directly.

If the code matches, the card_authentication status moves to authenticated_with_challenge.