Skip to main content
3D Secure (3DS) verifies that the person paying is the real cardholder. It shifts liability for fraudulent chargebacks from you to the card issuer, and for mada scheme and most Saudi card payments it is mandatory under SAMA rules for cardholder present payments. This is the standalone 3DS API: you run authentication yourself, then pass the result into the payment API. If you use hosted checkout, sdk or payment links; lite runs 3DS in either redirection or embedded mode; you don’t need to call the standalone APIs. You can also let Payment API trigger 3DS for you with threeds.force, this standalone flow is for when you want to authenticate before, or separately from, the payment flow.

How it works

  1. Create an authentication session against a stored instrument with POST /v1/threeds/authentications.
  2. Check the result. A frictionless authentication returns AUTHENTICATED right away. Otherwise the status is CHALLENGE_REQUIRED.
  3. Run the challenge. Send the cardholder to the issuer’s challenge using the session’s return_url. They return to you when done.
  4. Confirm the challenge with POST /v1/threeds/authentications/{authentication_id}/confirm.
  5. Authorize. Pass the authentication result (authentication_value, eci, version, ds_transaction_id, trans_status) into the payment’s threeds.data.

Authentication status

Before you begin

Authenticate with x-api-key.

Create an authentication session

POST /v1/threeds/authentications Required: instrument_id, customer, order, and return_url (where the cardholder lands after a challenge). Include the device block so the issuer can attempt a frictionless flow.

Response

If status is AUTHENTICATED, skip to authorizing the payment. If it is CHALLENGE_REQUIRED, run the challenge next. The response also carries the directory server and ACS identifiers (threeds_server_trans_id, acs_transaction_id) for diagnostics.

Run and confirm the challenge

When a challenge is required, send the cardholder to the issuer’s challenge screen and have them return to your return_url. Then confirm: POST /v1/threeds/authentications/{authentication_id}/confirm
The session must be in CHALLENGE_REQUIRED when you call this, otherwise you get 400 with the current status in the message. On success it returns 200; re-fetch the session to read the final AUTHENTICATED result.

Get an authentication session

GET /v1/threeds/authentications/{authentication_id} Returns the session in the same shape as create, use it to read the final status and authentication values after a challenge.

Use the result in a payment

Pass the authenticated values into the payment’s threeds.data:

Errors