3D Secure Card Payments with Sources

    Use Sources to accept card payments verified using 3D Secure, an additional layer of authentication that protects you from liability for fraudulent card payments.

    Stripe users in the United States, Canada, Europe, Hong Kong, and Singapore can process card payments that require authentication with 3D Secure using Sources—a single integration path for creating payments using any supported method. Users in other countries that Stripe supports can request an invite.

    The process for 3D Secure card payments begins in the same way as regular card payments with your integration first creating a Source object that represents the card information. Instead of using this source to make a charge request, it’s used to create a 3D Secure Source object. Your customer is then potentially redirected to their card issuer’s website to verify their identity using 3D Secure.

    Once completed, your integration uses the 3D Secure source to make a charge request and complete the payment. You then have the option of saving the card information to use for future payments.

    Within the scope of Sources, 3D Secure card payments are a pull-based, single-use and synchronous method of payment. This means that your integration takes action to debit the amount from the customer’s card and there is immediate confirmation about the success or failure of a payment.

    When to use 3D Secure

    3D Secure provides a layer of protection against fraudulent payments that is supported by most card-issuing banks. Unlike regular card payments, 3D Secure requires cardholders to complete an additional verification step with the issuer. Users are covered by a liability shift against fraudulent payments that have been authenticated with 3D Secure as the card issuer assumes full responsibility.

    While 3D Secure protects you from fraud, it requires your customers to complete additional steps during the payment process that could impact their checkout experience. For instance, if a customer does not know their 3D Secure information, they might not be able to complete the payment.

    When considering the use of 3D Secure, you might find the right balance is to use it only in situations where there is an increased risk of fraud, or if the customer’s card would be declined without it.

    Handling card information

    Card information is sensitive by nature. Card sources must be created client-side using Elements. This ensures that no sensitive card data passes through your server so your integration can operate in a PCI compliant way.

    When your customer submits their card information using your payment form, it is sent directly to Stripe, and a representative Source object is returned for you to use. The process is similar to the creation of tokens. If you’re already using Elements to tokenize card information, switching to sources is only a small change.

    Step 1: Create a card Source object using Elements

    To create a card Source client-side, please refer to the Elements QuickStart guide to set up Elements and create your payment form (Step 1 and Step 2). At Step 3, you should create a Source instead of a Token by calling the createSource instead of the createToken method.

    // Create a source or display an error when the form is submitted.
    var form = document.getElementById('payment-form');
    form.addEventListener('submit', function(event) {
      event.preventDefault();
    
      stripe.createSource(card).then(function(result) {
        if (result.error) {
          // Inform the user if there was an error
          var errorElement = document.getElementById('card-errors');
          errorElement.textContent = result.error.message;
        } else {
          // Send the source to your server
          stripeSourceHandler(result.source);
        }
      });
    });
    // Create a source or display an error when the form is submitted.
    const form = document.getElementById('payment-form');
    form.addEventListener('submit', async (event) => {
      event.preventDefault();
    
      const {source, error} = await stripe.createSource(card);
    
      if (error) {
        // Inform the user if there was an error
        const errorElement = document.getElementById('card-errors');
        errorElement.textContent = error.message;
      } else {
        // Send the source to your server
        stripeSourceHandler(source);
      }
    });

    The last step of the Elements QuickStart guide (Step 4) remains similar and consists in submitting the source, along with any additional information that has been collected, to your server.

    function stripeSourceHandler(source) {
      // Insert the source ID into the form so it gets submitted to the server
      var form = document.getElementById('payment-form');
      var hiddenInput = document.createElement('input');
      hiddenInput.setAttribute('type', 'hidden');
      hiddenInput.setAttribute('name', 'stripeSource');
      hiddenInput.setAttribute('value', source.id);
      form.appendChild(hiddenInput);
    
      // Submit the form
      form.submit();
    }
    const stripeSourceHandler = (source) => {
      // Insert the source ID into the form so it gets submitted to the server
      const form = document.getElementById('payment-form');
      const hiddenInput = document.createElement('input');
      hiddenInput.setAttribute('type', 'hidden');
      hiddenInput.setAttribute('name', 'stripeSource');
      hiddenInput.setAttribute('value', source.id);
      form.appendChild(hiddenInput);
    
      // Submit the form
      form.submit();
    }

    Once the source is created, you can either proceed with a regular card payment and make a charge request, or continue with the 3D Secure process.

    Source creation in mobile applications

    If you’re building an iOS or Android app, you can implement sources using our mobile SDKs. Refer to our sources documentation for iOS or Android to learn more.

    Step 2: Determine if the card supports or requires 3D Secure

    The behavior of, and support for, 3D Secure can vary across card networks and types. For cards that are not supported, perform a regular card payment instead.

    Some issuing banks, however, require the use of 3D Secure to reduce the risk for fraud, declining all charges that do not use this process. So you can best handle these different situations, check the card.three_d_secure attribute value of the card source before continuing with the 3D Secure process.

    Value Description
    required 3D Secure is required. The process must be completed for a charge to be successful.
    optional 3D Secure is optional. The process isn’t required but can be performed to help reduce the likelihood of fraud.
    not_supported 3D Secure is not supported on this card. Proceed with a regular card payment instead.

    At this stage, you can either proceed with the rest of the 3D Secure process below or perform a regular card payment (if 3D Secure is not supported). If you need to make use of subscriptions, continue to our 3D Secure and Subscriptions documentation.

    Step 3: Create a 3D Secure Source object

    Using the card source that has been created with Stripe.js, a 3D Secure Source object is then created. This can be created client-side using Stripe.js or server-side using the API, providing the following values:

    Parameter Value
    type three_d_secure
    amount A positive integer in the smallest currency unit representing the amount to charge the customer (e.g., 1099 for a €10.99 payment).
    currency The currency the payment is being created in (e.g., eur).
    redirect[return_url] The URL the customer should be redirected to after the verification process.
    three_d_secure[card] The ID of the card source.

    Client-side source creation

    stripe.createSource({
      type: 'three_d_secure',
      amount: 1099,
      currency: "eur",
      three_d_secure: {
        card: "src_19YP2AAHEMiOZZp1Di4rt1K6"
      },
      redirect: {
        return_url: "https://shop.example.com/crtA6B28E1"
      }
    }).then(function(result) {
      // handle result.error or result.source
    });
    

    Server-side source creation

    curl https://api.stripe.com/v1/sources \
       -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
       -d amount=1099 \
       -d currency=eur \
       -d type=three_d_secure \
       -d redirect[return_url]="https://shop.example.com/crtA6B28E1" \
       -d three_d_secure[card]=src_19YP2AAHEMiOZZp1Di4rt1K6
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    source = Stripe::Source.create({
      amount: 1099,
      currency: 'eur',
      type: 'three_d_secure',
      three_d_secure: {
        card: 'src_19YP2AAHEMiOZZp1Di4rt1K6',
      },
      redirect: {
        return_url: 'https://shop.example.com/crtA6B28E1'
      },
    })
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    source = stripe.Source.create(
      amount=1099,
      currency='eur',
      type='three_d_secure',
      three_d_secure={
        'card': 'src_19YP2AAHEMiOZZp1Di4rt1K6',
      },
      redirect={
        'return_url': 'https://shop.example.com/crtA6B28E1'
      },
    )
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    \Stripe\Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    $source = \Stripe\Source::create(array(
      "amount" => 1099,
      "currency" => "eur",
      "type" => "three_d_secure",
      "three_d_secure" => array(
        "card" => "src_19YP2AAHEMiOZZp1Di4rt1K6",
      ),
      "redirect" => array(
        "return_url" => "https://shop.example.com/crtA6B28E1"
      ),
    ));
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.apiKey = "sk_test_BQokikJOvBiI2HlWgH4olfQ2";
    
    Map<String, Object> sourceParams = new HashMap<String, Object>();
    sourceParams.put("amount", 1099);
    sourceParams.put("currency", "eur");
    sourceParams.put("type", "three_d_secure");
    Map<String, Object> redirectParams = new HashMap<String, Object>();
    redirectParams.put("return_url", "https://shop.example.com/crtA6B28E1");
    sourceParams.put("redirect", redirectParams);
    Map<String, Object> threeDSecureParams = new HashMap<String, Object>();
    threeDSecureParams.put("card", "src_19YP2AAHEMiOZZp1Di4rt1K6");
    sourceParams.put("three_d_secure", threeDSecureParams);
    Source source = Source.create(sourceParams);
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    var stripe = require("stripe")("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    stripe.sources.create({
      amount: 1099,
      currency: "eur",
      type: "three_d_secure",
      three_d_secure: {
        card: "src_19YP2AAHEMiOZZp1Di4rt1K6",
      },
      redirect: {
        return_url: "https://shop.example.com/crtA6B28E1"
      },
    }, function(err, source) {
      // asynchronously called
    });
    

    Using either method, Stripe returns a Source object containing the relevant details for the method of payment used. Information specific to 3D Secure is provided within the three_d_secure subhash.

    {
      "id": "src_19YlvWAHEMiOZZp1QQlOD79v",
      "object": "source",
      "amount": 1099,
      "client_secret": "src_client_secret_kBwCSm6Xz5MQETiJ43hUH8qv",
      "created": 1483663790,
      "currency": "eur",
      "flow": "redirect",
      "livemode": false,
      "metadata": {},
    See all 34 lines "owner": { "address": null, "email": null, "name": null, "phone": null, "verified_address": null, "verified_email": null, "verified_name": null, "verified_phone": null }, "redirect": { "return_url": "https://shop.example.com/crtA6B28E1", "status": "pending", "url": "https://hooks.stripe.com/redirect/authenticate/src_19YlvWAHEMiOZZp1QQlOD79v?client_secret=src_client_secret_kBwCSm6Xz5MQETiJ43hUH8qv" }, "status": "pending", "type": "three_d_secure", "usage": "single_use", "three_d_secure": { "card": "src_19YP2AAHEMiOZZp1Di4rt1K6", "customer": null, "authenticated": false } }

    As 3D Secure card payments are a pull-based payment method, there is no movement of funds during the creation of a source. Only when a charge request has been made, and the payment is successful, is the customer’s card debited and you receive the funds.

    Checking if verification is still required

    When creating a 3D Secure source, its status is most commonly first set to pending and cannot yet be used to create a charge. In some cases, a 3D Secure source’s status can be immediately set to chargeable. This can happen if the customer’s card has not yet been enrolled in 3D Secure. Should this occur, the redirect.status value is set to succeeded and three_d_secure.authenticated set to false.

    The status attribute of the 3D Secure source can be immediately set to failed if the card does not support 3D Secure, or there was a technical failure (e.g., the issuing bank’s 3D Secure service is down). Should this occur, you can either continue with a regular card payment, interrupt the payment flow, or attempt to create a 3D Secure source later.

    Error codes

    Source creation for 3D Secure card payments may return any of the following errors:

    Error Description
    payment_method_not_available The payment method is currently not available. You should invite your customer to fallback to another payment method to proceed.
    processing_error An unexpected error occurred preventing us from creating the source. The source creation should be retried.

    Step 4: Have the customer complete 3D Secure verification

    Once you determine if the card supports or requires 3D Secure, your customer must successfully verify their identity with their card issuer to make the source chargeable. To allow your customer to verify their identity using 3D Secure, redirect them to the URL provided within theredirect[url] attribute of the Source object.

    After the verification process, your customer is redirected back to the URL provided as a value of redirect[return_url]. This happens regardless of whether verification was successful or not. If the customer has completed verification, the Source object’s status is updated to chargeable and it is ready to use in a charge request. If not, the status transitions to failed.

    Stripe populates the redirect[return_url] with the following GET parameters when returning your customer to your website:

    • source: a string representing the original ID of the Source object
    • livemode: indicates if this is a live payment, either true or false
    • client_secret: used to confirm that the returning customer is the same one who triggered the creation of the source (source IDs are not considered secret)

    You may include any other GET parameters you may need when specifying redirect[return_url]. Do not use the above as parameter names yourself as these would be overridden with the values we populate.

    Mobile applications

    To integrate 3D Secure within a mobile application, provide your application URI scheme as the redirect[return_url] value. By doing so, your customers are returned to your app after completing authorization. Refer to our Sources documentation for iOS or Android to learn more.

    If you are integrating without using our mobile SDKs, the redirect URL must be opened using the device’s native browser. The use of in-app web views and containers can prevent your customer from completing authentication—resulting in a lower conversion rate.

    No verification required

    If the customer’s card is enrolled in 3D Secure but the issuing bank determines the risk of fraud is low, your customer may not be have to complete verification during the redirect. In that case, the source’s three_d_secure.authenticated attribute is set to false.

    Step 5: Charge the Source

    Once the customer has authenticated the payment, the source’s status transitions to chargeable and it can be used to make a charge request. This transitions happens asynchronously and may occur after the customer was redirected back to your website.

    Customers may also assume that the order process is complete once they have completed the 3D Secure authentication flow. This can result in the customers closing their browser instead of completing the redirection back to your app or website.

    For these reasons it is essential that your integration rely on webhooks to determine when the source becomes chargeable in order to create a charge. Please refer to our best practices for more details on how to best integrate payment methods using webhooks.

    Webhooks

    The following webhook events are also sent to notify you about changes to the source’s status:

    Event Description
    source.chargeable A Source object becomes chargeable after a customer has authenticated and verified a payment.
    source.failed A Source object failed to become chargeable as your customer declined or failed to authenticate the payment.
    source.canceled A Source object expired and cannot be used to create a charge.

    Make a charge request using the source

    Once the source is chargeable, from your source.chargeable webhook handler, you can make a charge request using the source ID as the value for the source parameter to complete the payment.

    curl https://api.stripe.com/v1/charges \
       -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
       -d amount=1099 \
       -d currency=eur \
       -d source=src_18eYalAHEMiOZZp1l9ZTjSU0
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    charge = Stripe::Charge.create({
      amount: 1099,
      currency: 'eur',
      source: 'src_18eYalAHEMiOZZp1l9ZTjSU0',
    })
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    charge = stripe.Charge.create(
      amount=1099,
      currency='eur',
      source='src_18eYalAHEMiOZZp1l9ZTjSU0',
    )
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    \Stripe\Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    $charge = \Stripe\Charge::create(array(
      "amount" => 1099,
      "currency" => "eur",
      "source" => "src_18eYalAHEMiOZZp1l9ZTjSU0",
    ));
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.apiKey = "sk_test_BQokikJOvBiI2HlWgH4olfQ2";
    
    Map<String, Object> chargeParams = new HashMap<String, Object>();
    chargeParams.put("amount", 1099);
    chargeParams.put("currency", "eur");
    chargeParams.put("source", "src_18eYalAHEMiOZZp1l9ZTjSU0");
    
    Charge charge = Charge.create(chargeParams);
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    var stripe = require("stripe")("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    stripe.charges.create({
      amount: 1099,
      currency: "eur",
      source: "src_18eYalAHEMiOZZp1l9ZTjSU0",
    }, function(err, charge) {
      // asynchronously called
    });
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.Key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    chargeParams := &stripe.ChargeParams{
      Amount: 1099,
      Currency: "eur",
    }
    chargeParams.SetSource("src_18eYalAHEMiOZZp1l9ZTjSU0")
    ch, err := charge.New(chargeParams)
    

    Step 6: Confirm that the charge has succeeded and the payment is complete

    Since 3D Secure-based card payments is a synchronous payment method, the Charge object’s status immediately reflects whether or not it has been successful. One of the following events is sent when the charge is created depending on its state.

    Event Description
    charge.succeeded The charge succeeded and the payment is complete.
    charge.failed The charge has failed and the payment could not be completed.

    We recommend that you rely on these webhook events to notify your customer about the payment success or failure. Please refer to our best practices for more details on how to best integrate payment methods using webhooks.

    Disputed payments and liability shift

    Card networks provide a process for cardholders to dispute payments made with their card. A dispute can be filed by the cardholder any time after a payment has been successful.

    Payments that are successfully authenticated using 3D Secure are covered by a liability shift. Should a 3D Secure payment be disputed as fraudulent by the cardholder, the liability shifts from you to the card issuer. These types of disputes are handled internally, do not appear in the Dashboard, and do not result in funds being withdrawn from your Stripe account.

    If the card or issuer isn’t enrolled in 3D Secure but the type of card could support 3D Secure (e.g., most Visa and Mastercard consumer cards), liability is still shifted to the card issuer. During the payment process, the cardholder is not redirected to to complete the 3D Secure process.

    Should a customer dispute a payment for any other reason (e.g., product not received), then the standard dispute process applies. As such, you should make the appropriate decisions regarding your business and how you manage disputes, if they occur, and how to avoid them completely.

    Source expiration

    A chargeable 3DSecure source must be charged within six hours of becoming chargeable. If it is not, its status is automatically transitioned to canceled and your integration receives a source.canceled webhook event. Make sure the order is canceled on your end and the customer is notified when you receive the source.canceled event.

    Additionally, pending sources are canceled after one hour if they are not used to authenticate a payment, ensuring that all sources eventually transition out of their pending state to the canceled state if they are not used.

    Saving 3D Secure card information for later

    Once the 3D Secure source has been used to make a successful payment, you can save the original card source to a new Customer object.

    curl https://api.stripe.com/v1/customers \
       -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
       -d email="paying.user@example.com" \
       -d source=src_18eYalAHEMiOZZp1l9ZTjSU0
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    customer = Stripe::Customer.create({
      email: 'paying.user@example.com',
      source: 'src_18eYalAHEMiOZZp1l9ZTjSU0',
    })
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    customer = stripe.Customer.create(
      email='paying.user@example.com',
      source='src_18eYalAHEMiOZZp1l9ZTjSU0',
    )
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    \Stripe\Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    $customer = \Stripe\Customer::create(array(
      "email" => "paying.user@example.com",
      "source" => "src_18eYalAHEMiOZZp1l9ZTjSU0",
    ));
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.apiKey = "sk_test_BQokikJOvBiI2HlWgH4olfQ2";
    
    Map<String, Object> customerParams = new HashMap<String, Object>();
    customerParams.put("email", "paying.user@example.com");
    customerParams.put("source", "src_18eYalAHEMiOZZp1l9ZTjSU0");
    
    Customer customer = Customer.create(customerParams);
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    var stripe = require("stripe")("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    stripe.customers.create({
      email: "paying.user@example.com",
      source: "src_18eYalAHEMiOZZp1l9ZTjSU0",
    }, function(err, customer) {
      // asynchronously called
    });
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.Key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    customerParams := &stripe.CustomerParams{
      Email: "paying.user@example.com",
    }
    customerParams.SetSource("src_18eYalAHEMiOZZp1l9ZTjSU0")
    c, err := customer.New(customerParams)
    

    The ID of the card source can be retrieved from the 3D Secure source as the value of the three_d_secure.card attribute.

    Since the 3D Secure process has already taken place, you can create additional payments using the customer as normal.

    curl https://api.stripe.com/v1/charges \
       -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
       -d amount=1099 \
       -d currency=eur \
       -d customer=cus_VWaMywLC4keKS6
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    charge = Stripe::Charge.create({
      amount: 1099,
      currency: 'eur',
      customer: 'cus_VWaMywLC4keKS6',
    })
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.api_key = "sk_test_BQokikJOvBiI2HlWgH4olfQ2"
    
    charge = stripe.Charge.create(
      amount=1099,
      currency='eur',
      customer='cus_VWaMywLC4keKS6',
    )
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    \Stripe\Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    $charge = \Stripe\Charge::create(array(
      "amount" => 1099,
      "currency" => "eur",
      "customer" => "cus_VWaMywLC4keKS6",
    ));
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.apiKey = "sk_test_BQokikJOvBiI2HlWgH4olfQ2";
    
    Map<String, Object> chargeParams = new HashMap<String, Object>();
    chargeParams.put("amount", 1099);
    chargeParams.put("currency", "eur");
    chargeParams.put("customer", "cus_VWaMywLC4keKS6");
    
    Charge charge = Charge.create(chargeParams);
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    var stripe = require("stripe")("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
    stripe.charges.create({
      amount: 1099,
      currency: "eur",
      customer: "cus_VWaMywLC4keKS6",
    }, function(err, charge) {
      // asynchronously called
    });
    

    As the 3D Secure process isn’t performed when using saved card information to make a charge request, future payments are not protected by 3D Secure’s liability shift.

    3D Secure cards and subscriptions

    If you wish to make use of 3D Secure-enabled cards for subscription payments, there are some additional steps you can take to ensure they are handled correctly.

    Testing 3D Secure payments

    Not all cards support 3D Secure or require the customer be redirected to their bank authentication page. Use the following card information to fully test 3D Secure payments.

    Number Description
    4000000000003055 3D Secure is supported but not required on this card. The value of the card source's card.three_d_secure attribute is optional. Charges succeed whether 3D Secure is used or not.
    4000000000003063 3D Secure is supported and required on this card. The value of the card source's card.three_d_secure attribute is required. 3D Secure must be completed for a charge to be successful.
    378282246310005 3D Secure is not supported or required on this card. The value of the card source's card.three_d_secure attribute is not_supported. Proceed with a regular card payment instead.

    All other Visa and Mastercard test cards do not require verification from the customer's bank. The 3D Secure Source status is immediately set to chargeable upon source creation.

    Testing the redirect process

    When creating a Source object using your test API keys, you can follow the URL returned in the redirect[url] field. This leads to a Stripe page that displays information about the API request, and where you can either authorize or cancel the payment. Authorizing the payment redirects you to the URL specified in redirect[return_url].

    Clicking on the Failure button results in the 3D Secure source status to transitioning to failed.

    Next steps

    Congrats! You've learned about processing 3D Secure-based card payments using Sources. Some documentation you might want to read next: