Skip to content
StraventaDocs
Payment Methods

Card 3DS

International card payments with a 3-D-Secure challenge redirect

Card 3DS is a generic, network-agnostic card flow gated by a 3-D-Secure challenge. The payer is redirected to an issuer-hosted page to authenticate; once approved, 505pay receives a payment.completed webhook and the intent flips to paid.

FieldValue
allowed_channels valuecard_3ds
TTL24 h
Refund supportProgrammatic
SettlementT+1
Channel-typed response fieldschallenge_url, checkout_url

Create intent

Pass allowed_channels: ["card_3ds"] (or channel: "card_3ds" for POS-terminal intents). The response includes a challenge_url field that you must redirect the payer to.

curl -X POST https://sandbox.505pay.link/v1/payments/intents \
  -H "Authorization: Bearer $PAYOPS_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $YOUR_KEY" \
  -d '{
    "merchant_id": "'"$PAYOPS_MERCHANT_ID"'",
    "amount_idr": 250000,
    "max_uses": 1,
    "allowed_channels": ["card_3ds"]
  }'

The response body includes:

{
  "id": "01HZ...",
  "shortcode": "AbCdEf123456",
  "status": "open",
  "checkout_url": "https://sandbox.505pay.link/pay/AbCdEf123456",
  "challenge_url": "https://sandbox.505pay.link/pay/AbCdEf123456/3ds"
}

Redirect the payer to challenge_url. After the issuer-hosted 3DS page collects authentication, the simulator (or, in production, the acquirer) posts back to POST /v1/payments/intents/{id}/3ds-callback?auth_code=<value> to advance the intent.

Sandbox 3DS callback

Drive the intent to paid or failed directly without touching a real card form:

# Approve
curl -X POST "https://sandbox.505pay.link/v1/payments/intents/$INTENT_ID/3ds-callback?auth_code=4111111111111111"

# Decline
curl -X POST "https://sandbox.505pay.link/v1/payments/intents/$INTENT_ID/3ds-callback?auth_code=4000000000000002"

Response shape:

{
  "intent_id": "01HZ...",
  "result": "approved",
  "message": "3-D-Secure challenge passed; intent advancing to paid"
}
Test card (auth_code)Outcome
4111111111111111Auto-approve — intent flips to paid, payment.completed webhook fires
4000000000000002Auto-decline — intent flips to failed, payment.failed webhook fires
anything else400 invalid_auth_code — use one of the two canonical PANs

Webhook events

  • payment_intent.created — fired on POST intent.
  • payment.completed — fired when the issuer approves the 3DS challenge.
  • payment.failed — fired when the issuer declines or the payer abandons the challenge.
  • payment_intent.expired — fired if the payer never completes the challenge within the 24h TTL.

See Payment lifecycle.

Test cards in production

The 4111111111111111 / 4000000000000002 test PANs work in the sandbox only. The production flow posts back to the same endpoint with an acquirer-generated auth_code instead. Never embed the test PANs in production code paths.

Was this page helpful?

On this page