# Persönliche Zahlungen annehmen
# Persönliche Zahlungen annehmen
Diese Anleitung zeigt Ihnen, wie Sie persönliche Zahlungen in Ihrem eigenen Point of Sale-(POS)-Anmeldeformular mit Stripe Terminal akzeptieren. Sie benötigen keine Hardware, um diese Schritte mit unserem [simulierten Lesegerät](https://docs.stripe.com/terminal/references/testing.md#simulated-reader) durchzuführen. Optional können Sie das Beispiel herunterladen und das Anmeldeformular ausführen.
Wenn Sie bereit sind, ein physisches Lesegerät zu verwenden, müssen Sie nur den [Lesegerät-Registrierungsschritt](https://docs.stripe.com/terminal/quickstart.md#register-reader) (für Server-gestützte Integrationen) oder den [Lesegerät-Erkennungsschritt](https://docs.stripe.com/terminal/quickstart.md#discover-reader) (für SDK-Integrationen) aktualisieren.
> #### Support für Verifone-Lesegeräte
>
> Verifone-Lesegeräte werden in der privaten Vorschau in den Vereinigten Staaten und in Kanada unterstützt. Einige Verifone-Lesegeräte werden in Irland und dem Vereinigten Königreich (V660p, UX700, P630) und in Singapur (V660p, P630) in der privaten Vorschau unterstützt. Um an der Vorschau teilzunehmen, müssen Sie das [Sales-Team kontaktieren und das entsprechende Lesegerät bestellen](https://stripe.com/contact/sales).
### 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
\ncom.stripe\nstripe-java\n{VERSION}\n
```
#### 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/v85
```
#### 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
```
### Erstellen Sie Standorte für Ihre Lesegeräte
[Erstellen Sie Standorte](https://docs.stripe.com/terminal/fleet/locations-and-zones.md), um Ihre Lesegeräte zu organisieren. Standorte gruppieren Lesegeräte und ermöglichen es ihnen, automatisch die für ihre Einsatzregion erforderliche Gerätekonfiguration herunterzuladen. Sie müssen jedem Lesegerät einen Standort zuweisen, wenn Sie es [registrieren](https://docs.stripe.com/terminal/fleet/register-readers.md), was Sie über die API oder das Dashboard tun können.
### Lesegerät registrieren
Mit einem simulierten Lesegerät können Sie schnell beginnen und eine funktionierende Integration aufbauen, ohne physische Hardware anfordern zu müssen. Erstellen Sie ein simuliertes Lesegerät, indem Sie den speziellen Registrierungscode `simulated-s700` verwenden. Verfolgen Sie die ID Ihres Lesegeräts, sodass Sie sie später zur Verarbeitung einer Zahlung auf dem Lesegerät verwenden können.
### Lesegerät registrieren
Mit einem simulierten Lesegerät können Sie schnell beginnen und eine funktionierende Integration aufbauen, ohne dass Sie physische Hardware benötigen. Erstellen Sie ein simuliertes Lesegerät, indem Sie den speziellen Registrierungscode `simulated-s710` verwenden. Bewahren Sie Ihre Lesegerät-ID sorgfältig auf, damit Sie sie später für die Verarbeitung einer Zahlung auf dem Lesegerät verwenden können.
### Lesegerät registrieren
Mit einem simulierten Lesegerät können Sie schnell beginnen und eine funktionierende Integration aufbauen, ohne dass Sie physische Hardware benötigen. Erstellen Sie ein simuliertes Lesegerät, indem Sie den speziellen Registrierungscode `simulated-v660p` verwenden. Bewahren Sie Ihre Lesegerät-ID sorgfältig auf, damit Sie sie später für die Verarbeitung einer Zahlung auf dem Lesegerät verwenden können.
### Lesegerät registrieren
Mit einem simulierten Lesegerät können Sie schnell beginnen und eine funktionierende Integration aufbauen, ohne dass Sie physische Hardware benötigen. Erstellen Sie ein simuliertes Lesegerät, indem Sie den speziellen Registrierungscode `simulated-wpe` verwenden. Bewahren Sie Ihre Lesegerät-ID sorgfältig auf, damit Sie sie später für die Verarbeitung einer Zahlung auf dem Lesegerät verwenden können.
### PaymentIntent erstellen
Erstellen Sie einen PaymentIntent auf Ihrem Server. Ein PaymentIntent verfolgt den Zahlungslebenszyklus von Kundinnen/Kunden, einschließlich aller fehlgeschlagenen Zahlungsversuche, damit sie nur einmal belastet werden. Speichern Sie die PaymentIntent-ID zur späteren Verarbeitung.
### PaymentIntent auf Ihrem Lesegerät verarbeiten
Erstellen Sie einen PaymentIntent mit dem konkreten Betrag und wickeln Sie die Zahlung auf Ihrem simulierten Lesegerät ab. Das Lesegerät fordert die Kundin bzw. den Kunden auf, die Karte einzuführen oder aufzulegen, bevor es einen Autorisierungsversuch unternimmt.
### Vorlage der Karte auf Ihrem Lesegerät simulieren
> Bei einem echten Transaktionsablauf führt die Kundin/der Kunde ihre/seine Karte in das physische Lesegerät ein oder hält sie daran. Bei einem simulierten Lesegerät simulieren Sie den Schritt der Kartenvorlage, indem Sie einen weiteren API-Aufruf tätigen.
Dieser Aufruf bestätigt den PaymentIntent erfolgreich mit einer Testkarte. Sie können auch andere Testkarten ausprobieren.
### PaymentIntent erfassen
Nachdem der PaymentIntent erfolgreich bestätigt wurde, können Sie ihn erfassen, um die Geldbewegungen durchzuführen.
### Umgang mit Fehlern
Jedes Fehlerszenario hat einen bestimmten Code, den Ihre Anwendung verarbeiten muss. Fehler erfordern in der Regel das Eingreifen eines Mitarbeiters/einer Mitarbeiterin im Laden. Zeigen Sie eine entsprechende Nachricht in Ihrer POS-Anwendung an, damit er/sie entsprechend reagieren kann. Weitere Informationen finden Sie in [der Dokumentation zum Umgang mit Fehlern](https://docs.stripe.com/terminal/payments/collect-card-payment.md?terminal-sdk-platform=server-driven#handle-errors).
### Anwendung ausführen
Führen Sie Ihren Server aus und gehen Sie zu http://localhost:4242.
### Integration mit Testkarte ausprobieren
Sie können das simulierte Lesegerät so konfigurieren, dass Sie verschiedene Abläufe in Ihrer Point-of-Sale-Anwendung testen, z. B. unterschiedliche Kartenmarken oder Fehlerszenarien wie eine abgelehnte Zahlung. Um dieses Verhalten zu aktivieren, übergeben Sie eine Test-Zahlungsmethode an den API-Aufruf [derzeitige Zahlungsmethode](https://docs.stripe.com/api/terminal/readers/present_payment_method.md).
| Scenario | Card Number |
| ------------------- | ---------------- |
| Payment succeeds | 4242424242424242 |
| Payment is declined | 4000000000009995 |
### 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
\ncom.stripe\nstripe-java\n{VERSION}\n
```
#### 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/v85
```
#### 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
```
> #### Terminal-Zugriff auf macOS
>
> Das Stripe Terminal SDK erfordert Zugriff auf das lokale Netzwerk. Wenn Sie macOS verwenden, müssen Sie Ihren Browser-Apps explizit Zugriff auf lokale Netzwerkgeräte gewähren. Weitere Informationen finden Sie im [Stripe-Support-Artikel](https://support.stripe.com/questions/ensuring-stripe-terminal-javascript-sdk-functionality-on-macos-15).
### ConnectionToken-Endpoint erstellen
Um sich mit einem Lesegerät verbinden zu können, muss das Backend dem SDK erlauben, es mit Ihrem Stripe-Konto zu verwenden. Dazu stellt es dem SDK den Geheimschlüssel aus einem [ConnectionToken](https://docs.stripe.com/api/terminal/connection_tokens.md) zur Verfügung. Erstellen Sie Verbindungstoken nur für vertrauenswürdige Clients und [übergeben Sie eine Standort-ID](https://docs.stripe.com/terminal/fleet/locations-and-zones.md#connection-tokens), wenn Sie ein Verbindungstoken erstellen, um den Zugriff auf Lesegeräte zu steuern. Wenn Sie Connect verwenden, können Sie das [Verbindungstoken](https://docs.stripe.com/terminal/features/connect.md) auf die relevanten verbundenen Konten beschränken.
### SDK installieren
Dieses Skript muss immer direkt von https://js.stripe.com geladen werden, damit es mit der neuesten Lesegerätesoftware kompatibel ist. Binden Sie das Skript nicht in ein Bundle ein und hosten Sie nicht selbst eine Kopie, da dies Ihre Integration ohne Vorwarnung beschädigen könnte. Wir stellen außerdem ein npm-Paket bereit, das das Laden und Verwenden des Terminal JS SDK als Modul erleichtert. Weitere Informationen finden Sie unter [Projekt auf GitHub](https://github.com/stripe/terminal-js).
### Erstellen Sie Standorte für Ihre Lesegeräte
[Erstellen Sie Standorte](https://docs.stripe.com/terminal/fleet/locations-and-zones.md), um Ihre Lesegeräte zu organisieren. Standorte gruppieren Lesegeräte und ermöglichen es ihnen, automatisch die für ihre Einsatzregion erforderliche Gerätekonfiguration herunterzuladen. Sie müssen jedem Lesegerät einen Standort zuweisen, wenn Sie es [registrieren](https://docs.stripe.com/terminal/fleet/register-readers.md), was Sie über die API oder das Dashboard tun können.
### ConnectionToken abrufen
Um dem SDK Zugriff auf diesen Endpoint zu ermöglichen, erstellen Sie eine Funktion in Ihrer Webanwendung, die ein ConnectionToken aus Ihrem Backend anfordert und den geheimen Schlüssel aus dem ConnectionToken-Objekt zurückgibt.
### SDK initialisieren
Um eine `StripeTerminal`-Instanz in Ihrer JavaScript-Anwendung zu initialisieren, müssen Sie die Funktion `onFetchConnectionToken` bereitstellen. Außerdem müssen Sie die Funktion `onUnexpectedReaderDisconnect` bereitstellen, mit der unerwartete Verbindungsabbrüche beim Lesegerät verarbeitet werden.
### Lesegeräte suchen
Das Stripe Terminal SDK umfasst ein integriertes simuliertes Kartenlesegerät, damit Sie Ihre App entwickeln und testen können, ohne eine Verbindung zu physischer Hardware herstellen zu müssen. Um das simulierte Lesegerät zu verwenden, rufen Sie `discoverReaders` auf, um nach Lesegeräten zu suchen, wobei die Option „simuliert“ auf „true“ festgelegt ist.Filtern Sie nach Standort, um passende Lesegeräte einfacher zu finden.
### Mit simuliertem Lesegerät verbinden
Wenn `discoverReaders` ein Ergebnis zurückgibt, rufen Sie `connectReader` zum Verbinden mit dem simulierten Lesegerät auf.
### PaymentIntent erstellen
Fügen Sie einen Endpoint auf Ihrem Server hinzu, der einen PaymentIntent erstellt. Ein PaymentIntent verfolgt den Zahlungslebenszyklus der Kundinnen/Kunden, einschließlich aller fehlgeschlagenen Zahlungsversuche, damit sie nur einmal belastet werden. Geben Sie das Client-Geheimnis des PaymentIntent in der Antwort zurück. Wenn Sie Connect verwenden, können Sie auch [Informationen zu verbundenen Konten](https://docs.stripe.com/terminal/features/connect.md) basierend auf der Zahlungslogik Ihrer Plattform angeben.
### PaymentIntent abrufen
Weisen Sie Ihren Server an, den Zahlungsvorgang mit einem PaymentIntent zu initiieren.
### Angaben zur Zahlungsmethode erfassen
Rufen Sie `collectPaymentMethod` mit dem Client-Geheimnis des PaymentIntent auf, um eine Zahlungsmethode zu erfassen. Wenn eine Verbindung zu einem simulierten Lesegerät besteht, wird mit dieser Methode das PaymentIntent-Objekt sofort mit einer [simulierten Testkarte](https://docs.stripe.com/terminal/references/testing.md#simulated-test-cards) aktualisiert. Ist das verbundene Lesegerät an ein physisches Lesegerät angeschlossen, wartet das verbundene Lesegerät auf die Vorlage einer Karte.
### Zahlung abwickeln
Rufen Sie nach dem erfolgreichen Erfassen der Zahlungsmethodendaten `processPayment` mit dem aktualisierten PaymentIntent auf, um die Zahlung abzuwickeln. Nach einem erfolgreichen Aufruf lautet der PaymentIntent-Status `requires_capture` für manuelle Erfassungen oder `succeeded` für automatische Erfassungen.
### Endpoint erstellen, um PaymentIntent zu erfassen
Erstellen Sie einen Endpoint in Ihrem Backend, der eine PaymentIntent-ID akzeptiert und eine Anfrage an die Stripe API sendet, um sie zu erfassen.
### PaymentIntent erfassen
Wenn Sie bei PaymentIntent Erstellung `capture_method` als `manual` definiert haben, gibt das SDK einen autorisierten, aber nicht erfassten PaymentIntent an Ihre Anwendung zurück. Wenn der PaymentIntent-Status `requires_capture` lautet, benachrichtigen Sie Ihr Backend, um den PaymentIntent zu erfassen.
Bei verbundenen Konten sollten Sie vor der manuellen Zahlungsbestätigung den Wert von `application_fee_amount` im PaymentIntent prüfen und bei Bedarf anpassen.
### Anwendung ausführen
Führen Sie Ihren Server aus und gehen Sie zu [localhost:4242](http://localhost:4242).
### Integration mit Testkarte ausprobieren
Sie können das simulierte Lesegerät so konfigurieren, dass Sie verschiedene Abläufe in Ihrer Point-of-Sale-Anwendung testen, zum Beispiel unterschiedliche Kartenmarken oder Fehlerszenarien wie eine abgelehnte Zahlung. Um dieses Verhalten zu aktivieren, fügen Sie diese Codezeile ein, bevor Sie `collectPaymentMethod` aufrufen.
| Scenario | Card Number |
| ------------------- | ---------------- |
| Payment succeeds | 4242424242424242 |
| Payment is declined | 4000000000009995 |
### 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
\ncom.stripe\nstripe-java\n{VERSION}\n
```
#### 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/v85
```
#### 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
```
> #### Terminal-Zugriff auf macOS
>
> Das Stripe Terminal SDK erfordert Zugriff auf das lokale Netzwerk. Wenn Sie macOS verwenden, müssen Sie Ihren Browser-Apps explizit Zugriff auf lokale Netzwerkgeräte gewähren. Weitere Informationen finden Sie im [Stripe-Support-Artikel](https://support.stripe.com/questions/ensuring-stripe-terminal-javascript-sdk-functionality-on-macos-15).
### ConnectionToken-Endpoint erstellen
Um sich mit einem Lesegerät verbinden zu können, muss das Backend dem SDK erlauben, es mit Ihrem Stripe-Konto zu verwenden. Dazu stellt es dem SDK den Geheimschlüssel aus einem [ConnectionToken](https://docs.stripe.com/api/terminal/connection_tokens.md) zur Verfügung. Erstellen Sie Verbindungstoken nur für vertrauenswürdige Clients und [übergeben Sie eine Standort-ID](https://docs.stripe.com/terminal/fleet/locations-and-zones.md#connection-tokens), wenn Sie ein Verbindungstoken erstellen, um den Zugriff auf Lesegeräte zu steuern. Wenn Sie Connect verwenden, können Sie das [Verbindungstoken](https://docs.stripe.com/terminal/features/connect.md) auf die relevanten verbundenen Konten beschränken.
### SDK installieren
Das iOS SDK ist [Open Source](https://github.com/stripe/stripe-terminal-ios), vollständig dokumentiert und kompatibel mit Apps, die iOS 10 oder höher unterstützen. Importieren Sie das Stripe-SDK in den UIViewController Ihres Bezahlvorgangs.
#### CocoaPods
Fügen Sie diese Zeile in Ihre Podfile ein und verwenden Sie ab jetzt anstelle der .xcodeproj-Datei die xcworkspace-Datei zum Öffnen Ihres Projekts in Xcode.
```bash
pod 'StripeTerminal', '~> 5.0'
```
#### Carthage
Fügen Sie diese Zeile in Ihre Cartfile ein.
```bash
github "stripe/stripe-terminal-ios"
```
#### XCFramework
1. Laden Sie StripeTerminal.xcframework.zip aus der neuesten Version auf GitHub herunter.
1. Dekomprimieren Sie die Datei und ziehen Sie die .xcframework-Datei in Ihr Projekt. Wählen Sie dabei unbedingt „Elemente kopieren, falls nötig“ aus.
1. Stellen Sie sicher, dass „.xcframework“ im Abschnitt „Frameworks, Libraries, and Embedded Content“ (Frameworks, Bibliotheken und eingebetteter Inhalt) Ihres Anwendungsziels in Xcode enthalten und auf „Embed & Sign“ (Einbetten und signieren) eingestellt ist.
#### Swift Package Manager
1. Wählen Sie in Xcode in der Menüleiste die Option **Datei** > **Pakete hinzufügen…** aus.
1. Geben Sie die GitHub-URL des Stripe Terminal iOS SDK ein:
```bash
https://github.com/stripe/stripe-terminal-ios
```
### Erstellen Sie Standorte für Ihre Lesegeräte
[Erstellen Sie Standorte](https://docs.stripe.com/terminal/fleet/locations-and-zones.md), um Ihre Lesegeräte zu organisieren. Standorte gruppieren Lesegeräte und ermöglichen es ihnen, automatisch die für ihre Einsatzregion erforderliche Gerätekonfiguration herunterzuladen. Sie müssen jedem Lesegerät einen Standort zuweisen, wenn Sie es [registrieren](https://docs.stripe.com/terminal/fleet/register-readers.md), was Sie über die API oder das Dashboard tun können.
### App konfigurieren
Damit Ihre App mit dem Stripe Terminal SDK verwendet werden kann, müssen Sie in Xcode einige Änderungen an Ihrer Datei „Info.plist“ vornehmen.
#### Standort
Aktivieren Sie Standortdienste mit dem folgenden Schlüssel-Wert-Paar.
```bash
NSLocationWhenInUseUsageDescription\nLocation access is required to accept payments.
```
#### Hintergrundmodi
Stellen Sie sicher, dass Ihre App im Hintergrund läuft und mit den Bluetooth-Lesegeräten verbunden bleibt.
```bash
UIBackgroundModes\n\nbluetooth-central\n
```
#### Bluetooth Peripheral
Übergeben Sie Validierungsprüfungen, wenn Sie die App an den App Store übermitteln.
```bash
NSBluetoothPeripheralUsageDescription\nBluetooth access is required to connect to supported bluetooth card readers.
```
#### Bluetooth Always
Ihre App sollte ein Dialogfeld für Bluetooth-Berechtigungen anzeigen.
```bash
NSBluetoothAlwaysUsageDescription\nThis app uses Bluetooth to connect to supported card readers.
```
### ConnectionToken abrufen
Implementieren Sie in Ihrer App das ConnectionTokenProvider-Protokoll, das eine einzelne Funktion definiert, die ein Verbindungstoken vom Backend anfordert.
### SDK initialisieren
Geben Sie als Erstes Ihren ConnectionTokenProvider an. Sie können `setTokenProvider` nur einmal in Ihrer App aufrufen und müssen den Aufruf vor dem Zugriff auf `Terminal.shared` durchführen.
### Lesegeräte suchen
Das Stripe Terminal SDK umfasst ein integriertes simuliertes Kartenlesegerät, damit Sie Ihre App entwickeln und testen können, ohne eine Verbindung zu physischer Hardware herstellen zu müssen. Um das simulierte Lesegerät zu verwenden, rufen Sie `discoverReaders` auf, um nach Lesegeräten zu suchen, wobei die Option „simuliert“ auf „true“ festgelegt ist.
### Lesegeräte suchen
Das Stripe Terminal SDK umfasst ein integriertes simuliertes Kartenlesegerät, damit Sie Ihre App entwickeln und testen können, ohne eine Verbindung zu physischer Hardware herstellen zu müssen. Um das simulierte Lesegerät zu verwenden, rufen Sie `discoverReaders` auf, um nach Lesegeräten zu suchen, wobei die Option „simuliert“ auf „true“ festgelegt ist. Filtern Sie nach Standort, um passende Lesegeräte einfacher zu finden.
### Mit simuliertem Lesegerät verbinden
Wenn die Delegatmethode `didUpdateDiscoveredReaders` aufgerufen wird, rufen Sie `connectReader` auf, um eine Verbindung zum simulierten Lesegerät herzustellen.
### PaymentIntent erstellen
Erstellen Sie ein [PaymentIntent](https://docs.stripe.com/api/payment_intents.md)-Objekt mithilfe des SDK. Ein PaymentIntent verfolgt den Zahlungslebenszyklus der Kundenkonten, einschließlich aller fehlgeschlagenen Zahlungsversuche, damit sie nur einmal belastet werden.
### PaymentIntent abwickeln
Rufen Sie `processPaymentIntent` mit dem PaymentIntent auf, um eine Zahlungsmethode zu erfassen und die Zahlung zu autorisieren. Wenn eine Verbindung zum simulierten Lesegerät besteht, wird das PaymentIntent-Objekt durch Aufrufen dieser Methode sofort mit einer [simulierten Testkarte](https://docs.stripe.com/terminal/references/testing.md#simulated-test-cards) aktualisiert. Bei einer Verbindung mit einem physischen Lesegerät, wartet das verbundene Lesegerät auf die Vorlage einer Karte. Ein erfolgreicher Aufruf führt zu einem PaymentIntent mit dem Status `requires_capture` für die manuelle Erfassung oder `succeeded` für die automatische Erfassung.
### Endpoint erstellen, um PaymentIntent zu erfassen
Erstellen Sie einen Endpoint in Ihrem Backend, der eine PaymentIntent-ID akzeptiert und eine Anfrage an die Stripe API sendet, um sie zu erfassen.
### PaymentIntent erfassen
Wenn Sie bei PaymentIntent Erstellung `capture_method` als `manual` definiert haben, gibt das SDK einen autorisierten, aber nicht erfassten PaymentIntent an Ihre Anwendung zurück. Wenn der PaymentIntent-Status `requires_capture` lautet, benachrichtigen Sie Ihr Backend, um den PaymentIntent zu erfassen.
Bei verbundenen Konten sollten Sie vor der manuellen Zahlungsbestätigung den Wert von `application_fee_amount` im PaymentIntent prüfen und bei Bedarf anpassen.
### Anwendung ausführen
Führen Sie Ihren Server aus und gehen Sie zu [localhost:4242](http://localhost:4242).
### Integration mit Testkarte ausprobieren
Sie können das simulierte Lesegerät so konfigurieren, dass Sie verschiedene Abläufe in Ihrer Point-of-Sale-Anwendung testen, zum Beispiel unterschiedliche Kartenmarken oder Fehlerszenarien wie eine abgelehnte Zahlung. Um dieses Verhalten zu aktivieren, fügen Sie diese Codezeile ein, bevor Sie `collectPaymentMethod` aufrufen.
| Scenario | Card Number |
| ------------------- | ---------------- |
| Payment succeeds | 4242424242424242 |
| Payment is declined | 4000000000009995 |
### 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
\ncom.stripe\nstripe-java\n{VERSION}\n
```
#### 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/v85
```
#### 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
```
> #### Terminal-Zugriff auf macOS
>
> Das Stripe Terminal SDK erfordert Zugriff auf das lokale Netzwerk. Wenn Sie macOS verwenden, müssen Sie Ihren Browser-Apps explizit Zugriff auf lokale Netzwerkgeräte gewähren. Weitere Informationen finden Sie im [Stripe-Support-Artikel](https://support.stripe.com/questions/ensuring-stripe-terminal-javascript-sdk-functionality-on-macos-15).
### ConnectionToken-Endpoint erstellen
Um sich mit einem Lesegerät verbinden zu können, muss das Backend dem SDK erlauben, es mit Ihrem Stripe-Konto zu verwenden. Dazu stellt es dem SDK den Geheimschlüssel aus einem [ConnectionToken](https://docs.stripe.com/api/terminal/connection_tokens.md) zur Verfügung. Erstellen Sie Verbindungstoken nur für vertrauenswürdige Clients und [übergeben Sie eine Standort-ID](https://docs.stripe.com/terminal/fleet/locations-and-zones.md#connection-tokens), wenn Sie ein Verbindungstoken erstellen, um den Zugriff auf Lesegeräte zu steuern. Wenn Sie Connect verwenden, können Sie das [Verbindungstoken](https://docs.stripe.com/terminal/features/connect.md) auf die relevanten verbundenen Konten beschränken.
### SDK installieren
Um das SDK zu installieren, fügen Sie `stripeterminal` in den Block „Abhängigkeiten“ Ihrer build.gradle-Datei ein.
#### Gradle
Fügen Sie die Abhängigkeiten zu Ihrer build.gradle-Datei hinzu:
#### Groovy
```groovy
dependencies {
// ...
// Stripe Terminal SDK
implementation 'com.stripe:stripeterminal:5.4.0'
}
```
#### GitHub
Das Stripe Android SDK ist als Open Source verfügbar. [Auf GitHub anzeigen](https://github.com/stripe/stripe-android)
### SDK installieren
Um das Tap to Pay SDK zu installieren, fügen Sie `stripeterminal-taptopay` und `stripeterminal-core` zum Dependencies-Block Ihrer `build.gradle` oder `build.gradle.kts`-Datei hinzu.
Wenn Sie bereits `stripeterminal`-Dependencies verwenden, ersetzen Sie diese durch die folgenden, indem Sie die Dependencies in Ihre `build.gradle` oder `build.gradle.kts`-Datei hinzufügen:
#### Groovy
```groovy
dependencies {
// ...
// Stripe Tap to Pay SDK
implementation 'com.stripe:stripeterminal-taptopay:5.4.0'
implementation 'com.stripe:stripeterminal-core:5.4.0'
}
```
### Erstellen Sie Standorte für Ihre Lesegeräte
[Erstellen Sie Standorte](https://docs.stripe.com/terminal/fleet/locations-and-zones.md), um Ihre Lesegeräte zu organisieren. Standorte gruppieren Lesegeräte und ermöglichen es ihnen, automatisch die für ihre Einsatzregion erforderliche Gerätekonfiguration herunterzuladen. Sie müssen jedem Lesegerät einen Standort zuweisen, wenn Sie es [registrieren](https://docs.stripe.com/terminal/fleet/register-readers.md), was Sie über die API oder das Dashboard tun können.
### Prüfen der Berechtigung ACCESS_FINE_LOCATION
Fügen Sie eine Prüfung hinzu, um sicherzustellen, dass die Berechtigung `ACCESS_FINE_LOCATION` in Ihrer App aktiviert ist.
### Das Gewähren der Standortberechtigung durch den/die Nutzer/in prüfen
Überschreiben Sie die Methode `onRequestPermissionsResult` in Ihrer App und prüfen Sie das Berechtigungsergebnis darauf, ob der/die App-Nutzer/in Standortberechtigungen gewährt.
### ConnectionToken abrufen
Implementieren Sie in Ihrer App die ConnectionTokenProvider-Schnittstelle, die eine einzelne Funktion definiert, die ein Verbindungstoken vom Backend anfordert.
### TerminalApplicationDelegate konfigurieren
Um Speicherlecks zu vermeiden und eine ordnungsgemäße Bereinigung von über einen langen Zeitraum ausgeführten Terminal-SDK-Prozessen zu gewährleisten, muss Ihre Anwendung die Unterklasse `Application` bilden und den `TerminalApplicationDelegate` über die Methode `onCreate` aufrufen.
### SDK initialisieren
Stellen Sie zunächst den aktuellen Anwendungskontext, den ConnectionTokenProvider und ein TerminalListener-Objekt bereit.
### Lesegeräte suchen
Das Stripe Terminal SDK umfasst ein integriertes simuliertes Kartenlesegerät, damit Sie Ihre App entwickeln und testen können, ohne eine Verbindung zu physischer Hardware herstellen zu müssen. Um das simulierte Lesegerät zu verwenden, rufen Sie `discoverReaders` auf, um nach Lesegeräten zu suchen, wobei die Option „simuliert“ auf „true“ festgelegt ist.
### Lesegeräte suchen
Das Stripe Terminal SDK umfasst ein integriertes simuliertes Kartenlesegerät, damit Sie Ihre App entwickeln und testen können, ohne eine Verbindung zu physischer Hardware herstellen zu müssen. Um das simulierte Lesegerät zu verwenden, rufen Sie `discoverReaders` auf, um nach Lesegeräten zu suchen, wobei die Option „simuliert“ auf „true“ festgelegt ist. Filtern Sie nach Standort, um passende Lesegeräte einfacher zu finden.
### Mit simuliertem Lesegerät verbinden
Wenn `discoverReaders` ein Ergebnis zurückgibt, rufen Sie `connectReader` zum Verbinden mit dem simulierten Lesegerät auf.
### PaymentIntent erstellen
Erstellen Sie ein [PaymentIntent](https://docs.stripe.com/api/payment_intents.md)-Objekt mithilfe des SDK. Ein PaymentIntent verfolgt den Zahlungslebenszyklus der Kundenkonten, einschließlich aller fehlgeschlagenen Zahlungsversuche, damit sie nur einmal belastet werden.
### PaymentIntent abwickeln
Rufen Sie `processPaymentIntent` mit dem PaymentIntent auf, um eine Zahlungsmethode zu erfassen und die Zahlung zu autorisieren. Wenn eine Verbindung zum simulierten Lesegerät besteht, wird das PaymentIntent-Objekt durch Aufrufen dieser Methode sofort mit einer [simulierten Testkarte](https://docs.stripe.com/terminal/references/testing.md#simulated-test-cards) aktualisiert. Bei einer Verbindung mit einem physischen Lesegerät, wartet das verbundene Lesegerät auf die Vorlage einer Karte. Ein erfolgreicher Aufruf führt zu einem PaymentIntent mit dem Status `requires_capture` für die manuelle Erfassung oder `succeeded` für die automatische Erfassung.
### Endpoint erstellen, um PaymentIntent zu erfassen
Erstellen Sie einen Endpoint in Ihrem Backend, der eine PaymentIntent-ID akzeptiert und eine Anfrage an die Stripe API sendet, um sie zu erfassen.
### PaymentIntent erfassen
Wenn Sie bei PaymentIntent Erstellung `capture_method` als `manual` definiert haben, gibt das SDK einen autorisierten, aber nicht erfassten PaymentIntent an Ihre Anwendung zurück. Wenn der PaymentIntent-Status `requires_capture` lautet, benachrichtigen Sie Ihr Backend, um den PaymentIntent zu erfassen.
Bei verbundenen Konten sollten Sie vor der manuellen Zahlungsbestätigung den Wert von `application_fee_amount` im PaymentIntent prüfen und bei Bedarf anpassen.
### Anwendung ausführen
Führen Sie Ihren Server aus und gehen Sie zu [localhost:4242](http://localhost:4242).
### Integration mit Testkarte ausprobieren
Sie können das simulierte Lesegerät so konfigurieren, dass Sie verschiedene Abläufe in Ihrer Point-of-Sale-Anwendung testen, zum Beispiel unterschiedliche Kartenmarken oder Fehlerszenarien wie eine abgelehnte Zahlung. Um dieses Verhalten zu aktivieren, fügen Sie diese Codezeile ein, bevor Sie `collectPaymentMethod` aufrufen.
| Scenario | Card Number |
| ------------------- | ---------------- |
| Payment succeeds | 4242424242424242 |
| Payment is declined | 4000000000009995 |
### 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
\ncom.stripe\nstripe-java\n{VERSION}\n
```
#### 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/v85
```
#### 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
```
> #### Terminal-Zugriff auf macOS
>
> Das Stripe Terminal SDK erfordert Zugriff auf das lokale Netzwerk. Wenn Sie macOS verwenden, müssen Sie Ihren Browser-Apps explizit Zugriff auf lokale Netzwerkgeräte gewähren. Weitere Informationen finden Sie im [Stripe-Support-Artikel](https://support.stripe.com/questions/ensuring-stripe-terminal-javascript-sdk-functionality-on-macos-15).
### ConnectionToken-Endpoint erstellen
Um sich mit einem Lesegerät verbinden zu können, muss das Backend dem SDK erlauben, es mit Ihrem Stripe-Konto zu verwenden. Dazu stellt es dem SDK den Geheimschlüssel aus einem [ConnectionToken](https://docs.stripe.com/api/terminal/connection_tokens.md) zur Verfügung. Erstellen Sie Verbindungstoken nur für vertrauenswürdige Clients und [übergeben Sie eine Standort-ID](https://docs.stripe.com/terminal/fleet/locations-and-zones.md#connection-tokens), wenn Sie ein Verbindungstoken erstellen, um den Zugriff auf Lesegeräte zu steuern. Wenn Sie Connect verwenden, können Sie das [Verbindungstoken](https://docs.stripe.com/terminal/features/connect.md) auf die relevanten verbundenen Konten beschränken.
### SDK installieren
```bash
yarn install @stripe/stripe-terminal-react-native
```
### Erstellen Sie Standorte für Ihre Lesegeräte
[Erstellen Sie Standorte](https://docs.stripe.com/terminal/fleet/locations-and-zones.md), um Ihre Lesegeräte zu organisieren. Standorte gruppieren Lesegeräte und ermöglichen es ihnen, automatisch die für ihre Einsatzregion erforderliche Gerätekonfiguration herunterzuladen. Sie müssen jedem Lesegerät einen Standort zuweisen, wenn Sie es [registrieren](https://docs.stripe.com/terminal/fleet/register-readers.md), was Sie über die API oder das Dashboard tun können.
### ConnectionToken abrufen
Um dem SDK Zugriff auf diesen Endpoint zu ermöglichen, erstellen Sie eine Funktion in Ihrer Webanwendung, die ein ConnectionToken aus Ihrem Backend anfordert und den geheimen Schlüssel aus dem ConnectionToken-Objekt zurückgibt.
### Berechtigungen konfigurieren
#### Android
Fügen Sie eine Prüfung hinzu, um sicherzustellen, dass die Berechtigung `ACCESS_FINE_LOCATION` in Ihrer App aktiviert ist.
#### iOS
Damit Ihre App mit dem Stripe Terminal SDK verwendet werden kann, müssen Sie in Xcode einige Änderungen an Ihrer Datei „Info.plist“ vornehmen.
#### Ort:
Aktivieren Sie Standortdienste mit dem folgenden Schlüssel-Wert-Paar.
```bash
NSLocationWhenInUseUsageDescription\nLocation access is required to accept payments.
```
#### Hintergrundmodi
Stellen Sie sicher, dass Ihre App im Hintergrund läuft und mit den Bluetooth-Lesegeräten verbunden bleibt.
```bash
UIBackgroundModes\n\nbluetooth-central\n
```
#### Bluetooth Peripheral
Übergeben Sie Validierungsprüfungen, wenn Sie die App an den App Store übermitteln.
```bash
NSBluetoothPeripheralUsageDescription\nBluetooth access is required to connect to supported bluetooth card readers.
```
#### Bluetooth Always
Gestatten Sie Ihrer App, ein Dialogfeld für Bluetooth-Berechtigungen anzuzeigen.
```bash
NSBluetoothAlwaysUsageDescription\nThis app uses Bluetooth to connect to supported card readers.
```
### Kontextanbieter einrichten
Übergeben Sie die Funktion `onFetchConnectionToken` als Eigenschaft an `StripeTerminalProvider`.
### SDK initialisieren
Um eine `StripeTerminal`-Instanz in Ihrer React Native-Anwendung zu initialisieren, rufen Sie die Initialisierungsmethode vom `useStripeTerminal`-Hook auf. Sie müssen die `initialize`-Methode von einer innerhalb von `StripeTerminalProvider` verschachtelten Komponente aufrufen und nicht von der Komponente, die `StripeTerminalProvider` enthält.
### Lesegeräte erkennen
Das Stripe Terminal SDK umfasst ein integriertes simuliertes Kartenlesegerät, damit Sie Ihre App entwickeln und testen können, ohne eine Verbindung zu physischer Hardware herstellen zu müssen. Um das simulierte Lesegerät zu verwenden, rufen Sie `discoverReaders` auf, um nach Lesegeräten zu suchen, wobei die Option „simuliert“ auf „true“ festgelegt ist.
### Lesegeräte erkennen
Das Stripe-Terminal-SDK verfügt über ein eingebautes simuliertes Kartenlesegerät. Um das simulierte Lesegerät zu verwenden, rufen Sie `discoverReaders` auf, um nach Lesegeräten zu suchen, wobei Sie die Option simuliert auf true setzen.
### Lesegeräte erkennen
Das Stripe Terminal SDK umfasst ein integriertes simuliertes Kartenlesegerät, damit Sie Ihre App entwickeln und testen können, ohne eine Verbindung zu physischer Hardware herstellen zu müssen. Um das simulierte Lesegerät zu verwenden, rufen Sie `discoverReaders` auf, um nach Lesegeräten zu suchen, wobei die Option „simuliert“ auf „true“ festgelegt ist. Filtern Sie nach Standort, um passende Lesegeräte einfacher zu finden.
### Mit simuliertem Lesegerät verbinden
Wenn `discoverReaders` ein Ergebnis zurückgibt, rufen Sie `connectReader` zum Verbinden mit dem simulierten Lesegerät auf.
### Einen PaymentIntent erstellen
Fügen Sie einen Endpoint auf Ihrem Server hinzu, der einen PaymentIntent erstellt. Ein PaymentIntent verfolgt den Zahlungslebenszyklus der Kundinnen/Kunden, einschließlich aller fehlgeschlagenen Zahlungsversuche, damit sie nur einmal belastet werden. Geben Sie das Client-Geheimnis des PaymentIntent in der Antwort zurück. Wenn Sie Connect verwenden, können Sie auch [Informationen zu verbundenen Konten](https://docs.stripe.com/terminal/features/connect.md) basierend auf der Zahlungslogik Ihrer Plattform angeben.
### PaymentIntent abrufen
Weisen Sie Ihren Server an, den Zahlungsvorgang mit einem PaymentIntent zu initiieren.
### Angaben zur Zahlungsmethode erfassen
Rufen Sie `collectPaymentMethod` mit dem Client-Geheimnis des PaymentIntent auf, um eine Zahlungsmethode zu erfassen. Wenn eine Verbindung zu einem simulierten Lesegerät besteht, wird mit dieser Methode das PaymentIntent-Objekt sofort mit einer [simulierten Testkarte](https://docs.stripe.com/terminal/references/testing.md#simulated-test-cards) aktualisiert. Ist das verbundene Lesegerät an ein physisches Lesegerät angeschlossen, wartet das verbundene Lesegerät auf die Vorlage einer Karte.
### Zahlung abwickeln
Rufen Sie nach dem erfolgreichen Erfassen der Zahlungsmethodendaten `processPayment` mit dem aktualisierten PaymentIntent auf, um die Zahlung abzuwickeln. Nach einem erfolgreichen Aufruf lautet der Status einer PaymentIntent `requires_capture` für die manuelle Erfassung oder `succeeded` für die automatische Erfassung.
### Endpoint erstellen, um PaymentIntent zu erfassen
Erstellen Sie einen Endpoint in Ihrem Backend, der eine PaymentIntent-ID akzeptiert und eine Anfrage an die Stripe API sendet, um sie zu erfassen.
### PaymentIntent erfassen
Wenn Sie bei PaymentIntent Erstellung `capture_method` als `manual` definiert haben, gibt das SDK einen autorisierten, aber nicht erfassten PaymentIntent an Ihre Anwendung zurück. Wenn der PaymentIntent-Status `requires_capture` lautet, benachrichtigen Sie Ihr Backend, um den PaymentIntent zu erfassen.
Bei verbundenen Konten sollten Sie vor der manuellen Zahlungsbestätigung den Wert von `application_fee_amount` im PaymentIntent prüfen und bei Bedarf anpassen.
### Anwendung ausführen
Führen Sie Ihren Server aus und gehen Sie zu [localhost:4242](http://localhost:4242).
### Integration mit Testkarte ausprobieren
Sie können das simulierte Lesegerät so konfigurieren, dass Sie verschiedene Abläufe in Ihrer Point-of-Sale-Anwendung testen, zum Beispiel unterschiedliche Kartenmarken oder Fehlerszenarien wie eine abgelehnte Zahlung. Um dieses Verhalten zu aktivieren, fügen Sie diese Codezeile ein, bevor Sie `collectPaymentMethod` aufrufen.
| Scenario | Card Number |
| ------------------- | ---------------- |
| Payment succeeds | 4242424242424242 |
| Payment is declined | 4000000000009995 |
// 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.
const stripe = require("stripe")("<>");
const createLocation = async () => {
const location = await stripe.terminal.locations.create({
display_name: '{{TERMINAL_LOCATION_NAME}}',
address: {
line1: '{{TERMINAL_LOCATION_LINE1}}',
line2: '{{TERMINAL_LOCATION_LINE2}}',
city: '{{TERMINAL_LOCATION_CITY}}',
state: '{{TERMINAL_LOCATION_STATE}}',
country: '{{TERMINAL_LOCATION_COUNTRY}}',
postal_code: '{{TERMINAL_LOCATION_POSTAL}}',
},
});
return location;
};
const createLocation = async () => {
const location = await stripe.terminal.locations.create({
display_name: '{{TERMINAL_LOCATION_NAME}}',
display_name_kana: '{{TERMINAL_LOCATION_NAMEKANA}}',
display_name_kanji: '{{TERMINAL_LOCATION_NAMEKANJI}}',
phone: '{{TERMINAL_LOCATION_PHONE}}',
address_kana: {
line1: '{{TERMINAL_LOCATION_LINE1KANA}}',
line2: '{{TERMINAL_LOCATION_LINE2KANA}}',
town: '{{TERMINAL_LOCATION_TOWNKANA}}',
city: '{{TERMINAL_LOCATION_CITYKANA}}',
state: '{{TERMINAL_LOCATION_STATEKANA}}',
postal_code: '{{TERMINAL_LOCATION_POSTALCODEKANA}}',
},
address_kanji: {
line1: '{{TERMINAL_LOCATION_LINE1KANJI}}',
line2: '{{TERMINAL_LOCATION_LINE2KANJI}}',
town: '{{TERMINAL_LOCATION_TOWNKANJI}}',
city: '{{TERMINAL_LOCATION_CITYKANJI}}',
state: '{{TERMINAL_LOCATION_STATEKANJI}}',
postal_code: '{{TERMINAL_LOCATION_POSTALCODEKANJI}}',
},
});
return location;
};
app.post("/create_location", async (req, res) => {
const location = await stripe.terminal.locations.create({
display_name: req.body.display_name,
address: {
line1: req.body.address.line1,
city: req.body.address.city,
state: req.body.address.state,
country: req.body.address.country,
postal_code: req.body.address.postal_code,
},
});
res.json(location);
});
app.post("/create_location", async (req, res) => {
const location = await stripe.terminal.locations.create({
display_name: '{{TERMINAL_LOCATION_NAME}}',
display_name_kana: '{{TERMINAL_LOCATION_NAMEKANA}}',
display_name_kanji: '{{TERMINAL_LOCATION_NAMEKANJI}}',
phone: '{{TERMINAL_LOCATION_PHONE}}',
address_kana: {
line1: '{{TERMINAL_LOCATION_LINE1KANA}}',
line2: '{{TERMINAL_LOCATION_LINE2KANA}}',
town: '{{TERMINAL_LOCATION_TOWNKANA}}',
city: '{{TERMINAL_LOCATION_CITYKANA}}',
state: '{{TERMINAL_LOCATION_STATEKANA}}',
postal_code: '{{TERMINAL_LOCATION_POSTALCODEKANA}}',
},
address_kanji: {
line1: '{{TERMINAL_LOCATION_LINE1KANJI}}',
line2: '{{TERMINAL_LOCATION_LINE2KANJI}}',
town: '{{TERMINAL_LOCATION_TOWNKANJI}}',
city: '{{TERMINAL_LOCATION_CITYKANJI}}',
state: '{{TERMINAL_LOCATION_STATEKANJI}}',
postal_code: '{{TERMINAL_LOCATION_POSTALCODEKANJI}}',
},
});
res.json(location);
});
app.post("/register_reader", async (req, res) => {
const reader = await stripe.terminal.readers.create({
location: req.body.location_id,
label: 'Quickstart - S700 Simulated Reader',
registration_code: 'simulated-s700',
label: 'Quickstart - S710 Simulated Reader',
registration_code: 'simulated-s710',
label: 'Quickstart - V660p Simulated Reader',
registration_code: 'simulated-v660p',
label: 'Quickstart - WisePOS E Simulated Reader',
registration_code: 'simulated-wpe',
});
res.json(reader);
});
// The ConnectionToken's secret lets you connect to any Stripe Terminal reader
// and take payments with your Stripe account.
// Be sure to authenticate the endpoint for creating connection tokens.
app.post("/connection_token", async (req, res) => {
let connectionToken = await stripe.terminal.connectionTokens.create();
res.json({secret: connectionToken.secret});
});
app.post("/create_payment_intent", async (req, res) => {
// For Terminal payments, the 'payment_method_types' parameter must include
// 'card_present'.
// To automatically capture funds when a charge is authorized,
// set `capture_method` to `automatic`.
const intent = await stripe.paymentIntents.create({
amount: req.body.amount,
currency: '{{TERMINAL_CURRENCY}}',
payment_method_types: [
'{{TERMINAL_PAYMENT_METHODS}}'
],
capture_method: 'automatic',
payment_method_options: {
card_present: {
capture_method: 'manual_preferred'
}
}
});
res.json(intent);
});
app.post("/process_payment", async (req, res) => {
var attempt = 0;
const tries = 3;
while (true) {
attempt++;
try {
const reader = await stripe.terminal.readers.processPaymentIntent(
req.body.reader_id,
{
payment_intent: req.body.payment_intent_id,
}
);
return res.send(reader);
} catch (error) {
console.log(error);
switch (error.code) {
case "terminal_reader_timeout":
// Temporary networking blip, automatically retry a few times.
if (attempt == tries) {
return res.send(error);
}
break;
case "terminal_reader_offline":
// Reader is offline and won't respond to API requests. Make sure the reader is powered on
// and connected to the internet before retrying.
return res.send(error);
case "terminal_reader_busy":
// Reader is currently busy processing another request, installing updates or changing settings.
// Remember to disable the pay button in your point-of-sale application while waiting for a
// reader to respond to an API request.
return res.send(error);
case "intent_invalid_state":
// Check PaymentIntent status because it's not ready to be processed. It might have been already
// successfully processed or canceled.
const paymentIntent = await stripe.paymentIntents.retrieve(
req.body.payment_intent_id
);
console.log(
"PaymentIntent is already in " + paymentIntent.status + " state."
);
return res.send(error);
default:
return res.send(error);
}
}
}
});
app.post("/simulate_payment", async (req, res) => {
const reader = await stripe.testHelpers.terminal.readers.presentPaymentMethod(
req.body.reader_id,
{
card_present: {
number: req.body.card_number,
},
type: "card_present",
}
);
res.send(reader);
});
app.post("/capture_payment_intent", async (req, res) => {
const intent = await stripe.paymentIntents.capture(req.body.payment_intent_id);
res.send(intent);
});
{
"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": "^21.0.1"
}
}
{
"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": "^3.4.0",
"stripe": "21.0.1"
},
"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 \"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"
]
}
}
require '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.
Stripe.api_key = '<>'
def create_location
Stripe::Terminal::Location.create({
display_name: '{{TERMINAL_LOCATION_NAME}}',
phone: '{{TERMINAL_LOCATION_PHONE}}',
address: {
line1: '{{TERMINAL_LOCATION_LINE1}}',
line2: '{{TERMINAL_LOCATION_LINE2}}',
city: '{{TERMINAL_LOCATION_CITY}}',
state: '{{TERMINAL_LOCATION_STATE}}',
country: '{{TERMINAL_LOCATION_COUNTRY}}',
postal_code: '{{TERMINAL_LOCATION_POSTAL}}',
}
})
end
def create_location
Stripe::Terminal::Location.create({
display_name: '{{TERMINAL_LOCATION_NAME}}',
display_name_kana: '{{TERMINAL_LOCATION_NAMEKANA}}',
display_name_kanji: '{{TERMINAL_LOCATION_NAMEKANJI}}',
phone: '{{TERMINAL_LOCATION_PHONE}}',
address_kana: {
line1: '{{TERMINAL_LOCATION_LINE1KANA}}',
line2: '{{TERMINAL_LOCATION_LINE2KANA}}',
town: '{{TERMINAL_LOCATION_TOWNKANA}}',
city: '{{TERMINAL_LOCATION_CITYKANA}}',
state: '{{TERMINAL_LOCATION_STATEKANA}}',
postal_code: '{{TERMINAL_LOCATION_POSTALCODEKANA}}',
},
address_kanji: {
line1: '{{TERMINAL_LOCATION_LINE1KANJI}}',
line2: '{{TERMINAL_LOCATION_LINE2KANJI}}',
town: '{{TERMINAL_LOCATION_TOWNKANJI}}',
city: '{{TERMINAL_LOCATION_CITYKANJI}}',
state: '{{TERMINAL_LOCATION_STATEKANJI}}',
postal_code: '{{TERMINAL_LOCATION_POSTALCODEKANJI}}',
}
})
end
post '/create_location' do
content_type 'application/json'
data = JSON.parse(request.body.read)
location = Stripe::Terminal::Location.create({
display_name: data['display_name'],
address: {
line1: data['address']['line1'],
city: data['address']['city'],
state: data['address']['state'],
country: data['address']['country'],
postal_code: data['address']['postal_code'],
}
})
location.to_json
end
post '/create_location' do
content_type 'application/json'
location = Stripe::Terminal::Location.create({
display_name: '{{TERMINAL_LOCATION_NAME}}',
display_name_kana: '{{TERMINAL_LOCATION_NAMEKANA}}',
display_name_kanji: '{{TERMINAL_LOCATION_NAMEKANJI}}',
phone: '{{TERMINAL_LOCATION_PHONE}}',
address_kana: {
line1: '{{TERMINAL_LOCATION_LINE1KANA}}',
line2: '{{TERMINAL_LOCATION_LINE2KANA}}',
town: '{{TERMINAL_LOCATION_TOWNKANA}}',
city: '{{TERMINAL_LOCATION_CITYKANA}}',
state: '{{TERMINAL_LOCATION_STATEKANA}}',
postal_code: '{{TERMINAL_LOCATION_POSTALCODEKANA}}',
},
address_kanji: {
line1: '{{TERMINAL_LOCATION_LINE1KANJI}}',
line2: '{{TERMINAL_LOCATION_LINE2KANJI}}',
town: '{{TERMINAL_LOCATION_TOWNKANJI}}',
city: '{{TERMINAL_LOCATION_CITYKANJI}}',
state: '{{TERMINAL_LOCATION_STATEKANJI}}',
postal_code: '{{TERMINAL_LOCATION_POSTALCODEKANJI}}',
},
})
location.to_json
end
post '/register_reader' do
content_type 'application/json'
data = JSON.parse(request.body.read)
reader = Stripe::Terminal::Reader.create(
location: data['location_id'],
label: 'Quickstart - S700 Simulated Reader',
registration_code: 'simulated-s700'
label: 'Quickstart - S710 Simulated Reader',
registration_code: 'simulated-s710'
label: 'Quickstart - V660p Simulated Reader',
registration_code: 'simulated-v660p'
label: 'Quickstart - WisePOS E Simulated Reader',
registration_code: 'simulated-wpe'
)
reader.to_json
end
\# The ConnectionToken's secret lets you connect to any Stripe Terminal reader
# and take payments with your Stripe account.
# Be sure to authenticate the endpoint for creating connection tokens.
post '/connection_token' do
content_type 'application/json'
connection_token = Stripe::Terminal::ConnectionToken.create
{secret: connection_token.secret}.to_json
end
post '/create_payment_intent' do
content_type 'application/json'
data = JSON.parse(request.body.read)
\# For Terminal payments, the 'payment_method_types' parameter must include
# 'card_present'.
# To automatically capture funds when a charge is authorized,
# set `capture_method` to `automatic`.
intent = Stripe::PaymentIntent.create(
amount: data['amount'],
currency: '{{TERMINAL_CURRENCY}}',
payment_method_types: [
'{{TERMINAL_PAYMENT_METHODS}}'
],
capture_method: 'automatic',
payment_method_options: {
card_present: {
capture_method: 'manual_preferred'
}
}
)
intent.to_json
end
post '/process_payment' do
content_type 'application/json'
data = JSON.parse(request.body.read)
tries = 0
begin
tries += 1
reader = Stripe::Terminal::Reader.process_payment_intent(
data['reader_id'],
payment_intent: data['payment_intent_id']
)
reader.to_json
rescue Stripe::InvalidRequestError => e
case e.code
when 'terminal_reader_timeout'
\# Temporary networking blip, automatically retry a few times.
retry if tries < 3
when 'terminal_reader_offline'
# Reader is offline and won't respond to API requests. Make sure the reader is powered on
# and connected to the internet before retrying.
request.logger.error(e.message)
when 'terminal_reader_busy'
# Reader is currently busy processing another request, installing updates, or changing settings.
# Remember to disable the pay button in your point-of-sale application while waiting for a
# reader to respond to an API request.
request.logger.error(e.message)
when 'intent_invalid_state'
# Check PaymentIntent status because it's not ready to be processed. It might have been already
# successfully processed or canceled.
payment_intent = Stripe::PaymentIntent.retrieve(data['payment_intent_id'])
request.logger.error("PaymentIntent is already in #{payment_intent.status} state.")
else
request.logger.error(e.message)
end
e.to_json
end
end
post '/simulate_payment' do
content_type 'application/json'
data = JSON.parse(request.body.read)
options = {
card_present: { number: data['card_number'] },
type: 'card_present'
}
reader = Stripe::Terminal::Reader::TestHelpers.present_payment_method(
data['reader_id'], options
)
reader.to_json
end
post '/capture_payment_intent' do
data = JSON.parse(request.body.read)
intent = Stripe::PaymentIntent.capture(data['payment_intent_id'])
intent.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.
stripe.api_key = '<>'
def create_location():
location = stripe.terminal.Location.create(
display_name='{{TERMINAL_LOCATION_NAME}}',
phone='{{TERMINAL_LOCATION_PHONE}}',
address={
'line1': '{{TERMINAL_LOCATION_LINE1}}',
'line2': '{{TERMINAL_LOCATION_LINE2}}',
'city': '{{TERMINAL_LOCATION_CITY}}',
'state': '{{TERMINAL_LOCATION_STATE}}',
'country': '{{TERMINAL_LOCATION_COUNTRY}}',
'postal_code': '{{TERMINAL_LOCATION_POSTAL}}',
},
)
return location
def create_location():
location = stripe.terminal.Location.create(
display_name='{{TERMINAL_LOCATION_NAME}}',
display_name_kana='{{TERMINAL_LOCATION_NAMEKANA}}',
display_name_kanji='{{TERMINAL_LOCATION_NAMEKANJI}}',
phone='{{TERMINAL_LOCATION_PHONE}}',
address_kana={
'line1': '{{TERMINAL_LOCATION_LINE1KANA}}',
'line2': '{{TERMINAL_LOCATION_LINE2KANA}}',
'town': '{{TERMINAL_LOCATION_TOWNKANA}}',
'city': '{{TERMINAL_LOCATION_CITYKANA}}',
'state': '{{TERMINAL_LOCATION_STATEKANA}}',
'postal_code': '{{TERMINAL_LOCATION_POSTALCODEKANA}}',
},
address_kanji={
'line1': '{{TERMINAL_LOCATION_LINE1KANJI}}',
'line2': '{{TERMINAL_LOCATION_LINE2KANJI}}',
'town': '{{TERMINAL_LOCATION_TOWNKANJI}}',
'city': '{{TERMINAL_LOCATION_CITYKANJI}}',
'state': '{{TERMINAL_LOCATION_STATEKANJI}}',
'postal_code': '{{TERMINAL_LOCATION_POSTALCODEKANJI}}',
},
)
return location
@app.route('/create_location', methods=['POST'])
def create_location():
data = json.loads(request.data)
location = stripe.terminal.Location.create(
display_name=data['display_name'],
address={
'line1': data['address']['line1'],
'city': data['address']['city'],
'state': data['address']['state'],
'country': data['address']['country'],
'postal_code': data['address']['postal_code'],
},
)
return location
@app.route('/create_location', methods=['POST'])
def create_location():
location = stripe.terminal.Location.create(
display_name='{{TERMINAL_LOCATION_NAME}}',
display_name_kana='{{TERMINAL_LOCATION_NAMEKANA}}',
display_name_kanji='{{TERMINAL_LOCATION_NAMEKANJI}}',
phone='{{TERMINAL_LOCATION_PHONE}}',
address_kana={
'line1': '{{TERMINAL_LOCATION_LINE1KANA}}',
'line2': '{{TERMINAL_LOCATION_LINE2KANA}}',
'town': '{{TERMINAL_LOCATION_TOWNKANA}}',
'city': '{{TERMINAL_LOCATION_CITYKANA}}',
'state': '{{TERMINAL_LOCATION_STATEKANA}}',
'postal_code': '{{TERMINAL_LOCATION_POSTALCODEKANA}}',
},
address_kanji={
'line1': '{{TERMINAL_LOCATION_LINE1KANJI}}',
'line2': '{{TERMINAL_LOCATION_LINE2KANJI}}',
'town': '{{TERMINAL_LOCATION_TOWNKANJI}}',
'city': '{{TERMINAL_LOCATION_CITYKANJI}}',
'state': '{{TERMINAL_LOCATION_STATEKANJI}}',
'postal_code': '{{TERMINAL_LOCATION_POSTALCODEKANJI}}',
},
)
return location
@app.route('/register_reader', methods=['POST'])
def register_reader():
data = json.loads(request.data)
reader = stripe.terminal.Reader.create(
location=data['location_id'],
label='Quickstart - S700 Simulated Reader',
registration_code='simulated-s700',
label='Quickstart - S710 Simulated Reader',
registration_code='simulated-s710',
label='Quickstart - V660p Simulated Reader',
registration_code='simulated-v660p',
label='Quickstart - WisePOS E Simulated Reader',
registration_code='simulated-wpe',
)
return reader
@app.route('/create_payment_intent', methods=['POST'])
def secret():
data = json.loads(request.data)
\# For Terminal payments, the 'payment_method_types' parameter must include
# 'card_present'.
# To automatically capture funds when a charge is authorized,
# set `capture_method` to `automatic`.
intent = stripe.PaymentIntent.create(
amount=data['amount'],
currency='{{TERMINAL_CURRENCY}}',
payment_method_types=[
'{{TERMINAL_PAYMENT_METHODS}}'
],
capture_method='automatic',
payment_method_options={
"card_present": {
"capture_method": "manual_preferred"
}
}
)
return intent
@app.route('/process_payment', methods=['POST'])
def process_payment():
data = json.loads(request.data)
tries = 3
for attempt in range(tries):
try:
reader = stripe.terminal.Reader.process_payment_intent(
data['reader_id'],
payment_intent=data['payment_intent_id'],
)
return reader
except stripe.error.InvalidRequestError as e:
if e.code == 'terminal_reader_timeout':
\# Temporary networking blip, automatically retry a few times.
if attempt < tries - 1:
continue
else:
return e.json_body
elif e.code == 'terminal_reader_offline':
# Reader is offline and won't respond to API requests. Make sure the reader is powered on
# and connected to the internet before retrying.
app.logger.error(e)
return e.json_body
elif e.code == 'terminal_reader_busy':
# Reader is currently busy processing another request, installing updates or changing settings.
# Remember to disable the pay button in your point-of-sale application while waiting for a
# reader to respond to an API request.
app.logger.error(e)
return e.json_body
elif e.code == 'intent_invalid_state':
# Check PaymentIntent status because it's not ready to be processed. It might have been already
# successfully processed or canceled.
payment_intent = stripe.PaymentIntent.retrieve(data['payment_intent_id'])
app.logger.error('PaymentIntent is already in %s state.' % payment_intent.status)
return e.json_body
else:
app.logger.error(e)
return e.json_body
@app.route('/simulate_payment', methods=['POST'])
def simulate_payment():
data = json.loads(request.data)
options = {
"card_present": {
"number": data['card_number']
},
"type": "card_present"
}
reader = stripe.terminal.Reader.TestHelpers.present_payment_method(
data['reader_id'],
**options
)
return reader
\# The ConnectionToken's secret lets you connect to any Stripe Terminal reader
# and take payments with your Stripe account.
# Be sure to authenticate the endpoint for creating connection tokens.
@app.route('/connection_token', methods=['POST'])
def token():
connection_token = stripe.terminal.ConnectionToken.create()
return jsonify(secret=connection_token.secret)
@app.route('/capture_payment_intent', methods=['POST'])
def capture():
data = json.loads(request.data)
intent = stripe.PaymentIntent.capture(
data['payment_intent_id']
)
return intent
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.0.0
toml==0.10.2
Werkzeug==3.1.5
$stripe = new \Stripe\StripeClient('<>');
$data = json_decode(file_get_contents('php://input'), true);
$location = $stripe->terminal->locations->create([
'display_name' => $data['display_name'],
'address' => [
'line1' => $data['address']['line1'],
'city' => $data['address']['city'],
'state' => $data['address']['state'],
'country' => $data['address']['country'],
'postal_code' => $data['address']['postal_code'],
],
]);
$location = $stripe->terminal->locations->create([
'display_name' => '{{TERMINAL_LOCATION_NAME}}',
'display_name_kana' => '{{TERMINAL_LOCATION_NAMEKANA}}',
'display_name_kanji' => '{{TERMINAL_LOCATION_NAMEKANJI}}',
'phone' => '{{TERMINAL_LOCATION_PHONE}}',
'address_kana' => [
'line1' => "{{TERMINAL_LOCATION_LINE1KANA}}",
'line2' => "{{TERMINAL_LOCATION_LINE2KANA}}",
'town' => "{{TERMINAL_LOCATION_TOWNKANA}}",
'city' => "{{TERMINAL_LOCATION_CITYKANA}}",
'state' => "{{TERMINAL_LOCATION_STATEKANA}}",
'postal_code' => "{{TERMINAL_LOCATION_POSTALCODEKANA}}",
],
'address_kanji' => [
'line1' => "{{TERMINAL_LOCATION_LINE1KANJI}}",
'line2' => "{{TERMINAL_LOCATION_LINE2KANJI}}",
'town' => "{{TERMINAL_LOCATION_TOWNKANJI}}",
'city' => "{{TERMINAL_LOCATION_CITYKANJI}}",
'state' => "{{TERMINAL_LOCATION_STATEKANJI}}",
'postal_code' => "{{TERMINAL_LOCATION_POSTALCODEKANJI}}",
],
]);
$stripe = new \Stripe\StripeClient('<>');
$reader = $stripe->terminal->readers->create([
'location' => $json_obj->location_id,
'label' => 'Quickstart - S700 Simulated Reader',
'registration_code' => 'simulated-s700'
'label' => 'Quickstart - S710 Simulated Reader',
'registration_code' => 'simulated-s710'
'label' => 'Quickstart - V660p Simulated Reader',
'registration_code' => 'simulated-v660p'
'label' => 'Quickstart - WisePOS E Simulated Reader',
'registration_code' => 'simulated-wpe'
]);
$stripe = new \Stripe\StripeClient('<>');
$intent = $stripe->paymentIntents->create([
'amount' => $json_obj->amount,
'currency' => '{{TERMINAL_CURRENCY}}',
'payment_method_types' => [
'{{TERMINAL_PAYMENT_METHODS}}'
],
'capture_method' => 'automic',
'payment_method_options' => [
'card_present' => [
'capture_method' => 'manual_preferred'
]
]
]);
$stripe = new \Stripe\StripeClient('<>');
$reader = $stripe->terminal->readers->processPaymentIntent($json_obj->reader_id, [
'payment_intent' => $json_obj->payment_intent_id,
]);
} catch (\Stripe\Exception\InvalidRequestException $e) {
switch($e->getStripeCode()) {
case "terminal_reader_timeout":
// Temporary networking blip, automatically retry a few times.
if ($attempt == $tries) {
$shouldRetry = false;
echo json_encode(['error' => $e->getMessage()]);
} else {
$shouldRetry = true;
}
break;
case "terminal_reader_offline":
// Reader is offline and won't respond to API requests. Make sure the reader is powered on
// and connected to the internet before retrying.
$shouldRetry = false;
echo json_encode(['error' => $e->getMessage()]);
break;
case "terminal_reader_busy":
// Reader is currently busy processing another request, installing updates or changing settings.
// Remember to disable the pay button in your point-of-sale application while waiting for a
// reader to respond to an API request.
$shouldRetry = false;
echo json_encode(['error' => $e->getMessage()]);
break;
case "intent_invalid_state":
// Check PaymentIntent status because it's not ready to be processed. It might have been already
// successfully processed or canceled.
$shouldRetry = false;
$paymentIntent = $stripe->paymentIntents->retrieve($json_obj->payment_intent_id);
echo json_encode(['error' => 'PaymentIntent is already in ' . $paymentIntent->status . ' state.']);
break;
default:
$shouldRetry = false;
echo json_encode(['error' => $e->getMessage()]);
break;
}
}
} while($shouldRetry);
$stripe = new \Stripe\StripeClient('<>');
$params = [
"card_present" => [
"number" => $json_obj->card_number
],
"type" => "card_present"
];
$reader = $stripe->testHelpers->terminal->readers->presentPaymentMethod($json_obj->reader_id, $params);
$stripe = new \Stripe\StripeClient('<>');
$intent = $stripe->paymentIntents->capture($json_obj->payment_intent_id);
$stripe = new \Stripe\StripeClient('<>');
$connectionToken = $stripe->terminal->connectionTokens->create();
echo json_encode(array('secret' => $connectionToken->secret));
private static Location createLocation(){
var options = new LocationCreateOptions
{
DisplayName = "{{TERMINAL_LOCATION_NAME}}",
Phone = "{{TERMINAL_LOCATION_PHONE}}",
Address = new AddressOptions
{
Line1 = "{{TERMINAL_LOCATION_LINE1}}",
Line2 = "{{TERMINAL_LOCATION_LINE2}}",
City = "{{TERMINAL_LOCATION_CITY}}",
State = "{{TERMINAL_LOCATION_STATE}}",
Country = "{{TERMINAL_LOCATION_COUNTRY}}",
PostalCode = "{{TERMINAL_LOCATION_POSTAL}}",
},
};
var client = new StripeClient("<>");
var location = client.V1.Terminal.Locations.Create(options);
return location;
}
private static Location createLocation(){
var options = new LocationCreateOptions
{
DisplayName = "{{TERMINAL_LOCATION_NAME}}",
DisplayNameKana = "{{TERMINAL_LOCATION_NAMEKANA}}",
DisplayNameKanji = "{{TERMINAL_LOCATION_NAMEKANJI}}",
Phone = "{{TERMINAL_LOCATION_PHONE}}",
AddressKana = new AddressJapanOptions
{
Line1 = "{{TERMINAL_LOCATION_LINE1KANA}}",
Line2 = "{{TERMINAL_LOCATION_LINE2KANA}}",
Town = "{{TERMINAL_LOCATION_TOWNKANA}}",
City = "{{TERMINAL_LOCATION_CITYKANA}}",
State = "{{TERMINAL_LOCATION_STATEKANA}}",
PostalCode = "{{TERMINAL_LOCATION_POSTALCODEKANA}}",
},
AddressKanji = new AddressJapanOptions
{
Line1 = "{{TERMINAL_LOCATION_LINE1KANJI}}",
Line2 = "{{TERMINAL_LOCATION_LINE2KANJI}}",
Town = "{{TERMINAL_LOCATION_TOWNKANJI}}",
City = "{{TERMINAL_LOCATION_CITYKANJI}}",
State = "{{TERMINAL_LOCATION_STATEKANJI}}",
PostalCode = "{{TERMINAL_LOCATION_POSTALCODEKANJI}}",
},
};
var client = new StripeClient("<>");
var location = client.V1.Terminal.Locations.Create(options);
return location;
}
// 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.
services.AddSingleton(new StripeClient("<>"));
// The ConnectionToken's secret lets you connect to any Stripe Terminal reader
// and take payments with your Stripe account.
// Be sure to authenticate the endpoint for creating connection tokens.
[Route("connection_token")]
[ApiController]
public class ConnectionTokenApiController : Controller
{
private readonly StripeClient _client;
public ConnectionTokenApiController(StripeClient client)
{
_client = client;
}
[HttpPost]
public ActionResult Post()
{
var options = new ConnectionTokenCreateOptions{};
var connectionToken = _client.V1.Terminal.ConnectionTokens.Create(options);
return Json(new {secret = connectionToken.Secret});
}
}
[Route("create_location")]
[ApiController]
public class CreateLocationApiController : Controller
{
private readonly StripeClient _client;
public CreateLocationApiController(StripeClient client)
{
_client = client;
}
[HttpPost]
public ActionResult Post(CreateLocationRequest request)
{
var options = new LocationCreateOptions
{
DisplayName = request.DisplayName,
Address = new AddressOptions
{
Line1 = request.Address.Line1,
City = request.Address.City,
State = request.Address.State,
Country = request.Address.Country,
PostalCode = request.Address.PostalCode,
},
};
var location = _client.V1.Terminal.Locations.Create(options);
return Json(location);
}
}
public class CreateLocationRequest
{
[JsonProperty("display_name")]
public string DisplayName { get; set; }
[JsonProperty("address")]
public CreateLocationAddress Address { get; set; }
}
public class CreateLocationAddress
{
[JsonProperty("line1")]
public string Line1 { get; set; }
[JsonProperty("city")]
public string City { get; set; }
[JsonProperty("state")]
public string State { get; set; }
[JsonProperty("country")]
public string Country { get; set; }
[JsonProperty("postal_code")]
public string PostalCode { get; set; }
}
[Route("create_location")]
[ApiController]
public class CreateLocationApiController : Controller
{
private readonly StripeClient _client;
public CreateLocationApiController(StripeClient client)
{
_client = client;
}
[HttpPost]
public ActionResult Post()
{
var options = new LocationCreateOptions
{
DisplayName = "{{TERMINAL_LOCATION_NAME}}",
DisplayNameKana = "{{TERMINAL_LOCATION_NAMEKANA}}",
DisplayNameKanji = "{{TERMINAL_LOCATION_NAMEKANJI}}",
Phone = "{{TERMINAL_LOCATION_PHONE}}",
AddressKana = new AddressJapanOptions
{
Line1 = "{{TERMINAL_LOCATION_LINE1KANA}}",
Line2 = "{{TERMINAL_LOCATION_LINE2KANA}}",
Town = "{{TERMINAL_LOCATION_TOWNKANA}}",
City = "{{TERMINAL_LOCATION_CITYKANA}}",
State = "{{TERMINAL_LOCATION_STATEKANA}}",
PostalCode = "{{TERMINAL_LOCATION_POSTALCODEKANA}}",
},
AddressKanji = new AddressJapanOptions
{
Line1 = "{{TERMINAL_LOCATION_LINE1KANJI}}",
Line2 = "{{TERMINAL_LOCATION_LINE2KANJI}}",
Town = "{{TERMINAL_LOCATION_TOWNKANJI}}",
City = "{{TERMINAL_LOCATION_CITYKANJI}}",
State = "{{TERMINAL_LOCATION_STATEKANJI}}",
PostalCode = "{{TERMINAL_LOCATION_POSTALCODEKANJI}}",
},
};
var location = _client.V1.Terminal.Locations.Create(options);
return Json(location);
}
}
[Route("register_reader")]
[ApiController]
public class RegisterReaderApiController : Controller
{
private readonly StripeClient _client;
public RegisterReaderApiController(StripeClient client)
{
_client = client;
}
[HttpPost]
public ActionResult Post(RegisterReaderRequest request)
{
var options = new ReaderCreateOptions
{
Location = request.LocationId,
Label = "Quickstart - S700 Simulated Reader",
RegistrationCode = "simulated-s700",
Label = "Quickstart - S710 Simulated Reader",
RegistrationCode = "simulated-s710",
Label = "Quickstart - V660p Simulated Reader",
RegistrationCode = "simulated-v660p",
Label = "Quickstart - WisePOS E Simulated Reader",
RegistrationCode = "simulated-wpe",
};
var reader = _client.V1.Terminal.Readers.Create(options);
return Json(reader);
}
}
public class RegisterReaderRequest
{
[JsonProperty("location_id")]
public string LocationId { get; set; }
}
[Route("create_payment_intent")]
[ApiController]
public class PaymentIntentApiController : Controller
{
private readonly StripeClient _client;
public PaymentIntentApiController(StripeClient client)
{
_client = client;
}
[HttpPost]
public ActionResult Post(PaymentIntentCreateRequest request)
{
// For Terminal payments, the 'payment_method_types' parameter must include
// 'card_present'.
// To automatically capture funds when a charge is authorized,
// set `capture_method` to `automatic`.
var options = new PaymentIntentCreateOptions
{
Amount = long.Parse(request.Amount),
Currency = "{{TERMINAL_CURRENCY}}",
PaymentMethodTypes = new List
{
"{{TERMINAL_PAYMENT_METHODS}}"
},
CaptureMethod = "automatic",
PaymentMethodOptions = new PaymentIntentPaymentMethodOptionsOptions
{
CardPresent = new PaymentIntentPaymentMethodOptionsCardPresentOptions
{
CaptureMethod = "manual_preferred"
}
}
};
var intent = _client.V1.PaymentIntents.Create(options);
return Json(intent);
}
public class PaymentIntentCreateRequest
{
[JsonProperty("amount")]
public string Amount { get; set; }
}
}
[Route("process_payment")]
[ApiController]
public class ProcessPaymentApiController : Controller
{
private readonly StripeClient _client;
public ProcessPaymentApiController(StripeClient client)
{
_client = client;
}
[HttpPost]
public ActionResult Post(ProcessPaymentRequest request)
{
var options = new ReaderProcessPaymentIntentOptions
{
PaymentIntent = request.PaymentIntentId,
};
var attempt = 0;
var tries = 3;
while (true)
{
attempt++;
try
{
var reader = _client.V1.Terminal.Readers.ProcessPaymentIntent(request.ReaderId, options);
return Json(reader);
}
catch (StripeException e)
{
switch (e.StripeError.Code)
{
case "terminal_reader_timeout":
// Temporary networking blip, automatically retry a few times.
if (attempt == tries)
{
return Json(e.StripeError);
}
break;
case "terminal_reader_offline":
// Reader is offline and won't respond to API requests. Make sure the reader is powered on
// and connected to the internet before retrying.
return Json(e.StripeError);
case "terminal_reader_busy":
// Reader is currently busy processing another request, installing updates or changing settings.
// Remember to disable the pay button in your point-of-sale application while waiting for a
// reader to respond to an API request.
return Json(e.StripeError);
case "intent_invalid_state":
// Check PaymentIntent status because it's not ready to be processed. It might have been already
// successfully processed or canceled.
var paymentIntent = _client.V1.PaymentIntents.Get(request.PaymentIntentId);
Console.WriteLine($"PaymentIntent is already in {paymentIntent.Status} state.");
return Json(e.StripeError);
default:
return Json(e.StripeError);
}
}
}
}
public class ProcessPaymentRequest
{
[JsonProperty("reader_id")]
public string ReaderId { get; set; }
[JsonProperty("payment_intent_id")]
public string PaymentIntentId { get; set; }
}
}
[Route("simulate_payment")]
[ApiController]
public class SimulatePaymentApiController : Controller
{
private readonly StripeClient _client;
public SimulatePaymentApiController(StripeClient client)
{
_client = client;
}
[HttpPost]
public ActionResult Post(SimulatePaymentRequest request)
{
var parameters = new Stripe.TestHelpers.Terminal.ReaderPresentPaymentMethodOptions
{
CardPresent = new Stripe.TestHelpers.Terminal.ReaderCardPresentOptions
{
Number = request.CardNumber
},
Type = "card_present"
};
var reader = _client.TestHelpers.Terminal.Readers.PresentPaymentMethod(request.ReaderId, parameters);
return Json(reader);
}
public class SimulatePaymentRequest
{
[JsonProperty("reader_id")]
public string ReaderId { get; set; }
[JsonProperty("card_number")]
public string CardNumber { get; set; }
}
}
[Route("capture_payment_intent")]
[ApiController]
public class CapturePaymentIntentApiController : Controller
{
private readonly StripeClient _client;
public CapturePaymentIntentApiController(StripeClient client)
{
_client = client;
}
[HttpPost]
public ActionResult Post(PaymentIntentCaptureRequest request)
{
var intent = _client.V1.PaymentIntents.Capture(request.PaymentIntentId, null);
return Json(intent);
}
public class PaymentIntentCaptureRequest
{
[JsonProperty("payment_intent_id")]
public string PaymentIntentId { get; set; }
}
}
"github.com/stripe/stripe-go/v85"
"github.com/stripe/stripe-go/v85/paymentintent"
"github.com/stripe/stripe-go/v85/terminal/connectiontoken"
"github.com/stripe/stripe-go/v85/terminal/location"
"github.com/stripe/stripe-go/v85/terminal/reader"
readertesthelpers "github.com/stripe/stripe-go/v85/testhelpers/terminal/reader"
// 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.
stripe.Key = "<>"
http.HandleFunc("/connection_token", handleConnectionToken)
http.HandleFunc("/create_location", handleCreateLocation)
http.HandleFunc("/register_reader", handleRegisterReader)
http.HandleFunc("/process_payment", handleProcessPayment)
http.HandleFunc("/simulate_payment", handleSimulatePayment)
func createLocation(w http.ResponseWriter, r *http.Request) *stripe.TerminalLocation {
params := &stripe.TerminalLocationParams{
Address: &stripe.AddressParams{
Line1: stripe.String("{{TERMINAL_LOCATION_LINE1}}"),
Line2: stripe.String("{{TERMINAL_LOCATION_LINE2}}"),
City: stripe.String("{{TERMINAL_LOCATION_CITY}}"),
State: stripe.String("{{TERMINAL_LOCATION_STATE}}"),
Country: stripe.String("{{TERMINAL_LOCATION_COUNTRY}}"),
PostalCode: stripe.String("{{TERMINAL_LOCATION_POSTAL}}"),
},
DisplayName: stripe.String("{{TERMINAL_LOCATION_NAME}}"),
Phone: stripe.String("{{TERMINAL_LOCATION_PHONE}}"),
}
l, _ := location.New(params)
return l
}
func createLocation(w http.ResponseWriter, r *http.Request) *stripe.TerminalLocation {
params := &stripe.TerminalLocationParams{
AddressKana: &stripe.TerminalLocationAddressKanaParams{
Line1: stripe.String("{{TERMINAL_LOCATION_LINE1KANA}}"),
Line2: stripe.String("{{TERMINAL_LOCATION_LINE2KANA}}"),
Town: stripe.String("{{TERMINAL_LOCATION_TOWNKANA}}"),
City: stripe.String("{{TERMINAL_LOCATION_CITYKANA}}"),
State: stripe.String("{{TERMINAL_LOCATION_STATEKANA}}"),
PostalCode: stripe.String("{{TERMINAL_LOCATION_POSTALCODEKANA}}"),
},
AddressKanji: &stripe.TerminalLocationAddressKanjiParams{
Line1: stripe.String("{{TERMINAL_LOCATION_LINE1KANJI}}"),
Line2: stripe.String("{{TERMINAL_LOCATION_LINE2KANJI}}"),
Town: stripe.String("{{TERMINAL_LOCATION_TOWNKANJI}}"),
City: stripe.String("{{TERMINAL_LOCATION_CITYKANJI}}"),
State: stripe.String("{{TERMINAL_LOCATION_STATEKANJI}}"),
PostalCode: stripe.String("{{TERMINAL_LOCATION_POSTALCODEKANJI}}"),
},
DisplayName: stripe.String("{{TERMINAL_LOCATION_NAME}}"),
DisplayNameKana: stripe.String("{{TERMINAL_LOCATION_NAMEKANA}}"),
DisplayNameKanji: stripe.String("{{TERMINAL_LOCATION_NAMEKANJI}}"),
Phone: stripe.String("{{TERMINAL_LOCATION_PHONE}}"),
}
l, _ := location.New(params)
return l
}
func handleCreateLocation(w http.ResponseWriter, r *http.Request) {
var req struct {
DisplayName string `json:"display_name"`
Address struct {
Line1 string `json:"line1"`
City string `json:"city"`
State string `json:"state"`
Country string `json:"country"`
PostalCode string `json:"postal_code"`
} `json:"address"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Printf("json.NewDecoder.Decode: %v", err)
return
}
params := &stripe.TerminalLocationParams{
Address: &stripe.AddressParams{
Line1: stripe.String(req.Address.Line1),
City: stripe.String(req.Address.City),
State: stripe.String(req.Address.State),
Country: stripe.String(req.Address.Country),
PostalCode: stripe.String(req.Address.PostalCode),
},
DisplayName: stripe.String(req.DisplayName),
}
l, err := location.New(params)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Printf("location.New: %v", err)
return
}
writeJSON(w, l)
}
func handleCreateLocation(w http.ResponseWriter, r *http.Request) {
params := &stripe.TerminalLocationParams{
AddressKana: &stripe.TerminalLocationAddressKanaParams{
Line1: stripe.String("{{TERMINAL_LOCATION_LINE1KANA}}"),
Line2: stripe.String("{{TERMINAL_LOCATION_LINE2KANA}}"),
Town: stripe.String("{{TERMINAL_LOCATION_TOWNKANA}}"),
City: stripe.String("{{TERMINAL_LOCATION_CITYKANA}}"),
State: stripe.String("{{TERMINAL_LOCATION_STATEKANA}}"),
PostalCode: stripe.String("{{TERMINAL_LOCATION_POSTALCODEKANA}}"),
},
AddressKanji: &stripe.TerminalLocationAddressKanjiParams{
Line1: stripe.String("{{TERMINAL_LOCATION_LINE1KANJI}}"),
Line2: stripe.String("{{TERMINAL_LOCATION_LINE2KANJI}}"),
Town: stripe.String("{{TERMINAL_LOCATION_TOWNKANJI}}"),
City: stripe.String("{{TERMINAL_LOCATION_CITYKANJI}}"),
State: stripe.String("{{TERMINAL_LOCATION_STATEKANJI}}"),
PostalCode: stripe.String("{{TERMINAL_LOCATION_POSTALCODEKANJI}}"),
},
DisplayName: stripe.String("{{TERMINAL_LOCATION_NAME}}"),
DisplayNameKana: stripe.String("{{TERMINAL_LOCATION_NAMEKANA}}"),
DisplayNameKanji: stripe.String("{{TERMINAL_LOCATION_NAMEKANJI}}"),
Phone: stripe.String("{{TERMINAL_LOCATION_PHONE}}"),
}
l, err := location.New(params)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Printf("location.New: %v", err)
return
}
writeJSON(w, l)
}
func handleRegisterReader(w http.ResponseWriter, r *http.Request) {
var req struct {
LocationID string `json:"location_id"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Printf("json.NewDecoder.Decode: %v", err)
return
}
params := &stripe.TerminalReaderParams{
Location: stripe.String(req.LocationID),
Label: stripe.String("Quickstart - S700 Simulated Reader"),
RegistrationCode: stripe.String("simulated-s700"),
Label: stripe.String("Quickstart - S710 Simulated Reader"),
RegistrationCode: stripe.String("simulated-s710"),
Label: stripe.String("Quickstart - V660p Simulated Reader"),
RegistrationCode: stripe.String("simulated-v660p"),
Label: stripe.String("Quickstart - WisePOS E Simulated Reader"),
RegistrationCode: stripe.String("simulated-wpe"),
}
reader, err := reader.New(params)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Printf("reader.New: %v", err)
return
}
writeJSON(w, reader)
}
// The ConnectionToken's secret lets you connect to any Stripe Terminal reader
// and take payments with your Stripe account.
// Be sure to authenticate the endpoint for creating connection tokens.
func handleConnectionToken(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
params := &stripe.TerminalConnectionTokenParams{}
ct, err := connectiontoken.New(params)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Printf("pi.New: %v", err)
return
}
writeJSON(w, struct {
Secret string `json:"secret"`
}{
Secret: ct.Secret,
})
}
func handleCreate(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
var req struct {
PaymentIntentAmount string `json:"amount"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Printf("json.NewDecoder.Decode: %v", err)
return
}
amount, _ := strconv.ParseInt(req.PaymentIntentAmount, 10, 64)
// For Terminal payments, the 'payment_method_types' parameter must include
// 'card_present'.
// To automatically capture funds when a charge is authorized,
// set `capture_method` to `automatic`.
params := &stripe.PaymentIntentParams{
Amount: stripe.Int64(amount),
Currency: stripe.String(string(stripe.Currency{{TERMINAL_CURRENCY}})),
PaymentMethodTypes: stripe.StringSlice([]string{
"{{TERMINAL_PAYMENT_METHODS}}"
}),
CaptureMethod: stripe.String("automatic"),
PaymentMethodOptions: &stripe.PaymentIntentPaymentMethodOptionsParams{
CardPresent: &stripe.PaymentIntentPaymentMethodOptionsCardPresentParams{
CaptureMethod: stripe.String("manual_preferred"),
},
},
}
pi, err := paymentintent.New(params)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Printf("pi.New: %v", err)
return
}
writeJSON(w, pi)
}
func handleProcessPayment(w http.ResponseWriter, r *http.Request) {
var req struct {
ReaderID string `json:"reader_id"`
PaymentIntentID string `json:"payment_intent_id"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Printf("json.NewDecoder.Decode: %v", err)
return
}
params := &stripe.TerminalReaderProcessPaymentIntentParams{
PaymentIntent: stripe.String(req.PaymentIntentID),
}
reader, err := reader.ProcessPaymentIntent(req.ReaderID, params)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Printf("reader.New: %v", err)
return
}
writeJSON(w, reader)
}
func handleSimulatePayment(w http.ResponseWriter, r *http.Request) {
var req struct {
ReaderID string `json:"reader_id"`
CardNumber string `json:"card_number"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Printf("json.NewDecoder.Decode: %v", err)
return
}
params := &stripe.TestHelpersTerminalReaderPresentPaymentMethodParams{
CardPresent: map[string]interface{}{
"number": stripe.String(req.CardNumber),
},
Type: stripe.String("card_present"),
}
reader, err := readertesthelpers.PresentPaymentMethod(req.ReaderID, params)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Printf("reader.New: %v", err)
return
}
writeJSON(w, reader)
}
func handleCapture(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
var req struct {
PaymentIntentID string `json:"payment_intent_id"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Printf("json.NewDecoder.Decode: %v", err)
return
}
pi, err := paymentintent.Capture(req.PaymentIntentID, nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Printf("pi.Capture: %v", err)
return
}
writeJSON(w, pi)
}
require github.com/stripe/stripe-go/v85 v85.0.0
import com.stripe.model.terminal.ConnectionToken;
import com.stripe.model.terminal.Reader;
import com.stripe.param.terminal.ReaderProcessPaymentIntentParams;
import com.stripe.param.terminal.ReaderCreateParams;
static class CreateLocationParams {
private String display_name;
private Address address;
static class Address {
private String line1;
private String city;
private String state;
private String country;
private String postal_code;
public String getLine1() {
return line1;
}
public String getCity() {
return city;
}
public String getState() {
return state;
}
public String getCountry() {
return country;
}
public String getPostalCode() {
return postal_code;
}
}
public String getDisplayName() {
return display_name;
}
public Address getAddress() {
return address;
}
}
static class ReaderParams {
private String reader_id;
private String location_id;
private String card_number;
public String getReaderId() {
return reader_id;
}
public String getLocationId() {
return location_id;
}
public String getCardNumber() {
return card_number;
}
}
static class ProcessPaymentParams {
private String reader_id;
private String payment_intent_id;
public String getReaderId() {
return reader_id;
}
public String getPaymentIntentId() {
return payment_intent_id;
}
}
// 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.
Stripe.apiKey = "<>";
post("/create_location", (request, response) -> {
CreateLocationParams postBody = gson.fromJson(request.body(), CreateLocationParams.class);
LocationCreateParams.Address address =
LocationCreateParams.Address.builder()
.setLine1(postBody.getAddress().getLine1())
.setCity(postBody.getAddress().getCity())
.setState(postBody.getAddress().getState())
.setCountry(postBody.getAddress().getCountry())
.setPostalCode(postBody.getAddress().getPostalCode())
.build();
LocationCreateParams params =
LocationCreateParams.builder()
.setDisplayName(postBody.getDisplayName())
.setAddress(address)
.build();
Location location = Location.create(params);
return location.toJson();
});
post("/create_location", (request, response) -> {
LocationCreateParams.AddressKana addressKana =
LocationCreateParams.AddressKana.builder()
.setLine1("{{TERMINAL_LOCATION_LINE1KANA}}")
.setLine2("{{TERMINAL_LOCATION_LINE2KANA}}")
.setTown("{{TERMINAL_LOCATION_TOWNKANA}}")
.setCity("{{TERMINAL_LOCATION_CITYKANA}}")
.setState("{{TERMINAL_LOCATION_STATEKANA}}")
.setPostalCode("{{TERMINAL_LOCATION_POSTALCODEKANA}}")
.build();
LocationCreateParams.AddressKanji addressKanji =
LocationCreateParams.AddressKanji.builder()
.setLine1("{{TERMINAL_LOCATION_LINE1KANJI}}")
.setLine2("{{TERMINAL_LOCATION_LINE2KANJI}}")
.setTown("{{TERMINAL_LOCATION_TOWNKANJI}}")
.setCity("{{TERMINAL_LOCATION_CITYKANJI}}")
.setState("{{TERMINAL_LOCATION_STATEKANJI}}")
.setPostalCode("{{TERMINAL_LOCATION_POSTALCODEKANJI}}")
.build();
LocationCreateParams params =
LocationCreateParams.builder()
.setDisplayName("{{TERMINAL_LOCATION_NAME}}")
.setDisplayNameKana("{{TERMINAL_LOCATION_NAMEKANA}}")
.setDisplayNameKanji("{{TERMINAL_LOCATION_NAMEKANJI}}")
.setPhone("{{TERMINAL_LOCATION_PHONE}}")
.setAddressKana(addressKana)
.setAddressKanji(addressKanji)
.build();
Location location = Location.create(params);
return location.toJson();
});
// The ConnectionToken's secret lets you connect to any Stripe Terminal reader
// and take payments with your Stripe account.
// Be sure to authenticate the endpoint for creating connection tokens.
post("/connection_token", (request, response) -> {
response.type("application/json");
ConnectionTokenCreateParams params = ConnectionTokenCreateParams.builder()
.build();
ConnectionToken connectionToken = ConnectionToken.create(params);
Map map = new HashMap();
map.put("secret", connectionToken.getSecret());
return gson.toJson(map);
});
post("/register_reader", (request, response) -> {
ReaderParams postBody = gson.fromJson(request.body(), ReaderParams.class);
ReaderCreateParams params =
ReaderCreateParams.builder()
.setLocation(postBody.getLocationId())
.setLabel("Quickstart - S700 Simulated Reader")
.setRegistrationCode("simulated-s700")
.setLabel("Quickstart - S710 Simulated Reader")
.setRegistrationCode("simulated-s710")
.setLabel("Quickstart - V660p Simulated Reader")
.setRegistrationCode("simulated-v660p")
.setLabel("Quickstart - WisePOS E Simulated Reader")
.setRegistrationCode("simulated-wpe")
.build();
Reader reader = Reader.create(params);
return reader.toJson();
});
post("/create_payment_intent", (request, response) -> {
response.type("application/json");
PaymentIntentParams postBody = gson.fromJson(request.body(), PaymentIntentParams.class);
// For Terminal payments, the 'payment_method_types' parameter must include
// 'card_present'.
// To automatically capture funds when a charge is authorized,
// set `capture_method` to `automatic`.
PaymentIntentCreateParams createParams = PaymentIntentCreateParams.builder()
.setCurrency("{{TERMINAL_CURRENCY}}")
.setAmount(postBody.getAmount())
.setCaptureMethod(PaymentIntentCreateParams.CaptureMethod.AUTOMATIC)
.putPaymentMethodOption(
"card_present",
PaymentIntentCreateParams.PaymentMethodOptions.CardPresent.builder()
.setCaptureMethod(PaymentIntentCreateParams.PaymentMethodOptions.CardPresent.CaptureMethod.MANUAL_PREFERRED)
.build()
)
{{TERMINAL_PAYMENT_METHODS}}
.build();
// Create a PaymentIntent with the order amount and currency
PaymentIntent intent = PaymentIntent.create(createParams);
return intent.toJson();
});
post("/process_payment", (request, response) -> {
ProcessPaymentParams postBody = gson.fromJson(request.body(), ProcessPaymentParams.class);
ReaderProcessPaymentIntentParams params =
ReaderProcessPaymentIntentParams.builder()
.setPaymentIntent(postBody.getPaymentIntentId())
.build();
Reader reader = Reader.retrieve(postBody.getReaderId());
int attempt = 0;
int tries = 3;
while (true) {
attempt++;
try {
reader = reader.processPaymentIntent(params);
return reader.toJson();
} catch (InvalidRequestException e) {
switch (e.getCode()) {
case "terminal_reader_timeout":
// Temporary networking blip, automatically retry a few times.
if (attempt == tries) {
return e.getStripeError().toJson();
}
break;
case "terminal_reader_offline":
// Reader is offline and won't respond to API requests. Make sure the reader is
// powered on and connected to the internet before retrying.
return e.getStripeError().toJson();
case "terminal_reader_busy":
// Reader is currently busy processing another request, installing updates or
// changing settings. Remember to disable the pay button in your point-of-sale
// application while waiting for a reader to respond to an API request.
return e.getStripeError().toJson();
case "intent_invalid_state":
// Check PaymentIntent status because it's not ready to be processed. It might
// have been already successfully processed or canceled.
PaymentIntent paymentIntent = PaymentIntent.retrieve(postBody.getPaymentIntentId());
Map errorResponse = Collections.singletonMap("error",
"PaymentIntent is already in " + paymentIntent.getStatus() + " state.");
return new Gson().toJson(errorResponse);
default:
return e.getStripeError().toJson();
}
}
}
});
post("/simulate_payment", (request, response) -> {
ReaderParams postBody = gson.fromJson(request.body(), ReaderParams.class);
Reader reader = Reader.retrieve(postBody.getReaderId());
Map paymentOptions = new HashMap<>();
Map cardPresent = new HashMap<>();
cardPresent.put("number", postBody.getCardNumber());
paymentOptions.put("card_present", cardPresent);
paymentOptions.put("type", "card_present");
reader = reader.getTestHelpers().presentPaymentMethod(paymentOptions);
return reader.toJson();
});
post("/capture_payment_intent", (request, response) -> {
response.type("application/json");
PaymentIntentParams postBody = gson.fromJson(request.body(), PaymentIntentParams.class);
PaymentIntent intent = PaymentIntent.retrieve(postBody.getPaymentIntentId());
intent = intent.capture();
return intent.toJson();
});
public static Location createLocation() throws StripeException {
LocationCreateParams.Address address =
LocationCreateParams.Address.builder()
.setLine1("{{TERMINAL_LOCATION_LINE1}}")
.setLine2("{{TERMINAL_LOCATION_LINE2}}")
.setCity("{{TERMINAL_LOCATION_CITY}}")
.setState("{{TERMINAL_LOCATION_STATE}}")
.setCountry("{{TERMINAL_LOCATION_COUNTRY}}")
.setPostalCode("{{TERMINAL_LOCATION_POSTAL}}")
.build();
LocationCreateParams params =
LocationCreateParams.builder()
.setDisplayName("{{TERMINAL_LOCATION_NAME}}")
.setPhone("{{TERMINAL_LOCATION_PHONE}}")
.setAddress(address)
.build();
Location location = Location.create(params);
return location;
}
public static Location createLocation() throws StripeException {
LocationCreateParams.AddressKana addressKana =
LocationCreateParams.AddressKana.builder()
.setLine1("{{TERMINAL_LOCATION_LINE1KANA}}")
.setLine2("{{TERMINAL_LOCATION_LINE2KANA}}")
.setTown("{{TERMINAL_LOCATION_TOWNKANA}}")
.setCity("{{TERMINAL_LOCATION_CITYKANA}}")
.setState("{{TERMINAL_LOCATION_STATEKANA}}")
.setPostalCode("{{TERMINAL_LOCATION_POSTALCODEKANA}}")
.build();
LocationCreateParams.AddressKanji addressKanji =
LocationCreateParams.AddressKanji.builder()
.setLine1("{{TERMINAL_LOCATION_LINE1KANJI}}")
.setLine2("{{TERMINAL_LOCATION_LINE2KANJI}}")
.setTown("{{TERMINAL_LOCATION_TOWNKANJI}}")
.setCity("{{TERMINAL_LOCATION_CITYKANJI}}")
.setState("{{TERMINAL_LOCATION_STATEKANJI}}")
.setPostalCode("{{TERMINAL_LOCATION_POSTALCODEKANJI}}")
.build();
LocationCreateParams params =
LocationCreateParams.builder()
.setDisplayName("{{TERMINAL_LOCATION_NAME}}")
.setDisplayNameKana("{{TERMINAL_LOCATION_NAMEKANA}}")
.setDisplayNameKanji("{{TERMINAL_LOCATION_NAMEKANJI}}")
.setPhone("{{TERMINAL_LOCATION_PHONE}}")
.setAddressKana(addressKana)
.setAddressKanji(addressKanji)
.build();
Location location = Location.create(params);
return location;
}
export const fetchConnectionToken = async () => {
const response = await fetch('http://localhost:4242/connection_token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
});
const data = await response.json();
if (!data) {
throw Error('No data in response from ConnectionToken endpoint');
}
if (!data.secret) {
throw Error('Missing `secret` in ConnectionToken JSON response');
}
return data.secret;
};
export const fetchPaymentIntent = async () => {
const parameters = {
amount: 1000,
};
const response = await fetch('http://localhost:4242/create_payment_intent', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(parameters),
});
const data = await response.json();
if (!data) {
throw Error('No data in response from PaymentIntent endpoint');
}
if (!data.client_secret) {
throw Error('Missing `client_secret` in ConnectionToken JSON response');
}
return data.client_secret;
};
export const capturePaymentIntent = async () => {
const parameters = {
id: 'paymentIntentId',
};
const response = await fetch('http://localhost:4242/capture_payment_intent', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(parameters),
});
if (response.status >= 200 && response.status < 300) {
return true;
} else {
return false;
}
};
const { reader, error } = await connectReader({
discoveryMethod: 'internet',
reader: selectedReader,
});
const { reader, error } = await connectReader({
discoveryMethod: 'tapToPay',
reader: selectedReader,
locationId: selectedReader.locationId,
});
const { reader, error } = await connectReader({
discoveryMethod: 'bluetoothScan',
reader: selectedReader,
locationId: selectedReader.locationId,
});
useEffect(() => {
async function init() {
try {
const granted = await PermissionsAndroid.request(
'android.permission.ACCESS_FINE_LOCATION',
{
title: 'Location Permission',
message: 'Stripe Terminal needs access to your location',
buttonPositive: 'Accept',
},
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
console.log('You can use the Location');
setPermissionsGranted(true);
} else {
Alert.alert(
'Location services are required to connect to a reader.',
);
}
} catch {
Alert.alert(
'Location services are required to connect to a reader.',
);
}
}
if (Platform.OS === 'android') {
init();
} else {
setPermissionsGranted(true);
}
}, []);
const {error} = await discoverReaders({
discoveryMethod: 'internet',
simulated: true,
});
const {error} = await discoverReaders({
discoveryMethod: 'tapToPay',
simulated: true,
});
const {error} = await discoverReaders({
discoveryMethod: 'bluetoothScan',
simulated: true,
});
await setSimulatedCard("4242424242424242");
const {paymentIntent, error} = await processPaymentIntent({
clientSecret,
});
const result = await capturePaymentIntent();
import {
StripeTerminalProvider,
} from '@stripe/stripe-terminal-react-native';
var terminal = StripeTerminal.create({
onFetchConnectionToken: fetchConnectionToken,
onUnexpectedReaderDisconnect: unexpectedDisconnect,
});
function unexpectedDisconnect() {
// In this function, your app should notify the user that the reader disconnected.
// You can also include a way to attempt to reconnect to a reader.
console.log("Disconnected from reader")
}
function fetchConnectionToken() {
// Do not cache or hardcode the ConnectionToken. The SDK manages the ConnectionToken's lifecycle.
return fetch('/connection_token', { method: "POST" })
.then(function(response) {
return response.json();
})
.then(function(data) {
return data.secret;
});
}
var config = {simulated: true};
terminal.discoverReaders(config).then(function(discoverResult) {
terminal.connectReader(selectedReader).then(function(connectResult) {
function fetchPaymentIntentClientSecret(amount) {
const bodyContent = JSON.stringify({ amount: amount });
return fetch('/create_payment_intent', {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: bodyContent
})
.then(function(response) {
return response.json();
})
.then(function(data) {
return data.client_secret;
});
}
// Use test card number to simulate different payment flows within your point of sale application
terminal.setSimulatorConfiguration({testCardNumber: '4242424242424242'});
terminal.collectPaymentMethod(client_secret).then(function(result) {
terminal.processPayment(result.paymentIntent).then(function(result) {
function capture(paymentIntentId) {
return fetch('/capture_payment_intent', {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({"payment_intent_id": paymentIntentId})
})
.then(function(response) {
return response.json();
})
.then(function(data) {
log('server.capture', data);
});
}
const terminal = StripeTerminal.create({
onFetchConnectionToken: fetchConnectionToken,
onUnexpectedReaderDisconnect: unexpectedDisconnect,
});
function unexpectedDisconnect() {
// In this function, your app should notify the user that the reader disconnected.
// You can also include a way to attempt to reconnect to a reader.
console.log("Disconnected from reader")
}
async function fetchConnectionToken() {
// Do not cache or hardcode the ConnectionToken. The SDK manages the ConnectionToken's lifecycle.
const response = await fetch('/connection_token', { method: "POST" });
const data = await response.json();
return data.secret;
}
const config = {simulated: true};
const discoverResult = await terminal.discoverReaders(config);
const selectedReader = discoveredReaders[0];
const connectResult = await terminal.connectReader(selectedReader);
async function fetchPaymentIntentClientSecret(amount) {
const bodyContent = JSON.stringify({ amount: amount });
const response = await fetch('/create_payment_intent', {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: bodyContent
});
const data = await response.json();
return data.client_secret;
}
// Use test card number to simulate different payment flows within your point of sale application
terminal.setSimulatorConfiguration({testCardNumber: '4242424242424242'});
const collectResult = await terminal.collectPaymentMethod(client_secret);
const processResult = await terminal.processPayment(collectResult.paymentIntent);
async function capture(paymentIntentId) {
const result = await fetch('/capture_payment_intent', {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({"payment_intent_id": paymentIntentId})
})
const data = result.json();
log('server.capture', data);
}
Terminal.initWithTokenProvider(APIClient.shared)
let config = try InternetDiscoveryConfigurationBuilder().setSimulated(true).build()
let config = try TapToPayDiscoveryConfigurationBuilder().setSimulated(true).build()
let config = try BluetoothScanDiscoveryConfigurationBuilder().setSimulated(true).build()
let params = try PaymentIntentParametersBuilder(amount: 1000,
currency: "{{TERMINAL_CURRENCY}}")
.setPaymentMethodTypes([{{TERMINAL_PAYMENT_METHODS}}])
.build()
Terminal.shared.processPaymentIntent(paymentIntent, collectConfig: nil, confirmConfig: nil) { processResult, processError in
let connectionConfig: InternetConnectionConfiguration
do {
connectionConfig = try InternetConnectionConfigurationBuilder(delegate: self).build()
} catch {
// Handle the error building the connection configuration
print("Error building connection configuration: \(error)")
return
}
let connectionConfig: TapToPayConnectionConfiguration
do {
connectionConfig = try TapToPayConnectionConfigurationBuilder(
delegate: self,
locationId: selectedReader.locationId!
).build()
} catch {
// Handle the error building the connection configuration
print("Error building connection configuration: \(error)")
return
}
let connectionConfig: BluetoothConnectionConfiguration
do {
connectionConfig = try BluetoothConnectionConfigurationBuilder(
delegate: self,
// When connecting to a physical reader, your integration should specify either the
// same location as the last connection (selectedReader.locationId) or a new location
// of your user's choosing.
//
// Since the simulated reader is not associated with a real location, we recommend
// specifying its existing mock location.
locationId: selectedReader.locationId!
).build()
} catch {
// Handle the error building the connection configuration
print("Error building connection configuration: \(error)")
return
}
extension ViewController: MobileReaderDelegate {
func reader(_ reader: Reader, didDisconnect reason: DisconnectReason) {
// Handle reader disconnect
}
func reader(_ reader: Reader, didRequestReaderInput inputOptions: ReaderInputOptions = []) {
readerMessageLabel.text = Terminal.stringFromReaderInputOptions(inputOptions)
}
func reader(_ reader: Reader, didRequestReaderDisplayMessage displayMessage: ReaderDisplayMessage) {
readerMessageLabel.text = Terminal.stringFromReaderDisplayMessage(displayMessage)
}
func reader(_ reader: Reader, didStartInstallingUpdate update: ReaderSoftwareUpdate, cancelable: Cancelable?) {
// Show UI communicating that a required update has started installing
}
func reader(_ reader: Reader, didReportReaderSoftwareUpdateProgress progress: Float) {
// Update the progress of the install
}
func reader(_ reader: Reader, didFinishInstallingUpdate update: ReaderSoftwareUpdate?, error: Error?) {
// Report success or failure of the update
}
func reader(_ reader: Reader, didReportAvailableUpdate update: ReaderSoftwareUpdate) {
// Show UI communicating that an update is available
}
}
extension ViewController: InternetReaderDelegate {
func reader(_ reader: Reader, didDisconnect reason: DisconnectReason) {
print("Disconnected from reader: \(reader)")
}
}
extension ViewController: TapToPayReaderDelegate {
func tapToPayReader(_ reader: Reader, didStartInstallingUpdate update: ReaderSoftwareUpdate, cancelable: Cancelable?) {
// In your app, let the user know that an update is being installed on the reader
}
func tapToPayReader(_ reader: Reader, didReportReaderSoftwareUpdateProgress progress: Float) {
// The update or configuration process has reached the specified progress (0.0 to 1.0)
// If you are displaying a progress bar or percentage, this can be updated here
}
func tapToPayReader(_ reader: Reader, didFinishInstallingUpdate update: ReaderSoftwareUpdate?, error: Error?) {
// The reader has finished installing an update
// If `error` is nil, it is safe to proceed and start collecting payments
// Otherwise, check the value of `error` for more information on what went wrong
}
func tapToPayReader(_ reader: Reader, didRequestReaderDisplayMessage displayMessage: ReaderDisplayMessage) {
// This is called to request that a prompt be displayed in your app.
readerMessageLabel.text = Terminal.stringFromReaderDisplayMessage(displayMessage)
}
func tapToPayReader(_ reader: Reader, didRequestReaderInput inputOptions: ReaderInputOptions = []) {
// This is called when the reader begins waiting for input
readerMessageLabel.text = Terminal.stringFromReaderInputOptions(inputOptions)
}
}
func fetchConnectionToken(_ completion: @escaping ConnectionTokenCompletionBlock) {
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let url = URL(string: "/connection_token", relativeTo: APIClient.backendUrl)!
var request = URLRequest(url: url)
request.httpMethod = "POST"
let task = session.dataTask(with: request) { (data, response, error) in
if let data = data {
do {
// Warning: casting using 'as? [String: String]' looks simpler, but isn't safe:
let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
if let secret = json?["secret"] as? String {
completion(secret, nil)
} else {
let error = NSError(domain: "com.stripe-terminal-ios.example",
code: 2000,
userInfo: [NSLocalizedDescriptionKey: "Missing 'secret' in ConnectionToken JSON response"])
completion(nil, error)
}
} catch {
completion(nil, error)
}
} else {
let error = NSError(domain: "com.stripe-terminal-ios.example",
code: 1000,
userInfo: [NSLocalizedDescriptionKey: "No data in response from ConnectionToken endpoint"])
completion(nil, error)
}
}
task.resume()
}
func capturePaymentIntent(_ paymentIntentId: String, completion: @escaping ErrorCompletionBlock) {
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config, delegate: nil, delegateQueue: OperationQueue.main)
let url = URL(string: "/capture_payment_intent", relativeTo: APIClient.backendUrl)!
let parameters = "{\"payment_intent_id\": \"\(paymentIntentId)\"}"
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpBody = parameters.data(using: .utf8)
let task = session.dataTask(with: request) {(data, response, error) in
if let response = response as? HTTPURLResponse, let data = data {
switch response.statusCode {
case 200..<300:
completion(nil)
case 402:
let description = String(data: data, encoding: .utf8) ?? "Failed to capture payment intent"
completion(NSError(domain: "com.stripe-terminal-ios.example", code: 2, userInfo: [NSLocalizedDescriptionKey: description]))
default:
completion(error ?? NSError(domain: "com.stripe-terminal-ios.example", code: 0, userInfo: [NSLocalizedDescriptionKey: "Other networking error encountered."]))
}
} else {
completion(error)
}
}
task.resume()
}
// Move this to your App initialization
Terminal.initWithTokenProvider(APIClient.shared)
let config = try InternetDiscoveryConfigurationBuilder().setSimulated(true).build()
let config = try TapToPayDiscoveryConfigurationBuilder().setSimulated(true).build()
let config = try BluetoothScanDiscoveryConfigurationBuilder().setSimulated(true).build()
let connectionConfig = try InternetConnectionConfigurationBuilder(delegate: self).build()
let connectionConfig = try TapToPayConnectionConfigurationBuilder(
delegate: self,
locationId: reader.locationId!
).build()
let connectionConfig = try BluetoothConnectionConfigurationBuilder(
delegate: self,
// When connecting to a physical reader, your integration should specify either the
// same location as the last connection (reader.locationId) or a new location
// of your user's choosing.
//
// Since the simulated reader is not associated with a real location, we recommend
// specifying its existing mock location.
locationId: reader.locationId!
).build()
let params = try PaymentIntentParametersBuilder(amount: 1000,
currency: "{{TERMINAL_CURRENCY}}")
.setPaymentMethodTypes([{{TERMINAL_PAYMENT_METHODS}}])
.build()
let processedIntent = try await Terminal.shared.processPaymentIntent(paymentIntent, collectConfig: nil, confirmConfig: nil)
// MARK: - Mobile Reader Delegate
extension TerminalManager: @MainActor MobileReaderDelegate {
func reader(_ reader: Reader, didDisconnect reason: DisconnectReason) {
statusMessage = "Reader disconnected"
currentState = .initial
buttonTitle = "Discover Readers"
connectedReader = nil
}
func reader(_ reader: Reader, didRequestReaderInput inputOptions: ReaderInputOptions = []) {
statusMessage = Terminal.stringFromReaderInputOptions(inputOptions)
}
func reader(_ reader: Reader, didRequestReaderDisplayMessage displayMessage: ReaderDisplayMessage) {
statusMessage = Terminal.stringFromReaderDisplayMessage(displayMessage)
}
func reader(_ reader: Reader, didStartInstallingUpdate update: ReaderSoftwareUpdate, cancelable: Cancelable?) {
statusMessage = "Installing update..."
}
func reader(_ reader: Reader, didReportReaderSoftwareUpdateProgress progress: Float) {
statusMessage = "Update progress: \(Int(progress * 100))%"
}
func reader(_ reader: Reader, didFinishInstallingUpdate update: ReaderSoftwareUpdate?, error: Error?) {
if let error = error {
statusMessage = "Update failed: \(error.localizedDescription)"
} else {
statusMessage = "Update complete"
}
}
func reader(_ reader: Reader, didReportAvailableUpdate update: ReaderSoftwareUpdate) {
statusMessage = "Update available"
}
}
// MARK: - Internet Reader Delegate
extension TerminalManager: @MainActor InternetReaderDelegate {
func reader(_ reader: Reader, didDisconnect reason: DisconnectReason) {
statusMessage = "Reader disconnected"
currentState = .initial
buttonTitle = "Discover Readers"
connectedReader = nil
}
}
// MARK: - Tap To Pay Reader Delegate
extension TerminalManager: @MainActor TapToPayReaderDelegate {
func tapToPayReader(_ reader: Reader, didStartInstallingUpdate update: ReaderSoftwareUpdate, cancelable: Cancelable?) {
statusMessage = "Installing update..."
}
func tapToPayReader(_ reader: Reader, didReportReaderSoftwareUpdateProgress progress: Float) {
statusMessage = "Update progress: \(Int(progress * 100))%"
}
func tapToPayReader(_ reader: Reader, didFinishInstallingUpdate update: ReaderSoftwareUpdate?, error: Error?) {
if let error = error {
statusMessage = "Update failed: \(error.localizedDescription)"
} else {
statusMessage = "Update complete"
}
}
func tapToPayReader(_ reader: Reader, didRequestReaderDisplayMessage displayMessage: ReaderDisplayMessage) {
statusMessage = Terminal.stringFromReaderDisplayMessage(displayMessage)
}
func tapToPayReader(_ reader: Reader, didRequestReaderInput inputOptions: ReaderInputOptions = []) {
statusMessage = Terminal.stringFromReaderInputOptions(inputOptions)
}
}
func fetchConnectionToken(_ completion: @escaping ConnectionTokenCompletionBlock) {
Task {
do {
let secret = try await fetchConnectionTokenAsync()
completion(secret, nil)
} catch {
completion(nil, error)
}
}
}
private func fetchConnectionTokenAsync() async throws -> String {
let url = URL(string: "/connection_token", relativeTo: APIClient.backendUrl)!
var request = URLRequest(url: url)
request.httpMethod = "POST"
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw NSError(domain: "com.stripe-terminal-ios.example",
code: 1000,
userInfo: [NSLocalizedDescriptionKey: "Invalid response from ConnectionToken endpoint"])
}
let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
guard let secret = json?["secret"] as? String else {
throw NSError(domain: "com.stripe-terminal-ios.example",
code: 2000,
userInfo: [NSLocalizedDescriptionKey: "Missing 'secret' in ConnectionToken JSON response"])
}
return secret
}
func capturePaymentIntent(_ paymentIntentId: String) async throws {
let url = URL(string: "/capture_payment_intent", relativeTo: APIClient.backendUrl)!
let parameters = ["payment_intent_id": paymentIntentId]
let jsonData = try JSONSerialization.data(withJSONObject: parameters)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse else {
throw NSError(domain: "com.stripe-terminal-ios.example",
code: 0,
userInfo: [NSLocalizedDescriptionKey: "Invalid response"])
}
switch httpResponse.statusCode {
case 200..<300:
return
case 402:
let description = String(data: data, encoding: .utf8) ?? "Failed to capture payment intent"
throw NSError(domain: "com.stripe-terminal-ios.example",
code: 2,
userInfo: [NSLocalizedDescriptionKey: description])
default:
throw NSError(domain: "com.stripe-terminal-ios.example",
code: 0,
userInfo: [NSLocalizedDescriptionKey: "Capture failed with status code \(httpResponse.statusCode)"])
}
}
@interface ViewController ()
@interface ViewController ()
@interface ViewController ()
[SCPTerminal initWithTokenProvider:APIClient.shared];
NSError *configError = nil;
SCPInternetDiscoveryConfiguration *config = [[[SCPInternetDiscoveryConfigurationBuilder new]
setSimulated:YES]
build:&configError];
if (configError) {
NSLog(@"Unexpected error building discovery configuration!");
} else {
self.discoverCancelable = [[SCPTerminal shared] discoverReaders:config
delegate:self
completion:^(NSError * _Nullable error) {
NSError *configError = nil;
SCPTapToPayDiscoveryConfiguration *config = [[[SCPTapToPayDiscoveryConfigurationBuilder new]
setSimulated:YES]
build:&configError];
if (configError) {
NSLog(@"Unexpected error building discovery configuration!");
} else {
self.discoverCancelable = [[SCPTerminal shared] discoverReaders:config
delegate:self
completion:^(NSError * _Nullable error) {
NSError *configError = nil;
SCPBluetoothProximityDiscoveryConfiguration *config = [[[SCPBluetoothProximityDiscoveryConfigurationBuilder new]
setSimulated:YES]
build:&configError];
if (configError) {
NSLog(@"Unexpected error building discovery configuration!");
} else {
self.discoverCancelable = [[SCPTerminal shared] discoverReaders:config
delegate:self
completion:^(NSError * _Nullable error) {
NSError *error = nil;
SCPPaymentIntentParameters *paymentIntentParams = [[[[SCPPaymentIntentParametersBuilder alloc] initWithAmount:1000
currency:@"{{TERMINAL_CURRENCY}}"]
setPaymentMethodTypes:@[{{TERMINAL_PAYMENT_METHODS}}]]
build:&error];
[[SCPTerminal shared] processPaymentIntent:intent
collectConfig:nil
confirmConfig:nil
completion:^(SCPPaymentIntent * _Nullable processedIntent, NSError * _Nullable processError) {
// When connecting to a physical reader, your integration should specify either the
// same location as the last connection (selectedReader.locationId) or a new location
// of your user's choosing.
//
// Since the simulated reader is not associated with a real location, we recommend
// specifying its existing mock location.
NSError *configError = nil;
SCPBluetoothConnectionConfiguration *config = [[[SCPBluetoothConnectionConfigurationBuilder alloc]
initWithDelegate:self
locationId:selectedReader.locationId]
build:&configError];
if (configError) {
NSLog(@"Error building connection configuration, check location id!");
} else {
NSError *configError = nil;
SCPInternetConnectionConfiguration *config = [[[[SCPInternetConnectionConfigurationBuilder alloc]
initWithDelegate:self]
setFailIfInUse:YES]
build:&configError];
if (configError) {
NSLog(@"Error building connection configuration, check location id!");
} else {
NSError *configError = nil;
SCPTapToPayConnectionConfiguration *config = [[[SCPTapToPayConnectionConfigurationBuilder alloc]
initWithDelegate:self
locationId:selectedReader.locationId]
build:&configError];
if (configError) {
NSLog(@"Error building connection configuration, check location id!");
} else {
#pragma mark - SCPBluetoothReaderDelegate
- (void)reader:(SCPReader *)reader didRequestReaderInput:(SCPReaderInputOptions)inputOptions {
// Update UI requesting reader input
self.readerMessageLabel.text = [SCPTerminal stringFromReaderInputOptions:inputOptions];
}
- (void)reader:(SCPReader *)reader didRequestReaderDisplayMessage:(SCPReaderDisplayMessage)displayMessage {
// Update UI showing reader message
self.readerMessageLabel.text = [SCPTerminal stringFromReaderDisplayMessage:displayMessage];
}
- (void)reader:(nonnull SCPReader *)reader didStartInstallingUpdate:(SCPReaderSoftwareUpdate *)update cancelable:(nullable SCPCancelable *)cancelable {
// Show UI communicating that a required update has started installing
}
- (void)reader:(nonnull SCPReader *)reader didReportReaderSoftwareUpdateProgress:(float)progress {
// Update the progress of the install
}
- (void)reader:(nonnull SCPReader *)reader didFinishInstallingUpdate:(nullable SCPReaderSoftwareUpdate *)update error:(nullable NSError *)error {
// Report success or failure of the update
}
- (void)reader:(nonnull SCPReader *)reader didReportAvailableUpdate:(SCPReaderSoftwareUpdate *)update {
// An update is available for the connected reader. Show this update in your application.
// This update can be installed using Terminal.shared.installAvailableUpdate.
}
#pragma mark - SCPInternetReaderDelegate
- (void)reader:(SCPReader *)reader didDisconnect:(SCPDisconnectReason)reason {
// Handle reader disconnects here.
}
#pragma mark - SCPTapToPayReaderDelegate
- (void)tapToPayReader:(nonnull SCPReader *)reader didStartInstallingUpdate:(nonnull SCPReaderSoftwareUpdate *)update cancelable:(nullable SCPCancelable *)cancelable {
// In your app, let the user know that an update is being installed on the reader
}
- (void)tapToPayReader:(nonnull SCPReader *)reader didReportReaderSoftwareUpdateProgress:(float)progress {
// The update or configuration process has reached the specified progress (0.0 to 1.0)
// If you are displaying a progress bar or percentage, this can be updated here
}
- (void)tapToPayReader:(nonnull SCPReader *)reader didFinishInstallingUpdate:(nullable SCPReaderSoftwareUpdate *)update error:(nullable NSError *)error {
// The reader has finished installing an update
// If `error` is nil, it is safe to proceed and start collecting payments
// Otherwise, check the value of `error` for more information on what went wrong
}
- (void)tapToPayReader:(nonnull SCPReader *)reader didRequestReaderDisplayMessage:(SCPReaderDisplayMessage)displayMessage {
// This is called to request that a prompt be displayed in your app.
self.readerMessageLabel.text = [SCPTerminal stringFromReaderDisplayMessage:displayMessage];
}
- (void)tapToPayReader:(nonnull SCPReader *)reader didRequestReaderInput:(SCPReaderInputOptions)inputOptions {
// This is called when the reader begins waiting for input
self.readerMessageLabel.text = [SCPTerminal stringFromReaderInputOptions:inputOptions];
}
- (void)fetchConnectionToken:(SCPConnectionTokenCompletionBlock)completion {
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
NSURL *url = [NSURL URLWithString:@"/connection_token" relativeToURL:[APIClient backendUrl]];
if (!url) {
NSAssert(NO, @"Invalid backend URL");
}
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
request.HTTPMethod = @"POST";
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
id jsonObject = nil;
NSError *jsonSerializationError;
if (data) {
jsonObject = [NSJSONSerialization JSONObjectWithData:data options:(NSJSONReadingOptions)kNilOptions error:&jsonSerializationError];
}
else {
NSError *error = [NSError errorWithDomain:@"com.stripe-terminal-ios.example"
code:1000
userInfo:@{NSLocalizedDescriptionKey: @"No data in response from ConnectionToken endpoint"}];
completion(nil, error);
}
if (!(jsonObject && [jsonObject isKindOfClass:[NSDictionary class]])) {
completion(nil, jsonSerializationError);
return;
}
NSDictionary *json = (NSDictionary *)jsonObject;
id secret = json[@"secret"];
if (!(secret && [secret isKindOfClass:[NSString class]])) {
NSError *error = [NSError errorWithDomain:@"com.stripe-terminal-ios.example"
code:2000
userInfo:@{NSLocalizedDescriptionKey: @"Missing 'secret' in ConnectionToken JSON response"}];
completion(nil, error);
return;
}
completion((NSString *)secret, nil);
}];
[task resume];
}
- (void)capturePaymentIntent:(NSString *)paymentIntentId
completion:(SCPErrorCompletionBlock)completion {
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
NSURL *url = [NSURL URLWithString:@"/capture_payment_intent" relativeToURL:[APIClient backendUrl]];
NSString *parameters = [NSString stringWithFormat:@"{\"payment_intent_id\":\"%@\"}", paymentIntentId];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
request.HTTPMethod = @"POST";
request.HTTPBody = [parameters dataUsingEncoding:NSUTF8StringEncoding];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (response) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
if (httpResponse.statusCode >= 200 && httpResponse.statusCode < 300) {
completion(nil);
} else if (httpResponse.statusCode == 402) {
NSString *description = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (!description) {
description = @"Failed to capture payment intent";
}
NSError *error = [NSError errorWithDomain:@"com.stripe-terminal-ios.example"
code:2
userInfo:@{NSLocalizedDescriptionKey: description}];
completion(error);
} else {
if(error) {
completion(error);
} else {
NSError *error = [NSError errorWithDomain:@"com.stripe-terminal-ios.example"
code:0
userInfo:@{NSLocalizedDescriptionKey: @"Other networking error occurred"}];
completion(error);
}
}
} else {
completion(error);
}
}];
[task resume];
}
private val paymentIntentParams =
PaymentIntentParameters.Builder(listOf(PaymentMethodType.CARD_PRESENT))
.setAmount(500)
.setCurrency("{{TERMINAL_CURRENCY}}")
.build()
private val discoveryConfig =
DiscoveryConfiguration.InternetDiscoveryConfiguration(isSimulated = true)
private val discoveryConfig =
DiscoveryConfiguration.TapToPayDiscoveryConfiguration(isSimulated = true)
private val discoveryConfig =
DiscoveryConfiguration.BluetoothDiscoveryConfiguration(isSimulated = true)
Terminal.getInstance()
.processPaymentIntent(
intent = paymentIntent,
callback = processPaymentIntentCallback,
)
// Check for location permissions
if (!isGranted(Manifest.permission.ACCESS_FINE_LOCATION)) {
// If we don't have them yet, request them before doing anything else
requestPermissionLauncher.launch(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION))
} else if (!Terminal.isInitialized() && verifyGpsEnabled()) {
initialize()
}
if (!isGranted(Manifest.permission.ACCESS_FINE_LOCATION)) add(Manifest.permission.ACCESS_FINE_LOCATION)
private fun onPermissionResult(result: Map) {
val deniedPermissions: List = result
.filter { !it.value }
.map { it.key }
// If we receive a response to our permission check, initialize
if (deniedPermissions.isEmpty() && !Terminal.isInitialized() && verifyGpsEnabled()) {
initialize()
}
}
try {
Terminal.init(
context = applicationContext,
logLevel = LogLevel.VERBOSE,
tokenProvider = TokenProvider(),
listener = TerminalEventListener(),
offlineListener = null,
)
} catch (e: TerminalException) {
throw RuntimeException(
"Location services are required to initialize " +
"the Terminal.",
e
)
}
Terminal.getInstance().discoverReaders(discoveryConfig, discoveryListener, discoveryCallback)
Terminal.getInstance().createPaymentIntent(paymentIntentParams, createPaymentIntentCallback)
class TokenProvider : ConnectionTokenProvider {
override fun fetchConnectionToken(callback: ConnectionTokenCallback) {
try {
val token = ApiClient.createConnectionToken()
callback.onSuccess(token)
} catch (e: ConnectionTokenException) {
callback.onFailure(e)
}
}
}
class StripeTerminalApplication : Application() {
override fun onCreate() {
super.onCreate()
// If you already have a class that extends 'Application',
// put whatever code you had in the 'onCreate' method here.
TerminalApplicationDelegate.onCreate(this)
}
}
class StripeTerminalApplication : Application() {
override fun onCreate() {
super.onCreate()
// If you already have a class that extends 'Application',
// put whatever code you had in the 'onCreate' method here.
// Skip initialization if running in the TTPA process.
if (TapToPay.isInTapToPayProcess()) return
TerminalApplicationDelegate.onCreate(this)
}
}
import com.stripe.stripeterminal.external.callable.InternetReaderListener
import com.stripe.stripeterminal.external.callable.TapToPayReaderListener
// When connecting to a physical reader, your integration should specify either the
// same location as the last connection (reader.locationId) or a new location
// of your user's choosing.
//
// Since the simulated reader is not associated with a real location, we recommend
// specifying its existing mock location.
val connectionConfig =
ConnectionConfiguration.BluetoothConnectionConfiguration(
locationId = reader.location!!.id!!,
autoReconnectOnUnexpectedDisconnect = true,
bluetoothReaderListener = TerminalBluetoothReaderListener(),
)
val connectionConfig =
ConnectionConfiguration.InternetConnectionConfiguration(
failIfInUse = true,
internetReaderListener = object : InternetReaderListener {
override fun onDisconnect(reason: DisconnectReason) {
// Show UI that your reader disconnected
}
},
)
val connectionConfig =
ConnectionConfiguration.TapToPayConnectionConfiguration(
locationId = reader.location?.id
?: throw RuntimeException("No location ID available"),
autoReconnectOnUnexpectedDisconnect = true,
tapToPayReaderListener = object : TapToPayReaderListener {}
)
Terminal.getInstance().connectReader(
reader = reader,
config = connectionConfig,
connectionCallback = readerCallback,
)
@Throws(Exception::class)
internal fun createPaymentIntent(
amount: Int, currency: String, callback: Callback
) {
service.createPaymentIntent(amount, currency).enqueue(callback)
}
internal fun capturePaymentIntent(id: String) {
service.capturePaymentIntent(id).execute()
}
import com.stripe.example.ServerPaymentIntent
/**
* Create a payment intent on the backend
*/
@FormUrlEncoded
@POST("create_payment_intent")
fun createPaymentIntent(
@Field("amount") amount: Int,
@Field("currency") currency: String
): Call
implementation "com.stripe:stripeterminal:5.4.0"
implementation("com.stripe:stripeterminal-taptopay:5.4.0")
implementation("com.stripe:stripeterminal-core:5.4.0")
.setAmount(500)
private final DiscoveryConfiguration discoveryConfig =
new DiscoveryConfiguration.InternetDiscoveryConfiguration(0, null, true, DiscoveryFilter.None.INSTANCE);
private final TapToPayDiscoveryConfiguration discoveryConfig =
new DiscoveryConfiguration.TapToPayDiscoveryConfiguration(true);
private final DiscoveryConfiguration discoveryConfig =
new DiscoveryConfiguration.BluetoothDiscoveryConfiguration(0, true);
Terminal.getInstance()
.processPaymentIntent(paymentIntent, new CollectPaymentIntentConfiguration.Builder().build(), new ConfirmPaymentIntentConfiguration.Builder().build(), processPaymentIntentCallback);
Terminal.getInstance()
.createPaymentIntent(paymentIntentParams, createPaymentIntentCallback);
try {
Terminal.init(
getApplicationContext(), LogLevel.VERBOSE, new TokenProvider(),
new TerminalEventListener(), null);
} catch (TerminalException e) {
throw new RuntimeException(
"Location services are required to initialize " +
"the Terminal.",
e
);
}
Terminal.getInstance()
.discoverReaders(discoveryConfig, discoveryListener, discoveryCallback);
if (!isGranted(Manifest.permission.ACCESS_FINE_LOCATION)) {
if (!isGranted(Manifest.permission.ACCESS_FINE_LOCATION)) {
deniedPermissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
void onPermissionResult(Map result) {
List deniedPermissions = result.entrySet().stream()
.filter(it -> !it.getValue())
.map(it -> it.getKey())
.collect(Collectors.toList());
// If we receive a response to our permission check, initialize
if (deniedPermissions.isEmpty() && !Terminal.isInitialized() && verifyGpsEnabled()) {
initialize();
}
}
public class TokenProvider implements ConnectionTokenProvider {
@Override
public void fetchConnectionToken(ConnectionTokenCallback callback) {
try {
final String token = ApiClient.createConnectionToken();
callback.onSuccess(token);
} catch (ConnectionTokenException e) {
callback.onFailure(e);
}
}
}
public class StripeTerminalApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// If you already have a class that extends 'Application',
// put whatever code you had in the 'onCreate' method here.
TerminalApplicationDelegate.onCreate(this);
}
}
public class StripeTerminalApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// If you already have a class that extends 'Application',
// put whatever code you had in the 'onCreate' method here.
// Skip initialization if running in the TTPA process.
if (TapToPay.isInTapToPayProcess()) return;
TerminalApplicationDelegate.onCreate(this);
}
}
import com.stripe.stripeterminal.external.callable.InternetReaderListener;
import com.stripe.stripeterminal.external.callable.TapToPayReaderListener;
ConnectionConfiguration.InternetConnectionConfiguration connectionConfig =
new ConnectionConfiguration.InternetConnectionConfiguration(
true,
new InternetReaderListener() {
@Override
public void onDisconnect(@NonNull DisconnectReason reason) {
final MainActivity activity = activityRef.get();
if (activity != null) {
activity.runOnUiThread(() -> {
// Show UI that your reader disconnected
});
}
}
}
);
ConnectionConfiguration.TapToPayConnectionConfiguration connectionConfig =
new ConnectionConfiguration.TapToPayConnectionConfiguration(
locationId,
true,
new TapToPayReaderListener() {}
);
ConnectionConfiguration.BluetoothConnectionConfiguration connectionConfig =
new ConnectionConfiguration.BluetoothConnectionConfiguration(
locationId,
true,
new TerminalBluetoothReaderListener()
);
Terminal.getInstance().connectReader(
reader,
connectionConfig,
new ReaderCallback() {
@Override
public void onSuccess(@NonNull Reader reader) {
final MainActivity activity = activityRef.get();
if (activity != null) {
activity.runOnUiThread(() -> {
// Update UI w/ connection success
activity.updateReaderConnection(true);
});
}
}
@Override
public void onFailure(@NonNull TerminalException e) {
final MainActivity activity = activityRef.get();
if (activity != null) {
activity.runOnUiThread(() -> {
// Update UI w/ connection failure
});
}
}
}
);
public static void createPaymentIntent(
Integer amount,
String currency,
Callback callback)
{
mService.createPaymentIntent(amount, currency).enqueue(callback);
}
public static void capturePaymentIntent(@NonNull String id) throws IOException {
mService.capturePaymentIntent(id).execute();
}
/**
* Create a payment intent on the backend
*/
@FormUrlEncoded
@POST("create_payment_intent")
Call createPaymentIntent(
@Field("amount") Integer amount,
@Field("currency") String currency
);
/**
* Create a payment intent on the backend
*/
@FormUrlEncoded
@POST("create_payment_intent")
Call createPaymentIntent(
@Field("amount") Integer amount,
@Field("currency") String currency
);
implementation 'com.stripe:stripeterminal:5.4.0'
implementation 'com.stripe:stripeterminal-taptopay:5.4.0'
implementation 'com.stripe:stripeterminal-core:5.4.0'
1. Build the server
~~~
npm install
~~~
2. Run the server
~~~
npm start
~~~
1. Run the server
~~~
go run server.go
~~~
1. Build the server
~~~
pip3 install -r requirements.txt
~~~
2. Run the server
~~~
export FLASK_APP="server.py" && python3 -m flask run --port=4242
~~~
1. Build the server
~~~
bundle install
~~~
2. Run the server
~~~
ruby server.rb
~~~
1. Build the server
~~~
composer install
~~~
2. Run the server
~~~
php -S 127.0.0.1:4242 --docroot=public
~~~
1. Build the server
~~~
dotnet restore
~~~
2. Run the server
~~~
dotnet run
~~~
1. Build the server
~~~
mvn package
~~~
2. Run the server
~~~
java -cp target/sample-jar-with-dependencies.jar com.stripe.sample.Server
~~~
## Nächste Schritte
#### [Verbindung mit einem Lesegerät herstellen](https://docs.stripe.com/terminal/payments/connect-reader.md)
Erfahren Sie, wie Sie Ihre App mit einem Lesegerät verbinden.
#### [Gerätemanagement](https://docs.stripe.com/terminal/fleet/locations-and-zones.md)
Gruppieren und verwalten Sie Ihre Lesegeräte nach physischem Standort.
#### [Connect](https://docs.stripe.com/terminal/features/connect.md)
Integrieren Sie Stripe Terminal in Ihre Connect-Plattform.