# Build a subscriptions integration

Create and manage subscriptions to accept recurring payments.

# Android


Learn how to sell fixed-price *subscriptions* (A Subscription represents the product details associated with the plan that your customer subscribes to. Allows you to charge the customer on a recurring basis). You’ll use the [Mobile Payment Element](https://docs.stripe.com/payments/accept-a-payment.md) to create a custom payment form that you embed in your app.
![Fixed-price subscription page with Mobile Payment Element](https://b.stripecdn.com/docs-statics-srv/assets/fixed-price-collect-payment-details-mobile.b11cdc8fa8952d753238df4df3375fa6.png)

> If you’re selling digital products or services that are consumed within your app (for example, subscriptions, in-game currencies, game levels, access to premium content, or unlocking a full version), you must use Apple’s in-app purchase APIs. This rule has some exceptions, including one-to-one personal services and [apps based in specific regions](https://support.stripe.com/questions/changes-to-mobile-app-store-rules). See the [App Store review guidelines](https://developer.apple.com/app-store/review/guidelines/#payments) for more information.

## Build your subscription 

This guide shows you how to:

- Model your business by building a product catalog.
- Create a registration process to add customers.
- Create subscriptions and collect payment information.
- Test and monitor the status of payments and subscriptions.
- Let customers change their plan or cancel the subscription.
- Learn how to use [flexible billing mode](https://docs.stripe.com/billing/subscriptions/billing-mode.md) to access enhanced billing behavior and additional features.

## How to model it on Stripe

[Subscriptions](https://docs.stripe.com/api/subscriptions.md) simplify your billing by automatically creating *Invoices* (Invoices are statements of amounts owed by a customer. They track the status of payments from draft through paid or otherwise finalized. Subscriptions automatically generate invoices, or you can manually create a one-off invoice) and [PaymentIntents](https://docs.stripe.com/api/payment_intents.md) for you. To create and activate a subscription, you need to first create a *Product* (Products represent what your business sells—whether that's a good or a service) to model what’s being sold, and a *Price* (Prices define how much and how often to charge for products. This includes how much the product costs, what currency to use, and the interval if the price is for subscriptions) which determines the interval and amount to charge. You also need either a customer-configured `Account` object or a `Customer` object to store *PaymentMethods* (PaymentMethods represent your customer's payment instruments, used with the Payment Intents or Setup Intents APIs) used to make each recurring payment.

#### Accounts v2

A diagram illustrating common billing objects and their relationships (See full diagram at https://docs.stripe.com/billing/subscriptions/build-subscriptions)

```text
+---------------------------------+
| Subscription object             |
+---------------------------------+
| id: sub_1234                    |
| status: active                  |
| latest_invoice: in_1234         |
| default_payment_method: pm_1234 |
| customer_account: acct_1234     |
| items.data.price: price_1234    |
+---------------------------------+

+----------------+
| Invoice object |
+----------------+
| id: in_1234    |
| currency: usd  |
| status: open   |
+----------------+

+----------------------+
| PaymentMethod object |
+----------------------+
| id: pm_1234          |
| type: card           |
| card[brand]: visa    |
+----------------------+

+---------------------------------------+
| Customer-configured Account object    |
+---------------------------------------+
| id: acct_1234                         |
| display_name: Jenny Rosen             |
| contact_email: jennyrosen@example.com |
+---------------------------------------+

+--------------------+
| Price object       |
+--------------------+
| id: price_1234     |
| product: prod_1234 |
| type: recurring    |
+--------------------+

+---------------------------+
| Product object            |
+---------------------------+
| id: prod_1234             |
| active: true              |
| name: Widget, blue        |
| default_price: price_1234 |
+---------------------------+

+-----------------------------+
| PaymentIntent               |
+-----------------------------+
| id: pi_1234                 |
| amount: 1000                |
| customer_account: acct_1234 |
| invoice: in_1234            |
| status: processing          |
+-----------------------------+

[Subscription object.latest_invoice] --> [Invoice object]
[Subscription object.default_payment_method] --> [PaymentMethod object]
[Subscription object.customer_account] --> [Customer-configured Account object]
[Subscription object.items.data.price] --> [Price object]
[Price object.product] --> [Product object]
[PaymentIntent.invoice] --> [Invoice object]
```

#### Customer v1

A diagram illustrating common billing objects and their relationships (See full diagram at https://docs.stripe.com/billing/subscriptions/build-subscriptions)

```text
+---------------------------------+
| Subscription object             |
+---------------------------------+
| id: sub_1234                    |
| status: active                  |
| latest_invoice: in_1234         |
| default_payment_method: pm_1234 |
| customer: cus_1234              |
| items.data.price: price_1234    |
+---------------------------------+

+----------------+
| Invoice object |
+----------------+
| id: in_1234    |
| currency: usd  |
| status: open   |
+----------------+

+----------------------+
| PaymentMethod object |
+----------------------+
| id: pm_1234          |
| type: card           |
| card[brand]: visa    |
+----------------------+

+-------------------------------+
| Customer object               |
+-------------------------------+
| id: cus_1234                  |
| name: Jenny Rosen             |
| email: jennyrosen@example.com |
+-------------------------------+

+--------------------+
| Price object       |
+--------------------+
| id: price_1234     |
| product: prod_1234 |
| type: recurring    |
+--------------------+

+---------------------------+
| Product object            |
+---------------------------+
| id: prod_1234             |
| active: true              |
| name: Widget, blue        |
| default_price: price_1234 |
+---------------------------+

+--------------------+
| PaymentIntent      |
+--------------------+
| id: pi_1234        |
| amount: 1000       |
| customer: cus_1234 |
| invoice: in_1234   |
| status: processing |
+--------------------+

[Subscription object.latest_invoice] --> [Invoice object]
[Subscription object.default_payment_method] --> [PaymentMethod object]
[Subscription object.customer] --> [Customer object]
[Subscription object.items.data.price] --> [Price object]
[Price object.product] --> [Product object]
[PaymentIntent.invoice] --> [Invoice object]
```

### API object definitions

| Resource                                                                                                                             | Definition                                                                                                                                                                                                                                                                                                                                                                                                    |
| ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Account configured as a customer](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer) | Represents a customer in the Accounts v2 API who purchases a subscription. Configure an `Account` object as a customer and associate it with a subscription to make and track recurring charges and to manage the products that they subscribe to. For more information, see the [Use Accounts as customers guide](https://docs.stripe.com/accounts-v2/use-accounts-as-customers.md).                         |
| [Customer](https://docs.stripe.com/api/customers.md)                                                                                 | Represents a customer in the Customers API who purchases a subscription. Use the `Customer` object associated with a subscription to make and track recurring charges and to manage the products that they subscribe to.                                                                                                                                                                                      |
| [Entitlement](https://docs.stripe.com/api/entitlements/active-entitlement.md)                                                        | Represents a customer’s access to a feature included in a service product that they subscribe to. When you create a subscription for a customer’s recurring purchase of a product, an active entitlement is automatically created for each feature associated with that product. When a customer accesses your services, use their active entitlements to enable the features included in their subscription. |
| [Feature](https://docs.stripe.com/api/entitlements/feature.md)                                                                       | Represents a function or ability that your customers can access when they subscribe to a service product. You can include features in a product by creating ProductFeatures.                                                                                                                                                                                                                                  |
| [Invoice](https://docs.stripe.com/api/invoices.md)                                                                                   | A statement of amounts a customer owes that tracks payment statuses from draft through paid or otherwise finalized. Subscriptions automatically generate invoices.                                                                                                                                                                                                                                            |
| [PaymentIntent](https://docs.stripe.com/api/payment_intents.md)                                                                      | A way to build dynamic payment flows. A PaymentIntent tracks the lifecycle of a customer checkout flow and triggers additional authentication steps when required by regulatory mandates, custom Radar fraud rules, or redirect-based payment methods. Invoices automatically create PaymentIntents.                                                                                                          |
| [PaymentMethod](https://docs.stripe.com/api/payment_methods.md)                                                                      | A customer’s payment methods that they use to pay for your products. For example, you can store a credit card on a customer-configured `Account` or `Customer` object and use it to make recurring payments for that customer. Typically used with the Payment Intents or Setup Intents APIs.                                                                                                                 |
| [Price](https://docs.stripe.com/api/prices.md)                                                                                       | Defines the unit price, currency, and billing cycle for a product.                                                                                                                                                                                                                                                                                                                                            |
| [Product](https://docs.stripe.com/api/products.md)                                                                                   | A good or service that your business sells. A service product can include one or more features.                                                                                                                                                                                                                                                                                                               |
| [ProductFeature](https://docs.stripe.com/api/product-feature.md)                                                                     | Represents a single feature’s inclusion in a single product. Each product is associated with a ProductFeature for each feature that it includes, and each feature is associated with a ProductFeature for each product that includes it.                                                                                                                                                                      |
| [Subscription](https://docs.stripe.com/api/subscriptions.md)                                                                         | Represents a customer’s scheduled recurring purchase of a product. Use a subscription to collect payments and provide repeated delivery of or continuous access to a product.                                                                                                                                                                                                                                 |

Here’s an example of how products, features, and entitlements work together. Imagine that you want to set up a recurring service that offers two tiers: a standard product with basic functionality, and an advanced product that adds extended functionality.

1. You create two features: `basic_features` and `extended_features`.
2. You create two products: `standard_product` and `advanced_product`.
3. For the standard product, you create one ProductFeature that associates `basic_features` with `standard_product`.
4. For the advanced product, you create two ProductFeatures: one that associates `basic_features` with `advanced_product` and one that associates `extended_features` with `advanced_product`.

A customer, `first_customer`, subscribes to the standard product. When you create the subscription, Stripe automatically creates an Entitlement that associates `first_customer` with `basic_features`.

Another customer, `second_customer`, subscribes to the advanced product. When you create the Subscription, Stripe automatically creates two Entitlements: one that associates `second_customer` with `basic_features`, and one that associates `second_customer` with `extended_features`.

You can determine which features to provision for a customer by [retrieving their active entitlements or listening to the Active Entitlement Summary event](https://docs.stripe.com/billing/entitlements.md?dashboard-or-api=api#entitlements). You don’t have to retrieve their subscriptions, products, and features.

## Set up Stripe

The [Stripe Android SDK](https://github.com/stripe/stripe-android) is open source and [fully documented](https://stripe.dev/stripe-android/).

To install the SDK, add `stripe-android` to the `dependencies` block of your [app/build.gradle](https://developer.android.com/studio/build/dependencies) file:

#### Kotlin

```kotlin
plugins {
    id("com.android.application")
}

android { ... }

dependencies {
  // ...

  // Stripe Android SDK
  implementation("com.stripe:stripe-android:23.17.0")
  // Include the financial connections SDK to support US bank account as a payment method
  implementation("com.stripe:financial-connections:23.17.0")
}
```

> For details on the latest SDK release and past versions, see the [Releases](https://github.com/stripe/stripe-android/releases) page on GitHub. To receive notifications when a new release is published, [watch releases for the repository](https://docs.github.com/en/github/managing-subscriptions-and-notifications-on-github/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository).

Configure the SDK with your Stripe [publishable key](https://dashboard.stripe.com/apikeys) so that it can make requests to the Stripe API, such as in your `Application` subclass:

#### Kotlin

```kotlin
import com.stripe.android.PaymentConfiguration

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        PaymentConfiguration.init(
            applicationContext,
            "<<YOUR_PUBLISHABLE_KEY>>"
        )
    }
}
```

> Use your [test keys](https://docs.stripe.com/keys.md#obtain-api-keys) while you test and develop, and your [live mode](https://docs.stripe.com/keys.md#test-live-modes) keys when you publish your app.

And then install the Stripe CLI. The CLI provides webhook testing and you can run it to make API calls to Stripe. This guide shows how to use the CLI to set up a pricing model in a later section.

Install the Stripe CLI with [npm](https://www.npmjs.com/):

```bash
npm install --global @stripe/cli
```

> For more installation options for Windows, macOS, Linux, and Docker, check the [Stripe CLI readme](https://github.com/stripe/stripe-cli#installation) on GitHub.

After installation, connect the CLI to your Stripe account by logging in:

```bash
stripe login
```

The CLI displays a pairing code and opens the Stripe Dashboard, where you approve access to accounts, sandboxes, and live mode. The CLI stores your credentials in your operating system’s secure credential store (when available) and refreshes the session automatically. To authenticate with an API key instead, run `stripe login --interactive`, use `stripe config`, pass `--api-key`, or set the `STRIPE_API_KEY` environment variable.

## Create the pricing model [Stripe CLI or Dashboard]

[Recurring pricing models](https://docs.stripe.com/products-prices/pricing-models.md) represent the products or services you sell, how much they cost, what currency you accept for payments, and the service period for subscriptions. To build the pricing model, create [products](https://docs.stripe.com/api/products.md) (what you sell) and [prices](https://docs.stripe.com/api/prices.md) (how much and how often to charge for your products).

This example uses flat-rate pricing with two different service-level options: Basic and Premium. For each service-level option, you need to create a product and a recurring price. To add a one-time charge for something like a setup fee, create a third product with a one-time price.

Each product bills at monthly intervals. The price for the Basic product is 5 USD. The price for the Premium product is 15 USD. See the [flat rate pricing](https://docs.stripe.com/subscriptions/pricing-models/flat-rate-pricing.md) guide for an example with three tiers.

#### Dashboard

Go to the [Add a product](https://dashboard.stripe.com/test/products/create) page and create two products. Add one price for each product, each with a monthly recurring billing period:

- Premium product: Premium service with extra features

  - Price: Flat rate | 15 USD

- Basic product: Basic service with minimum features

  - Price: Flat rate | 5 USD

After you create the prices, record the price IDs so you can use them in other  steps. Price IDs look like this: `price_G0FvDp6vZvdwRZ`.

When you’re ready, use the **Copy to live mode** button at the top right of the page to clone your product from [a sandbox to live mode](https://docs.stripe.com/keys.md#test-live-modes).

#### API

You can use the API to create the [Products](https://docs.stripe.com/api/products.md) and [Prices](https://docs.stripe.com/api/prices.md).

Create the Premium product:

```curl
curl https://api.stripe.com/v1/products \
  -u "<<YOUR_SECRET_KEY>>:" \
  --data-urlencode "name=Billing Guide: Premium Service" \
  -d "description=Premium service with extra features"
```

Create the Basic product:

```curl
curl https://api.stripe.com/v1/products \
  -u "<<YOUR_SECRET_KEY>>:" \
  --data-urlencode "name=Billing Guide: Basic Service" \
  -d "description=Basic service with minimum features"
```

Record the product ID for each product. They look like this:

```json
{
  "id": "prod_H94k5odtwJXMtQ",
  "object": "product",
  "active": true,
  "attributes": [

  ],
  "created": 1587577341,
  "description": "Premium service with extra features",
  "images": [

  ],
  "livemode": false,
  "metadata": {
  },
  "name": "Billing Guide: Premium Service",
  "statement_descriptor": null,
  "type": "service",
  "unit_label": null,
  "updated": 1587577341
}
```

Use the product IDs to create a price for each product. The [unit_amount](https://docs.stripe.com/api/prices/object.md#price_object-unit_amount) number is in cents, so `1500` = 15 USD, for example.

Create the Premium price:

```curl
curl https://api.stripe.com/v1/prices \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d product={{PREMIUM_PRODUCT_ID}} \
  -d unit_amount=1500 \
  -d currency=usd \
  -d "recurring[interval]=month"
```

Create the Basic price:

```curl
curl https://api.stripe.com/v1/prices \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d product={{BASIC_PRODUCT_ID}} \
  -d unit_amount=500 \
  -d currency=usd \
  -d "recurring[interval]=month"
```

Record the price ID for each price so you can use them in subsequent steps. They look like this:

```json
{
  "id": "price_HGd7M3DV3IMXkC",
  "object": "price",
  "product": "prod_HGd6W1VUqqXGvr",
  "type": "recurring",
  "currency": "usd",
  "recurring": {
    "interval": "month",
    "interval_count": 1,
    "trial_period_days": null,
    "usage_type": "licensed"
  },
  "active": true,
  "billing_scheme": "per_unit",
  "created": 1589319695,
  "livemode": false,
  "lookup_key": null,
  "metadata": {},
  "nickname": null,
  "unit_amount": 1500,
  "unit_amount_decimal": "1500",
  "tiers": null,
  "tiers_mode": null,
  "transform_quantity": null
}
```

## Create the customer [Client and Server]

Stripe needs a customer for each subscription. In your application front end, collect any necessary information from your users and pass it to the backend.

You might want to use a Network library to send network requests to your backend. This document uses [okhttp](https://square.github.io/okhttp/), but you can use any library that work best in your project.

```groovy
dependencies {
  ...
  implementation "com.squareup.okhttp3:okhttp:4.12.0"
}
```

If you need to collect address details, the Address Element enables you to collect a shipping or billing address for your customers. For more information on the Address Element, visit the [Address Element](https://docs.stripe.com/elements/address-element.md) page.

```kotlin
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Button
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject

@Composable
fun RegisterView() {
    var email by remember { mutableStateOf("") }
    Column {
        OutlinedTextField(value = email,
            label = { Text(text = "Email") },
            onValueChange = { email = it })
        Button(onClick = {
            val body = JSONObject().put("email", email).toString()
                .toRequestBody("application/json".toMediaType())
            val request =
                Request.Builder().url("http://10.0.2.2:4567/create-customer").post(body).build()
            CoroutineScope(Dispatchers.IO).launch {
                OkHttpClient().newCall(request).execute().use { response ->
                    if (response.isSuccessful) {
                        println(JSONObject(response.body!!.string()).get("customer"))
                    }
                }
            }
        }) {
            Text(text = "Submit")
        }
    }
}
```

On the server, create the Stripe customer object.

> #### Use the Accounts v2 API to represent customers
> 
> The Accounts v2 API is generally available for Connect users, and in public preview for other Stripe users. If you’re part of the Accounts v2 preview, you need to specify a [preview version](https://docs.stripe.com/api-v2-overview.md#sdk-and-api-versioning) in your code.
> 
> To join the Accounts v2 preview, go to [Account previews and features](https://dashboard.stripe.com/settings/previews) in your Dashboard and enable **Reusable payment methods for Global Payouts**.
> 
> For most use cases, we recommend [modeling your customers as customer-configured Account objects](https://docs.stripe.com/accounts-v2/use-accounts-as-customers.md) instead of using [Customer](https://docs.stripe.com/api/customers.md) objects.

#### Accounts v2

```curl
curl -X POST https://api.stripe.com/v2/core/accounts \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-04-22.preview" \
  --json '{
    "contact_email": "jenny.rosen@example.com",
    "display_name": "Jenny Rosen",
    "identity": {
        "individual": {
            "given_name": "Jenny Rosen",
            "address": {
                "city": "San Francisco",
                "country": "US",
                "line1": "123 Main Street",
                "postal_code": "94605",
                "state": "CA"
            }
        }
    },
    "configuration": {
        "customer": {
            "capabilities": {
                "automatic_indirect_tax": {
                    "requested": true
                }
            },
            "shipping": {
                "address": {
                    "city": "San Francisco",
                    "country": "US",
                    "line1": "123 Main Street",
                    "postal_code": "94605",
                    "state": "CA"
                }
            }
        }
    },
    "include": [
        "configuration.customer",
        "identity"
    ]
  }'
```

#### Customers v1

```curl
curl https://api.stripe.com/v1/customers \
  -u "<<YOUR_SECRET_KEY>>:" \
  --data-urlencode "email=jenny.rosen@example.com" \
  -d "name=Jenny Rosen" \
  -d "shipping[address][city]=San Francisco" \
  -d "shipping[address][country]=US" \
  -d "shipping[address][line1]=123 Main Street" \
  -d "shipping[address][postal_code]=9460" \
  -d "shipping[address][state]=CA" \
  -d "shipping[name]=Jenny Rosen" \
  -d "address[city]=San Francisco" \
  -d "address[country]=US" \
  -d "address[line1]=123 Main Street" \
  -d "address[postal_code]=9460" \
  -d "address[state]=CA"
```

## Create the subscription [Client and Server]

> If you want to render the Payment Element without first creating a subscription, see [Collect payment details before creating an Intent](https://docs.stripe.com/payments/accept-a-payment-deferred.md?type=subscription).

Let your new customer choose a plan and then create the subscription—in this guide, they choose between Basic and Premium.

In your app, pass the selected price ID and the ID of the customer record to the backend.

#### Accounts v2

```kotlin
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject

fun createSubscription(priceId: String, customerAccountId: String): SubscriptionResponse? {
    val body = JSONObject()
        .put("priceId", priceId)
        .put("customerAccountId", customerAccountId).toString()
        .toRequestBody("application/json".toMediaType())
    val request =
        Request.Builder().url("http://10.0.2.2:4567/create-subscription").post(body).build()
    OkHttpClient().newCall(request).execute().use { response ->
        if (response.isSuccessful) {
            // SubscriptionsResponse is data class conforming to the expected response from your backend.
            // It should include the client_secret, as discussed below.
            return Gson().fromJson(response.body!!.string(), SubscriptionResponse::class.java)
        }
    }
    return null
}
```

#### Customers v1

```kotlin
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject

fun createSubscription(priceId: String, customerId: String): SubscriptionResponse? {
    val body = JSONObject()
        .put("priceId", priceId)
        .put("customerId", customerId).toString()
        .toRequestBody("application/json".toMediaType())
    val request =
        Request.Builder().url("http://10.0.2.2:4567/create-subscription").post(body).build()
    OkHttpClient().newCall(request).execute().use { response ->
        if (response.isSuccessful) {
            // SubscriptionsResponse is data class conforming to the expected response from your backend.
            // It should include the client_secret, as discussed below.
            return Gson().fromJson(response.body!!.string(), SubscriptionResponse::class.java)
        }
    }
    return null
}
```

On the backend, create the subscription with status `incomplete` using `payment_behavior=default_incomplete`. Then return the `client_secret` from the subscription’s first [payment intent](https://docs.stripe.com/payments/payment-intents.md) to the frontend to complete payment by expanding the[`confirmation_secret`](https://docs.stripe.com/api/invoices/object.md#invoice_object-confirmation_secret) on the latest invoice of the subscription.

To enable [improved subscription behavior](https://docs.stripe.com/billing/subscriptions/billing-mode.md), set `billing_mode[type]` to `flexible`. You must use Stripe API version [2025-06-30.basil](https://docs.stripe.com/changelog/basil.md#2025-06-30.basil) or later.

Set [save_default_payment_method](https://docs.stripe.com/api/subscriptions/object.md#subscription_object-payment_settings-save_default_payment_method) to `on_subscription` to save the payment method as the default for a subscription when a payment succeeds. Saving a default payment method increases the success rate of future subscription payments.

The following example creates a `Subscription` and expands the `confirmation_secret` from its latest invoice in the response. After the subscription is created, read `subscription.latest_invoice.confirmation_secret.client_secret` and return that value to the front end to confirm the payment.

#### Accounts v2

```curl
curl https://api.stripe.com/v1/subscriptions \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d "customer_account={{CUSTOMERACCOUNT_ID}}" \
  -d "items[0][price]={{PRICE_ID}}" \
  -d payment_behavior=default_incomplete \
  -d "payment_settings[save_default_payment_method]=on_subscription" \
  -d "billing_mode[type]=flexible" \
  -d "expand[0]=latest_invoice.confirmation_secret"
```

#### Customers v1

```curl
curl https://api.stripe.com/v1/subscriptions \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d "customer={{CUSTOMER_ID}}" \
  -d "items[0][price]={{PRICE_ID}}" \
  -d payment_behavior=default_incomplete \
  -d "payment_settings[save_default_payment_method]=on_subscription" \
  -d "billing_mode[type]=flexible" \
  -d "expand[0]=latest_invoice.confirmation_secret"
```

> If you’re using a *multi-currency Price* (A single Price object can support multiple currencies. Each purchase uses one of the supported currencies for the Price, depending on how you use the Price in your integration), use the [currency](https://docs.stripe.com/api/subscriptions/create.md#create_subscription-currency) parameter to tell the Subscription which of the Price’s currencies to use. (If you omit the `currency` parameter, then the Subscription uses the Price’s default currency.)

The Subscription is now `inactive` and awaiting payment. The following example response highlights the minimum fields to store, but you can store whatever your application frequently accesses.

#### Accounts v2

```json
{
  "id": "sub_JgRjFjhKbtD2qz",
  "object": "subscription",
  "application_fee_percent": null,
  "automatic_tax": {
    "disabled_reason": null,
    "enabled": false,
    "liability": "null"
  },
  "billing_cycle_anchor": 1623873347,
  "billing_cycle_anchor_config": null,
  "cancel_at": null,
  "cancel_at_period_end": false,
  "canceled_at": null,
  "cancellation_details": {
    "comment": null,
    "feedback": null,
    "reason": null
  },
  "collection_method": "charge_automatically",
  "created": 1623873347,
  "currency": "usd",
  "customer_account": identifier("customerAccount"),
  "days_until_due": null,
  "default_payment_method": null,
  "default_source": null,
  "default_tax_rates": [

  ],
  "discounts": [],
  "ended_at": null,
  "invoice_customer_balance_settings": {
    "account_tax_ids": null,
    "issuer": {
      "type": "self"
    }
  },
  "items": {
    "object": "list",
    "data": [
      {
        "id": "si_JgRjmS4Ur1khEx",
        "object": "subscription_item",
        "created": 1623873347,
        "current_period_end": 1626465347,
        "current_period_start": 1623873347,
        "discounts": [],
        "metadata": {
        },
        "plan": {
          "id": "price_1J32RfGPZ1iASj5zHHp57z7C",
          "object": "plan",
          "active": true,
          "amount": 2000,
          "amount_decimal": "2000",
          "billing_scheme": "per_unit",
          "created": 1623864151,
          "currency": "usd",
          "interval": "month",
          "interval_count": 1,
          "livemode": false,
          "metadata": {
          },
          "nickname": null,
          "product": "prod_JgPF5xnq7qBun3",
          "tiers": null,
          "tiers_mode": null,
          "transform_usage": null,
          "trial_period_days": null,
          "usage_type": "licensed"
        },
        "price": {
          "id": "price_1J32RfGPZ1iASj5zHHp57z7C",
          "object": "price",
          "active": true,
          "billing_scheme": "per_unit",
          "created": 1623864151,
          "currency": "usd",
          "livemode": false,
          "lookup_key": null,
          "metadata": {
          },
          "nickname": null,
          "product": "prod_JgPF5xnq7qBun3",
          "recurring": {
            "interval": "month",
            "interval_count": 1,
            "trial_period_days": null,
            "usage_type": "licensed"
          },
          "tiers_mode": null,
          "transform_quantity": null,
          "type": "recurring",
          "unit_amount": 2000,
          "unit_amount_decimal": "2000"
        },
        "quantity": 1,
        "subscription": "sub_JgRjFjhKbtD2qz",
        "tax_rates": [

        ]
      }
    ],
    "has_more": false,
    "total_count": 1,
    "url": "/v1/subscription_items?subscription=sub_JgRjFjhKbtD2qz"
  },
  "latest_invoice": {
    "id": "in_1J34pzGPZ1iASj5zB87qdBNZ",
    "object": "invoice",
    "account_country": "US",
    "account_name": "Angelina's Store",
    "account_tax_ids": null,
    "amount_due": 2000,
    "amount_overpaid": 0,
    "amount_paid": 0,
    "amount_remaining": 2000,
    "amount_shipping": 0,
    "attempt_count": 0,
    "attempted": false,
    "auto_advance": false,
    "automatic_tax": {
      "disabled_reason": null,
      "enabled": false,
      "liability": null,
      "status": null
    },
    "automatically_finalizes_at": null,
    "billing_reason": "subscription_update",
    "collection_method": "charge_automatically",
    "created": 1623873347,
    "currency": "usd",
    "custom_fields": null,
    "customer_account": identifier("customerAccount"),
    "customer_address": null,
    "customer_email": "angelina@stripe.com",
    "customer_name": null,
    "customer_phone": null,
    "customer_shipping": {
      "address": {
        "city": "",
        "country": "US",
        "line1": "Berry",
        "line2": "",
        "postal_code": "",
        "state": ""
      },
      "name": "",
      "phone": null
    },
    "customer_tax_exempt": "none",
    "customer_tax_ids": [

    ],
    "default_payment_method": null,
    "default_source": null,
    "default_tax_rates": [

    ],
    "description": null,
    "discounts": [],
    "due_date": null,
    "effective_at": "1623873347",
    "ending_balance": 0,
    "footer": null,
    "from_invoice": null,
    "hosted_invoice_url": "https://invoice.stripe.com/i/acct_1By64KGPZ1iASj5z/invst_JgRjzIOILGeq2MKC9T0KtyXnD5udsLp",
    "invoice_pdf": "https://pay.stripe.com/invoice/acct_1By64KGPZ1iASj5z/invst_JgRjzIOILGeq2MKC9T0KtyXnD5udsLp/pdf",
    "last_finalization_error": null,
    "latest_revision": null,
    "lines": {
      "object": "list",
      "data": [
        {
          "id": "il_1N2CjMBwKQ696a5NeOawRQP2",
          "object": "line_item",
          "amount": 2000,
          "currency": "usd",
          "description": "1 × Gold Special (at $20.00 / month)",
          "discount_amounts": [

          ],
          "discountable": true,
          "discounts": [

          ],
          "invoice": "in_1J34pzGPZ1iASj5zB87qdBNZ",
          "livemode": false,
          "metadata": {
          },
          "parent": {
            "invoice_item_details": null,
            "subscription_item_details":
            {
              "invoice_item": null,
              "proration": false,
              "proration_details":
              {
                "credited_items": null
              },
              "subscription":
              "sub_JgRjFjhKbtD2qz",
              "subscription_item":
                "si_JgRjmS4Ur1khEx"
            },
            "type": "subscription_item_details"
          },
          "period": {
            "end": 1626465347,
            "start": 1623873347
          },
          "plan": {
            "id": "price_1J32RfGPZ1iASj5zHHp57z7C",
            "object": "plan",
            "active": true,
            "amount": 2000,
            "amount_decimal": "2000",
            "billing_scheme": "per_unit",
            "created": 1623864151,
            "currency": "usd",
            "interval": "month",
            "interval_count": 1,
            "livemode": false,
            "metadata": {
            },
            "nickname": null,
            "product": "prod_JgPF5xnq7qBun3",
            "tiers": null,
            "tiers_mode": null,
            "transform_usage": null,
            "trial_period_days": null,
            "usage_type": "licensed"
          },
          "price": {
            "id": "price_1J32RfGPZ1iASj5zHHp57z7C",
            "object": "price",
            "active": true,
            "billing_scheme": "per_unit",
            "created": 1623864151,
            "currency": "usd",
            "livemode": false,
            "lookup_key": null,
            "metadata": {
            },
            "nickname": null,
            "product": "prod_JgPF5xnq7qBun3",
            "recurring": {
              "interval": "month",
              "interval_count": 1,
              "trial_period_days": null,
              "usage_type": "licensed"
            },
            "tiers_mode": null,
            "transform_quantity": null,
            "type": "recurring",
            "unit_amount": 2000,
            "unit_amount_decimal": "2000"
          },
          "quantity": 1,
          "taxes": []
        }
      ],
      "has_more": false,
      "total_count": 1,
      "url": "/v1/invoices/in_1J34pzGPZ1iASj5zB87qdBNZ/lines"
    },
    "livemode": false,
    "metadata": {
    },
    "next_payment_attempt": null,
    "number": "C008FC2-0354",
    "on_behalf_of": null,
    "parent": {
      "quote_details": null,
      "subscription_details": {
        "metadata": {},
        "pause_collection": null,
        "subscription": "sub_JgRjFjhKbtD2qz"
      }
    },
    "confirmation_secret": {
      "client_secret": "pi_1J34pzGPZ1iASj5zI2nOAaE6_secret_l7FN6ldFfXiFmJEumenJ2y2wu",
      "type": "payment_intent"
    },
    "payment_intent": {
      "id": "pi_1J34pzGPZ1iASj5zI2nOAaE6",
      "object": "payment_intent",
      "allowed_source_types": [
        "card"
      ],
      "amount": 2000,
      "amount_capturable": 0,
      "amount_received": 0,
      "application": null,
      "application_fee_amount": null,
      "canceled_at": null,
      "cancellation_reason": null,
      "capture_method": "automatic",
      "charges": {
        "object": "list",
        "data": [

        ],
        "has_more": false,
        "total_count": 0,
        "url": "/v1/charges?payment_intent=pi_1J34pzGPZ1iASj5zI2nOAaE6"
      },
      "client_secret": "pi_1J34pzGPZ1iASj5zI2nOAaE6_secret_l7FN6ldFfXiFmJEumenJ2y2wu",
      "confirmation_method": "automatic",
      "created": 1623873347,
      "currency": "usd",
      "customer": "cus_CMqDWO2xODTZqt",
      "description": "Subscription creation",
      "invoice": "in_1J34pzGPZ1iASj5zB87qdBNZ",
      "last_payment_error": null,
      "livemode": false,
      "metadata": {
      },
      "next_action": null,
      "next_source_action": null,
      "on_behalf_of": null,
      "payment_method": null,
      "payment_method_options": {
        "card": {
          "installments": null,
          "network": null,
          "request_three_d_secure": "automatic"
        }
      },
      "payment_method_types": [
        "card"
      ],
      "receipt_email": null,
      "review": null,
      "setup_future_usage": "off_session",
      "shipping": null,
      "source": "card_1By6iQGPZ1iASj5z7ijKBnXJ",
      "statement_descriptor": null,
      "statement_descriptor_suffix": null,
      "status": "requires_confirmation",
      "transfer_data": null,
      "transfer_group": null
    },
    "payment_settings": {
      "payment_method_options": null,
      "payment_method_types": null,
      "save_default_payment_method": "on_subscription"
    },
    "period_end": 1623873347,
    "period_start": 1623873347,
    "post_payment_credit_notes_amount": 0,
    "pre_payment_credit_notes_amount": 0,
    "receipt_number": null,
    "starting_balance": 0,
    "statement_descriptor": null,
    "status": "open",
    "status_transitions": {
      "finalized_at": 1623873347,
      "marked_uncollectible_at": null,
      "paid_at": null,
      "voided_at": null
    },
    "subscription": "sub_JgRjFjhKbtD2qz",
    "subtotal": 2000,
    "tax": null,
    "tax_percent": null,
    "total": 2000,
    "total_discount_amounts": [],
    "total_tax_amounts": [],
    "transfer_data": null,
    "webhooks_delivered_at": 1623873347
  },
  "livemode": false,
  "metadata": {
  },
  "next_pending_invoice_item_invoice": null,
  "pause_collection": null,
  "pending_invoice_item_interval": null,
  "pending_setup_intent": null,
  "pending_update": null,
  "plan": {
    "id": "price_1J32RfGPZ1iASj5zHHp57z7C",
    "object": "plan",
    "active": true,
    "amount": 2000,
    "amount_decimal": "2000",
    "billing_scheme": "per_unit",
    "created": 1623864151,
    "currency": "usd",
    "interval": "month",
    "interval_count": 1,
    "livemode": false,
    "metadata": {
    },
    "nickname": null,
    "product": "prod_JgPF5xnq7qBun3",
    "tiers": null,
    "tiers_mode": null,
    "transform_usage": null,
    "trial_period_days": null,
    "usage_type": "licensed"
  },
  "quantity": 1,
  "schedule": null,
  "start": 1623873347,
  "start_date": 1623873347,
  "status": "incomplete",
  "tax_percent": null,
  "transfer_data": null,
  "trial_end": null,
  "trial_start": null
}
```

#### Customers v1

```json
{
  "id": "sub_JgRjFjhKbtD2qz",
  "object": "subscription",
  "application_fee_percent": null,
  "automatic_tax": {
    "disabled_reason": null,
    "enabled": false,
    "liability": "null"
  },
  "billing_cycle_anchor": 1623873347,
  "billing_cycle_anchor_config": null,
  "cancel_at": null,
  "cancel_at_period_end": false,
  "canceled_at": null,
  "cancellation_details": {
    "comment": null,
    "feedback": null,
    "reason": null
  },
  "collection_method": "charge_automatically",
  "created": 1623873347,
  "currency": "usd",
  "customer": identifier("customer"),
  "days_until_due": null,
  "default_payment_method": null,
  "default_source": null,
  "default_tax_rates": [

  ],
  "discounts": [],
  "ended_at": null,
  "invoice_customer_balance_settings": {
    "account_tax_ids": null,
    "issuer": {
      "type": "self"
    }
  },
  "items": {
    "object": "list",
    "data": [
      {
        "id": "si_JgRjmS4Ur1khEx",
        "object": "subscription_item",
        "created": 1623873347,
        "current_period_end": 1626465347,
        "current_period_start": 1623873347,
        "discounts": [],
        "metadata": {
        },
        "plan": {
          "id": "price_1J32RfGPZ1iASj5zHHp57z7C",
          "object": "plan",
          "active": true,
          "amount": 2000,
          "amount_decimal": "2000",
          "billing_scheme": "per_unit",
          "created": 1623864151,
          "currency": "usd",
          "interval": "month",
          "interval_count": 1,
          "livemode": false,
          "metadata": {
          },
          "nickname": null,
          "product": "prod_JgPF5xnq7qBun3",
          "tiers": null,
          "tiers_mode": null,
          "transform_usage": null,
          "trial_period_days": null,
          "usage_type": "licensed"
        },
        "price": {
          "id": "price_1J32RfGPZ1iASj5zHHp57z7C",
          "object": "price",
          "active": true,
          "billing_scheme": "per_unit",
          "created": 1623864151,
          "currency": "usd",
          "livemode": false,
          "lookup_key": null,
          "metadata": {
          },
          "nickname": null,
          "product": "prod_JgPF5xnq7qBun3",
          "recurring": {
            "interval": "month",
            "interval_count": 1,
            "trial_period_days": null,
            "usage_type": "licensed"
          },
          "tiers_mode": null,
          "transform_quantity": null,
          "type": "recurring",
          "unit_amount": 2000,
          "unit_amount_decimal": "2000"
        },
        "quantity": 1,
        "subscription": "sub_JgRjFjhKbtD2qz",
        "tax_rates": [

        ]
      }
    ],
    "has_more": false,
    "total_count": 1,
    "url": "/v1/subscription_items?subscription=sub_JgRjFjhKbtD2qz"
  },
  "latest_invoice": {
    "id": "in_1J34pzGPZ1iASj5zB87qdBNZ",
    "object": "invoice",
    "account_country": "US",
    "account_name": "Angelina's Store",
    "account_tax_ids": null,
    "amount_due": 2000,
    "amount_overpaid": 0,
    "amount_paid": 0,
    "amount_remaining": 2000,
    "amount_shipping": 0,
    "attempt_count": 0,
    "attempted": false,
    "auto_advance": false,
    "automatic_tax": {
      "disabled_reason": null,
      "enabled": false,
      "liability": null,
      "status": null
    },
    "automatically_finalizes_at": null,
    "billing_reason": "subscription_update",
    "collection_method": "charge_automatically",
    "created": 1623873347,
    "currency": "usd",
    "custom_fields": null,
    "customer": identifier("customer"),
    "customer_address": null,
    "customer_email": "angelina@stripe.com",
    "customer_name": null,
    "customer_phone": null,
    "customer_shipping": {
      "address": {
        "city": "",
        "country": "US",
        "line1": "Berry",
        "line2": "",
        "postal_code": "",
        "state": ""
      },
      "name": "",
      "phone": null
    },
    "customer_tax_exempt": "none",
    "customer_tax_ids": [

    ],
    "default_payment_method": null,
    "default_source": null,
    "default_tax_rates": [

    ],
    "description": null,
    "discounts": [],
    "due_date": null,
    "effective_at": "1623873347",
    "ending_balance": 0,
    "footer": null,
    "from_invoice": null,
    "hosted_invoice_url": "https://invoice.stripe.com/i/acct_1By64KGPZ1iASj5z/invst_JgRjzIOILGeq2MKC9T0KtyXnD5udsLp",
    "invoice_pdf": "https://pay.stripe.com/invoice/acct_1By64KGPZ1iASj5z/invst_JgRjzIOILGeq2MKC9T0KtyXnD5udsLp/pdf",
    "last_finalization_error": null,
    "latest_revision": null,
    "lines": {
      "object": "list",
      "data": [
        {
          "id": "il_1N2CjMBwKQ696a5NeOawRQP2",
          "object": "line_item",
          "amount": 2000,
          "currency": "usd",
          "description": "1 × Gold Special (at $20.00 / month)",
          "discount_amounts": [

          ],
          "discountable": true,
          "discounts": [

          ],
          "invoice": "in_1J34pzGPZ1iASj5zB87qdBNZ",
          "livemode": false,
          "metadata": {
          },
          "parent": {
            "invoice_item_details": null,
            "subscription_item_details":
            {
              "invoice_item": null,
              "proration": false,
              "proration_details":
              {
                "credited_items": null
              },
              "subscription":
              "sub_JgRjFjhKbtD2qz",
              "subscription_item":
                "si_JgRjmS4Ur1khEx"
            },
            "type": "subscription_item_details"
          },
          "period": {
            "end": 1626465347,
            "start": 1623873347
          },
          "plan": {
            "id": "price_1J32RfGPZ1iASj5zHHp57z7C",
            "object": "plan",
            "active": true,
            "amount": 2000,
            "amount_decimal": "2000",
            "billing_scheme": "per_unit",
            "created": 1623864151,
            "currency": "usd",
            "interval": "month",
            "interval_count": 1,
            "livemode": false,
            "metadata": {
            },
            "nickname": null,
            "product": "prod_JgPF5xnq7qBun3",
            "tiers": null,
            "tiers_mode": null,
            "transform_usage": null,
            "trial_period_days": null,
            "usage_type": "licensed"
          },
          "price": {
            "id": "price_1J32RfGPZ1iASj5zHHp57z7C",
            "object": "price",
            "active": true,
            "billing_scheme": "per_unit",
            "created": 1623864151,
            "currency": "usd",
            "livemode": false,
            "lookup_key": null,
            "metadata": {
            },
            "nickname": null,
            "product": "prod_JgPF5xnq7qBun3",
            "recurring": {
              "interval": "month",
              "interval_count": 1,
              "trial_period_days": null,
              "usage_type": "licensed"
            },
            "tiers_mode": null,
            "transform_quantity": null,
            "type": "recurring",
            "unit_amount": 2000,
            "unit_amount_decimal": "2000"
          },
          "quantity": 1,
          "taxes": []
        }
      ],
      "has_more": false,
      "total_count": 1,
      "url": "/v1/invoices/in_1J34pzGPZ1iASj5zB87qdBNZ/lines"
    },
    "livemode": false,
    "metadata": {
    },
    "next_payment_attempt": null,
    "number": "C008FC2-0354",
    "on_behalf_of": null,
    "parent": {
      "quote_details": null,
      "subscription_details": {
        "metadata": {},
        "pause_collection": null,
        "subscription": "sub_JgRjFjhKbtD2qz"
      }
    },
    "confirmation_secret": {
      "client_secret": "pi_1J34pzGPZ1iASj5zI2nOAaE6_secret_l7FN6ldFfXiFmJEumenJ2y2wu",
      "type": "payment_intent"
    },
    "payment_intent": {
      "id": "pi_1J34pzGPZ1iASj5zI2nOAaE6",
      "object": "payment_intent",
      "allowed_source_types": [
        "card"
      ],
      "amount": 2000,
      "amount_capturable": 0,
      "amount_received": 0,
      "application": null,
      "application_fee_amount": null,
      "canceled_at": null,
      "cancellation_reason": null,
      "capture_method": "automatic",
      "charges": {
        "object": "list",
        "data": [

        ],
        "has_more": false,
        "total_count": 0,
        "url": "/v1/charges?payment_intent=pi_1J34pzGPZ1iASj5zI2nOAaE6"
      },
      "client_secret": "pi_1J34pzGPZ1iASj5zI2nOAaE6_secret_l7FN6ldFfXiFmJEumenJ2y2wu",
      "confirmation_method": "automatic",
      "created": 1623873347,
      "currency": "usd",
      "customer": "cus_CMqDWO2xODTZqt",
      "description": "Subscription creation",
      "invoice": "in_1J34pzGPZ1iASj5zB87qdBNZ",
      "last_payment_error": null,
      "livemode": false,
      "metadata": {
      },
      "next_action": null,
      "next_source_action": null,
      "on_behalf_of": null,
      "payment_method": null,
      "payment_method_options": {
        "card": {
          "installments": null,
          "network": null,
          "request_three_d_secure": "automatic"
        }
      },
      "payment_method_types": [
        "card"
      ],
      "receipt_email": null,
      "review": null,
      "setup_future_usage": "off_session",
      "shipping": null,
      "source": "card_1By6iQGPZ1iASj5z7ijKBnXJ",
      "statement_descriptor": null,
      "statement_descriptor_suffix": null,
      "status": "requires_confirmation",
      "transfer_data": null,
      "transfer_group": null
    },
    "payment_settings": {
      "payment_method_options": null,
      "payment_method_types": null,
      "save_default_payment_method": "on_subscription"
    },
    "period_end": 1623873347,
    "period_start": 1623873347,
    "post_payment_credit_notes_amount": 0,
    "pre_payment_credit_notes_amount": 0,
    "receipt_number": null,
    "starting_balance": 0,
    "statement_descriptor": null,
    "status": "open",
    "status_transitions": {
      "finalized_at": 1623873347,
      "marked_uncollectible_at": null,
      "paid_at": null,
      "voided_at": null
    },
    "subscription": "sub_JgRjFjhKbtD2qz",
    "subtotal": 2000,
    "tax": null,
    "tax_percent": null,
    "total": 2000,
    "total_discount_amounts": [],
    "total_tax_amounts": [],
    "transfer_data": null,
    "webhooks_delivered_at": 1623873347
  },
  "livemode": false,
  "metadata": {
  },
  "next_pending_invoice_item_invoice": null,
  "pause_collection": null,
  "pending_invoice_item_interval": null,
  "pending_setup_intent": null,
  "pending_update": null,
  "plan": {
    "id": "price_1J32RfGPZ1iASj5zHHp57z7C",
    "object": "plan",
    "active": true,
    "amount": 2000,
    "amount_decimal": "2000",
    "billing_scheme": "per_unit",
    "created": 1623864151,
    "currency": "usd",
    "interval": "month",
    "interval_count": 1,
    "livemode": false,
    "metadata": {
    },
    "nickname": null,
    "product": "prod_JgPF5xnq7qBun3",
    "tiers": null,
    "tiers_mode": null,
    "transform_usage": null,
    "trial_period_days": null,
    "usage_type": "licensed"
  },
  "quantity": 1,
  "schedule": null,
  "start": 1623873347,
  "start_date": 1623873347,
  "status": "incomplete",
  "tax_percent": null,
  "transfer_data": null,
  "trial_end": null,
  "trial_start": null
}
```

### Update your server endpoint

Add ephemeral key creation to the subscription endpoint and return it in the response:

#### Accounts v2

#### Ruby

```ruby
ephemeral_key = Stripe::EphemeralKey.create(
  {customer_account: customer_account_id},
  {stripe_version: '2026-03-25.dahlia'}
)

{
  subscriptionId: subscription.id,
  clientSecret: subscription.latest_invoice.confirmation_secret.client_secret,
  ephemeralKey: ephemeral_key.secret,
  customerAccountId: customer_account_id,
}.to_json
```

#### Customers v1

#### Ruby

```ruby
ephemeral_key = client.v1.ephemeral_keys.create(
  {customer: customer_id},
  {stripe_version: '2025-06-30.basil'}
)

{
  subscriptionId: subscription.id,
  clientSecret: subscription.latest_invoice.confirmation_secret.client_secret,
  ephemeralKey: ephemeral_key.secret,
  customerId: customer_id,
}.to_json
```

### Update your response model

#### Accounts v2

```kotlin
data class SubscriptionsResponse(
    val subscriptionId: String,
    val clientSecret: String,
    val ephemeralKey: String,
    val customerAccountId: String
)
```

#### Customers v1

```kotlin
data class SubscriptionsResponse(
    val subscriptionId: String,
    val clientSecret: String,
    val ephemeralKey: String,
    val customerId: String
)
```

### Pass the customer configuration to PaymentSheet

#### Accounts v2

Add the following when configuring PaymentSheet:

```kotlin
PaymentSheet.Configuration(
    primaryButtonLabel = "Subscribe for $15/month",
    merchantDisplayName = "My merchant name",
    customerAccount = PaymentSheet.CustomerConfiguration(
        id = customerAccountId,
        ephemeralKeySecret = ephemeralKey
    )
)
```

#### Customers v1

Add the following when configuring PaymentSheet:

```kotlin
PaymentSheet.Configuration(
    primaryButtonLabel = "Subscribe for $15/month",
    merchantDisplayName = "My merchant name",
    customer = PaymentSheet.CustomerConfiguration(
        id = customerId,
        ephemeralKeySecret = ephemeralKey
    )
)
```

## Collect payment information [Client]

Use the [Payment Sheet](https://docs.stripe.com/payments/mobile/payment-sheet.md) to collect payment details and activate the subscription. You can customize Elements to match the look and feel of your application.

The Payment Sheet securely collects all necessary payment details for a wide variety of payments methods. Learn about the [supported payment methods](https://docs.stripe.com/payments/payment-methods/payment-method-support.md#product-support) for Payment Sheet and Subscriptions.

### Add the Payment Element to your app

> This step shows one way to get started, but you can use any [in-app payments integration](https://docs.stripe.com/payments/mobile.md).

Initialize and present the Mobile Payment Element using the PaymentSheet class.

```kotlin
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import com.stripe.android.paymentsheet.PaymentSheet
import com.stripe.android.paymentsheet.PaymentSheetResult
import com.stripe.android.paymentsheet.rememberPaymentSheet

@Composable
fun SubscribeView(clientSecret: String) {
    val paymentSheet = rememberPaymentSheet(::onPaymentSheetResult)

    Button(onClick = {
        paymentSheet.presentWithPaymentIntent(
            clientSecret, PaymentSheet.Configuration(
                primaryButtonLabel = "Subscribe for $15/month",
                merchantDisplayName = "My merchant name",
                // Set `allowsDelayedPaymentMethods` to true if your business handles
                // delayed notification payment methods like US bank accounts.
                allowsDelayedPaymentMethods = true
            )
        )
    }) {
        Text(text = "Subscribe")
    }
}

fun onPaymentSheetResult(paymentSheetResult: PaymentSheetResult) {
    when (paymentSheetResult) {
        is PaymentSheetResult.Canceled -> {
            print("Canceled")
        }

        is PaymentSheetResult.Failed -> {
            print("Error: ${paymentSheetResult.error}")
        }

        is PaymentSheetResult.Completed -> {
            // Display for example, an order confirmation screen
            print("Completed")
        }
    }
}
```

The Mobile Payment Element renders a sheet that allows your customer to select a payment method. The form automatically collects all necessary payments details for the payment method that they select.

Setting `allowsDelayedPaymentMethods` to true allows [delayed notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment methods like US bank accounts. For these payment methods, the final payment status isn’t known when the `PaymentSheet` completes, and instead succeeds or fails later. If you support these types of payment methods, inform the customer their order is confirmed and only fulfill their order (for example, ship their product) when the payment is successful.

You can customize the Payment Element to match the design of your app by using the [`appearance` property](https://docs.stripe.com/elements/appearance-api/mobile.md?platform=ios) your `PaymentSheet.Configuration` object.

### Confirm payment 

The Mobile Payment Element creates a PaymentMethod and confirms the incomplete Subscription’s first PaymentIntent, causing a charge to be made. If *Strong Customer Authentication* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase) (SCA) is required for the payment, the Payment Element handles the authentication process before confirming the PaymentIntent.

## Listen for webhooks [Server]

To complete the integration, you need to process *webhooks* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) sent by Stripe. These are events triggered whenever state inside of Stripe changes, such as subscriptions creating new invoices. In your application, set up an HTTP handler to accept a POST request containing the webhook event, and verify the signature of the event:

#### Ruby

```ruby

# Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
# Find your keys at https://dashboard.stripe.com/apikeys.
client = Stripe::StripeClient.new('<<YOUR_SECRET_KEY>>')

post '/webhook' do
  # You can use webhooks to receive information about asynchronous payment events.
  # For more about our webhook events check out https://stripe.com/docs/webhooks.
  webhook_secret = ENV['STRIPE_WEBHOOK_SECRET']
  payload = request.body.read
  if !webhook_secret.empty?
    # Retrieve the event by verifying the signature using the raw body and secret if webhook signing is configured.
    sig_header = request.env['HTTP_STRIPE_SIGNATURE']
    event = nil

    begin
      event = Stripe::Webhook.construct_event(
        payload, sig_header, webhook_secret
      )
    rescue JSON::ParserError => e
      # Invalid payload
      status 400
      return
    rescue Stripe::SignatureVerificationError => e
      # Invalid signature
      puts '⚠️  Webhook signature verification failed.'
      status 400
      return
    end
  else
    data = JSON.parse(payload, symbolize_names: true)
    event = Stripe::Event.construct_from(data)
  end
  # Get the type of webhook event sent - used to check the status of PaymentIntents.
  event_type = event['type']
  data = event['data']
  data_object = data['object']

  if event_type == 'invoice.paid'
    # Used to provision services after the trial has ended.
    # The status of the invoice will show up as paid. Store the status in your
    # database to reference when a user accesses your service to avoid hitting rate
    # limits.
    # puts data_object
  end

  if event_type == 'invoice.payment_failed'
    # If the payment fails or the customer does not have a valid payment method,
    # an invoice.payment_failed event is sent, the subscription becomes past_due.
    # Use this webhook to notify your user that their payment has
    # failed and to retrieve new card details.
    # puts data_object
  end

  if event_type == 'customer.subscription.deleted'
    # handle subscription canceled automatically based
    # upon your subscription settings. Or if the user cancels it.
    # puts data_object
  end

  content_type 'application/json'
  { status: 'success' }.to_json
end
```

During development, use the Stripe CLI to [observe webhooks and forward them to your application](https://docs.stripe.com/webhooks.md#test-webhook). Run the following in a new terminal while your development app is running:

#### curl

```bash
  stripe listen --forward-to localhost:4242/webhook
```

For production, set up a webhook endpoint URL in the Dashboard, or use the [Webhook Endpoints API](https://docs.stripe.com/api/webhook_endpoints.md).

You need to listen to a few events to complete the remaining steps in this guide. See [Subscription events](https://docs.stripe.com/billing/subscriptions/webhooks.md#events) for more details about subscription-specific webhooks.

## Provision access to your service [Client and Server]

Now that the subscription is active, give your user access to your service. To do this, listen to the `customer.subscription.created`, `customer.subscription.updated`, and `customer.subscription.deleted` events. These events pass a subscription object which contains a `status` field indicating whether the subscription is active, past due, or canceled. See [the subscription lifecycle](https://docs.stripe.com/billing/subscriptions/overview.md#subscription-lifecycle) for a complete list of statuses.

In your webhook handler:

1. Verify the subscription status. If it’s `active` then your user has paid for your product.
2. Check the product the customer subscribed to and grant access to your service. Checking the product instead of the price gives you more flexibility if you need to change the pricing or billing interval.
3. Store the `product.id`, `subscription.id` and `subscription.status` in your database along with the `customer.id` you already saved. Check this record when determining which features to enable for the user in your application.

The state of a subscription might change at any point during its lifetime, even if your application doesn’t directly make any calls to Stripe. For example, a renewal might fail due to an expired credit card, which puts the subscription into a past due state. Or, if you implement the [customer portal](https://docs.stripe.com/customer-management.md), a user might cancel their subscription without directly visiting your application. Implementing your handler correctly keeps your application state in sync with Stripe.

## Cancel the subscription [Client and Server]

It’s common to allow customers to cancel their subscriptions. This example adds a cancellation option to the account settings page.

The example collects the subscription ID on the frontend, but your application can get this information from your database for your logged in user.
![Sample subscription cancelation interface.](https://b.stripecdn.com/docs-statics-srv/assets/fixed-price-subscriptions-guide-account-settings.6559626ba4b434826a67abfea165e097.png)

Account settings with the ability to cancel the subscription

```kotlin
fun cancelSubscription(subscriptionId: String): SubscriptionResponse? {
    val body = JSONObject().put("subscriptionId", subscriptionId).toString()
        .toRequestBody("application/json".toMediaType())
    val request =
        Request.Builder().url("http://10.0.2.2:4567/cancel-subscription").post(body).build()
    OkHttpClient().newCall(request).execute().use { response ->
        if (response.isSuccessful) {
            return Gson().fromJson(response.body!!.string(), SubscriptionResponse::class.java)
        }
    }
    return null
}
```

On the backend, define the endpoint for your app to call.

#### Ruby

```ruby

# Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
# Find your keys at https://dashboard.stripe.com/apikeys.
client = Stripe::StripeClient.new('<<YOUR_SECRET_KEY>>')

post '/cancel-subscription' do
  content_type 'application/json'
  data = JSON.parse request.body.read

  deleted_subscription = client.v1.subscriptions.cancel(data['subscriptionId'])

  deleted_subscription.to_json
end
```

Your backend receives a `customer.subscription.deleted` event.

After the subscription is canceled, update your database to remove the Stripe subscription ID you previously stored, and limit access to your service.

When a subscription is canceled, it can’t be reactivated. Instead, collect updated billing information from your customer, update their default payment method, and create a new subscription with their existing customer record.

## Test your integration

### Test payment methods

Use the following table to test different payment methods and scenarios.

| Payment method    | Scenario                                                                                                                                                                                                                                                                                      | How to test                                                                                                                                                                                                 |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| BECS Direct Debit | Your customer successfully pays with BECS Direct Debit.                                                                                                                                                                                                                                       | Fill out the form using the account number `900123456` and BSB `000000`. The confirmed PaymentIntent initially transitions to `processing`, then transitions to the `succeeded` status three minutes later. |
| BECS Direct Debit | Your customer’s payment fails with an `account_closed` error code.                                                                                                                                                                                                                            | Fill out the form using the account number `111111113` and BSB `000000`.                                                                                                                                    |
| Credit card       | The card payment succeeds and doesn’t require authentication.                                                                                                                                                                                                                                 | Fill out the credit card form using the credit card number `4242 4242 4242 4242` with any expiration, CVC, and postal code.                                                                                 |
| Credit card       | The card payment requires *authentication* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase). | Fill out the credit card form using the credit card number `4000 0025 0000 3155` with any expiration, CVC, and postal code.                                                                                 |
| Credit card       | The card is declined with a decline code like `insufficient_funds`.                                                                                                                                                                                                                           | Fill out the credit card form using the credit card number `4000 0000 0000 9995` with any expiration, CVC, and postal code.                                                                                 |
| SEPA Direct Debit | Your customer successfully pays with SEPA Direct Debit.                                                                                                                                                                                                                                       | Fill out the form using the account number `AT321904300235473204`. The confirmed PaymentIntent initially transitions to processing, then transitions to the succeeded status three minutes later.           |
| SEPA Direct Debit | Your customer’s PaymentIntent status transitions from `processing` to `requires_payment_method`.                                                                                                                                                                                              | Fill out the form using the account number `AT861904300235473202`.                                                                                                                                          |

### Monitor events

Set up webhooks to listen to subscription change events, such as upgrades and cancellations. Learn more about [subscription webhooks](https://docs.stripe.com/billing/subscriptions/webhooks.md). You can view events in the [Dashboard](https://dashboard.stripe.com/test/events) or with the [Stripe CLI](https://docs.stripe.com/webhooks.md#test-webhook).

For more details, see [testing your Billing integration](https://docs.stripe.com/billing/testing.md).

## Optional: Let customers change their plans [Client and Server]

To let your customers change their subscription, collect the price ID of the option they want to change to. Then send the new price ID from the app to a backend endpoint. This example also passes the subscription ID, but you can retrieve it from your database for your logged in user.

```kotlin
fun updateSubscription(subscriptionId: String, priceId: String): SubscriptionResponse? {
    val body = JSONObject()
        .put("priceId", priceId)
        .put("subscriptionId", subscriptionId).toString()
        .toRequestBody("application/json".toMediaType())
    val request =
        Request.Builder().url("http://10.0.2.2:4567/update-subscription").post(body).build()
    OkHttpClient().newCall(request).execute().use { response ->
        if (response.isSuccessful) {
            // It should include the client_secret, as discussed below.
            return Gson().fromJson(response.body!!.string(), SubscriptionResponse::class.java)
        }
    }
    return null
}
```

On the backend, define the endpoint for your frontend to call, passing the subscription ID and the new price ID. The subscription is now Premium, at 15 USD per month, instead of Basic at 5 USD per month.

#### Ruby

```ruby

# Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
# Find your keys at https://dashboard.stripe.com/apikeys.
client = Stripe::StripeClient.new('<<YOUR_SECRET_KEY>>')

post '/update-subscription' do
  content_type 'application/json'
  data = JSON.parse request.body.read

  subscription = client.v1.subscriptions.retrieve(data['subscriptionId'])

  updated_subscription =
    client.v1.subscriptions.update(
      data['subscriptionId'],
      cancel_at_period_end: false,
      items: [
        { id: subscription.items.data[0].id, price: data['newPriceId'] }
      ]
    )

  updated_subscription.to_json
end
```

Your application receives a `customer.subscription.updated` event.

## Optional: Preview a price change [Client and Server]

When your customer changes their subscription, there’s often an adjustment to the amount they owe, known as a [proration](https://docs.stripe.com/billing/subscriptions/prorations.md). You can use the [create preview invoice endpoint](https://docs.stripe.com/api/invoices/create_preview.md) to display the adjusted amount to your customers.

From the app, pass the preview invoice details to a backend endpoint.

```kotlin
fun createPreviewInvoice(
    subscriptionId: String,
    priceId: String,
    newPriceId: String
): InvoiceResponse? {
    val body = JSONObject()
        .put("priceId", priceId)
        .put("subscriptionId", subscriptionId)
        .put("newPriceId", newPriceId).toString()
        .toRequestBody("application/json".toMediaType())
    val request =
        Request.Builder().url("http://10.0.2.2:4567/create-preview-invoice").post(body).build()
    OkHttpClient().newCall(request).execute().use { response ->
        if (response.isSuccessful) {
            // InvoiceResponse is a data class conforming to the expected response from your backend
            return Gson().fromJson(response.body!!.string(), InvoiceResponse::class.java)
        }
    }
    return null
}
```

On the backend, define the endpoint for your frontend to call.

#### Accounts v2

#### Ruby

```ruby

# Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
# Find your keys at https://dashboard.stripe.com/apikeys.
client = Stripe::StripeClient.new('<<YOUR_SECRET_KEY>>')

post '/create-preview-invoice' do
  content_type 'application/json'
  data = JSON.parse request.body.read

  subscription = Stripe::Subscription.retrieve(data['subscriptionId'])

  invoice =
    Stripe::Invoice.create_preview(
      customer_account: data['customerAccountId'],
      subscription: data['subscriptionId'],
      subscription_details: {
        items: [
          { id: subscription.items.data[0].id, deleted: true },
          { price: data['newPriceId'], deleted: false }
        ]
      }
    )

  invoice.to_json
end
```

#### Customers v1

#### Ruby

```ruby

# Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
# Find your keys at https://dashboard.stripe.com/apikeys.
client = Stripe::StripeClient.new('<<YOUR_SECRET_KEY>>')

post '/create-preview-invoice' do
  content_type 'application/json'
  data = JSON.parse request.body.read

  subscription = client.v1.subscriptions.retrieve(data['subscriptionId'])

  invoice =
    client.v1.invoices.create_preview(
      customer: data['customerId'],
      subscription: data['subscriptionId'],
      subscription_details: {
        items: [
          { id: subscription.items.data[0].id, deleted: true },
          { price: data['newPriceId'], deleted: false }
        ]
      }
    )

  invoice.to_json
end
```

## Optional: Display the customer payment method [Client and Server]

Displaying the brand and last four digits of your customer’s card can help them know which card is being charged, or if they need to update their payment method.

On the front end, send the payment method ID to a back-end endpoint that retrieves the payment method details.

```kotlin
fun retrieveCustomerPaymentMethod(paymentMethodId: String): PaymentMethodResponse? {
    val body = JSONObject()
        .put("paymentMethodId", paymentMethodId).toString()
        .toRequestBody("application/json".toMediaType())
    val request =
        Request.Builder().url("http://10.0.2.2:4567/retrieve-customer-payment-method").post(body)
            .build()
    OkHttpClient().newCall(request).execute().use { response ->
        if (response.isSuccessful) {
            // PaymentMethodResponse is a data class conforming to the expected response from your backend
            return Gson().fromJson(response.body!!.string(), PaymentMethodResponse::class.java)
        }
    }
    return null
}
```

On the back end, define the endpoint for your app to call.

#### Ruby

```ruby

# Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
# Find your keys at https://dashboard.stripe.com/apikeys.
client = Stripe::StripeClient.new('<<YOUR_SECRET_KEY>>')

post '/retrieve-customer-payment-method' do
  content_type 'application/json'
  data = JSON.parse request.body.read

  payment_method = client.v1.payment_methods.retrieve(data['paymentMethodId'])

  payment_method.to_json
end
```

Example response:

```json
{
  "id": "pm_1GcbHY2eZvKYlo2CoqlVxo42",
  "object": "payment_method",
  "billing_details": {
    "address": {
      "city": null,
      "country": null,
      "line1": null,
      "line2": null,
      "postal_code": null,
      "state": null
    },
    "email": null,
    "name": null,
    "phone": null
  },
  "card": {
    "brand": "visa",
    "checks": {
      "address_line1_check": null,
      "address_postal_code_check": null,
      "cvc_check": "pass"
    },
    "country": "US",
    "exp_month": 8,
    "exp_year": 2021,
    "fingerprint": "Xt5EWLLDS7FJjR1c",
    "funding": "credit",
    "generated_from": null,
    "last4": "4242",
    "three_d_secure_usage": {
      "supported": true
    },
    "wallet": null
  },
  "created": 1588010536,
  "customer": "cus_HAxB7dVQxhoKLh",
  "livemode": false,
  "metadata": {},
  "type": "card"
}
```

> We recommend that you save the `paymentMethod.id` and `last4` in your database, for example, `paymentMethod.id` as `stripeCustomerPaymentMethodId` in your `users` collection or table. You can optionally store `exp_month`, `exp_year`, `fingerprint`, `billing_details` as needed. This is to limit the number of calls you make to Stripe—for both performance efficiency and to avoid possible rate limiting.

## Disclose Stripe to your customers 

Stripe collects information on customer interactions with Elements to provide services to you, prevent fraud, and improve its services. This includes using cookies and IP addresses to identify which Elements a customer saw during a single checkout session. You’re responsible for disclosing and obtaining all rights and consents necessary for Stripe to use data in these ways. For more information, visit our [privacy center](https://stripe.com/legal/privacy-center#as-a-business-user-what-notice-do-i-provide-to-my-end-customers-about-stripe).

