PHPackages                             craftcms/stripe - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Payment Processing](/categories/payments)
4. /
5. craftcms/stripe

ActiveCraft-plugin[Payment Processing](/categories/payments)

craftcms/stripe
===============

Stripe Integration for Craft CMS

1.7.1(4mo ago)62.2k3[3 issues](https://github.com/craftcms/stripe/issues)[2 PRs](https://github.com/craftcms/stripe/pulls)MITPHPPHP ^8.2CI passing

Since Apr 30Pushed 2mo ago5 watchersCompare

[ Source](https://github.com/craftcms/stripe)[ Packagist](https://packagist.org/packages/craftcms/stripe)[ Docs](https://github.com/craftcms/stripe)[ RSS](/packages/craftcms-stripe/feed)WikiDiscussions 1.x Synced 1mo ago

READMEChangelog (10)Dependencies (8)Versions (19)Used By (0)

Stripe for Craft CMS
====================

[](#stripe-for-craft-cms)

Connect your Craft content to [Stripe](https://stripe.com)’s powerful billing tools, and build a streamlined storefront.

Requirements
------------

[](#requirements)

This plugin requires Craft CMS 5.6.0 or later, and a Stripe account with access to developer features.

Tip

Transitioning from Craft Commerce? Check out the dedicated [migration](#migrating-from-commerce) section.

Installation
------------

[](#installation)

You can install this plugin via the in-app [Plugin Store](#plugin-store) or with [the command line](#composer).

### Plugin Store

[](#plugin-store)

Visit the **Plugin Store** screen of your installation’s control panel, then search for **Stripe**.

Click the **Install** button, then check out the [configuration](#configuration) instructions!

### Composer

[](#composer)

These instructions assume you are using DDEV, but you can run similar commands in other environments. Open up a terminal and run…

```
# Navigate to the project directory:
cd /path/to/my-project

# Require the plugin with Composer:
ddev composer require craftcms/stripe

# Install the plugin with Craft:
ddev craft plugin/install stripe
```

Configuration
-------------

[](#configuration)

The Stripe plugin builds its configuration from three sources:

- [Project config](https://craftcms.com/docs/5.x/system/project-config.html) — Managed via the **Stripe** → **Settings** screen in Craft’s control panel.
- **A plugin config file** — Add a `config/stripe.php` file to your project and return a map of options keyed with properties from the `craft\stripe\models\Settings` class.
- **Environment variables** — Some options can be set directly as environment variables.

### API Keys

[](#api-keys)

Stripe uses a pair of “publishable” and “secret” keys to communicate with their API. In your Stripe account, switch into **Test mode**, then visit the **Developer** section and grab your development keys.

Note

Read more about [Stripe API Keys](https://docs.stripe.com/keys).

Add these keys to your project’s `.env` file:

```
STRIPE_PUBLISHABLE_KEY="pk_test_************************"
STRIPE_SECRET_KEY="sk_test_************************"
```

Then, in the control panel, visit **Stripe** → **Settings**, and enter the variable names you chose, in the respective fields. Craft will provide suggestions based on what it discovers in the environment.

### Webhooks

[](#webhooks)

[Webhooks](https://docs.stripe.com/webhooks) are essential for the plugin to work correctly—they allow changes to product data and off-platform customer activity to be rapidly synchronized into your site.

Tip

Be sure and perform an initial [synchronization](#synchronization) to import existing Stripe data.

To test webhooks in your local development environment, we recommend using the [Stripe CLI](https://docs.stripe.com/stripe-cli) to create a tunnel and forward events. Follow the installation instructions for your platform, then run:

```
stripe listen --forward-to https://my-craft-project.ddev.site/stripe/webhooks/handle
```

Note

The hostname you provide here should agree with how you access the project, locally—Stripe does not need to be able to resolve it on the public internet for testing webhooks to be delivered!

The CLI will let you know when it’s ready, and output a webhook signing secret starting with `whsec_`. Add this value to your `.env` file, and return to the **Stripe** → **Settings** in the control panel

### Synchronization

[](#synchronization)

Webhooks keep product and customer data synchronized between Stripe and Craft, but they will only report *changes*.

You have two options for doing an initial import of Stripe data:

- Small product catalogs can usually get away with using the control panel utility: visit **Utilities** → **Stripe Sync All** and click **Sync all data**.
- Large catalogs should perform synchronizations via the command line: Run `ddev craft stripe/sync/all` if you’re just getting started, or use one of the finer-grained [CLI tools](#cli) to import specific types of records.

### Content + Fields

[](#content--fields)

Stripe [products](https://docs.stripe.com/products-prices/overview), [prices](https://docs.stripe.com/products-prices/how-products-and-prices-work#what-is-a-price), and [subscriptions](https://docs.stripe.com/subscriptions) are all stored as *elements* in Craft. This means that they have access to the full suite of content modeling tools you would expect!

Field layouts for each element type are managed in the plugin’s **Settings** screen.

### Product URLs

[](#product-urls)

In addition to a field layout, product elements support **URI Format** and **Template** settings, which work just like they do on other element types: when a product’s URL is requested, Craft loads the element and passes it to the specified template under a `product` variable.

Note

Prices and subscriptions do *not* have their own URLs. You can use query parameters or [custom routes](https://craftcms.com/docs/5.x/system/routing.html) to load those elements in response to specific URI patterns.

Migrating from [Craft Commerce](https://craftcms.com/commerce)
--------------------------------------------------------------

[](#migrating-from-craft-commerce)

Users of our full-featured ecommerce system, *Craft Commerce* can migrate existing subscriptions to the standalone Stripe plugin without losing any customer data.

Once you have fully upgraded to Craft 5.1 and Craft Commerce 5.0, follow the normal [installation](#installation) and [configuration](#configuration) instructions, above. Then, run this pair of console commands:

```
# Pre-populate plugin tables with existing Stripe data:
ddev craft stripe/commerce/migrate

# Perform a synchronization to bring in additional records:
ddev craft stripe/sync/all
```

### API Changes

[](#api-changes)

You will interact with subscriptions differently than in Craft Commerce, as they have shifted to more closely resemble Stripe’s billing architecture than the legacy single-item “plans”:

- Plans are not configured in Craft. Instead, products (or more accurately, *prices*) can be set up in Stripe as *recurring*. You will see this reflected as a combination of price and interval (i.e. $5.00/day) in **Prices** tables on an individual product element, in the control panel.
- Some gateway-agnostic element query methods were not translated into the Stripe plugin:
    - `dateExpired()`: Not tracked as a native property. You can access the timestamp when a subscription ended with `subscription.data.ended_at`.
    - `isExpired()`: Similar to the above, non-expired subscriptions will have a `null` `subscription.data.ended_at` value.
    - `trialDays()`: Use `subscription.data.trial_start` and `trial_end`, or access the subscription’s underlying `items` array for info about each recurring item’s price and configuration.
    - `status()`: Statuses may not behave in a way that is consistent with Craft Commerce’s definition.

---

Storefront
----------

[](#storefront)

Once you have populated your Craft project with data from Stripe (via [synchronization](#synchronization) and/or [webhooks](#webhooks)), you can begin scaffolding your content and storefront.

Tip

The [reference section](#reference) has information about each type of object you’re apt to encounter in the system.

### Listing Products

[](#listing-products)

Individual products automatically get URLs based on their [URI format](#product-urls), but it is up to you how they are gathered and displayed.

To get a list of products, use the `craft.stripeProducts` [element query](https://craftcms.com/docs/5.x/development/element-queries.html) factory:

```
{% set products = craft.stripeProducts.all() %}

  {% for product in products %}
    {% set image = product.featureImage.eagerly().one() %}

        {{ image.getImg() }}

      {{ product.getLink() }}

  {% endfor %}

```

### The Product Template

[](#the-product-template)

On an individual product’s page, Craft provides the current product under a `product` variable:

```
{{ product.title }}
```

Any [custom fields](#content--fields) you’ve configured for products will be available as properties, just as they are for other element types:

```
{{ product.customDescriptionField|md }}
```

### Prices

[](#prices)

Like Craft Commerce, Stripe uses “products” as a means of logically grouping goods and services—the things your customers actually buy are called “prices.”

The Stripe plugin handles this relationship using [nested elements](https://craftcms.com/docs/5.x/system/elements.html). Each product element will own one or more price elements, and expose them via a `prices` property or `getPrices()` method:

```
{{ product.title }}

  {% for price in product.prices %}

      {{ price.data|unitAmount }}
      {{ tag('a', {
        text: "Buy now",
        href: price.getCheckoutUrl(
          currentUser ?? false,
          'shop/thank-you?session={CHECKOUT_SESSION_ID}',
          product.url,
          {}
        ),
      }) }}

  {% endfor %}

```

### Checkout Links

[](#checkout-links)

When a customer is ready to buy a product or start a subscription, you’ll provide a *checkout link*. Checkout links are special, secure, parameterized URLs that exist as part of a [checkout session](https://docs.stripe.com/payments/checkout) for a pre-configured list of items. Stripe has no “cart,” per se; instead, products are purchased piecemeal.

Clicking a checkout link takes the customer to Stripe’s hosted checkout page, where they can complete a payment using whatever methods are available and enabled in your account.

To output a checkout link, use the `stripeCheckoutUrl()` function:

```
{% set price = product.prices.one() %}

{{ tag('a', {
  href: stripeCheckoutUrl(
    [
      {
        price: price.stripeId,
        quantity: 1,
      },
    ],
    currentUser ?? false,
    'shop/thank-you?session={CHECKOUT_SESSION_ID}',
    product.url,
    {}
  ),
  text: 'Checkout',
}) }}
```

Tip

Passing `false` as the second parameter to the `stripeCheckoutUrl()` allows you to create an anonymous checkout URL.

### Checkout Form

[](#checkout-form)

As an alternative to generating static Checkout links, you can build a [form](https://craftcms.com/docs/5.x/development/forms.html) that sends a list of items and other params to Craft, which will create a checkout session on-the-fly, then redirect the customer to the Stripe-hosted checkout page:

```
{% set prices = product.prices.all() %}

  {{ csrfInput() }}
  {{ actionInput('stripe/checkout') }}
  {{ hiddenInput('successUrl', 'shop/thank-you?session={CHECKOUT_SESSION_ID}'|hash) }}
  {{ hiddenInput('cancelUrl', 'shop'|hash) }}
  {% if not currentUser %}
    {{ hiddenInput('customer', 'false') }}
  {% endif %}

    {% for price in prices %}
      {{ price.data|unitAmount }}
    {% endfor %}

  Buy now

```

Tip

By default, the currently logged-in user will be used.

To allow an anonymous checkout, you can add `{{ hiddenInput('customer', 'false') }}` to the form.

If you use this method, you can pass custom field values that should be saved in Craft against a newly created Subscription. These values need to be passed as `fields[]`. For example:

```

```

### Billing Portal

[](#billing-portal)

Customers can manage their subscriptions and payment methods via Stripe’s hosted [billing portal](https://docs.stripe.com/customer-management). You can generate a URL to a customer’s billing portal using the `currentUser.getStripeBillingPortalSessionUrl()` method:

```
{{ tag('a', {
  text: "Billing Portal",
  href: currentUser.getStripeBillingPortalSessionUrl('shop'),
}) }}
```

The method takes a `returnUrl` parameter that specifies the URL to redirect the customer to after they have finished managing their subscriptions and payment methods.

In addition to this method, there is also `currentUser.getStripeBillingPortalSessionPaymentMethodUpdateUrl()`, which generates a URL for the customer to update their default payment method.

```
{{ tag('a', {
  text: "Update Payment Method",
  href: currentUser.getStripeBillingPortalSessionPaymentMethodUpdateUrl('shop'),
}) }}
```

This uses the Stripe [flow type](https://docs.stripe.com/customer-management/portal-deep-links#flow-types) to deep link directly to the payment method update screen.

### Element API

[](#element-api)

Our [Element API](https://plugins.craftcms.com/element-api) plugin works great with Stripe! All three plugin-provided element types (products, prices, and subscriptions) can be used in your `element-api.php` config file:

```
return [
    'endpoints' => [
        'api/products' => function() {
            return [
                'elementType' => craft\stripe\elements\Product::class,
                // ...
            ];
        },
    ],
];
```

Other Features
--------------

[](#other-features)

### Product Field

[](#product-field)

Create a **Stripe Products** field and add it to a field layout to [relate](https://craftcms.com/docs/5.x/system/relations.html) product elements to other content throughout the system.

### Direct API Access

[](#direct-api-access)

The plugin exposes its Stripe API client for advanced usage. In Twig, you would access it via `craft.stripe.api.client`:

```
{% set client = craft.stripe.api.client %}
{% set checkout = client
  .getService('checkout')
  .getService('sessions')
  .retrieve('cs_test_****************************************') %}
```

In PHP, you can make the equivalent call like this:

```
$client = craft\stripe\Plugin::getInstance()->getApi()->getClient();

$checkout = $client
    ->checkout
    ->sessions
    ->retrieve('cs_test_****************************************');
```

Warning

We cannot provide support for customizations that involve direct use of Stripe APIs. If you find yourself needing access to specific APIs during the course of your project, consider [starting a discussion](https://github.com/craftcms/stripe/discussions)!

Tips, Troubleshooting, FAQ
--------------------------

[](#tips-troubleshooting-faq)

### Where do I change a product’s title?

[](#where-do-i-change-a-products-title)

Product and price titles are kept in sync with Stripe to make them easily identifiable in both spaces.

If you would like to customize product names in Craft, create a [plain text field](https://craftcms.com/docs/5.x/reference/field-types/plain-text.html) and add it to the product [field layout](#content--fields). Stripe will only ever display the canonical title at checkout or on invoices, so it is important you have a way for customers to identify which products are which—and not re-use product definitions for other goods.

### I can’t create a webhook.

[](#i-cant-create-a-webhook)

If Craft can't write to a `.env` file in the project root, you may need to manually create a webhook in the Stripe dashboard, then expose it to the environment:

```
STRIPE_WH_ID="we_************************"
STRIPE_WH_KEY="whsec_**************************************************************"
```

Warning

In this case, the environment variable names are strict!

---

Reference
---------

[](#reference)

### Twig Filters

[](#twig-filters)

The plugin provides four new [Twig filters](https://craftcms.com/docs/5.x/reference/twig/filters.html):

- `unitPrice` — Takes a [price](#prices) element’s Stripe `data` array and outputs a formatted expression of its cost *and* interval: `£10.50 per unit/month`
- `pricePerUnit` — Similar to the above, but only outputs the *cost* component, without the interval: `Starts at $5.00 per unit + $20.00`
- `unitAmount` — Similar to the above, but only outputs the *unit* component, i.e. `$13.00 per group of 10`.
- `interval` — Similar to the above, but only outputs the *interval* component, i.e. `One-time` or `Every 1 month`.

In most cases, you will want to use the `unitPrice` filter, as it will provide the most complete information about a price. All filters should be passed the price’s `data` property, which is the raw [Price object](https://docs.stripe.com/api/prices/object) from Stripe:

```
{{ price.data|unitPrice }}
```

### CLI

[](#cli)

To view all available console commands, run `ddev craft help`. The Stripe plugin adds two main groups of commands:

#### Craft Commerce Migration

[](#craft-commerce-migration)

Migrates [preexisting Craft Commerce subscriptions](#migrating-from-craft-commerce) to records compatible with the Stripe plugin.

```
ddev craft stripe/commerce/migrate
```

#### Atomic Synchronization

[](#atomic-synchronization)

You can synchronize *everything* at once…

```
ddev craft stripe/sync/all
```

…or just pull in slices of it:

- **Customers**: `ddev craft stripe/sync/customers`
- **Invoices**: `ddev craft stripe/sync/invoices`
- **Payment Methods**: `ddev craft stripe/sync/payment-methods`
- **Products *and* Prices**: `ddev craft stripe/sync/products-and-prices`
- **Subscriptions**: `ddev craft stripe/sync/subscriptions`

#### Remove Duplicate Subscriptions

[](#remove-duplicate-subscriptions)

Before version 1.7, duplicate subscription elements may have been created for the same Stripe subscription ID.

Use the `stripe/data/remove-duplicates` command to find and remove these duplicates:

```
ddev craft stripe/data/remove-duplicates
```

The command will:

1. Scan for subscription elements that share the same Stripe subscription ID
2. Keep the most recently updated element and delete the others
3. If duplicates have different custom field values, prompt you to choose which element to keep

To preview what would be deleted without actually removing anything, use the `--dryRun` flag:

```
ddev craft stripe/data/remove-duplicates --dryRun
```

---

Extending
---------

[](#extending)

### Synchronization Events

[](#synchronization-events)

The Stripe plugin emits events just before updating each product, price, or subscription element during a [synchronization](#synchronization). A synchronization may occur via the CLI, control panel utility, or in response to a webhook.

Class + EventEvent Model`$source``craft\stripe\services\Products::EVENT_BEFORE_SYNCHRONIZE_PRODUCT``craft\stripe\events\StripeProductSyncEvent`[Product](https://docs.stripe.com/api/products/object)`craft\stripe\services\Products::EVENT_AFTER_SYNCHRONIZE_PRODUCT``craft\stripe\events\StripeProductSyncEvent`[Product](https://docs.stripe.com/api/products/object)`craft\stripe\services\Prices::EVENT_BEFORE_SYNCHRONIZE_PRICE``craft\stripe\events\StripePriceSyncEvent`[Price](https://docs.stripe.com/api/prices/object)`craft\stripe\services\Prices::EVENT_AFTER_SYNCHRONIZE_PRICE``craft\stripe\events\StripePriceSyncEvent`[Price](https://docs.stripe.com/api/prices/object)`craft\stripe\services\Subscriptions::EVENT_BEFORE_SYNCHRONIZE_SUBSCRIPTION``craft\stripe\events\StripeSubscriptionSyncEvent`[Subscription](https://docs.stripe.com/api/subscriptions/object)`craft\stripe\services\Subscriptions::EVENT_AFTER_SYNCHRONIZE_SUBSCRIPTION``craft\stripe\events\StripeSubscriptionSyncEvent`[Subscription](https://docs.stripe.com/api/subscriptions/object)```
craft\base\Event::on(
    craft\stripe\services\Products::class,
    craft\stripe\services\Products::EVENT_BEFORE_SYNCHRONIZE_PRODUCT,
    function(craft\stripe\events\StripeProductSyncEvent $event) {
        // Set a custom field value when a product looks “shippable”:
        if ($event->source->package_dimensions !== null) {
            $event->element->setFieldValue('requiresShipping', true);
        }
    },
);
```

You can set `$event->isValid` to prevent updates from being persisted during the synchronization.

### Checkout Events

[](#checkout-events)

Customize the parameters sent to Stripe when generating a Checkout session by listening to the `craft\stripe\services\Checkout::EVENT_BEFORE_START_CHECKOUT_SESSION` event. The `craft\stripe\events\CheckoutSessionEvent` will have a `params` property containing the request data that is about to be sent with the Stripe API client. You may modify or extend this data to suit your application—whatever the value of the property is after all handlers have been invoked is passed verbatim to the API client:

```
craft\base\Event::on(
    craft\stripe\services\Checkout::class,
    craft\stripe\services\Checkout::EVENT_BEFORE_START_CHECKOUT_SESSION,
    function(craft\stripe\events\CheckoutSessionEvent $event) {
        // Add metadata if the customer is a logged-in “member”:
        $currentUser = Craft::$app->getUser()->getIdentity();

        // Nothing to do:
        if (!$currentUser) {
            return;
        }

        if ($currentUser->isInGroup('members')) {
            // Memoize + assign values:
            $data = $event->params;
            $data['metadata']['is_member'] = true;

            // Set back onto the event:
            $event->params = $data;
        }
    },
);
```

###  Health Score

48

—

FairBetter than 95% of packages

Maintenance73

Regular maintenance activity

Popularity27

Limited adoption so far

Community18

Small or concentrated contributor base

Maturity62

Established project with proven stability

 Bus Factor1

Top contributor holds 61.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~40 days

Recently: every ~25 days

Total

18

Last Release

67d ago

Major Versions

1.7.1 → 2.x-dev2026-03-04

### Community

Maintainers

![](https://www.gravatar.com/avatar/3ccdf8b493035de2343c55bd889513e3af5c04d5823482a2b186ad16adb1c3e3?d=identicon)[brandonkelly](/maintainers/brandonkelly)

---

Top Contributors

[![i-just](https://avatars.githubusercontent.com/u/4500340?v=4)](https://github.com/i-just "i-just (332 commits)")[![lukeholder](https://avatars.githubusercontent.com/u/133571?v=4)](https://github.com/lukeholder "lukeholder (80 commits)")[![nfourtythree](https://avatars.githubusercontent.com/u/266453?v=4)](https://github.com/nfourtythree "nfourtythree (54 commits)")[![brandonkelly](https://avatars.githubusercontent.com/u/47792?v=4)](https://github.com/brandonkelly "brandonkelly (25 commits)")[![AugustMiller](https://avatars.githubusercontent.com/u/1895522?v=4)](https://github.com/AugustMiller "AugustMiller (20 commits)")[![brianjhanson](https://avatars.githubusercontent.com/u/1843073?v=4)](https://github.com/brianjhanson "brianjhanson (17 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (7 commits)")[![timkelty](https://avatars.githubusercontent.com/u/18329?v=4)](https://github.com/timkelty "timkelty (2 commits)")

---

Tags

stripecmscraftcms

### Embed Badge

![Health badge](/badges/craftcms-stripe/health.svg)

```
[![Health](https://phpackages.com/badges/craftcms-stripe/health.svg)](https://phpackages.com/packages/craftcms-stripe)
```

###  Alternatives

[enupal/stripe

Allows customers sign up for recurring and one-time payments with Stripe, perfect for orders, donations, subscriptions, and events. Create simple payment forms in seconds easily without coding. For Craft CMS 3.x

3416.5k1](/packages/enupal-stripe)[verbb/formie

The most user-friendly forms plugin for Craft.

101372.9k40](/packages/verbb-formie)[craftcms/commerce-stripe

Stripe integration for Craft Commerce 5.0+

32157.4k3](/packages/craftcms-commerce-stripe)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
