Search code examples
stripe-payments

Can I confirm payment and save card for future uses in case of subscription in one call?


Is there a way to create Stipe subscription (I am using Java and React) that will require to add card for future subscription payments and charge first amount immediately in one call during confirmation on front end. For now what I was able to research is that you first need to create Subscription and confirm SetupIntent with clientSecret by calling stripe.confirmCardSetup in front end first and after successful confirmation - initiate stripe.confirmCardPayment with clientSecret retrieved from subscription.getLatestInvoiceObject().getPaymentIntentObject().getClientSecret();

Is it possible to associate card details with subscription when calling stripe.confirmCardPayment instead of calling confirmCardSetup first? I thought that if you confirmCardPayment with clientSecret that is associated with subscription, card details will be automatically saved for subscription without first confirming card setup?


Solution

  • The Stripe public docs have a pretty good walkthrough that describes the recommended way to handle this:

    https://docs.stripe.com/billing/subscriptions/build-subscriptions?platform=web&ui=elements&lang=java#create-subscription

    In short, the flow is:

    • Your backend creates subscription and uses expansion to pass latest_invoice.payment_intent.client_secret back to frontend.
    • Your frontend mounts the payment element using the client secret you get from your backend.
    • When the frontend Stripe payments element is submitted, you use stripe.confirmPayment to confirm payment details immediately and try to charge the card. This is also where Stripe will automatically save the payment method, assuming you passed the correct params in step 1.

    Here’s the relevant code snippet that shows you how you should configure your server code to save the default payment method and pass the client secret back.

    // Set your secret key. Remember to switch to your live secret key in production.
    // See your keys here: https://dashboard.stripe.com/apikeys
    Stripe.apiKey = "your_test_key";
    
    post(
      "/create-subscription",
      (request, response) -> {
        response.type("application/json");
        String customerId = request.cookie("customer");
        CreateSubscriptionRequest postBody = gson.fromJson(
          request.body(),
          CreateSubscriptionRequest.class
        );
        String priceId = postBody.getPriceId();
    
        // Automatically save the payment method to the subscription
        // when the first payment is successful
        SubscriptionCreateParams.PaymentSettings paymentSettings =
          SubscriptionCreateParams.PaymentSettings
            .builder()
            .setSaveDefaultPaymentMethod(SaveDefaultPaymentMethod.ON_SUBSCRIPTION)
            .build();
    
        // Create the subscription. Note we're expanding the Subscription's
        // latest invoice and that invoice's payment_intent
        // so we can pass it to the front end to confirm the payment
        SubscriptionCreateParams subCreateParams = SubscriptionCreateParams
          .builder()
          .setCustomer(customerId)
          .addItem(
            SubscriptionCreateParams
              .Item.builder()
              .setPrice(priceId)
              .build()
          )
          .setPaymentSettings(paymentSettings)
          .setPaymentBehavior(SubscriptionCreateParams.PaymentBehavior.DEFAULT_INCOMPLETE)
          .addAllExpand(Arrays.asList("latest_invoice.payment_intent"))
          .build();
    
        Subscription subscription = Subscription.create(subCreateParams);
    
        Map<String, Object> responseData = new HashMap<>();
        responseData.put("subscriptionId", subscription.getId());
        responseData.put("clientSecret", subscription.getLatestInvoiceObject().getPaymentIntentObject().getClientSecret());
        return StripeObject.PRETTY_PRINT_GSON.toJson(responseData);
      }
    );