Billing
SEPA Direct Debit in the EU

Set up a subscription with SEPA Direct Debit in the EU

Learn how to create and charge for a subscription with SEPA Direct Debit.

1 Create a product and price Dashboard

Products are what you sell, and you need to create at least one before you can charge for it. This guide uses a stock photo service as an example. Generally, if you only have a few products, you should create and manage them in the Dashboard.

To create a product in the Dashboard:

 

  1. Navigate to the Add a product page.

  2. Enter a Name for your product.

  3. Scroll down to the Pricing section.

  4. Create your price by entering in price data.

  5. Click the Save product button.

 

 

 

This creates the product and any entered prices and automatically opens the product detail page. Prices define how much and how frequently you charge for a product. This includes how much the product costs, what currency to use, and the billing period to use for recurring charges. For each currency you charge, a separate price should be created. Similar to products, if you only have a few prices it’s preferable to manage them in the Dashboard.

In this guide, a recurring quantity is used. This means customers are charged the same amount on a recurring basis. For example, charging 15 EUR a month for a streaming service or 120 EUR for a yearly subscription to an online publication. From the product detail page, click the Add price (or Add another price) button:

  1. In the Price field, enter 15.
  2. In the currency field, select EUR.
  3. Click the Add price button.

You have several other options for creating prices, but this basic example results in a price that:

  • Uses EUR
  • Costs 15 EUR per subscription
  • Charges customers monthly

After you create the price, record the ID so it can be used in subsequent steps. It’s displayed on the pricing page and should look similar to this: price_G0FvDp6vZvdwRZ.

2 Create a SetupIntent Server-side

A SetupIntent is an object that represents your intent and tracks the steps to set up your customer’s payment method for future payments. For SEPA Direct Debit, this includes collecting a mandate from the customer and checking the validity of the IBAN.

Create a SetupIntent on your server with payment_method_types set to sepa_debit and specify the Customer’s id.:

curl https://api.stripe.com/v1/setup_intents \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d "payment_method_types[]"=sepa_debit \ -d customer="{{CUSTOMER_ID}}"
require 'sinatra' require 'json' require 'stripe' # Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' get '/wallet' do setup_intent = Stripe::SetupIntent.create({ payment_method_types: ['sepa_debit'], customer: customer['id'], }) client_secret = setup_intent['client_secret'] # Pass the client secret to the client end
import stripe import json from flask import request, render_template app = Flask(__name__, static_folder=".", static_url_path="", template_folder=".") # Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' @app.route('/wallet') def wallet(): setup_intent = stripe.SetupIntent.create( payment_method_types=['sepa_debit'], customer=customer['id'] ) client_secret = setup_intent.client_secret # Pass the client secret to the client if __name__ == '__main__': app.run()
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); // vendor using composer require_once('vendor/autoload.php'); $setup_intent = \Stripe\SetupIntent::create([ 'payment_method_types' => ['sepa_debit'], 'customer' => $customer->id, ]); $client_secret = $setup_intent->client_secret // Pass the client secret to the client
import com.stripe.Stripe; import com.stripe.model.SetupIntent; import com.stripe.params.SetupIntentCreateParams; public class StripeJavaQuickStart { public static void main(String[] args) { // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; SetupIntentCreateParams params = SetupIntentCreateParams.builder() .addPaymentMethodType("sepa_debit") .setCustomer(cistomer.getId()) .build(); SetupIntent setupIntent = SetupIntent.create(params); String clientSecret = setupIntent.getClientSecret(); // Pass the client secret to the client } }
// Using Express const express = require('express'); const app = express(); app.use(express.json()); const { resolve } = require("path"); // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); const setupIntent = await stripe.setupIntents.create({ payment_method_types: ['sepa_debit'], customer: customer.id, }); const clientSecret = setupIntent.client_secret; // Pass the client secret to the client
package main import ( "encoding/json" "log" "net/http" "github.com/stripe/stripe-go/v71" "github.com/stripe/stripe-go/v71/setupintent" ) func main() { // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" params := &stripe.SetupIntentParams{ PaymentMethodTypes: stripe.StringSlice([]string{ "sepa_debit", }), Customer: stripe.String(customer.ID), } si, _ := setupintent.New(params) clientSecret := si.ClientSecret // Pass the client secret to the client }
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; using System; using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Stripe; namespace StripeExampleApi.Controllers { [Route("/wallet")] public class WalletController : Controller { public IActionResult Index() { var options = new SetupIntentCreateOptions { PaymentMethodTypes = new List<string> { "sepa_debit", }, Customer = "{{CUSTOMER_ID}}", }; var service = new SetupIntentService(); var setupIntent = service.Create(options); var clientSecret = setupIntent.ClientSecret; // Pass the client secret to the client } } }

3 Collect payment method details and mandate acknowledgment Client-side

You’re ready to collect payment information on the client with Stripe Elements. Elements is a set of prebuilt UI components for collecting payment details.

A Stripe Element contains an iframe that securely sends the payment information to Stripe over a HTTPS connection. The checkout page address must also start with https:// rather than http:// for your integration to work.

You can test your integration without using HTTPS. Enable it when you’re ready to accept live payments.

Set up Stripe Elements

Stripe Elements is automatically available as a feature of Stripe.js. Include the Stripe.js script on your payment page by adding it to the head of your HTML file. Always load Stripe.js directly from js.stripe.com to remain PCI compliant. Do not include the script in a bundle or host a copy of it yourself.

<head> <title>Submit Payment</title> <script src="https://js.stripe.com/v3/"></script> </head>

Create an instance of Elements with the following JavaScript on your payment page:

var stripe = Stripe('pk_test_TYooMQauvdEDq54NiTphI7jx'); var elements = stripe.elements();
const stripe = Stripe('pk_test_TYooMQauvdEDq54NiTphI7jx'); const elements = stripe.elements();

Add and configure an IBAN Element

Elements needs a place to live in your payment form. Create empty DOM nodes (container) with unique IDs in your payment form. Additionally, your customer must read and accept the SEPA Direct Debit mandate.

Display the following standard authorization text for your customer to implicitly sign this mandate. Replace Rocketship Inc with your company name.

The details of the accepted mandate are generated when setting up a payment method. Because the customer has implicitly signed the mandate when accepting the terms suggested above, you must communicate the terms on the form or in an email.

<form action="/form" method="post" id="setup-form"> <div class="form-row inline"> <div class="col"> <label for="accountholder-name"> Name </label> <input id="accountholder-name" name="accountholder-name" placeholder="Jenny Rosen" required /> </div> <div class="col"> <label for="email"> Email Address </label> <input id="email" name="email" type="email" placeholder="jenny.rosen@example.com" required /> </div> </div> <div class="form-row"> <!-- Using a label with a for attribute that matches the ID of the Element container enables the Element to automatically gain focus when the customer clicks on the label. --> <label for="iban-element"> IBAN </label> <div id="iban-element"> <!-- A Stripe Element will be inserted here. --> </div> </div> <!-- Add the client_secret from the SetupIntent as a data attribute --> <button id="submit-button" data-secret="{CLIENT_SECRET}"> Set up SEPA Direct Debit </button> <!-- Display mandate acceptance text. --> <div id="mandate-acceptance"> By providing your payment information and confirming this payment, you authorise (A) Rocketship Inc and Stripe, our payment service provider, to send instructions to your bank to debit your account and (B) your bank to debit your account in accordance with those instructions. As part of your rights, you are entitled to a refund from your bank under the terms and conditions of your agreement with your bank. A refund must be claimed within 8 weeks starting from the date on which your account was debited. Your rights are explained in a statement that you can obtain from your bank. You agree to receive notifications for future debits up to 2 days before they occur. </div> <!-- Used to display form errors. --> <div id="error-message" role="alert"></div> </form>

When the form loads, you can create an instance of the IBAN Element and mount it to the Element container:

// Custom styling can be passed to options when creating an Element. var style = { base: { color: '#32325d', fontSize: '16px', '::placeholder': { color: '#aab7c4' }, ':-webkit-autofill': { color: '#32325d', }, }, invalid: { color: '#fa755a', iconColor: '#fa755a', ':-webkit-autofill': { color: '#fa755a', }, }, }; var options = { style: style, supportedCountries: ['SEPA'], // Elements can use a placeholder as an example IBAN that reflects // the IBAN format of your customer's country. If you know your // customer's country, we recommend that you pass it to the Element as the // placeholderCountry. placeholderCountry: 'DE', }; // Create an instance of the IBAN Element var iban = elements.create('iban', options); // Add an instance of the IBAN Element into the `iban-element` <div> iban.mount('#iban-element');
// Custom styling can be passed to options when creating an Element. const style = { base: { color: '#32325d', fontSize: '16px', '::placeholder': { color: '#aab7c4' }, ':-webkit-autofill': { color: '#32325d', }, }, invalid: { color: '#fa755a', iconColor: '#fa755a', ':-webkit-autofill': { color: '#fa755a', }, }, }; const options = { style, supportedCountries: ['SEPA'], // Elements can use a placeholder as an example IBAN that reflects // the IBAN format of your customer's country. If you know your // customer's country, we recommend passing it to the Element as the // placeholderCountry. placeholderCountry: 'DE', }; // Create an instance of the IBAN Element const iban = elements.create('iban', options); // Add an instance of the IBAN Element into the `iban-element` <div> iban.mount('#iban-element');

Install React Stripe.js and the Stripe.js loader from the npm public registry.

npm install --save @stripe/react-stripe-js @stripe/stripe-js

We also provide a UMD build for sites that do not use npm or modules.

Include the Stripe.js script, which exports a global Stripe function, and the UMD build of React Stripe.js, which exports a global ReactStripe object. Always load the Stripe.js script directly from js.stripe.com to remain PCI compliant. Do not include the script in a bundle or host a copy of it yourself.

<!-- Stripe.js --> <script src="https://js.stripe.com/v3/"></script> <!-- React Stripe.js development build --> <script src="https://unpkg.com/@stripe/react-stripe-js@latest/dist/react-stripe.umd.js"></script> <!-- When you are ready to deploy your site to production, remove the above development script, and include the following production build. --> <script src="https://unpkg.com/@stripe/react-stripe-js@latest/dist/react-stripe.umd.min.js"></script>

Add Stripe.js and Elements to your page

To use Element components, wrap the root of your React app in an Elements provider. Call loadStripe with your publishable key and pass the returned Promise to the Elements provider.

import React from 'react'; import ReactDOM from 'react-dom'; import {Elements} from '@stripe/react-stripe-js'; import {loadStripe} from '@stripe/stripe-js'; import PaymentSetupForm from './PaymentSetupForm'; // Make sure to call `loadStripe` outside of a component’s render to avoid // recreating the `Stripe` object on every render. const stripePromise = loadStripe("pk_test_TYooMQauvdEDq54NiTphI7jx"); function App() { return ( <Elements stripe={stripePromise}> <PaymentSetupForm /> </Elements> ); }; ReactDOM.render(<App />, document.getElementById('root'));

Add and configure an IbanElement component

Use the IbanElement to collect your users IBAN. Additionally, your customer must read and accept the SEPA Direct Debit mandate.

Display the following standard authorization text for your customer to implicitly sign this mandate. Replace Rocketship Inc with your company name.

The details of the accepted mandate are generated when setting up a payment method. Because the customer has implicitly signed the mandate when accepting the terms suggested above, you must communicate the terms on the form or in an email.

/** * Use the CSS tab above to style your Element's container. */ import React from 'react'; import {IbanElement} from '@stripe/react-stripe-js'; import './IbanFormStyles.css' // Custom styling can be passed as options when creating an Element. const IBAN_STYLE = { base: { color: '#32325d', fontSize: '16px', '::placeholder': { color: '#aab7c4' }, ':-webkit-autofill': { color: '#32325d', }, }, invalid: { color: '#fa755a', iconColor: '#fa755a', ':-webkit-autofill': { color: '#fa755a', }, } }; const IBAN_ELEMENT_OPTIONS = { supportedCountries: ['SEPA'], // Elements can use a placeholder as an example IBAN that reflects // the IBAN format of your customer's country. If you know your // customer's country, we recommend that you pass it to the Element as the // placeholderCountry. placeholderCountry: 'DE', style: IBAN_STYLE, }; export default function IbanForm({onSubmit, disabled}) { return ( <form onSubmit={onSubmit}> <div className="form-row inline"> <div className="col"> <label> Name <input name="accountholder-name" placeholder="Jenny Rosen" required /> </label> </div> <div className="col"> <label> Email Address <input name="email" type="email" placeholder="jenny.rosen@example.com" required /> </label> </div> </div> <div className="form-row"> <label> IBAN <IbanElement options={IBAN_ELEMENT_OPTIONS} /> </label> </div> <button type="submit" disabled={disabled}> Set up SEPA Direct Debit </button> {/* Display mandate acceptance text. */} <div className="mandate-acceptance"> By providing your payment information and confirming this payment, you authorise (A) Rocketship Inc and Stripe, our payment service provider, to send instructions to your bank to debit your account and (B) your bank to debit your account in accordance with those instructions. As part of your rights, you are entitled to a refund from your bank under the terms and conditions of your agreement with your bank. A refund must be claimed within 8 weeks starting from the date on which your account was debited. Your rights are explained in a statement that you can obtain from your bank. You agree to receive notifications for future debits up to 2 days before they occur. </div> </form> ); };
/** * Shows how you can use CSS to style your Element's container. * These classes are added to your Stripe Element by default. * You can override these classNames by using the options passed * to the IbanElement component. * https://stripe.com/docs/js/elements_object/create_element?type=iban#elements_create-options-classes */ input, .StripeElement { height: 40px; padding: 10px 12px; color: #32325d; background-color: white; border: 1px solid transparent; border-radius: 4px; box-shadow: 0 1px 3px 0 #e6ebf1; -webkit-transition: box-shadow 150ms ease; transition: box-shadow 150ms ease; } input:focus, .StripeElement--focus { box-shadow: 0 1px 3px 0 #cfd7df; } .StripeElement--invalid { border-color: #fa755a; } .StripeElement--webkit-autofill { background-color: #fefde5 !important; }

Elements are completely customizable. You can style Elements to match the look and feel of your site, providing a seamless checkout experience for your customers. It’s also possible to style various input states, for example when the Element has focus.

4 Submit the payment method details to Stripe Client-side

Rather than sending the entire SetupIntent object to the client, use its client secret from step 2. This is different from your API keys that authenticate Stripe API requests.

The client secret should still be handled carefully because it can complete the setup. Do not log it, embed it in URLs, or expose it to anyone but the customer.

Use stripe.confirmSepaDebitSetup to complete the setup when the user submits the form. Including the customer’s name and email address in the billing_details property of the payment_method parameter is required to create a SEPA Direct Debit PaymentMethod.

A successful setup will return a succeeded value for the SetupIntent’s status property. If the setup is not successful, inspect the returned error to determine the cause.

Because setup_future_usage and customer were set, the PaymentMethod will be attached to the provided Customer object after a successful setup. This allows you to use the stored PaymentMethod to collect future payments without prompting for your customer’s payment method details.

var form = document.getElementById('payment-form'); var accountholderName = document.getElementById('accountholder-name'); var email = document.getElementById('email'); var submitButton = document.getElementById('submit-button'); var clientSecret = submitButton.dataset.secret; form.addEventListener('submit', function(event) { event.preventDefault(); stripe.confirmSepaDebitSetup( clientSecret, { payment_method: { sepa_debit: iban, billing_details: { name: accountholderName.value, email: email.value, }, }, } ); });
const form = document.getElementById('payment-form'); const accountholderName = document.getElementById('accountholder-name'); const email = document.getElementById('email'); const submitButton = document.getElementById('submit-button'); const clientSecret = submitButton.dataset.secret; form.addEventListener('submit', (event) => { event.preventDefault(); stripe.confirmSepaDebitSetup( clientSecret, { payment_method: { sepa_debit: iban, billing_details: { name: accountholderName.value, email: email.value, }, }, } ); });

Use stripe.confirmSepaDebitSetup to complete the payment when the user submits the form. Including the customer’s name and email address in the billing_details property of the payment_method parameter is required to create a SEPA Direct Debit PaymentMethod.

To call stripe.confirmSepaDebitSetup from your payment form component, use the useStripe and useElements hooks.

If you prefer traditional class components over hooks, you can instead use an ElementsConsumer.

import React from 'react'; import {useStripe, useElements, IbanElement} from '@stripe/react-stripe-js'; import IbanForm from './IbanForm'; export default function PaymentSetupForm() { const stripe = useStripe(); const elements = useElements(); const handleSubmit = async (event) => { // We don't want to let default form submission happen here, // which would refresh the page. event.preventDefault(); if (!stripe || !elements) { // Stripe.js has not yet loaded. // Make sure to disable form submission until Stripe.js has loaded. return; } const iban = elements.getElement(IbanElement); // For brevity, this example is using uncontrolled components for // the accountholder's name and email. In a real world app you will // probably want to use controlled components. // https://reactjs.org/docs/uncontrolled-components.html // https://reactjs.org/docs/forms.html#controlled-components const accountholderName = event.target['accountholder-name']; const email = event.target.email; const result = await stripe.confirmSepaDebitSetup('{CLIENT_SECRET}', { payment_method: { sepa_debit: iban, billing_details: { name: accountholderName.value, email: email.value, }, } }); if (result.error) { // Show error to your customer. console.log(result.error.message); } else { // Show a confirmation message to your customer. // The SetupIntent is in the 'succeeded' state. } }; return ( <IbanForm onSubmit={handleSubmit} disabled={!stripe} /> ); }
import React from 'react'; import {ElementsConsumer, IbanElement} from '@stripe/react-stripe-js'; import IbanForm from './IbanForm'; class PaymentSetupForm extends React.Component { handleSubmit = async (event) => { // We don't want to let default form submission happen here, // which would refresh the page. event.preventDefault(); const {stripe, elements} = this.props if (!stripe || !elements) { // Stripe.js has not yet loaded. // Make sure to disable form submission until Stripe.js has loaded. return; } const clientSecret = await getClientSecret(); const iban = elements.getElement(IbanElement); // For brevity, this example is using uncontrolled components for // the accountholder's name and email. In a real world app you will // probably want to use controlled components. // https://reactjs.org/docs/uncontrolled-components.html // https://reactjs.org/docs/forms.html#controlled-components const accountholderName = event.target['accountholder-name']; const email = event.target.email; const result = await stripe.confirmSepaDebitSetup('{CLIENT_SECRET}', { payment_method: { sepa_debit: iban, billing_details: { name: accountholderName.value, email: email.value, }, } }); if (result.error) { // Show error to your customer. console.log(result.error.message); } else { // Show a confirmation message to your customer. // The SetupIntent is in the 'succeeded' state. } }; render() { const {stripe} = this.props; return ( <IbanForm onSubmit={this.handleSubmit} disabled={!stripe} /> ); } } export default function InjectedPaymentSetupForm() { return ( <ElementsConsumer> {({stripe, elements}) => ( <PaymentSetupForm stripe={stripe} elements={elements} /> )} </ElementsConsumer> ); }

5 Set the default payment method Server-side

You need to add a stored payment method to the customer so future payments are successful. You do this by setting the payment method you just collected at the top level of the Customer object and as the default payment method for invoices:

curl https://api.stripe.com/v1/customers/cus_Gk0uVzT2M4xOKD \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d "invoice_settings[default_payment_method]"=pm_1F0c9v2eZvKYlo2CJDeTrB4n
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' Stripe::Customer.update( 'cus_Gk0uVzT2M4xOKD', { invoice_settings: { default_payment_method: 'pm_1F0c9v2eZvKYlo2CJDeTrB4n', }, } )
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' stripe.Customer.modify( 'cus_Gk0uVzT2M4xOKD', invoice_settings={ 'default_payment_method': 'pm_1F0c9v2eZvKYlo2CJDeTrB4n', } )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); \Stripe\Customer::update( 'cus_Gk0uVzT2M4xOKD', [ 'invoice_settings' => [ 'default_payment_method' => 'pm_1F0c9v2eZvKYlo2CJDeTrB4n' ], ] );
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; Customer customer = Customer.retrieve("cus_Gk0uVzT2M4xOKD"); CustomerUpdateParams params = CustomerUpdateParams.builder() .setInvoiceSettings( CustomerUpdateParams.InvoiceSettings.builder() .setDefaultPaymentMethod("pm_1F0c9v2eZvKYlo2CJDeTrB4n") .build()) .build(); customer.update(params);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); const customer = await stripe.customers.update( 'cus_Gk0uVzT2M4xOKD', { invoice_settings: { default_payment_method: 'pm_1F0c9v2eZvKYlo2CJDeTrB4n', }, } );
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" params := &stripe.CustomerParams{ InvoiceSettings: &stripe.CustomerInvoiceSettingsParams{ DefaultPaymentMethod: stripe.String("pm_1F0c9v2eZvKYlo2CJDeTrB4n"), }, } c, _ := customer.Update("cus_Gk0uVzT2M4xOKD", params)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var options = new CustomerUpdateOptions { InvoiceSettings = new CustomerInvoiceSettingsOptions { DefaultPaymentMethod = "pm_1F0c9v2eZvKYlo2CJDeTrB4n", }, }; var service = new CustomerService(); service.Update("cus_Gk0uVzT2M4xOKD", options);

6 Create the subscription Server-side

To create a subscription, combine a price with a customer:

curl https://api.stripe.com/v1/subscriptions \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d customer=cus_Gk0uVzT2M4xOKD \ -d "items[0][price]"=price_F52b2UdntfQsfR \ -d "expand[0]"="latest_invoice.payment_intent"
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' subscription = Stripe::Subscription.create({ customer: customer.id, items: [ { price: 'price_FSDjyHWis0QVwl', }, ], expand: ['latest_invoice.payment_intent'], })
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' subscription = stripe.Subscription.create( customer=customer.id, items=[ { 'price': 'price_FSDjyHWis0QVwl', }, ], expand=['latest_invoice.payment_intent'], )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); $subscription = \Stripe\Subscription::create([ 'customer' => $customer->id, 'items' => [ [ 'price' => 'price_FSDjyHWis0QVwl', ], ], 'expand' => ['latest_invoice.payment_intent'], ]);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; Map<String, Object> item = new HashMap<>(); item.put("price", "price_FSDjyHWis0QVwl"); Map<String, Object> items = new HashMap<>(); items.put("0", item); Map<String, Object> expand = new HashMap<>(); expand.put("0", "latest_invoice.payment_intent"); Map<String, Object> params = new HashMap<>(); params.put("customer", customer.getId()); params.put("items", items); params.put("expand", expand); Subscription subscription = Subscription.create(params);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); const subscription = await stripe.subscriptions.create({ customer: customer.id, items: [ { price: 'price_FSDjyHWis0QVwl', }, ], expand: ['latest_invoice.payment_intent'] });
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" items := []*stripe.SubscriptionItemsParams{ { Price: stripe.String("price_FSDjyHWis0QVwl"), }, } params := &stripe.SubscriptionParams{ Customer: stripe.String(customer.ID), Items: items, } params.AddExpand("latest_invoice.payment_intent") subscription, _ := sub.New(params)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var items = new List<SubscriptionItemOptions> { new SubscriptionItemOptions { Price = "price_CBXbz9i7AIOTzr" } }; var options = new SubscriptionCreateOptions { Customer = customer.Id, Items = items }; options.AddExpand("latest_invoice.payment_intent"); var service = new SubscriptionService(); Subscription subscription = service.Create(options);

Creating subscriptions automatically charges customers because the default payment method is set. After a successful payment, the status in the Stripe Dashboard changes to Active. The price you created earlier determines subsequent billings.

7 Manage subscription status Client-side

Assuming the initial payment succeeds, the state of the subscription is active and no further action is needed. When payments fail, the status is changed to the Subscription status configured in your automatic collection settings. You should notify the customer on failure and charge them with a different payment method.

8 Test the integration

Test account numbers
Account Number Description
AT611904300234573201 The payment method details are successfully collected.
Account Number Description
BE62510007547061 The payment method details are successfully collected.
Account Number Description
DK5000400440116243 The payment method details are successfully collected.
Account Number Description
EE382200221020145689 The payment method details are successfully collected.
Account Number Description
FI2112345600000785 The payment method details are successfully collected.
Account Number Description
FR1420041010050500013M02606 The payment method details are successfully collected.
Account Number Description
DE89370400440532013000 The payment method details are successfully collected.
Account Number Description
IE29AIBK93115212345678 The payment method details are successfully collected.
Account Number Description
IT40S0542811101000000123456 The payment method details are successfully collected.
Account Number Description
LT121000011101001000 The payment method details are successfully collected.
Account Number Description
LU280019400644750000 The payment method details are successfully collected.
Account Number Description
NL39RABO0300065264 The payment method details are successfully collected.
Account Number Description
NO9386011117947 The payment method details are successfully collected.
Account Number Description
PT50000201231234567890154 The payment method details are successfully collected.
Account Number Description
ES0700120345030000067890 The payment method details are successfully collected.
Account Number Description
SE3550000000054910000003 The payment method details are successfully collected.
Account Number Description
GB82WEST12345698765432 The payment method details are successfully collected.

Optional Setting the billing cycle

By default, the billing cycles for subscriptions are set automatically when they’re created. For example, if a customer subscribes to a monthly plan on September 7th, they’re billed on the 7th of every month after that. Some businesses prefer to set the billing cycle manually so that their customers are charged at the same time. The billing cycle anchor argument allows you to do this.

curl https://api.stripe.com/v1/subscriptions \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d customer=cus_4fdAW5ftNQow1a \ -d "items[0][price]"=price_CBb6IXqvTLXp3f \ -d billing_cycle_anchor=1604979375
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' subscription = Stripe::Subscription.create({ customer: 'cus_4fdAW5ftNQow1a', items: [ { price: 'price_CBb6IXqvTLXp3f', }, ], billing_cycle_anchor: 1604979375, })
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' subscription = stripe.Subscription.create( customer='cus_4fdAW5ftNQow1a', items=[ { 'price': 'price_CBb6IXqvTLXp3f', }, ], billing_cycle_anchor=1604979375, )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); $subscription = \Stripe\Subscription::create([ 'customer' => 'cus_4fdAW5ftNQow1a', 'items' => [ [ 'price' => 'price_CBb6IXqvTLXp3f', ], ], 'billing_cycle_anchor' => 1604979375, ]);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; SubscriptionCreateParams params = SubscriptionCreateParams.builder() .setCustomer("cus_4fdAW5ftNQow1a") .addItem( SubscriptionCreateParams.Item.builder() .setPrice("price_CBb6IXqvTLXp3f") .build()) .setBillingCycleAnchor(1604979375L) .build(); Subscription subscription = Subscription.create(params);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); const subscription = await stripe.subscriptions.create({ customer: 'cus_4fdAW5ftNQow1a', items: [ { price: 'price_CBb6IXqvTLXp3f', }, ], billing_cycle_anchor: 1604979375, });
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" items := []*stripe.SubscriptionItemsParams{ { Price: stripe.String("price_CBb6IXqvTLXp3f"), }, } params := &stripe.SubscriptionParams{ Customer: stripe.String("cus_4fdAW5ftNQow1a"), Items: items, BillingCycleAnchor: stripe.Int64(1604979375), } subscription, _ := sub.New(params)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var items = new List<SubscriptionItemOptions> { new SubscriptionItemOptions {Price = "price_CBb6IXqvTLXp3f"} }; var options = new SubscriptionCreateOptions { Customer = "cus_4fdAW5ftNQow1a", Items = items, BillingCycleAnchor = DateTimeOffset.FromUnixTimeSeconds(1604979375).UtcDateTime, }; var service = new SubscriptionService(); Subscription subscription = service.Create(options);

When setting the billing cycle manually, the customer is automatically charged a prorated amount for the time between the subscription being created and the billing cycle anchor. If you don’t want to charge customers for this time, you can set the prorate argument to false. You can also combine the billing cycle anchor with trial periods to give users free access to your product and then charge them a prorated amount.

Optional Subscription trials

Free trials allow customers access to your product for a period of time for free. Using free trials is different from setting prorate to false because you can customize how long the free period lasts. You can set the trial period by passing a timestamp in the trial end argument.

curl https://api.stripe.com/v1/subscriptions \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d customer=cus_4fdAW5ftNQow1a \ -d "items[0][price]"=price_CBb6IXqvTLXp3f \ -d trial_end=1604374575
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' subscription = Stripe::Subscription.create({ customer: 'cus_4fdAW5ftNQow1a', items: [ { price: 'price_CBb6IXqvTLXp3f', }, ], trial_end: 1604374575, })
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' subscription = stripe.Subscription.create( customer='cus_4fdAW5ftNQow1a', items=[ { 'price': 'price_CBb6IXqvTLXp3f', }, ], trial_end=1604374575, )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); $subscription = \Stripe\Subscription::create([ 'customer' => 'cus_4fdAW5ftNQow1a', 'items' => [ [ 'price' => 'price_CBb6IXqvTLXp3f', ], ], 'trial_end' => 1604374575, ]);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; SubscriptionCreateParams params = SubscriptionCreateParams.builder() .setCustomer("cus_4fdAW5ftNQow1a") .addItem( SubscriptionCreateParams.Item.builder() .setPrice("price_CBb6IXqvTLXp3f") .build()) .setTrialEnd(1604374575L) .build(); Subscription subscription = Subscription.create(params);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); const subscription = await stripe.subscriptions.create({ customer: 'cus_4fdAW5ftNQow1a', items: [ { price: 'price_CBb6IXqvTLXp3f', }, ], trial_end: 1604374575, });
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" items := []*stripe.SubscriptionItemsParams{ { Price: stripe.String("price_CBb6IXqvTLXp3f"), }, } params := &stripe.SubscriptionParams{ Customer: stripe.String("cus_4fdAW5ftNQow1a"), Items: items, TrialEnd: stripe.Int64(1604374575), } subscription, _ := sub.New(params)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var items = new List<SubscriptionItemOptions> { new SubscriptionItemOptions {Price = "price_CBb6IXqvTLXp3f"} }; var options = new SubscriptionCreateOptions { Customer = "cus_4fdAW5ftNQow1a", Items = items, TrialEnd = DateTimeOffset.FromUnixTimeSeconds(1604374575).UtcDateTime, }; var service = new SubscriptionService(); Subscription subscription = service.Create(options);

You can combine a billing cycle anchor with a free trial if you want. For example, let’s say it’s September 15th and you want to give your customer a free trial for seven days and then start the normal billing cycle on October 1st. You can set the free trial to end on September 22nd and the billing cycle anchor to October 1st. This gives the customer a free trial for seven days and then charges a prorated amount for the time between the trial ending and October 1st. On October 1st, the customer is charged the normal subscription amount for their first full billing cycle.

Optional Create SEPA Direct Debit payments using other payment methods

You can create SEPA Direct Debit payments using other payment methods. This includes:

Using these payment methods requires a few additional steps. The steps below cover iDEAL but you can substitute ideal for bancontact or sofort, and stripe.confirmIdealSetup for stripe.confirmBancontactSetup or stripe.confirmSofortSetup.

  1. Create the SetupIntent and set ideal as a payment_method_type.
  2. Use an idealBank Element to collect payment information.
  3. Confirm set up using stripe.confirmIdealSetup.
  4. List the customer’s payment methods to find the SEPA Direct Debit payment method, then set it as the customer’s default payment method.
Was this page helpful?
Questions? Contact us.
Developer tutorials on YouTube.