External 3DS

Charge with a 3-D Secure result you obtained from your own provider — one call, no challenge.

If you authenticate the cardholder with your own 3DS provider before charging, you already hold the result: the cryptogram, the ECI and the Directory Server transaction ID. External 3DS lets you pass that result to Tonder inside the /process/ request you already send. Tonder does not run its own 3DS — it forwards your authentication data to the acquirer and processes the payment.

In short: you authenticate → you send us the result → we charge with it.

Available on the Direct API only (POST /process/). The SDKs and Hosted Checkout run 3DS for you, so there is nothing to pass.

Prerequisites

External 3DS is off by default. Ask your Tonder representative to enable it on your account. If it is not enabled and you send threeDomainSecure, the request is rejected with a clear error.

  • Your existing Direct API integration — same endpoint, same Authorization: Token <API_KEY>, same tokenized card. No new endpoint or credentials.
  • A completed 3DS authentication from your provider, from which you have the cryptogram (CAVV or UCAF), the ECI and — for Mastercard — the Directory Server transaction ID.

What changes in the request

One addition: a top-level threeDomainSecure object carrying your result. We also strongly recommend card_brand inside payment_method (see below). Everything else stays exactly as it is.

threeDomainSecure

FieldRequiredDescription
eciYesElectronic Commerce Indicator from your 3DS result.
cavvVisaBase64 authentication cryptogram (Visa).
ucafMastercardBase64 authentication cryptogram / AAV (Mastercard). Same value family as cavv.
directoryServerTransactionIDMastercardDirectory Server transaction ID from your 3DS result.
specificationVersionNoEMVCo protocol version. Defaults to 2.2.0.
collectionIndicatorNo (Mastercard)Mastercard collection indicator. Derived from eci if omitted.
acceptRiskConditionalMust be true when eci indicates not authenticated (Mastercard 00 / Visa 07) — you accept liability.

Where each thing goes

Three things live at three different levels. Getting this wrong is the most common integration mistake:

ItemWhere it goes
threeDomainSecure (the whole object)Top level of the request body
eci, cavv, ucaf, directoryServerTransactionID, acceptRisk, …Inside threeDomainSecure
card_brandInside payment_method

If you nest threeDomainSecure inside payment_method, it is ignored: the payment does not use your authentication data and Tonder runs its own 3DS instead. It must be at the top level.

ECI values and rules

NetworkECIMeaning
Visa05Authenticated
Visa06Attempted
Visa07Not authenticated — requires acceptRisk: true
Mastercard02Authenticated
Mastercard01Attempted
Mastercard00Not authenticated — requires acceptRisk: true

Cryptogram format. cavv / ucaf must be the Base64-encoded cryptogram your provider returned, not hex. A hex string is rejected.

card_brand — recommended. Tonder receives a tokenized card, not the PAN, so it cannot always determine the network on its own. You just authenticated the card, so you know it — send it:

  • With card_brand: Tonder validates threeDomainSecure against the network up front and answers a clear 400 if something is inconsistent (a Visa ECI on a Mastercard card, say).
  • Without it: validation is lighter and an inconsistency is caught later by the acquirer, as a decline. card_brand gets you faster, clearer errors.

Accepted values: "visa", "mastercard" (case-insensitive).

Examples

Mastercard

POST
curl -X POST "https://stage.tonder.io/api/v1/process/" \
  -H "Authorization: Token YOUR_TONDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operation_type": "payment",
    "amount": 150.00,
    "currency": "MXN",
    "customer": {
      "name": "Jane Doe",
      "email": "jane@testuser.com"
    },
    "payment_method": {
      "type": "CARD",
      "card_number": "9230-0892-4469-1474",
      "cardholder_name": "c05d89b2-299c-4f93-b49a-42be00d3b64b",
      "cvv": "d31f0da3-0ed3-4ad8-8b68-14c2669a99a7",
      "expiration_month": "e401a32e-4174-424f-9688-727005f6a80e",
      "expiration_year": "bd9ccc23-3d00-4109-9626-fc6581389063",
      "card_brand": "mastercard"
    },
    "threeDomainSecure": {
      "ucaf": "kCO52e75N318oAB3MPZU6EhB2Td6",
      "eci": "02",
      "directoryServerTransactionID": "9e8c4ff6-23d9-4fba-8446-6e8e9d13f42e",
      "specificationVersion": "2.2.0",
      "collectionIndicator": "2"
    },
    "client_reference": "ORD-001",
    "return_url": "https://tonder.io"
  }'

Visa

Same request, with cavv instead of ucaf and no Directory Server transaction ID:

{
  "operation_type": "payment",
  "amount": 150.00,
  "currency": "MXN",
  "customer": { "name": "Jane Doe", "email": "jane@testuser.com" },
  "payment_method": {
    "type": "CARD",
    "card_number": "9230-0892-4469-1474",
    "cardholder_name": "c05d89b2-299c-4f93-b49a-42be00d3b64b",
    "cvv": "d31f0da3-0ed3-4ad8-8b68-14c2669a99a7",
    "expiration_month": "e401a32e-4174-424f-9688-727005f6a80e",
    "expiration_year": "bd9ccc23-3d00-4109-9626-fc6581389063",
    "card_brand": "visa"
  },
  "threeDomainSecure": {
    "cavv": "AAABBoVBaZKAR3BkdkFpELpWIiE=",
    "eci": "05",
    "specificationVersion": "2.2.0"
  },
  "client_reference": "ORD-002",
  "return_url": "https://tonder.io"
}

Not-authenticated ECI (acceptRisk)

When eci is 00 (Mastercard) or 07 (Visa) you must accept the liability explicitly, with acceptRisk: true inside threeDomainSecure:

"threeDomainSecure": {
  "ucaf": "kCO52e75N318oAB3MPZU6EhB2Td6",
  "eci": "00",
  "directoryServerTransactionID": "9e8c4ff6-23d9-4fba-8446-6e8e9d13f42e",
  "specificationVersion": "2.2.0",
  "collectionIndicator": "2",
  "acceptRisk": true
}

What to expect in the response

  • A successful charge comes back approved in a single call, with no challenge step — you already authenticated the cardholder, so Tonder does not initiate its own 3DS.
  • A Pending response with a next_action (a challenge) means your authentication data was not applied. The usual causes: threeDomainSecure nested inside payment_method instead of the top level; your account is not enabled for External 3DS; the object was missing or empty.

As with any payment, verify the final status at GET /api/v1/transactions/{id}/ — it's the source of truth.

Common errors

ResponseCauseFix
4xx "not enabled for this business"External 3DS is not enabled on your accountAsk Tonder to enable it
Pending / challenge instead of a direct chargethreeDomainSecure nested in payment_method, or emptyMove it to the top level; make sure it has values
400 "eci … is not valid for {brand}"The ECI does not match the card networkSend the correct ECI for the network
400 "ucaf/directoryServerTransactionID is required"Missing Mastercard fieldsInclude both ucaf and directoryServerTransactionID
400 "cavv is required"Missing Visa cryptogramInclude cavv
400 "requires acceptRisk=true"Not-authenticated ECI (00/07) without acceptanceAdd acceptRisk: true inside threeDomainSecure
400 "must be a base64-encoded cryptogram"Cryptogram sent as hexSend the Base64 value from your provider
Declined at the acquirer (200, declined)Network/ECI mismatch not caught up frontSend card_brand so Tonder validates before the acquirer

Next steps

Was this page helpful?

On this page