SettleFlow API

3D Secure

Handle the 3DS challenge redirect and resume the flow after the customer returns

Overview

3D Secure (3DS2 / EMV 3DS) is required for most European card payments under PSD2 Strong Customer Authentication rules. SettleFlow handles the orchestration with the acquirer — your integration only needs to handle the browser redirect and the status check after the customer comes back.

When does 3DS trigger?

  • When the card's issuer requires it (the common case for European cards).
  • When you force it explicitly by sending "3DS": "yes" on the payment request.
  • When your account is configured as 3DS-only — in that case payments without 3DS=yes fail with error code 15.

Some combinations are mandatory:

ScenarioBehaviour
Maestro cardAlways requires 3DS. Missing 3DS=yes returns code 22.
Account not allowed to use 3DS3DS=yes rejected with code 8.
3DS=yes sent without ReturnUrlRejected with code 106.

Flow

 ┌────────────┐   1. POST /v1/payment/direct   ┌─────────────┐
 │  Merchant  │ ─────────────────────────────▶ │ SettleFlow  │
 │   server   │                                 │             │
 │            │ ◀───── { 3DSecureUrl } ──────── │             │
 └────────────┘                                 └─────────────┘

       │ 2. Return 3DSecureUrl to the browser

 ┌────────────┐   3. Browser redirected        ┌─────────────┐
 │  Customer  │ ─────────────────────────────▶ │ Card issuer │
 │  browser   │       (3DS challenge)          │   ACS page  │
 │            │ ◀───────────────────────────── │             │
 └────────────┘                                 └─────────────┘

       │ 4. Customer redirected back

 ┌────────────┐   5. POST /v1/status/direct    ┌─────────────┐
 │  Merchant  │ ─────────────────────────────▶ │ SettleFlow  │
 │   server   │ ◀────── { Status: ... } ────── │             │
 └────────────┘                                 └─────────────┘

       │ 6. Settleflow also fires a webhook
       ▼  asynchronously to CallbackUrl

Step-by-step

1. Request the payment with 3DS enabled

curl -X POST https://api.settleflow.io/v1/payment/direct \
  -H "epro-api-key: sk_test_..." \
  -d '{
    "Amount": "4999",
    "Uid": "customer-42",
    "Tid": "order-2026-001",
    "Email": "jane@example.com",
    "CardNumber": "4000000000003220",
    "CardMonth": "12",
    "CardYear": "2028",
    "CardCVV": "123",
    "3DS": "yes",
    "ReturnUrl": "https://your-shop.com/payment/return",
    "CallbackUrl": "https://your-shop.com/webhooks/settleflow"
  }'

2. Inspect the response

{
  "Code": 0,
  "Result": {
    "OperationType": "payment",
    "Status": "pending",
    "Tid": "order-2026-001",
    "Reference": "pr_abc123",
    "3DSecure": "yes",
    "3DSecureUrl": "https://3ds-acs.example.com/challenge?token=..."
  }
}

When 3DSecure=yes, the 3DSecureUrl field is present and Status is pending.

3. Redirect the customer

Return an HTTP 302 from your server, or open 3DSecureUrl in the customer's browser. The customer will see the issuer's challenge page.

res.redirect(302, result["3DSecureUrl"]);

4. Handle the return to ReturnUrl

After the challenge, the customer is redirected back to the ReturnUrl you supplied. SettleFlow may append query parameters identifying the transaction — at minimum, you always have your own Tid and the Reference from step 2.

5. Confirm the final status

Query POST /v1/status/direct to resolve the payment:

curl -X POST https://api.settleflow.io/v1/status/direct \
  -H "epro-api-key: sk_test_..." \
  -d '{ "Reference": "pr_abc123" }'

Possible outcomes:

StatusWhat to show the customer
capturedSuccess — order confirmed.
authorizedSuccess — capture pending.
pendingStill processing. Retry the status call after 1–2 s, or display a processing screen.
failedChallenge failed or declined — surface a recoverable error.
cancelledCustomer abandoned the challenge.

See the polling pattern on the status page for a defensive retry loop.

6. Trust the webhook for authoritative state

Even if the customer never returns to your ReturnUrl (closed tab, mobile browser lost focus…), SettleFlow will still deliver a webhook to your CallbackUrl. Use that as the source of truth for order fulfillment — see Webhooks.

Testing

Use the dedicated 3DS test card in sandbox:

Card numberBehaviour
4000000000003220Forces a 3DS challenge and returns a 3DSecureUrl in sandbox.

See Sandbox & test cards for the full list.

On this page