# Erstellen Sie eine vorgefertigte Abonnementseite mit Stripe Checkout

# Vorgefertigte Abonnementseite mit Stripe Checkout

Beginnen Sie mit unserer Beispiel-App, um eine vollständige, funktionierende Abonnementintegration mit [Stripe Billing](https://docs.stripe.com/billing.md) und [Stripe Checkout](https://docs.stripe.com/payments/checkout.md) durchzuführen.

In der Beispiel-App wird gezeigt, wie Sie Ihre Kundinnen/Kunden von Ihrer Website zu einer vorgefertigten, von Stripe gehosteten Bezahlseite weiterleiten. Die Stripe Billing APIs erstellen und verwalten Abonnements, Rechnungen und wiederkehrende Zahlungen, während Checkout die vorgefertigte, sichere, von Stripe gehostete Nutzeroberfläche für die Erfassung von Zahlungsdaten bietet.

Sie können Kundinnen und Kunden in Ihrer Integration entweder als [kundenkonfigurierte Kontoobjekte](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer) oder als [Kundenobjekte](https://docs.stripe.com/api/customers/object.md) darstellen. Weitere Informationen zu den Unterschieden zwischen diesen Optionen finden Sie unter [Konten als Kundinnen und Kunden verwenden](https://docs.stripe.com/accounts-v2/use-accounts-as-customers.md).

Klicken Sie auf die einzelnen Schritte, um den entsprechenden Beispielcode anzuzeigen. Während Sie Angaben machen, indem Sie zum Beispiel Preisdaten hinzufügen, aktualisiert der Builder den Beispielcode.

Laden Sie die Beispiel-App herunter und passen Sie diese lokal an, um Ihre Integration zu testen.

### Produkte und Preise hinzufügen

Erstellen oder wählen Sie *Produkte* (Products represent what your business sells—whether that's a good or a service) und *Preise* (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), die Sie in diesem Beispiel verwenden können.

> Melden Sie sich bei Ihrem Stripe-Konto an, um Ihre Produkte und Preise zu konfigurieren.

### Fügen Sie Ihrem Produkt Funktionen hinzu

Erstellen Sie Funktionen wie etwa ein jährliches Geburtstagsgeschenk und verknüpfen Sie diese mit Ihrem Abonnement, um neuen Abonnentinnen und Abonnenten [Anspruch](https://docs.stripe.com/billing/entitlements.md) darauf zu gewähren.

Beobachten Sie die [Ereignisse zur Zusammenfassung der aktiven Berechtigungen](https://docs.stripe.com/billing/entitlements.md#webhooks) für Ihr [Ereignisziel](https://docs.stripe.com/event-destinations.md) und nutzen Sie die [API zur Auflistung der aktiven Berechtigungen](https://docs.stripe.com/api/entitlements/active-entitlement/list.md) für einen bestimmten Kundinnen und Kunden, um die Berechtigungen Ihres Kunden bzw. Ihrer Kundin zu erfüllen.

### (Optional) Aktivieren Sie zusätzliche Zahlungsmethoden

Verwenden Sie Ihr [Dashboard](https://dashboard.stripe.com/settings/payment_methods), um [unterstützte Zahlungsmethoden](https://docs.stripe.com/payments/payment-methods/payment-method-support.md) zu aktivieren, die Sie zusätzlich zu Karten akzeptieren möchten. Checkout zeigt Ihre aktivierten Zahlungsmethoden dynamisch nach Relevanz an, basierend auf dem Standort der Kundinnen/Kunden und anderen Merkmalen.

### Seite mit einer Preisvorschau hinzufügen

Fügen Sie Ihrer Website eine Seite hinzu, auf der Ihr Produkt angezeigt wird und auf der Ihre Kundinnen/Kunden es abonnieren können. Wenn sie auf **Checkout** klicken, werden sie zu einer von Stripe gehosteten [Checkout](https://docs.stripe.com/payments/checkout.md)-Seite weitergeleitet, auf der die Bestellung abgeschlossen und weitere Änderungen verhindert werden.

Erwägen Sie, eine [Preistabelle einzubetten](https://docs.stripe.com/payments/checkout/pricing-table.md), um Ihre Preisinformationen dynamisch über das Dashboard anzuzeigen. Ein Klick auf eine Preisoption leitet Ihre Kundin oder Ihren Kunden zur Zahlungsseite weiter.

### Schaltfläche zum Bezahlen hinzufügen

Die Schaltfläche auf Ihrer Bestellvorschauseite leitet Ihre Kundin oder Ihren Kunden zur von Stripe gehosteten Zahlungsseite weiter und verwendet den `lookup_key` Ihres Produkts, um die `price_id` vom Server abzurufen.

### Bestätigungsseite hinzufügen

Erstellen Sie eine Bestätigungsseite, um Ihren Kundinnen und Kunden eine Bestellbestätigung oder Bestelldetails anzuzeigen. Verknüpfen Sie diese Seite mit dem `success_url` der Checkout-Sitzung, an die Stripe weiterleitet, nachdem der Kunde/die Kundin den Bezahlvorgang erfolgreich abgeschlossen hat.

### Schaltfläche für das Kundenportal hinzufügen

Fügen Sie eine Schaltfläche hinzu, die an das Kundenportal weiterleitet, damit Kund/innen ihr Abonnement verwalten können. Durch Anklicken dieser Schaltfläche werden sie zu der von Stripe gehosteten Kundenportal-Seite weitergeleitet.

### An die Kundenportal-Sitzung weiterleiten

Stellen Sie eine Anfrage an den Endpoint auf Ihrem Server, um zu einer neuen Kundenportal-Sitzung umzuleiten. In diesem Beispiel wird die `session_id` aus der [Checkout-Sitzung](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-id) verwendet, um das Abrufen der `customer_id` zu demonstrieren. In einer Produktionsumgebung wird empfohlen, diesen Wert zusammen mit dem/der authentifizierten Nutzer/in in Ihrer Datenbank zu speichern.

### Stripe Node-Bibliothek installieren

Installieren Sie das Paket und importieren Sie es in Ihren Code. Wenn Sie dagegen von Grund auf neu beginnen möchten und eine package.json-Datei benötigen, laden Sie die Projektdateien über den Download-Link im Code-Editor herunter.

#### npm

Bibliothek installieren:

```bash
npm install --save stripe
```

#### GitHub

Oder laden Sie den Quellcode der Stripe-Node-Bibliothek direkt von [GitHub](https://github.com/stripe/stripe-node) herunter.

### Stripe-Ruby-Bibliothek installieren

Installieren Sie Stripe Ruby Gem und fordern Sie es in Ihrem Code an. Wenn Sie dagegen von Grund auf neu beginnen möchten und eine Gemfile benötigen, laden Sie die Projektdateien über den Download-Link im Code-Editor herunter.

#### Terminal

Gem installieren:

```bash
gem install stripe
```

#### Bundler

Fügen Sie diese Zeile in Ihre Gemfile ein:

```bash
gem 'stripe'
```

#### GitHub

Oder laden Sie den Quellcode von Stripe Ruby Gem direkt von [GitHub](https://github.com/stripe/stripe-ruby) herunter.

### Stripe Java-Bibliothek installieren

Fügen Sie Ihrem Build die Abhängigkeit hinzu und importieren Sie die Bibliothek. Wenn Sie dagegen von Grund auf neu beginnen möchten und eine pom.xml-Beispieldatei (für Maven) benötigen, laden Sie die Projektdateien über den Download-Link im Code-Editor herunter.

#### Maven

Fügen Sie folgende Abhängigkeit zu Ihrer POM-Datei hinzu und ersetzen Sie {VERSION} durch die Versionsnummer, die Sie verwenden möchten.

```bash
<dependency>\n<groupId>com.stripe</groupId>\n<artifactId>stripe-java</artifactId>\n<version>{VERSION}</version>\n</dependency>
```

#### Gradle

Fügen Sie die Abhängigkeit zu Ihrer build.gradle-Datei hinzu und ersetzen Sie {VERSION} durch die Versionsnummer, die Sie verwenden möchten.

```bash
implementation "com.stripe:stripe-java:{VERSION}"
```

#### GitHub

Laden Sie die JAR-Datei direkt von [GitHub](https://github.com/stripe/stripe-java/releases/latest) herunter.

### Stripe-Python-Paket installieren

Installieren Sie das Stripe-Paket und importieren Sie es in Ihren Code. Wenn Sie dagegen von Grund auf neu beginnen möchten und eine requirements.txt-Datei benötigen, laden Sie die Projektdateien über den Download-Link im Code-Editor herunter.

#### pip

Installieren Sie das Paket über pip:

```bash
pip3 install stripe
```

#### GitHub

Laden Sie den Quellcode der Stripe-Python-Bibliothek direkt [von GitHub](https://github.com/stripe/stripe-python) herunter.

### Stripe PHP-Bibliothek installieren

Installieren Sie die Bibliothek mit Composer und initialisieren Sie sie mit Ihrem geheimen API-Schlüssel. Wenn Sie dagegen von Grund auf neu beginnen möchten und eine composer.csproj-Datei benötigen, laden Sie die Dateien über den Download-Link im Code-Editor herunter.

#### Composer

Bibliothek installieren:

```bash
composer require stripe/stripe-php
```

#### GitHub

Oder laden Sie den Quellcode der Stripe-PHP-Bibliothek direkt von [GitHub](https://github.com/stripe/stripe-php) herunter.

### Server einrichten

Fügen Sie Ihrem Build die Abhängigkeit hinzu und importieren Sie die Bibliothek. Wenn Sie dagegen von Grund auf neu beginnen möchten und eine go.mod-Datei benötigen, laden Sie die Projektdateien über den Download-Link im Code-Editor herunter.

#### Go

Nutzen Sie für die Initialisierung Go-Module:

```bash
go get -u github.com/stripe/stripe-go/v86
```

#### GitHub

Oder laden Sie den Quellcode des Stripe-Go-Moduls direkt von [GitHub](https://github.com/stripe/stripe-go) herunter.

### Stripe.net-Bibliothek installieren

Installieren Sie das Paket mit .NET oder NuGet. Wenn Sie aber von Grund auf neu beginnen möchten, laden Sie die Dateien herunter, die eine konfigurierte .csproj-Datei enthalten.

#### dotnet

Bibliothek installieren:

```bash
dotnet add package Stripe.net
```

#### NuGet

Bibliothek installieren:

```bash
Install-Package Stripe.net
```

#### GitHub

Oder laden Sie den Quellcode der Stripe.net-Bibliothek direkt von [GitHub](https://github.com/stripe/stripe-dotnet) herunter.

### Stripe-Bibliotheken installieren

Installieren Sie die Pakete und importieren Sie sie in Ihren Code. Wenn Sie dagegen von Grund auf neu beginnen möchten und eine `package.json`-Datei benötigen, laden Sie die Projektdateien über den Download-Link im Code-Editor herunter.

Bibliotheken installieren:

```bash
npm install --save stripe @stripe/stripe-js next
```

### Checkout-Sitzung erstellen

Über eine [Checkout-Sitzung](https://docs.stripe.com/api/checkout/sessions.md) wird gesteuert, was die Kundinnen/Kunden auf der von Stripe gehosteten Zahlungsseite sehen, z.&nbsp;B. Positionen, den Bestellbetrag und die Währung sowie die akzeptierten Zahlungsmethoden.

### Preis vom Lookup-Schlüssel anfordern

Übergeben Sie den Suchschlüssel, den Sie für Ihr Produkt definiert haben, im [Preis](https://docs.stripe.com/api/prices/list.md)-Endpoint, um dessen Preis auf die Bestellung anzuwenden.

### Posten definieren

Bewahren Sie sensible Informationen über Ihren Produktbestand, wie Preis und Verfügbarkeit, immer auf Ihrem Server auf, um Änderungen durch Kund/innen auf dem Client zu verhindern. Übergeben Sie die oben abgerufenen Preis-IDs.

### Modus festlegen

Legen Sie den Modus auf `subscription` fest. Checkout unterstützt auch die Modi [Zahlung](https://docs.stripe.com/checkout/quickstart.md) und [Einrichtung](https://docs.stripe.com/payments/save-and-reuse.md) für einmalige Zahlungen.

### Erfolgs-URL angeben

Geben Sie eine öffentlich zugängliche URL an, zu der Stripe Kundinnen und Kunden nach erfolgreichem Abschluss weiterleiten kann. Fügen Sie am Ende Ihrer URL den Query-Parameter `session_id` hinzu, damit Sie die Kundin/den Kunden später abrufen können und Stripe das gehostete Dashboard für die Kundin/den Kunden erzeugen kann.

### Von Checkout weiterleiten

Leiten Sie Ihre Kund/innen nach dem Erstellen der Sitzung an die in der Antwort zurückgegebene URL weiter (entweder die Erfolgs- oder Abbruch-URL).

### Kundenportal-Sitzung erstellen

Initiieren Sie eine sichere, von Stripe gehostete [Kundenportal-Sitzung](https://docs.stripe.com/api/customer_portal/sessions/create.md), in der Ihre Kundinnen/Kunden ihre Abonnements und Rechnungsdetails verwalten können.

### An das Kundenportal weiterleiten

Leiten Sie Ihre Kundinnen/Kunden nach dem Erstellen der Portalsitzung zu der in der Antwort zurückgegebenen URL weiter.

### Abonnement abwickeln

Erstellen Sie einen `/webhook`-Endpoint und rufen Sie Ihren geheimen Webhook-Schlüssel auf der Registerkarte [Webhooks](https://dashboard.stripe.com/webhooks) in Workbench ab, um Ereignisse im Zusammenhang mit der Abonnementaktivität zu überwachen. Überprüfen Sie nach einer erfolgreichen Zahlung und Weiterleitung an die Bestätigungsseite, ob der Abonnementstatus `active` ist, und gewähren Sie Ihrer Kundin/Ihrem Kunden Zugriff auf die abonnierten Produkte und Funktionen.

### Server ausführen

Setzen Sie die Umgebungsvariable `STRIPE_WEBHOOK_SECRET` auf Ihr Webhook-Signaturgeheimnis. Sie finden dieses Geheimnis auf der Registerkarte [Webhooks](https://dashboard.stripe.com/webhooks) in der Workbench.

Starten Sie Ihren Server und gehen Sie zu <http://localhost:4242/>.

```bash
npm start
```

### Server ausführen

Setzen Sie die Umgebungsvariable `STRIPE_WEBHOOK_SECRET` auf Ihr Webhook-Signaturgeheimnis. Sie finden dieses Geheimnis auf der Registerkarte [Webhooks](https://dashboard.stripe.com/webhooks) in der Workbench.

Starten Sie Ihren Server. Es öffnet sich automatisch ein Browserfenster zu <http://localhost:3000/checkout>

```bash
npm start
```

### Server ausführen

Setzen Sie die Umgebungsvariable `STRIPE_WEBHOOK_SECRET` auf Ihr Webhook-Signaturgeheimnis. Sie finden dieses Geheimnis auf der Registerkarte [Webhooks](https://dashboard.stripe.com/webhooks) in der Workbench.

Starten Sie Ihren Server und gehen Sie zu <http://localhost:4242/>.

```bash
ruby server.rb
```

### Server ausführen

Setzen Sie die Umgebungsvariable `STRIPE_WEBHOOK_SECRET` auf Ihr Webhook-Signaturgeheimnis. Sie finden dieses Geheimnis auf der Registerkarte [Webhooks](https://dashboard.stripe.com/webhooks) in der Workbench.

Starten Sie Ihren Server. Es öffnet sich automatisch ein Browserfenster zu <http://localhost:3000/checkout>

```bash
ruby server.rb
```

### Server ausführen

Setzen Sie die Umgebungsvariable `STRIPE_WEBHOOK_SECRET` auf Ihr Webhook-Signaturgeheimnis. Sie finden dieses Geheimnis auf der Registerkarte [Webhooks](https://dashboard.stripe.com/webhooks) in der Workbench.

Starten Sie Ihren Server und gehen Sie zu <http://localhost:4242/>.

```bash
python3 -m flask run --port=4242
```

### Server ausführen

Setzen Sie die Umgebungsvariable `STRIPE_WEBHOOK_SECRET` auf Ihr Webhook-Signaturgeheimnis. Sie finden dieses Geheimnis auf der Registerkarte [Webhooks](https://dashboard.stripe.com/webhooks) in der Workbench.

Starten Sie Ihren Server. Es öffnet sich automatisch ein Browserfenster zu <http://localhost:3000/checkout>

```bash
python3 -m flask run --port=4242
```

### Server ausführen

Setzen Sie die Umgebungsvariable `STRIPE_WEBHOOK_SECRET` auf Ihr Webhook-Signaturgeheimnis. Sie finden dieses Geheimnis auf der Registerkarte [Webhooks](https://dashboard.stripe.com/webhooks) in der Workbench.

Starten Sie Ihren Server und gehen Sie zu <http://localhost:4242/>.

```bash
php -S 127.0.0.1:4242 --docroot=public
```

### Server ausführen

Setzen Sie die Umgebungsvariable `STRIPE_WEBHOOK_SECRET` auf Ihr Webhook-Signaturgeheimnis. Sie finden dieses Geheimnis auf der Registerkarte [Webhooks](https://dashboard.stripe.com/webhooks) in der Workbench.

Starten Sie Ihren Server. Es öffnet sich automatisch ein Browserfenster zu <http://localhost:3000/checkout>

```bash
php -S 127.0.0.1:4242 --docroot=public
```

### Server ausführen

Setzen Sie die Umgebungsvariable `STRIPE_WEBHOOK_SECRET` auf Ihr Webhook-Signaturgeheimnis. Sie finden dieses Geheimnis auf der Registerkarte [Webhooks](https://dashboard.stripe.com/webhooks) in der Workbench.

Starten Sie Ihren Server und gehen Sie zu <http://localhost:4242/>.

```bash
dotnet run
```

### Server ausführen

Setzen Sie die Umgebungsvariable `STRIPE_WEBHOOK_SECRET` auf Ihr Webhook-Signaturgeheimnis. Sie finden dieses Geheimnis auf der Registerkarte [Webhooks](https://dashboard.stripe.com/webhooks) in der Workbench.

Starten Sie Ihren Server. Es öffnet sich automatisch ein Browserfenster zu <http://localhost:3000/checkout>

```bash
dotnet run
```

### Server ausführen

Setzen Sie die Umgebungsvariable `STRIPE_WEBHOOK_SECRET` auf Ihr Webhook-Signaturgeheimnis. Sie finden dieses Geheimnis auf der Registerkarte [Webhooks](https://dashboard.stripe.com/webhooks) in der Workbench.

Starten Sie Ihren Server und gehen Sie zu <http://localhost:4242/>.

```bash
go run server.go
```

### Server ausführen

Setzen Sie die Umgebungsvariable `STRIPE_WEBHOOK_SECRET` auf Ihr Webhook-Signaturgeheimnis. Sie finden dieses Geheimnis auf der Registerkarte [Webhooks](https://dashboard.stripe.com/webhooks) in der Workbench.

Starten Sie Ihren Server. Es öffnet sich automatisch ein Browserfenster zu <http://localhost:3000/checkout>

```bash
go run server.go
```

### Server ausführen

Setzen Sie die Umgebungsvariable `STRIPE_WEBHOOK_SECRET` auf Ihr Webhook-Signaturgeheimnis. Sie finden dieses Geheimnis auf der Registerkarte [Webhooks](https://dashboard.stripe.com/webhooks) in der Workbench.

Starten Sie Ihren Server und gehen Sie zu <http://localhost:4242/>.

```bash
java -cp target/sample-jar-with-dependencies.jar com.stripe.sample.Server
```

### Server ausführen

Setzen Sie die Umgebungsvariable `STRIPE_WEBHOOK_SECRET` auf Ihr Webhook-Signaturgeheimnis. Sie finden dieses Geheimnis auf der Registerkarte [Webhooks](https://dashboard.stripe.com/webhooks) in der Workbench.

Starten Sie Ihren Server. Es öffnet sich automatisch ein Browserfenster zu <http://localhost:3000/checkout>

```bash
java -cp target/sample-jar-with-dependencies.jar com.stripe.sample.Server
```

### Jetzt testen

Klicken Sie auf die Schaltfläche „Zur Kasse“. Verwenden Sie auf der von Stripe gehosteten Zahlungsseite eine dieser Testkarten, um eine Zahlung zu simulieren.

| Scenario | Card Number |
| --- | --- |
| Payment succeeds | 4242424242424242 |
| Payment requires 3DS authentication | 4000002500003155 |
| Payment is declined | 4000000000009995 |

## Anpassungsfunktionen hinzufügen

Wenn Sie Ihr Produkt in Ihrem Test erfolgreich abonniert haben, verfügen Sie über eine funktionierende grundlegende Checkout-Integration für Abonnements. Verwenden Sie die Schalter unten, um zu sehen, wie Sie dieses Beispiel mit zusätzlichen Funktionen anpassen können.

### Testversionen hinzufügen

Hängen Sie der Checkout-Sitzung einen Testzeitraum an.

### Testversion hinzufügen

Verwenden Sie `subscription_data`, um eine Ganzzahl hinzuzufügen, die die Anzahl der `trial_period_days` darstellt, bevor das Kundenkonto zum ersten Mal belastet wird. Diese muss mindestens `1` betragen.

Setzen Sie, wenn Sie eine kostenlose Testversion ohne Zahlungsmethode starten, das Feld `trial_settings[end_behavior][missing_payment_method]` auf `pause` oder `cancel`, damit das Abonnement nicht ohne Zahlungsmethode fortgesetzt wird, wenn die Testphase endet. Übergeben Sie diesen Parameter in `subscription_data`, wenn Sie eine Checkout-Sitzung erstellen, oder aktualisieren Sie ihn zu einem anderen Zeitpunkt für das Abonnement. Weitere Informationen finden Sie unter [Testphasen nutzen](https://docs.stripe.com/billing/subscriptions/trials/free-trials.md#create-free-trials-without-payment).

### Datum für den Abrechnungszyklus festlegen

Geben Sie beim Erstellen einer Checkout-Sitzung einen Abrechnungszyklusanker an.

### Abrechnungszyklus eines Abonnements festlegen

Verwenden Sie `subscription_data`, um einen `billing_cycle_anchor`-Zeitstempel für das nächste Abrechnungsdatum eines Abonnements festzulegen. Unter [Datum für den Abrechnungszyklus in Checkout festlegen](https://docs.stripe.com/payments/checkout/billing-cycle.md) erhalten Sie weitere Informationen.

### Steuererhebung automatisieren

Berechnen und erheben Sie den richtigen Steuerbetrag für Ihre Stripe-Transaktionen. Erfahren Sie mehr über [Stripe Tax](https://docs.stripe.com/tax.md) und [wie die Funktion zu Checkout hinzugefügt werden kann](https://docs.stripe.com/tax/checkout.md). [Aktivieren Sie Stripe Tax](https://dashboard.stripe.com/tax) im Dashboard, bevor Sie die Integration durchführen.

### Parameter für die automatische Steuererhebung hinzufügen

Legen Sie den Parameter `automatic_tax` auf `enabled: true` fest.

    <script src="https://js.stripe.com/endive/stripe.js"></script>
      <div class="product">
        <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14px" height="16px" viewBox="0 0 14 16" version="1.1">
            <defs/>
            <g id="Flow" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
                <g id="0-Default" transform="translate(-121.000000, -40.000000)" fill="#E184DF">
                    <path d="M127,50 L126,50 C123.238576,50 121,47.7614237 121,45 C121,42.2385763 123.238576,40 126,40 L135,40 L135,56 L133,56 L133,42 L129,42 L129,56 L127,56 L127,50 Z M127,48 L127,42 L126,42 C124.343146,42 123,43.3431458 123,45 C123,46.6568542 124.343146,48 126,48 L127,48 Z" id="Pilcrow"/>
                </g>
            </g>
        </svg>
        <div class="description">
          <h3>{{PRODUCT_NAME}}</h3>
          <h5>{{FORMATTED_RECURRING_PRICE}}</h5>
        </div>
      </div>
      <form action="/create-checkout-session" method="POST">
        <!-- Add a hidden field with the lookup_key of your Price -->
        <input type="hidden" name="lookup_key" value="{{PRICE_LOOKUP_KEY}}" />
        <button id="checkout-and-portal-button" type="submit">Checkout</button>
      </form>
      <form action="/create-checkout-session.php" method="POST">
        <!-- Add a hidden field with the lookup_key of your Price -->
        <input type="hidden" name="lookup_key" value="{{PRICE_LOOKUP_KEY}}" />
        <button id="checkout-and-portal-button" type="submit">Checkout</button>
      </form>
<body>
  <section>
    <div class="product Box-root">
      <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14px" height="16px" viewBox="0 0 14 16" version="1.1">
          <defs/>
          <g id="Flow" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
              <g id="0-Default" transform="translate(-121.000000, -40.000000)" fill="#E184DF">
                  <path d="M127,50 L126,50 C123.238576,50 121,47.7614237 121,45 C121,42.2385763 123.238576,40 126,40 L135,40 L135,56 L133,56 L133,42 L129,42 L129,56 L127,56 L127,50 Z M127,48 L127,42 L126,42 C124.343146,42 123,43.3431458 123,45 C123,46.6568542 124.343146,48 126,48 L127,48 Z" id="Pilcrow"/>
              </g>
          </g>
      </svg>
      <div class="description Box-root">
        <h3>Subscription to {{PRODUCT_NAME}} successful!</h3>
      </div>
    </div>
    <form action="/create-portal-session" method="POST">
      <input type="hidden" id="session-id" name="session_id" value="" />
      <button id="checkout-and-portal-button" type="submit">Manage your billing information</button>
    </form>
    <form action="/create-portal-session.php" method="POST">
      <input type="hidden" id="session-id" name="session_id" value="" />
      <button id="checkout-and-portal-button" type="submit">Manage your billing information</button>
    </form>
  </section>
</body>
<body>
  <section>
    <p>Picked the wrong subscription? Shop around then come back to pay!</p>
  </section>
</body>
    <div className="product">
      <Logo />
      <div className="description">
        <h3>{{PRODUCT_NAME}}</h3>
        <h5>{{FORMATTED_RECURRING_PRICE}}</h5>
      </div>
    </div>
    <form action="/create-checkout-session" method="POST">
      {/* Add a hidden field with the lookup_key of your Price */}
      <input type="hidden" name="lookup_key" value="{{PRICE_LOOKUP_KEY}}" />
      <button id="checkout-and-portal-button" type="submit">
        Checkout
      </button>
    </form>
    <form action="/create-checkout-session.php" method="POST">
      {/* Add a hidden field with the lookup_key of your Price */}
      <input type="hidden" name="lookup_key" value="{{PRICE_LOOKUP_KEY}}" />
      <button id="checkout-and-portal-button" type="submit">
        Checkout
      </button>
    </form>
    <section>
      <div className="product Box-root">
        <Logo />
        <div className="description Box-root">
          <h3>Subscription to {{PRODUCT_NAME}} successful!</h3>
        </div>
      </div>
      <form action="/create-portal-session" method="POST">
        <input
          type="hidden"
          id="session-id"
          name="session_id"
          value={sessionId}
        />
        <button id="checkout-and-portal-button" type="submit">
          Manage your billing information
        </button>
      </form>
      <form action="/create-portal-session.php" method="POST">
        <input
          type="hidden"
          id="session-id"
          name="session_id"
          value={sessionId}
        />
        <button id="checkout-and-portal-button" type="submit">
          Manage your billing information
        </button>
      </form>
    </section>
{
  "name": "stripe-sample",
  "version": "0.1.0",
  "dependencies": {
    "@stripe/react-stripe-js": "^3.7.0",
    "@stripe/stripe-js": "^7.3.0",
    "express": "^4.17.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "^5.0.1",
    "stripe": "^8.202.0"
  },
  "devDependencies": {
    "concurrently": "4.1.2"
  },
  "homepage": "http://localhost:3000/checkout",
  "proxy": "http://127.0.0.1:4242",
  "scripts": {
    "start-client": "react-scripts start",
    "start-server": "node server.js",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "start": "concurrently \"yarn start-client\" \"yarn start-server\""
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}
{
  "name": "client",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@stripe/react-stripe-js": "^3.7.0",
    "@stripe/stripe-js": "^7.3.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "^5.0.1"
  },
  "homepage": "http://localhost:3000/checkout",
  "proxy": "http://127.0.0.1:4242",
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}
// This is a public sample test API key.
// Don't submit any personally identifiable information in requests made with this key.
// Sign in to see your own test API key embedded in code samples.
// Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
const stripe = require('stripe')('<<YOUR_SECRET_KEY>>');
const YOUR_DOMAIN = "http://localhost:4242";
const YOUR_DOMAIN = "http://localhost:3000";
  const prices = await stripe.prices.list({
    lookup_keys: [req.body.lookup_key],
    expand: ['data.product'],
  });
  const session = await stripe.checkout.sessions.create({
    billing_address_collection: 'auto',
    line_items: [
      {
        price: prices.data[0].id,
        // For usage-based billing, don't pass quantity
        quantity: 1,

      },
    ],
    mode: 'subscription',
    success_url: `${YOUR_DOMAIN}/success.html?session_id={CHECKOUT_SESSION_ID}`,
    success_url: `${YOUR_DOMAIN}/?success=true&session_id={CHECKOUT_SESSION_ID}`,
    discounts: [{
      coupon: '{{COUPON_ID}}',
    }],
    customer: 'cus_123',
    customer_account: 'acct_123',
    subscription_data: {
      trial_period_days: 7,
      billing_cycle_anchor: 1672531200,
    },
    subscription_data: {
      billing_cycle_anchor: 1672531200,
    },
    automatic_tax: { enabled: true },
  });

  res.redirect(303, session.url);
  // This is the url to which the customer will be redirected when they're done
  // managing their billing with the portal.
  const returnUrl = YOUR_DOMAIN;

  const portalSession = await stripe.billingPortal.sessions.create({
    customer: checkoutSession.customer,
    return_url: returnUrl,
  });
  // This is the url to which the customer will be redirected when they're done
  // managing their billing with the portal.
  const returnUrl = YOUR_DOMAIN;

  const portalSession = await stripe.billingPortal.sessions.create({
    customer_account: checkoutSession.customer_account,
    return_url: returnUrl,
  });
  res.redirect(303, portalSession.url);
app.post(
  '/webhook',
  express.raw({ type: 'application/json' }),
  (request, response) => {
    let event = request.body;

    // To run this example, set an environment variable STRIPE_WEBHOOK_SECRET to
    // your endpoint's unique secret.
    //
    // If you are testing with the CLI, find the secret by running 'stripe listen'.
    // If you are using an endpoint defined with the API or dashboard, look in
    // your webhook settings at https://dashboard.stripe.com/webhooks.
    //
    // Don't include webhook secrets in code.
    const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;

    // Only verify the event if you have an endpoint secret defined.
    // Otherwise use the basic event deserialized with JSON.parse
    if (endpointSecret) {
      // Get the signature sent by Stripe
      const signature = request.headers['stripe-signature'];
      try {
        event = stripe.webhooks.constructEvent(
          request.body,
          signature,
          endpointSecret
        );
      } catch (err) {
        console.log(`⚠️  Webhook signature verification failed.`, err.message);
        return response.sendStatus(400);
      }
    }
    let subscription;
    let status;
    // Handle the event
    switch (event.type) {
      case 'customer.subscription.trial_will_end':
        subscription = event.data.object;
        status = subscription.status;
        console.log(`Subscription status is ${status}.`);
        // Then define and call a method to handle the subscription trial ending.
        // handleSubscriptionTrialEnding(subscription);
        break;
      case 'customer.subscription.deleted':
        subscription = event.data.object;
        status = subscription.status;
        console.log(`Subscription status is ${status}.`);
        // Then define and call a method to handle the subscription deleted.
        // handleSubscriptionDeleted(subscriptionDeleted);
        break;
      case 'customer.subscription.created':
        subscription = event.data.object;
        status = subscription.status;
        console.log(`Subscription status is ${status}.`);
        // Then define and call a method to handle the subscription created.
        // handleSubscriptionCreated(subscription);
        break;
      case 'customer.subscription.updated':
        subscription = event.data.object;
        status = subscription.status;
        console.log(`Subscription status is ${status}.`);
        // Then define and call a method to handle the subscription update.
        // handleSubscriptionUpdated(subscription);
        break;
      case 'entitlements.active_entitlement_summary.updated':
        subscription = event.data.object;
        console.log(`Active entitlement summary updated for ${subscription}.`);
        // Then define and call a method to handle active entitlement summary updated
        // handleEntitlementUpdated(subscription);
        break;
      default:
        // Unexpected event type
        console.log(`Unhandled event type ${event.type}.`);
    }
    // Return a 200 response to acknowledge receipt of the event
    response.send();
  }
);
{
  "name": "stripe-sample",
  "version": "1.0.0",
  "description": "A sample Stripe implementation",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "author": "stripe-samples",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1",
    "stripe": "^22.6.0"
  }
}
{
  "name": "stripe-sample",
  "version": "0.1.0",
  "dependencies": {
    "@stripe/react-stripe-js": "^3.7.0",
    "@stripe/stripe-js": "^7.3.0",
    "express": "^4.17.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "^5.0.1",
    "stripe": "22.6.0"
  },
  "devDependencies": {
    "concurrently": "4.1.2"
  },
  "homepage": "http://localhost:3000/checkout",
  "proxy": "http://localhost:4242",
  "scripts": {
    "start-client": "react-scripts start",
    "start-server": "node server.js",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "start": "concurrently \"npm run start-client\" \"npm run start-server\""
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}
\# This is a public sample test API key.
# Don't submit any personally identifiable information in requests made with this key.
# Sign in to see your own test API key embedded in code samples.
\# Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
client = Stripe::StripeClient.new('<<YOUR_SECRET_KEY>>')
  prices = client.v1.prices.list(
    lookup_keys: [params['lookup_key']],
    expand: ['data.product']
  )
    session = client.v1.checkout.sessions.create({
      mode: 'subscription',
      line_items: [{
        quantity: 1,
        price: prices.data[0].id
      }],
      success_url: YOUR_DOMAIN + '/success.html?session_id={CHECKOUT_SESSION_ID}',
      success_url: YOUR_DOMAIN + '?success=true&session_id={CHECKOUT_SESSION_ID}',
      subscription_data: {
        trial_period_days: 7,
        billing_cycle_anchor: 1672531200
      },
      subscription_data: {
        billing_cycle_anchor: 1672531200
      },
      customer: 'cus_JyTTNqVDAoRYE1',
      customer_account: 'acct_123',
      discounts: [{
        coupon: 'gBY6sFUf'
      }],
      automatic_tax: {
        enabled: true
      },
    })
  redirect session.url, 303
  session = client.v1.billing_portal.sessions.create({

                                                    customer: checkout_session.customer,
                                                    return_url: return_url
                                                  })
  session = client.v1.billing_portal.sessions.create({

                                                    customer_account: checkout_session.customer_account,
                                                    return_url: return_url
                                                  })
  redirect session.url, 303
post '/webhook' do
  \# To run this example, set an environment variable STRIPE_WEBHOOK_SECRET to
  # your endpoint's unique secret.
  #
  # If you are testing with the CLI, find the secret by running 'stripe listen'.
  # If you are using an endpoint defined with the API or dashboard, look in
  # your webhook settings at https://dashboard.stripe.com/webhooks.
  #
  # Don't include webhook secrets in code.
  webhook_secret = ENV['STRIPE_WEBHOOK_SECRET']

  payload = request.body.read
  if webhook_secret
    # 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 == 'customer.subscription.deleted'
    # handle subscription canceled automatically based
    # upon your subscription settings. Or if the user cancels it.
    # puts data_object
    puts "Subscription canceled: #{event.id}"
  end

  if event.type == 'customer.subscription.updated'
    # handle subscription updated
    # puts data_object
    puts "Subscription updated: #{event.id}"
  end

  if event.type == 'customer.subscription.created'
    # handle subscription created
    # puts data_object
    puts "Subscription created: #{event.id}"
  end

  if event.type == 'customer.subscription.trial_will_end'
    # handle subscription trial ending
    # puts data_object
    puts "Subscription trial will end: #{event.id}"
  end

  if event.type == 'entitlements.active_entitlement_summary.updated'
    # handle active entitlement summary updated
    # puts data_object
    puts "Active entitlement summary updated: #{event.id}"
  end

  content_type 'application/json'
  {
    status: 'success'
  }.to_json
end
import stripe
\# This is a public sample test API key.
# Don't submit any personally identifiable information in requests made with this key.
# Sign in to see your own test API key embedded in code samples.
\# Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
client = stripe.StripeClient('<<YOUR_SECRET_KEY>>')
    try:
        prices = client.v1.prices.list(params={
            'lookup_keys': [request.form['lookup_key']],
            'expand': ['data.product'],
        })

        checkout_session = client.v1.checkout.sessions.create(params={
            'line_items': [
                {
                    'price': prices.data[0].id,
                    'quantity': 1,
                },
            ],
            'mode': 'subscription',
            'success_url': YOUR_DOMAIN +
            '/success.html?session_id={CHECKOUT_SESSION_ID}',
            'success_url': YOUR_DOMAIN +
            '?success=true&session_id={CHECKOUT_SESSION_ID}',
            'subscription_data': {
                'trial_period_days': 7,
                'billing_cycle_anchor': 1672531200,
            },
            'subscription_data': {
                'billing_cycle_anchor': 1672531200,
            },
            'discounts': [
                {
                    'coupon': '{{COUPON_ID}}'
                }
            ],
            'customer': 'cus_123',
            'customer_account': 'acct_123',
            'automatic_tax': {
              'enabled': True
            },
        })
        return redirect(checkout_session.url, code=303)
    portalSession = client.v1.billing_portal.sessions.create(params={
        'customer': checkout_session.customer,
        'return_url': return_url,
    })
    portalSession = client.v1.billing_portal.sessions.create(params={
        'customer_account': checkout_session.customer_account,
        'return_url': return_url,
    })
    return redirect(portalSession.url, code=303)
@app.route('/webhook', methods=['POST'])
def webhook_received():
    \# To run this example, set an environment variable STRIPE_WEBHOOK_SECRET to
    # your endpoint's unique secret.
    #
    # If you are testing with the CLI, find the secret by running 'stripe listen'.
    # If you are using an endpoint defined with the API or dashboard, look in
    # your webhook settings at https://dashboard.stripe.com/webhooks.
    #
    # Don't include webhook secrets in code.
    webhook_secret = os.environ.get('STRIPE_WEBHOOK_SECRET')

    request_data = json.loads(request.data)

    if webhook_secret:
        # Retrieve the event by verifying the signature using the raw body and secret if webhook signing is configured.
        signature = request.headers.get('stripe-signature')
        try:
            event = client.construct_event(
                payload=request.data, sig_header=signature, secret=webhook_secret)
            data = event['data']
        except Exception as e:
            return e
        # Get the type of webhook event sent - used to check the status of PaymentIntents.
        event_type = event['type']
    else:
        data = request_data['data']
        event_type = request_data['type']
    data_object = data['object']

    print('event ' + event_type)

    if event_type == 'checkout.session.completed':
        print('🔔 Payment succeeded!')
    elif event_type == 'customer.subscription.trial_will_end':
        print('Subscription trial will end')
    elif event_type == 'customer.subscription.created':
        print('Subscription created %s', event.id)
    elif event_type == 'customer.subscription.updated':
        print('Subscription created %s', event.id)
    elif event_type == 'customer.subscription.deleted':
        # handle subscription canceled automatically based
        # upon your subscription settings. Or if the user cancels it.
        print('Subscription canceled: %s', event.id)
    elif event_type == 'entitlements.active_entitlement_summary.updated':
        # handle active entitlement summary updated
        print('Active entitlement summary updated: %s', event.id)

    return jsonify({'status': 'success'})
certifi==2026.1.4
chardet==5.2.0
click==8.3.1
Flask==3.1.2
idna==3.11
itsdangerous==2.2.0
Jinja2==3.1.6
MarkupSafe==3.0.3
requests==2.32.5
stripe==15.6.0
toml==0.10.2
Werkzeug==3.1.5
  $session = $stripe->billingPortal->sessions->create([
    'customer' => $checkout_session->customer,
    'return_url' => $return_url,
  ]);
  $session = $stripe->billingPortal->sessions->create([
    'customer_account' => $checkout_session->customer_account,
    'return_url' => $return_url,
  ]);
  header("HTTP/1.1 303 See Other");
  header("Location: " . $session->url);

// To run this example, set an environment variable STRIPE_WEBHOOK_SECRET to
// your endpoint's unique secret.
//
// If you are testing with the CLI, find the secret by running 'stripe listen'.
// If you are using an endpoint defined with the API or dashboard, look in
// your webhook settings at https://dashboard.stripe.com/webhooks.
//
// Don't include webhook secrets in code.
$endpoint_secret = getenv('STRIPE_WEBHOOK_SECRET');

$payload = @file_get_contents('php://input');
$event = null;
try {
  $event = \Stripe\Event::constructFrom(
    json_decode($payload, true)
  );
} catch(\UnexpectedValueException $e) {
  // Invalid payload
  echo '⚠️  Webhook error while parsing basic request.';
  http_response_code(400);
  exit();
}
// Handle the event
switch ($event->type) {
  case 'customer.subscription.trial_will_end':
    $subscription = $event->data->object; // contains a \Stripe\Subscription
    // Then define and call a method to handle the trial ending.
    // handleTrialWillEnd($subscription);
    break;
  case 'customer.subscription.created':
    $subscription = $event->data->object; // contains a \Stripe\Subscription
    // Then define and call a method to handle the subscription being created.
    // handleSubscriptionCreated($subscription);
    break;
  case 'customer.subscription.deleted':
    $subscription = $event->data->object; // contains a \Stripe\Subscription
    // Then define and call a method to handle the subscription being deleted.
    // handleSubscriptionDeleted($subscription);
    break;
  case 'customer.subscription.updated':
    $subscription = $event->data->object; // contains a \Stripe\Subscription
    // Then define and call a method to handle the subscription being updated.
    // handleSubscriptionUpdated($subscription);
    break;
  case 'entitlements.active_entitlement_summary.updated':
    $subscription = $event->data->object; // contains a \Stripe\Subscription
    // Then define and call a method to handle active entitlement summary updated.
    // handleEntitlementUpdated($subscription);
    break;
  default:
    // Unexpected event type
    echo 'Received unknown event type';
}
// Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
$stripeSecretKey = '<<YOUR_SECRET_KEY>>';
$stripe = new \Stripe\StripeClient($stripeSecretKey);
  $prices = $stripe->prices->all([
    // retrieve lookup_key from form data POST body
    'lookup_keys' => [$_POST['lookup_key']],
    'expand' => ['data.product']
  ]);
  $checkout_session = $stripe->checkout->sessions->create([
    'line_items' => [[
      'price' => $prices->data[0]->id,
      'quantity' => 1,
    ]],
    'mode' => 'subscription',
    'success_url' => $YOUR_DOMAIN . '/success.html?session_id={CHECKOUT_SESSION_ID}',
    'success_url' => $YOUR_DOMAIN . '?success=true&session_id={CHECKOUT_SESSION_ID}',
    'subscription_data' => [
      'trial_period_days' => 7,
      'billing_cycle_anchor' => 1672531200,
    ],
    'subscription_data' => [
      'billing_cycle_anchor' => 1672531200,
    ],
    'discounts' => [[
        'coupon' => '{{COUPON_ID}}',
    ]],
    'customer' => 'cus_123',
    'automatic_tax' => [
      'enabled' => true,
    ],
  ]);
  header("HTTP/1.1 303 See Other");
  header("Location: " . $checkout_session->url);
            // This is a public sample test API key.
            // Don't submit any personally identifiable information in requests made with this key.
            // Sign in to see your own test API key embedded in code samples.
            // Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
            services.AddSingleton(new StripeClient("<<YOUR_SECRET_KEY>>"));
            var priceOptions = new PriceListOptions
            {
                LookupKeys = new List<string> {
                    Request.Form["lookup_key"]
                }
            };
            StripeList<Price> prices = _client.V1.Prices.List(priceOptions);
            var options = new SessionCreateOptions
            {
                LineItems = new List<SessionLineItemOptions>
                {
                  new SessionLineItemOptions
                  {
                    Price = prices.Data[0].Id,
                    Quantity = 1,
                  },
                },
                Mode = "subscription",
                SuccessUrl = domain + "/success.html?session_id={CHECKOUT_SESSION_ID}",
                SuccessUrl = domain + "?success=true&session_id={CHECKOUT_SESSION_ID}",
                SubscriptionData = new SessionSubscriptionDataOptions
                {
                    TrialPeriodDays = 7,
                    BillingCycleAnchor = 1672531200,
                },
                SubscriptionData = new SessionSubscriptionDataOptions
                {
                    BillingCycleAnchor = 1672531200,
                },
                Customer = "cus_123",
      CustomerAccount: stripe.String("acct_123"),
                AutomaticTax = new SessionAutomaticTaxOptions { Enabled = true },
                CustomerAccount = "acct_123",
            };
            Session session = _client.V1.Checkout.Sessions.Create(options);
            Response.Headers.Add("Location", session.Url);
            return new StatusCodeResult(303);
            var options = new Stripe.BillingPortal.SessionCreateOptions
            {
                Customer = checkoutSession.CustomerId,
                ReturnUrl = returnUrl,
            };
            var session = _client.V1.BillingPortal.Sessions.Create(options);
            var options = new Stripe.BillingPortal.SessionCreateOptions
            {
                CustomerAccount = checkoutSession.CustomerAccount,
                ReturnUrl = returnUrl,
            };
            var session = _client.V1.BillingPortal.Sessions.Create(options);
            Response.Headers.Add("Location", session.Url);
            return new StatusCodeResult(303);
    [Route("webhook")]
    [ApiController]
    public class WebhookController : Controller
    {
        [HttpPost]
        public async Task<IActionResult> Index()
        {
            // To run this example, set an environment variable STRIPE_WEBHOOK_SECRET to
            // your endpoint's unique secret.
            //
            // If you are testing with the CLI, find the secret by running 'stripe listen'.
            // If you are using an endpoint defined with the API or dashboard, look in
            // your webhook settings at https://dashboard.stripe.com/webhooks.
            //
            // Don't include webhook secrets in code.
            var endpointSecret = Environment.GetEnvironmentVariable("STRIPE_WEBHOOK_SECRET");

            var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();

            try
            {
                var stripeEvent = EventUtility.ParseEvent(json);
                var signatureHeader = Request.Headers["Stripe-Signature"];
                stripeEvent = EventUtility.ConstructEvent(json,
                        signatureHeader, endpointSecret);
                // If on SDK version < 46, use class Events instead of EventTypes
                if (stripeEvent.Type == EventTypes.CustomerSubscriptionDeleted)
                {
                    var subscription = stripeEvent.Data.Object as Subscription;
                    Console.WriteLine("A subscription was canceled.", subscription.Id);
                    // Then define and call a method to handle the successful payment intent.
                    // handleSubscriptionCanceled(subscription);
                }
                else if (stripeEvent.Type == EventTypes.CustomerSubscriptionUpdated)
                {
                    var subscription = stripeEvent.Data.Object as Subscription;
                    Console.WriteLine("A subscription was updated.", subscription.Id);
                    // Then define and call a method to handle the successful payment intent.
                    // handleSubscriptionUpdated(subscription);
                }
                else if (stripeEvent.Type == EventTypes.CustomerSubscriptionCreated)
                {
                    var subscription = stripeEvent.Data.Object as Subscription;
                    Console.WriteLine("A subscription was created.", subscription.Id);
                    // Then define and call a method to handle the successful payment intent.
                    // handleSubscriptionUpdated(subscription);
                }
                else if (stripeEvent.Type == EventTypes.CustomerSubscriptionTrialWillEnd)
                {
                    var subscription = stripeEvent.Data.Object as Subscription;
                    Console.WriteLine("A subscription trial will end", subscription.Id);
                    // Then define and call a method to handle the successful payment intent.
                    // handleSubscriptionUpdated(subscription);
                }
                else if (stripeEvent.Type == EventTypes.ActiveEntitlementSummaryUpdated)
                {
                    var summary = stripeEvent.Data.Object as ActiveEntitlementSummary;
                    Console.WriteLine("Active entitlement summary updated for customer", summary.Customer);
                    // Then define and call a method to handle active entitlement summary updated.
                    // handleEntitlementUpdated($subscription);
                }
                else
                {
                    Console.WriteLine("Unhandled event type: {0}", stripeEvent.Type);
                }
                return Ok();
            }
            catch (StripeException e)
            {
                Console.WriteLine("Error: {0}", e.Message);
                return BadRequest();
            }
        }
    "github.com/stripe/stripe-go/v86"
    "github.com/stripe/stripe-go/v86/webhook"
    // This is a public sample test API key.
    // Don't submit any personally identifiable information in requests made with this key.
    // Sign in to see your own test API key embedded in code samples.
    // Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
    sc = stripe.NewClient("<<YOUR_SECRET_KEY>>")
    params := &stripe.PriceListParams{
      LookupKeys: stripe.StringSlice([]string{
        lookup_key,
      }),
    }
    var price *stripe.Price
    for p, err := range sc.V1Prices.List(context.TODO(), params).All(context.TODO()) {
      if err != nil {
        log.Printf("sc.V1Prices.List: %v", err)
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
      }
      price = p
      break
    }
    if price == nil {
      log.Printf(">>>>>>>>>>>>>>>>>>>>>>>>>>> Add a price lookup key to checkout.html for the demo <<<<<<<<<<<<<<<<<<<<<<<<")
      return
    }
    checkoutParams := &stripe.CheckoutSessionCreateParams{
      Mode: stripe.String(stripe.CheckoutSessionModeSubscription),
      LineItems: []*stripe.CheckoutSessionCreateLineItemParams{
        &stripe.CheckoutSessionCreateLineItemParams{
          Price:    stripe.String(price.ID),
          Quantity: stripe.Int64(1),
        },
      },
      SubscriptionData: &stripe.CheckoutSessionCreateSubscriptionDataParams{
        TrialPeriodDays: stripe.Int64(7),
        BillingCycleAnchor: stripe.Int64(1672531200),
      },
      SubscriptionData: &stripe.CheckoutSessionCreateSubscriptionDataParams{
        BillingCycleAnchor: stripe.Int64(1672531200),
      },
      Discounts: []*stripe.CheckoutSessionCreateDiscountParams{
        &stripe.CheckoutSessionCreateDiscountParams{
          Coupon: stripe.String("gBY6sFUf"),
        },
      },
      SuccessURL: stripe.String(domain + "/success.html?session_id={CHECKOUT_SESSION_ID}"),
      SuccessURL: stripe.String(domain + "?success=true&session_id={CHECKOUT_SESSION_ID}"),
      Customer: stripe.String("cus_123"),
      CustomerAccount: stripe.String("acct_123"),
      AutomaticTax: &stripe.CheckoutSessionCreateAutomaticTaxParams{
        Enabled: stripe.Bool(true),
      },
    }

    s, err := sc.V1CheckoutSessions.Create(context.TODO(), checkoutParams)
    http.Redirect(w, r, s.URL, http.StatusSeeOther)
    // Authenticate your user.
    params := &stripe.BillingPortalSessionCreateParams{
      Customer:  stripe.String(s.Customer.ID),
      ReturnURL: stripe.String(domain),
    }
    ps, _ := sc.V1BillingPortalSessions.Create(context.TODO(), params)
    log.Printf("sc.V1BillingPortalSessions.Create: %v", ps.URL)
    // Authenticate your user.
    params := &stripe.BillingPortalSessionCreateParams{
      CustomerAccount: stripe.String(s.CustomerAccount),
      ReturnURL: stripe.String(domain),
    }
    ps, _ := sc.V1BillingPortalSessions.Create(context.TODO(), params)
    log.Printf("sc.V1BillingPortalSessions.Create: %v", ps.URL)
    http.Redirect(w, r, ps.URL, http.StatusSeeOther)
func handleWebhook(w http.ResponseWriter, req *http.Request) {
    const MaxBodyBytes = int64(65536)
    bodyReader := http.MaxBytesReader(w, req.Body, MaxBodyBytes)
    payload, err := ioutil.ReadAll(bodyReader)
    if err != nil {
      fmt.Fprintf(os.Stderr, "Error reading request body: %v\n", err)
      w.WriteHeader(http.StatusServiceUnavailable)
      return
    }

    // To run this example, set an environment variable STRIPE_WEBHOOK_SECRET to
    // your endpoint's unique secret.
    //
    // If you are testing with the CLI, find the secret by running 'stripe listen'.
    // If you are using an endpoint defined with the API or dashboard, look in
    // your webhook settings at https://dashboard.stripe.com/webhooks.
    //
    // Don't include webhook secrets in code.
    endpointSecret := os.Getenv("STRIPE_WEBHOOK_SECRET")

    signatureHeader := req.Header.Get("Stripe-Signature")
    event, err := sc.ConstructEvent(payload, signatureHeader, endpointSecret)
    if err != nil {
      fmt.Fprintf(os.Stderr, "⚠️  Webhook signature verification failed. %v\n", err)
      w.WriteHeader(http.StatusBadRequest) // Return a 400 error on a bad signature
      return
    }
    // Unmarshal the event data into an appropriate struct depending on its Type
    switch event.Type {
    case "customer.subscription.deleted":
      var subscription stripe.Subscription
      err := json.Unmarshal(event.Data.Raw, &subscription)
      if err != nil {
        fmt.Fprintf(os.Stderr, "Error parsing webhook JSON: %v\n", err)
        w.WriteHeader(http.StatusBadRequest)
        return
      }
      log.Printf("Subscription deleted for %d.", subscription.ID)
      // Then define and call a func to handle the deleted subscription.
      // handleSubscriptionCanceled(subscription)
    case "customer.subscription.updated":
      var subscription stripe.Subscription
      err := json.Unmarshal(event.Data.Raw, &subscription)
      if err != nil {
        fmt.Fprintf(os.Stderr, "Error parsing webhook JSON: %v\n", err)
        w.WriteHeader(http.StatusBadRequest)
        return
      }
      log.Printf("Subscription updated for %d.", subscription.ID)
      // Then define and call a func to handle the successful attachment of a PaymentMethod.
      // handleSubscriptionUpdated(subscription)
    case "customer.subscription.created":
      var subscription stripe.Subscription
      err := json.Unmarshal(event.Data.Raw, &subscription)
      if err != nil {
        fmt.Fprintf(os.Stderr, "Error parsing webhook JSON: %v\n", err)
        w.WriteHeader(http.StatusBadRequest)
        return
      }
      log.Printf("Subscription created for %d.", subscription.ID)
      // Then define and call a func to handle the successful attachment of a PaymentMethod.
      // handleSubscriptionCreated(subscription)
    case "customer.subscription.trial_will_end":
      var subscription stripe.Subscription
      err := json.Unmarshal(event.Data.Raw, &subscription)
      if err != nil {
        fmt.Fprintf(os.Stderr, "Error parsing webhook JSON: %v\n", err)
        w.WriteHeader(http.StatusBadRequest)
        return
      }
      log.Printf("Subscription trial will end for %d.", subscription.ID)
      // Then define and call a func to handle the successful attachment of a PaymentMethod.
      // handleSubscriptionTrialWillEnd(subscription)
    case "entitlements.active_entitlement_summary.updated":
      var subscription stripe.Subscription
      err := json.Unmarshal(event.Data.Raw, &subscription)
      if err != nil {
        fmt.Fprintf(os.Stderr, "Error parsing webhook JSON: %v\n", err)
        w.WriteHeader(http.StatusBadRequest)
        return
      }
      log.Printf("Active entitlement summary updated for %d.", subscription.ID)
      // Then define and call a func to handle active entitlement summary updated.
      // handleEntitlementUpdated(subscription)
    default:
      fmt.Fprintf(os.Stderr, "Unhandled event type: %s\n", event.Type)
    }
    w.WriteHeader(http.StatusOK)
  }
require github.com/stripe/stripe-go/v86 v86.4.0
    // This is a public sample test API key.
    // Don't submit any personally identifiable information in requests made with this key.
    // Sign in to see your own test API key embedded in code samples.
    // Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
    StripeClient client = new StripeClient("<<YOUR_SECRET_KEY>>");
      PriceListParams priceParams = PriceListParams.builder().addLookupKey(request.queryParams("lookup_key")).build();
      StripeCollection<Price> prices = client.v1().prices().list(priceParams);
      SessionCreateParams params = SessionCreateParams.builder()
          .addLineItem(
              SessionCreateParams.LineItem.builder().setPrice(prices.getData().get(0).getId()).setQuantity(1L).build())
          .setMode(SessionCreateParams.Mode.SUBSCRIPTION)
          .setSuccessUrl(YOUR_DOMAIN + "/success.html?session_id={CHECKOUT_SESSION_ID}")
          .setSuccessUrl(YOUR_DOMAIN + "?success=true&session_id={CHECKOUT_SESSION_ID}")
          .setSubscriptionData(SessionCreateParams.SubscriptionData.builder().setTrialPeriodDays(7L).setBillingCycleAnchor(1672531200).build())
          .setSubscriptionData(SessionCreateParams.SubscriptionData.builder().setBillingCycleAnchor(1672531200).build())
          .addDiscount(SessionCreateParams.Discount.builder().setCoupon("{{COUPON_ID}}").build())
          .setCustomer("cus_JyTTNqVDAoRYE1")
          .setCustomerAccount("acct_123")
          .setAutomaticTax(
            SessionCreateParams.AutomaticTax.builder()
              .setEnabled(true)
              .build())
          .build();
      Session session = client.v1().checkout().sessions().create(params);
      response.redirect(session.getUrl(), 303);
      com.stripe.param.billingportal.SessionCreateParams params = new com.stripe.param.billingportal.SessionCreateParams.Builder()
          .setCustomer(checkoutSession.getCustomer())
          .setReturnUrl(YOUR_DOMAIN).build();

      com.stripe.model.billingportal.Session portalSession = client.v1().billingPortal().sessions().create(params);

      com.stripe.param.billingportal.SessionCreateParams params = new com.stripe.param.billingportal.SessionCreateParams.Builder()
          .setCustomerAccount(checkoutSession.getCustomerAccount())
          .setReturnUrl(YOUR_DOMAIN).build();

      com.stripe.model.billingportal.Session portalSession = client.v1().billingPortal().sessions().create(params);

      response.redirect(portalSession.getUrl(), 303);
      return "";
    post("/webhook", (request, response) -> {
      String payload = request.body();
      Event event = null;
      try {
        event = ApiResource.GSON.fromJson(payload, Event.class);
      } catch (JsonSyntaxException e) {
        // Invalid payload
        System.out.println("⚠️  Webhook error while parsing basic request.");
        response.status(400);
        return "";
      }
      String sigHeader = request.headers("Stripe-Signature");
      if (endpointSecret != null && sigHeader != null) {
        // Only verify the event if you have an endpoint secret defined.
        // Otherwise use the basic event deserialized with GSON.
        try {
          event = client.constructEvent(payload, sigHeader, endpointSecret);
        } catch (SignatureVerificationException e) {
          // Invalid signature
          System.out.println("⚠️  Webhook error while validating signature.");
          response.status(400);
          return "";
        }
      }
      // Deserialize the nested object inside the event
      EventDataObjectDeserializer dataObjectDeserializer = event.getDataObjectDeserializer();
      StripeObject stripeObject = null;
      if (dataObjectDeserializer.getObject().isPresent()) {
        stripeObject = dataObjectDeserializer.getObject().get();
      } else {
        // Deserialization failed, probably due to an API version mismatch.
        // Refer to the Javadoc documentation on `EventDataObjectDeserializer` for
        // instructions on how to handle this case, or return an error here.
      }
      // Handle the event
      Subscription subscription = null;
      switch (event.getType()) {
        case "customer.subscription.deleted":
          subscription = (Subscription) stripeObject;
          // Then define and call a function to handle the event
          // customer.subscription.deleted
          // handleSubscriptionTrialEnding(subscription);
        case "customer.subscription.trial_will_end":
          subscription = (Subscription) stripeObject;
          // Then define and call a function to handle the event
          // customer.subscription.trial_will_end
          // handleSubscriptionDeleted(subscriptionDeleted);
        case "customer.subscription.created":
          subscription = (Subscription) stripeObject;
          // Then define and call a function to handle the event
          // customer.subscription.created
          // handleSubscriptionCreated(subscription);
        case "customer.subscription.updated":
          subscription = (Subscription) stripeObject;
          // Then define and call a function to handle the event
          // customer.subscription.updated
          // handleSubscriptionUpdated(subscription);
        case "entitlements.active_entitlement_summary.updated":
          subscription = (Subscription) stripeObject;
          // Then define and call a function to handle the event
          // entitlements.active_entitlement_summary.updated
          // handleEntitlementUpdated(subscription);
          // ... handle other event types
        default:
          System.out.println("Unhandled event type: " + event.getType());
      }
      response.status(200);
      return "";
    });
1. Build the server

~~~
pip3 install -r requirements.txt
~~~
1. Build the server

~~~
bundle install
~~~
1. Build the server

~~~
composer install
~~~
1. Build the server

~~~
dotnet restore
~~~
1. Build the server

~~~
mvn package
~~~

2. Run the server

~~~
export FLASK_APP=server.py
python3 -m flask run --port=4242
~~~

2. Run the server

~~~
ruby server.rb -o 0.0.0.0
~~~

2. Run the server

~~~
php -S 127.0.0.1:4242 --docroot=public
~~~

2. Run the server

~~~
dotnet run
~~~

2. Run the server

~~~
java -cp target/sample-jar-with-dependencies.jar com.stripe.sample.Server
~~~

3. Build the client app

~~~
npm install
~~~

4. Run the client app

~~~
npm start
~~~

5. Go to [http://localhost:3000/checkout](http://localhost:3000/checkout)

3. Go to [http://localhost:4242/checkout.html](http://localhost:4242/checkout.html)

3. Build the client app

~~~
npm install
~~~

4. Run the client app

~~~
npm start
~~~

5. Go to [http://localhost:3000/checkout](http://localhost:3000/checkout)

3. Go to [http://localhost:4242/checkout.html](http://localhost:4242/checkout.html)

3. Build the client app

~~~
npm install
~~~

4. Run the client app

~~~
npm start
~~~

5. Go to [http://localhost:3000/checkout](http://localhost:3000/checkout)

3. Go to [http://localhost:4242/checkout.html](http://localhost:4242/checkout.html)

3. Build the client app

~~~
npm install
~~~

4. Run the client app

~~~
npm start
~~~

5. Go to [http://localhost:3000/checkout](http://localhost:3000/checkout)

3. Go to [http://localhost:4242/checkout.html](http://localhost:4242/checkout.html)

3. Build the client app

~~~
npm install
~~~

4. Run the client app

~~~
npm start
~~~

5. Go to [http://localhost:3000/checkout](http://localhost:3000/checkout)

3. Go to [http://localhost:4242/checkout.html](http://localhost:4242/checkout.html)
1. Run the server

~~~
go run server.go
~~~

2. Build the client app

~~~
npm install
~~~

3. Run the client app

~~~
npm start
~~~

4. Go to [http://localhost:3000/checkout](http://localhost:3000/checkout)
1. Run the server

~~~
go run server.go
~~~

2. Go to [http://localhost:4242/checkout.html](http://localhost:4242/checkout.html)
1. Build the application

~~~
npm install
~~~

2. Run the application

~~~
npm start
~~~

3. Go to [http://localhost:3000/checkout](http://localhost:3000/checkout)
1. Build the server

~~~
npm install
~~~

2. Run the server

~~~
npm start
~~~

3. Go to [http://localhost:4242/checkout.html](http://localhost:4242/checkout.html)
## Nächste Schritte

#### [Abonnementpreise ändern](https://docs.stripe.com/billing/subscriptions/change-price.md)

Aktualisieren Sie Abonnements, um Kundinnen und Kunden zu bearbeiten, die ihren Preisplan hoch- oder herabstufen.

#### [Anteilmäßige Verrechnungen anwenden](https://docs.stripe.com/billing/subscriptions/prorations.md)

Erfahren Sie, wie Sie eine Kundenrechnung so anpassen, dass Preisänderungen während eines Zyklus genau widergespiegelt werden.

#### [Upselling anbieten](https://docs.stripe.com/payments/checkout/upsells.md)

Anreize für Kundinnen/Kunden schaffen mit Rabatten für die Zusage zu längeren Abrechnungsintervallen.
