# Accepter les paiements par TPE
# Accepter les paiements par TPE
Ce guide explique comment accepter des paiements en personne dans votre propre application de point de vente (POS) en utilisant Stripe Terminal. Vous n’avez besoin d’aucun matériel pour réaliser ces étapes avec notre [lecteur simulé](https://docs.stripe.com/terminal/references/testing.md#simulated-reader). Vous pouvez également, si vous le souhaitez, télécharger l’exemple et exécuter l’application.
Lorsque vous êtes prêt à utiliser un lecteur physique, il vous suffit de mettre à jour l"[étape inscription lecteur](https://docs.stripe.com/terminal/quickstart.md#register-reader) (pour les intégrations pilotées par serveur) ou [l"étape découverte lecteur](https://docs.stripe.com/terminal/quickstart.md#discover-reader) (pour les intégrations SDK).
> #### Prise en charge des lecteurs Verifone
>
> La prise en charge des lecteurs Verifone est en version bêta publique aux États-Unis et au Canada. Certains lecteurs Verifone sont en version preview privée en Irlande et au Royaume-Uni (V660p, UX700, P630) ainsi qu’à Singapour (V660p, P630). Pour rejoindre la version bêta, vous devez [contacter l’équipe commerciale afin de commander le lecteur concerné](https://stripe.com/contact/sales).
### Installer la bibliothèque Node de Stripe
Installez le package et importez-le dans votre code. Si vous partez de zéro et qu’il vous faut un fichier package.json, vous pouvez également télécharger les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### npm
Installez la bibliothèque :
```bash
npm install --save stripe
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque Node de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-node).
### Installer la bibliothèque Ruby de Stripe
Installez le gem Ruby de Stripe et exigez-le dans votre code. Si vous partez de zéro et avez besoin d’un Gemfile, téléchargez les fichiers du projet à l’aide du lien dans l’éditeur de code.
#### Terminal
Installez le gem :
```bash
gem install stripe
```
#### Bundler
Ajoutez cette ligne à votre Gemfile :
```bash
gem 'stripe'
```
#### GitHub
Vous pouvez sinon télécharger le code source du gem Ruby de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-ruby).
### Installer la bibliothèque Java
Ajoutez la dépendance à votre build et importez la bibliothèque. Ou bien, si vous partez de zéro et avez besoin d’un exemple de fichier pom.xml (pour Maven), téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### Maven
Ajoutez la dépendance suivante à votre POM et remplacez {VERSION} par le numéro de version que vous souhaitez utiliser.
```bash
\ncom.stripe\nstripe-java\n{VERSION}\n
```
#### Gradle
Ajoutez la dépendance à votre fichier build.gradle et remplacez {VERSION} par le numéro de version que vous souhaitez utiliser.
```bash
implementation "com.stripe:stripe-java:{VERSION}"
```
#### GitHub
Téléchargez le fichier JAR directement [depuis GitHub](https://github.com/stripe/stripe-java/releases/latest).
### Installer le package Python de Stripe
Installez le package Stripe et importez-le dans votre code. Si vous partez de zéro et qu’il vous faut un fichier requirements.txt, téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### pip
Installez le package via pip :
```bash
pip3 install stripe
```
#### GitHub
Téléchargez le code source de la bibliothèque stripe-python directement [depuis GitHub](https://github.com/stripe/stripe-python).
### Installer la bibliothèque PHP
Installez la bibliothèque avec composer et initialisez-la avec votre clé API secrète. Si vous partez de zéro et que vous avez besoin d’un fichier composer.json, vous pouvez également télécharger les fichiers à l’aide du lien de téléchargement dans l’éditeur de code.
#### Composer
Installez la bibliothèque :
```bash
composer require stripe/stripe-php
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque php de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-php).
### Configurer votre serveur
Ajoutez la dépendance à votre build et importez la bibliothèque. Si vous partez de zéro et avez besoin d’un fichier go.mod, téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### Go
Veillez à initialiser avec des modules Go :
```bash
go get -u github.com/stripe/stripe-go/v85
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque Go de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-go).
### Installer la bibliothèque Stripe.net
Installez le package avec .NET ou NuGet. Si vous partez de zéro, vous pouvez également télécharger les fichiers qui contiennent un fichier .csproj configuré.
#### .NET
Installez la bibliothèque :
```bash
dotnet add package Stripe.net
```
#### NuGet
Installez la bibliothèque :
```bash
Install-Package Stripe.net
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque .NET de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-dotnet).
### Installer les bibliothèques Stripe
Installez les packages et importez-les dans votre code. Si vous partez de zéro et qu’il vous faut un fichier `package.json`, vous pouvez également télécharger les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
Installez les bibliothèques :
```bash
npm install --save stripe @stripe/stripe-js next
```
### Créer des emplacements pour vos lecteurs
[Créez des emplacements](https://docs.stripe.com/terminal/fleet/locations-and-zones.md) pour organiser vos lecteurs. Les emplacements regroupent les lecteurs et leur permettent de télécharger automatiquement la configuration du lecteur nécessaire à leur région d’utilisation. Vous devez attribuer un emplacement à chaque lecteur lorsque vous l’[enregistrez](https://docs.stripe.com/terminal/fleet/register-readers.md), ce que vous pouvez faire à l’aide de l’API ou du Dashboard.
### Enregistrer un lecteur
Un lecteur de simulation vous permet de vous lancer rapidement et de créer une intégration fonctionnelle sans nécessiter de matériel. Pour créer un lecteur de simulation, utilisez le code d’inscription spécial `simulated-s700`. Notez l’ID de votre lecteur. Il vous servira ensuite pour traiter un paiement sur le lecteur.
### Enregistrer un lecteur
Un lecteur simulé vous permet de commencer rapidement et de construire une intégration fonctionnelle sans nécessiter de matériel physique. Créez un lecteur simulé en utilisant le code d’enregistrement spécial `simulated-s710`. Conservez l’identifiant de votre lecteur afin de pouvoir l’utiliser plus tard pour traiter un paiement sur celui-ci.
### Enregistrer un lecteur
Un lecteur de simulation vous permet de vous lancer rapidement et de créer une intégration fonctionnelle sans nécessiter de matériel. Pour créer un lecteur de simulation, utilisez le code d’inscription spécial `simulated-v660p`. Notez l’ID de votre lecteur. Il vous servira ensuite pour traiter un paiement sur le lecteur.
### Enregistrer un lecteur
Un lecteur de simulation vous permet de vous lancer rapidement et de créer une intégration fonctionnelle sans nécessiter de matériel. Pour créer un lecteur de simulation, utilisez le code d’inscription spécial `simulated-wpe`. Notez l’ID de votre lecteur. Il vous servira ensuite pour traiter un paiement sur le lecteur.
### Créer un PaymentIntent
Créez un PaymentIntent sur votre serveur. Un PaymentIntent suit le cycle de vie du paiement du client, en gardant trace de toutes les tentatives de paiement ayant échoué et en s’assurant qu’il n’est débité qu’une seule fois. Enregistrez l’ID du PaymentIntent pour les paiements futurs.
### Traiter le Paymentintent sur votre lecteur
Créez un PaymentIntent avec le montant spécifique et traitez le paiement sur votre lecteur simulé. Le lecteur invite le client à présenter sa carte bancaire en l’insérant ou en la tapotant avant de tenter une autorisation.
### Simuler une présentation de carte sur votre lecteur
> Dans un flux de transaction réel, le client insère ou tape sa carte bancaire sur le lecteur physique. Avec un lecteur simulé, vous simulez l’étape de présentation de la carte bancaire en effectuant un autre appel à l’API.
Cet appel confirme avec succès le PaymentIntent avec une carte de test. Vous pouvez également essayer d’autres cartes de test.
### Capturer le PaymentIntent
Une fois le PaymentIntent confirmé, vous pouvez le capturer pour recevoir les fonds.
### Gérer les erreurs
Chaque scénario d’erreur est associé à un code spécifique que votre application doit gérer. Les erreurs nécessitent généralement l’intervention d’un caissier dans le magasin. Affichez un message approprié dans votre application de point de vente afin qu’il puisse réagir en conséquence. Pour en savoir plus, consultez la [documentation relative à la gestion des erreurs](https://docs.stripe.com/terminal/payments/collect-card-payment.md?terminal-sdk-platform=server-driven#handle-errors).
### Exécuter l’application
Exécutez votre serveur et accédez à l’adresse http://localhost:4242.
### Tester l’intégration avec un numéro de carte de test
Vous pouvez configurer le lecteur simulé afin de tester différents flux au sein de votre application de point de vente, par exemple différentes marques de cartes ou des scénarios d’erreur comme un paiement refusé. Afin d’activer ce comportement, transmettez un moyen de paiement test en effectuant un appel à l’API pour le [moyen de paiement actuel](https://docs.stripe.com/api/terminal/readers/present_payment_method.md).
| Scenario | Card Number |
| ------------------- | ---------------- |
| Payment succeeds | 4242424242424242 |
| Payment is declined | 4000000000009995 |
### Installer la bibliothèque Node de Stripe
Installez le package et importez-le dans votre code. Si vous partez de zéro et qu’il vous faut un fichier package.json, vous pouvez également télécharger les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### npm
Installez la bibliothèque :
```bash
npm install --save stripe
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque Node de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-node).
### Installer la bibliothèque Ruby de Stripe
Installez le gem Ruby de Stripe et exigez-le dans votre code. Si vous partez de zéro et avez besoin d’un Gemfile, téléchargez les fichiers du projet à l’aide du lien dans l’éditeur de code.
#### Terminal
Installez le gem :
```bash
gem install stripe
```
#### Bundler
Ajoutez cette ligne à votre Gemfile :
```bash
gem 'stripe'
```
#### GitHub
Vous pouvez sinon télécharger le code source du gem Ruby de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-ruby).
### Installer la bibliothèque Java
Ajoutez la dépendance à votre build et importez la bibliothèque. Ou bien, si vous partez de zéro et avez besoin d’un exemple de fichier pom.xml (pour Maven), téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### Maven
Ajoutez la dépendance suivante à votre POM et remplacez {VERSION} par le numéro de version que vous souhaitez utiliser.
```bash
\ncom.stripe\nstripe-java\n{VERSION}\n
```
#### Gradle
Ajoutez la dépendance à votre fichier build.gradle et remplacez {VERSION} par le numéro de version que vous souhaitez utiliser.
```bash
implementation "com.stripe:stripe-java:{VERSION}"
```
#### GitHub
Téléchargez le fichier JAR directement [depuis GitHub](https://github.com/stripe/stripe-java/releases/latest).
### Installer le package Python de Stripe
Installez le package Stripe et importez-le dans votre code. Si vous partez de zéro et qu’il vous faut un fichier requirements.txt, téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### pip
Installez le package via pip :
```bash
pip3 install stripe
```
#### GitHub
Téléchargez le code source de la bibliothèque stripe-python directement [depuis GitHub](https://github.com/stripe/stripe-python).
### Installer la bibliothèque PHP
Installez la bibliothèque avec composer et initialisez-la avec votre clé API secrète. Si vous partez de zéro et que vous avez besoin d’un fichier composer.json, vous pouvez également télécharger les fichiers à l’aide du lien de téléchargement dans l’éditeur de code.
#### Composer
Installez la bibliothèque :
```bash
composer require stripe/stripe-php
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque php de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-php).
### Configurer votre serveur
Ajoutez la dépendance à votre build et importez la bibliothèque. Si vous partez de zéro et avez besoin d’un fichier go.mod, téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### Go
Veillez à initialiser avec des modules Go :
```bash
go get -u github.com/stripe/stripe-go/v85
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque Go de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-go).
### Installer la bibliothèque Stripe.net
Installez le package avec .NET ou NuGet. Si vous partez de zéro, vous pouvez également télécharger les fichiers qui contiennent un fichier .csproj configuré.
#### .NET
Installez la bibliothèque :
```bash
dotnet add package Stripe.net
```
#### NuGet
Installez la bibliothèque :
```bash
Install-Package Stripe.net
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque .NET de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-dotnet).
### Installer les bibliothèques Stripe
Installez les packages et importez-les dans votre code. Si vous partez de zéro et qu’il vous faut un fichier `package.json`, vous pouvez également télécharger les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
Installez les bibliothèques :
```bash
npm install --save stripe @stripe/stripe-js next
```
> #### Accès à Terminal sur macOS
>
> Le SDK Stripe Terminal nécessite un accès au réseau local. Lorsque vous utilisez macOS, vous devez explicitement autoriser les applications de votre navigateur à accéder aux périphériques du réseau local. Pour en savoir plus, consultez l’[article d’aide Stripe](https://support.stripe.com/questions/ensuring-stripe-terminal-javascript-sdk-functionality-on-macos-15).
### Créer un endpoint ConnectionToken
Pour se connecter à un lecteur, votre back-end doit donner au SDK la permission d’utiliser le lecteur avec votre compte Stripe en lui fournissant la clé secrète d’un [ConnectionToken](https://docs.stripe.com/api/terminal/connection_tokens.md). Créez des tokens de connexion uniquement pour les clients de confiance et [transmettez un ID d’emplacement](https://docs.stripe.com/terminal/fleet/locations-and-zones.md#connection-tokens) lors de la création d’un token de connexion pour contrôler l’accès aux lecteurs. Si vous utilisez Connect, [appliquez le token de connexion](https://docs.stripe.com/terminal/features/connect.md) aux comptes connectés pertinents.
### Installer le SDK
Ce script doit toujours être chargé directement à partir du site https://js.stripe.com pour être compatible avec les derniers logiciels de lecture. N’incluez pas le script avec d’autres éléments et n’hébergez pas une copie vous-même, car cela pourrait interrompre sans prévenir votre intégration. Nous fournissons également un paquet npm qui facilite le chargement et l’utilisation du SDK JS Terminal en tant que module. Pour plus d’informations, consultez [le projet sur GitHub](https://github.com/stripe/terminal-js).
### Créer des emplacements pour vos lecteurs
[Créez des emplacements](https://docs.stripe.com/terminal/fleet/locations-and-zones.md) pour organiser vos lecteurs. Les emplacements regroupent les lecteurs et leur permettent de télécharger automatiquement la configuration du lecteur nécessaire à leur région d’utilisation. Vous devez attribuer un emplacement à chaque lecteur lorsque vous l’[enregistrez](https://docs.stripe.com/terminal/fleet/register-readers.md), ce que vous pouvez faire à l’aide de l’API ou du Dashboard.
### Récupérer le ConnectionToken
Pour permettre au SDK d’accéder à cet endpoint, créez une fonction dans votre application Web qui demande un ConnectionToken à votre back-end et renvoie la clé secrète de l’objet ConnectionToken.
### Initialiser le SDK
Pour initialiser une instance de `StripeTerminal` dans votre application`onFetchConnectionToken` JavaScript, fournissez la fonction `onFetchConnectionToken`. Vous devez également fournir la fonction `onUnexpectedReaderDisconnect` pour gérer les déconnexions inattendues du lecteur.
### Détecter les lecteurs
Le SDK Stripe Terminal est livré avec un lecteur de carte de simulation intégré, ce qui vous permet de développer et de tester votre application sans vous connecter à du matériel physique. Pour utiliser le lecteur de simulation, appelez `discoverReaders` afin de rechercher des lecteurs, avec l’option de simulation définie sur true. Pour détecter plus facilement les lecteurs prévus, filtrez par emplacement.
### Se connecter au lecteur de simulation
Lorsque `discoverReaders` renvoie un résultat, appelez le `connectReader` pour vous connecter au lecteur de simulation.
### Créer un PaymentIntent
Ajoutez un endpoint sur votre serveur qui crée un PaymentIntent. Un PaymentIntent suit le cycle de vie du paiement du client, en gardant trace de toutes les tentatives de paiement échouées et en s’assurant qu’il n’est facturé qu’une seule fois. Renvoyez la clé secrète du client du PaymentIntent dans la réponse. Si vous utilisez Connect, vous pouvez également spécifier des [informations sur le compte connecté](https://docs.stripe.com/terminal/features/connect.md) en fonction de la logique de facturation de votre plateforme.
### Récupérer le Paymentintent
Envoyez une requête à votre serveur pour obtenir un PaymentIntent afin d’initier le processus de paiement.
### Collecter les informations du moyen de paiement
Appelez `collectPaymentMethod` avec la clé secrète client du PaymentIntent pour collecter un moyen de paiement. Si vous utilisez un lecteur de simulation, l’appel de cette méthode met immédiatement à jour l’objet PaymentIntent en utilisant une [carte de test simulée](https://docs.stripe.com/terminal/references/testing.md#simulated-test-cards). Si vous utilisez un lecteur physique, le lecteur connecté attend qu’une carte lui soit présentée.
### Traiter le paiement
Après avoir recueilli les données relatives au moyen de paiement, appelez le `processPayment` avec le PaymentIntent actualisé pour traiter le paiement. Un appel réussi se traduit par un PaymentIntent à l’état `requires_capture` pour les captures manuelles ou `succeeded` pour les captures automatiques.
### Créer un endpoint pour capturer le PaymentIntent
Créez un endpoint dans votre back-end qui accepte un ID de PaymentIntent et envoie une requête à l’API Stripe pour le capturer.
### Capturer le PaymentIntent
Si vous avez défini `capture_method` sur `manual` lors de la création du PaymentIntent, le SDK renvoie à votre application un PaymentIntent autorisé, mais non capturé. Lorsque l’état du PaymentIntent est `requires_capture`, indiquez à votre back-end de capturer le PaymentIntent.
Pour les comptes connectés, avant de capturer manuellement un paiement, inspectez le `application_fee_amount` du PaymentIntent et modifiez-le si nécessaire.
### Exécuter l’application
Exécutez votre serveur et allez à [localhost:4242](http://localhost:4242).
### Tester l’intégration avec un numéro de carte de test
Vous pouvez configurer le lecteur simulé afin de tester différents flux au sein de votre application de point de vente, par exemple différentes marques de cartes ou des scénarios d’erreur comme un paiement refusé. Afin d’activer ce comportement, insérez cette ligne de code avant d’appeler `collectPaymentMethod`.
| Scenario | Card Number |
| ------------------- | ---------------- |
| Payment succeeds | 4242424242424242 |
| Payment is declined | 4000000000009995 |
### Installer la bibliothèque Node de Stripe
Installez le package et importez-le dans votre code. Si vous partez de zéro et qu’il vous faut un fichier package.json, vous pouvez également télécharger les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### npm
Installez la bibliothèque :
```bash
npm install --save stripe
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque Node de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-node).
### Installer la bibliothèque Ruby de Stripe
Installez le gem Ruby de Stripe et exigez-le dans votre code. Si vous partez de zéro et avez besoin d’un Gemfile, téléchargez les fichiers du projet à l’aide du lien dans l’éditeur de code.
#### Terminal
Installez le gem :
```bash
gem install stripe
```
#### Bundler
Ajoutez cette ligne à votre Gemfile :
```bash
gem 'stripe'
```
#### GitHub
Vous pouvez sinon télécharger le code source du gem Ruby de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-ruby).
### Installer la bibliothèque Java
Ajoutez la dépendance à votre build et importez la bibliothèque. Ou bien, si vous partez de zéro et avez besoin d’un exemple de fichier pom.xml (pour Maven), téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### Maven
Ajoutez la dépendance suivante à votre POM et remplacez {VERSION} par le numéro de version que vous souhaitez utiliser.
```bash
\ncom.stripe\nstripe-java\n{VERSION}\n
```
#### Gradle
Ajoutez la dépendance à votre fichier build.gradle et remplacez {VERSION} par le numéro de version que vous souhaitez utiliser.
```bash
implementation "com.stripe:stripe-java:{VERSION}"
```
#### GitHub
Téléchargez le fichier JAR directement [depuis GitHub](https://github.com/stripe/stripe-java/releases/latest).
### Installer le package Python de Stripe
Installez le package Stripe et importez-le dans votre code. Si vous partez de zéro et qu’il vous faut un fichier requirements.txt, téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### pip
Installez le package via pip :
```bash
pip3 install stripe
```
#### GitHub
Téléchargez le code source de la bibliothèque stripe-python directement [depuis GitHub](https://github.com/stripe/stripe-python).
### Installer la bibliothèque PHP
Installez la bibliothèque avec composer et initialisez-la avec votre clé API secrète. Si vous partez de zéro et que vous avez besoin d’un fichier composer.json, vous pouvez également télécharger les fichiers à l’aide du lien de téléchargement dans l’éditeur de code.
#### Composer
Installez la bibliothèque :
```bash
composer require stripe/stripe-php
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque php de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-php).
### Configurer votre serveur
Ajoutez la dépendance à votre build et importez la bibliothèque. Si vous partez de zéro et avez besoin d’un fichier go.mod, téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### Go
Veillez à initialiser avec des modules Go :
```bash
go get -u github.com/stripe/stripe-go/v85
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque Go de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-go).
### Installer la bibliothèque Stripe.net
Installez le package avec .NET ou NuGet. Si vous partez de zéro, vous pouvez également télécharger les fichiers qui contiennent un fichier .csproj configuré.
#### .NET
Installez la bibliothèque :
```bash
dotnet add package Stripe.net
```
#### NuGet
Installez la bibliothèque :
```bash
Install-Package Stripe.net
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque .NET de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-dotnet).
### Installer les bibliothèques Stripe
Installez les packages et importez-les dans votre code. Si vous partez de zéro et qu’il vous faut un fichier `package.json`, vous pouvez également télécharger les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
Installez les bibliothèques :
```bash
npm install --save stripe @stripe/stripe-js next
```
> #### Accès à Terminal sur macOS
>
> Le SDK Stripe Terminal nécessite un accès au réseau local. Lorsque vous utilisez macOS, vous devez explicitement autoriser les applications de votre navigateur à accéder aux périphériques du réseau local. Pour en savoir plus, consultez l’[article d’aide Stripe](https://support.stripe.com/questions/ensuring-stripe-terminal-javascript-sdk-functionality-on-macos-15).
### Créer un endpoint ConnectionToken
Pour se connecter à un lecteur, votre back-end doit donner au SDK la permission d’utiliser le lecteur avec votre compte Stripe en lui fournissant la clé secrète d’un [ConnectionToken](https://docs.stripe.com/api/terminal/connection_tokens.md). Créez des tokens de connexion uniquement pour les clients de confiance et [transmettez un ID d’emplacement](https://docs.stripe.com/terminal/fleet/locations-and-zones.md#connection-tokens) lors de la création d’un token de connexion pour contrôler l’accès aux lecteurs. Si vous utilisez Connect, [appliquez le token de connexion](https://docs.stripe.com/terminal/features/connect.md) aux comptes connectés pertinents.
### Installer le SDK
Le SDK iOS est [open source](https://github.com/stripe/stripe-terminal-ios) et possède une documentation complète. Il est compatible avec les applications prendre en charge iOS 10 et versions ultérieures. Importez le SDK Stripe dans le UIViewController de votre écran de paiement.
#### CocoaPods
Ajoutez cette ligne à votre Podfile, et à partir de maintenant, utilisez le fichier .xcworkspace pour ouvrir votre projet dans Xcode, au lieu du fichier .xcodeproj.
```bash
pod 'StripeTerminal', '~> 5.0'
```
#### Carthage
Ajoutez cette ligne à votre Cartfile.
```bash
github "stripe/stripe-terminal-ios"
```
#### XCFramework
1. Téléchargez le fichier StripeTerminal.xcframework.zip de la dernière version sur GitHub.
1. Décompressez-le et faites glisser le fichier .xcframework dans votre projet en veillant à sélectionner « Copy items if needed » (copier les éléments si nécessaire).
1. Vérifiez que le fichier xcframework est présent dans la section « Frameworks, Libraries, and Embedded Content » (infrastructures logicielles, bibliothèques et contenu intégré) de votre application cible dans Xcode et défini sur « Embed & Sign » (intégrer et signer).
#### Swift Package Manager
1. Dans Xcode, sélectionnez **Fichier** > **Ajouter des packages…** dans la barre de menus.
1. Saisissez l’URL GitHub du SDK iOS Stripe Terminal :
```bash
https://github.com/stripe/stripe-terminal-ios
```
### Créer des emplacements pour vos lecteurs
[Créez des emplacements](https://docs.stripe.com/terminal/fleet/locations-and-zones.md) pour organiser vos lecteurs. Les emplacements regroupent les lecteurs et leur permettent de télécharger automatiquement la configuration du lecteur nécessaire à leur région d’utilisation. Vous devez attribuer un emplacement à chaque lecteur lorsque vous l’[enregistrez](https://docs.stripe.com/terminal/fleet/register-readers.md), ce que vous pouvez faire à l’aide de l’API ou du Dashboard.
### Configurer votre application
Pour que votre application puisse fonctionner avec le SDK Stripe Terminal, apportez quelques modifications à votre fichier Info.plist dans Xcode.
#### Emplacement
Activez les services d’emplacement avec la paire clé-valeur suivante.
```bash
NSLocationWhenInUseUsageDescription\nLocation access is required to accept payments.
```
#### Modes d'arrière-plan
Assurez-vous que votre application fonctionne en arrière-plan et reste connectée aux lecteurs Bluetooth.
```bash
UIBackgroundModes\n\nbluetooth-central\n
```
#### Périphérique Bluetooth
Passez les contrôles de validation de l’application lors de sa soumission à l’App Store.
```bash
NSBluetoothPeripheralUsageDescription\nBluetooth access is required to connect to supported bluetooth card readers.
```
#### Bluetooth systématique
Permettez à votre application d’afficher une boîte de dialogue d’autorisation Bluetooth.
```bash
NSBluetoothAlwaysUsageDescription\nThis app uses Bluetooth to connect to supported card readers.
```
### Récupérer le ConnectionToken
Implémentez le protocole ConnectionTokenProvider dans votre application. Celui-ci définit une fonction unique qui demande un token de connexion à votre back-end.
### Initialiser le SDK
Pour commencer, fournissez votre ConnectionTokenProvider. Vous ne pouvez appeler `setTokenProvider` qu’une seule fois dans votre application, et devez l’appeler avant d’accéder à `Terminal.shared`.
### Détecter les lecteurs
Le SDK Stripe Terminal est livré avec un lecteur de carte de simulation intégré, ce qui vous permet de développer et de tester votre application sans vous connecter à du matériel physique. Pour utiliser le lecteur de simulation, appelez `discoverReaders` pour rechercher des lecteurs, avec l’option de simulation définie sur true.
### Détecter les lecteurs
Le SDK Stripe Terminal est livré avec un lecteur de carte de simulation intégré, ce qui vous permet de développer et de tester votre application sans vous connecter à du matériel physique. Pour utiliser le lecteur de simulation, appelez `discoverReaders` pour rechercher des lecteurs, avec l’option de simulation définie sur true. Pour détecter plus facilement les lecteurs prévus, filtrez par emplacement.
### Se connecter au lecteur de simulation
Lorsque la méthode déléguée `didUpdateDiscoveredReaders`est appelée, appelez `connectReader` pour vous connecter au lecteur simulé.
### Créer un PaymentIntent
Créez un objet [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) à l’aide du SDK. Un PaymentIntent suit le cycle de vie de paiement du client, en gardant une trace de toutes les tentatives de paiement échouées et en s’assurant que le client n’est facturé qu’une seule fois.
### Traiter la PaymentIntent
Appeler `processPaymentIntent` avec PaymentIntent pour collecter un moyen de paiement et autoriser le paiement. En cas de connexion au lecteur simulé, l’appel de cette méthode met immédiatement à jour l’objet PaymentIntent avec une [carte bancaire test simulée](https://docs.stripe.com/terminal/references/testing.md#simulated-test-cards). En cas de connexion à un lecteur physique, le lecteur connecté attend qu’une carte soit présentée. Un appel réussi entraîne une PaymentIntent avec un état `requires_capture` pour une capture manuelle, ou `réussi` pour une capture automatique.
### Créer un endpoint pour capturer le PaymentIntent
Créez un endpoint dans votre back-end qui accepte un ID de PaymentIntent et envoie une requête à l’API Stripe pour le capturer.
### Capturer le PaymentIntent
Si vous avez défini `capture_method` sur `manual` lors de la création du PaymentIntent, le SDK renvoie à votre application un PaymentIntent autorisé, mais non capturé. Lorsque l’état du PaymentIntent est `requires_capture`, indiquez à votre back-end de capturer le PaymentIntent.
Pour les comptes connectés, avant de capturer manuellement un paiement, inspectez le `application_fee_amount` du PaymentIntent et modifiez-le si nécessaire.
### Exécuter l’application
Exécutez votre serveur et allez à [localhost:4242](http://localhost:4242).
### Tester l’intégration avec un numéro de carte de test
Vous pouvez configurer le lecteur simulé afin de tester différents flux au sein de votre application de point de vente, par exemple différentes marques de cartes ou des scénarios d’erreur comme un paiement refusé. Afin d’activer ce comportement, insérez cette ligne de code avant d’appeler `collectPaymentMethod`.
| Scenario | Card Number |
| ------------------- | ---------------- |
| Payment succeeds | 4242424242424242 |
| Payment is declined | 4000000000009995 |
### Installer la bibliothèque Node de Stripe
Installez le package et importez-le dans votre code. Si vous partez de zéro et qu’il vous faut un fichier package.json, vous pouvez également télécharger les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### npm
Installez la bibliothèque :
```bash
npm install --save stripe
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque Node de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-node).
### Installer la bibliothèque Ruby de Stripe
Installez le gem Ruby de Stripe et exigez-le dans votre code. Si vous partez de zéro et avez besoin d’un Gemfile, téléchargez les fichiers du projet à l’aide du lien dans l’éditeur de code.
#### Terminal
Installez le gem :
```bash
gem install stripe
```
#### Bundler
Ajoutez cette ligne à votre Gemfile :
```bash
gem 'stripe'
```
#### GitHub
Vous pouvez sinon télécharger le code source du gem Ruby de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-ruby).
### Installer la bibliothèque Java
Ajoutez la dépendance à votre build et importez la bibliothèque. Ou bien, si vous partez de zéro et avez besoin d’un exemple de fichier pom.xml (pour Maven), téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### Maven
Ajoutez la dépendance suivante à votre POM et remplacez {VERSION} par le numéro de version que vous souhaitez utiliser.
```bash
\ncom.stripe\nstripe-java\n{VERSION}\n
```
#### Gradle
Ajoutez la dépendance à votre fichier build.gradle et remplacez {VERSION} par le numéro de version que vous souhaitez utiliser.
```bash
implementation "com.stripe:stripe-java:{VERSION}"
```
#### GitHub
Téléchargez le fichier JAR directement [depuis GitHub](https://github.com/stripe/stripe-java/releases/latest).
### Installer le package Python de Stripe
Installez le package Stripe et importez-le dans votre code. Si vous partez de zéro et qu’il vous faut un fichier requirements.txt, téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### pip
Installez le package via pip :
```bash
pip3 install stripe
```
#### GitHub
Téléchargez le code source de la bibliothèque stripe-python directement [depuis GitHub](https://github.com/stripe/stripe-python).
### Installer la bibliothèque PHP
Installez la bibliothèque avec composer et initialisez-la avec votre clé API secrète. Si vous partez de zéro et que vous avez besoin d’un fichier composer.json, vous pouvez également télécharger les fichiers à l’aide du lien de téléchargement dans l’éditeur de code.
#### Composer
Installez la bibliothèque :
```bash
composer require stripe/stripe-php
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque php de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-php).
### Configurer votre serveur
Ajoutez la dépendance à votre build et importez la bibliothèque. Si vous partez de zéro et avez besoin d’un fichier go.mod, téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### Go
Veillez à initialiser avec des modules Go :
```bash
go get -u github.com/stripe/stripe-go/v85
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque Go de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-go).
### Installer la bibliothèque Stripe.net
Installez le package avec .NET ou NuGet. Si vous partez de zéro, vous pouvez également télécharger les fichiers qui contiennent un fichier .csproj configuré.
#### .NET
Installez la bibliothèque :
```bash
dotnet add package Stripe.net
```
#### NuGet
Installez la bibliothèque :
```bash
Install-Package Stripe.net
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque .NET de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-dotnet).
### Installer les bibliothèques Stripe
Installez les packages et importez-les dans votre code. Si vous partez de zéro et qu’il vous faut un fichier `package.json`, vous pouvez également télécharger les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
Installez les bibliothèques :
```bash
npm install --save stripe @stripe/stripe-js next
```
> #### Accès à Terminal sur macOS
>
> Le SDK Stripe Terminal nécessite un accès au réseau local. Lorsque vous utilisez macOS, vous devez explicitement autoriser les applications de votre navigateur à accéder aux périphériques du réseau local. Pour en savoir plus, consultez l’[article d’aide Stripe](https://support.stripe.com/questions/ensuring-stripe-terminal-javascript-sdk-functionality-on-macos-15).
### Créer un endpoint ConnectionToken
Pour se connecter à un lecteur, votre back-end doit donner au SDK la permission d’utiliser le lecteur avec votre compte Stripe en lui fournissant la clé secrète d’un [ConnectionToken](https://docs.stripe.com/api/terminal/connection_tokens.md). Créez des tokens de connexion uniquement pour les clients de confiance et [transmettez un ID d’emplacement](https://docs.stripe.com/terminal/fleet/locations-and-zones.md#connection-tokens) lors de la création d’un token de connexion pour contrôler l’accès aux lecteurs. Si vous utilisez Connect, [appliquez le token de connexion](https://docs.stripe.com/terminal/features/connect.md) aux comptes connectés pertinents.
### Installer le SDK
Pour installer le SDK, ajoutez `stripeterminal` au bloc des dépendances de votre fichier build.gradle.
#### Gradle
Ajoutez les dépendances à votre fichier build.gradle :
#### Groovy
```groovy
dependencies {
// ...
// Stripe Terminal SDK
implementation 'com.stripe:stripeterminal:5.4.0'
}
```
#### GitHub
Le SDK Android de Stripe est open source. [Afficher sur GitHub.](https://github.com/stripe/stripe-android)
### Installer le SDK
Pour installer le SDK Tap to Pay, ajoutez `stripeterminal-taptopay` et `stripeterminal-core` au bloc de dépendances de votre fichier `build.gradle` ou `build.gradle.kts`.
Si vous avez déjà des dépendances `stripeterminal`, remplacez-les par ce qui suit en ajoutant les dépendances à votre fichier `build.gradle` ou `build.gradle.kts` :
#### Groovy
```groovy
dependencies {
// ...
// Stripe Tap to Pay SDK
implementation 'com.stripe:stripeterminal-taptopay:5.4.0'
implementation 'com.stripe:stripeterminal-core:5.4.0'
}
```
### Créer des emplacements pour vos lecteurs
[Créez des emplacements](https://docs.stripe.com/terminal/fleet/locations-and-zones.md) pour organiser vos lecteurs. Les emplacements regroupent les lecteurs et leur permettent de télécharger automatiquement la configuration du lecteur nécessaire à leur région d’utilisation. Vous devez attribuer un emplacement à chaque lecteur lorsque vous l’[enregistrez](https://docs.stripe.com/terminal/fleet/register-readers.md), ce que vous pouvez faire à l’aide de l’API ou du Dashboard.
### Vérifier l’autorisation ACCESS_FINE_LOCATION
Ajoutez une vérification pour vous assurer que l’autorisation `ACCESS_FINE_LOCATION` est activée dans votre application.
### Vérifier l’autorisation de localisation de l’utilisateur
Écrasez la méthode <`onRequestPermissionsResult` dans votre application et vérifiez le résultat de l’autorisation pour vous assurer que l’utilisateur de l’application accorde l’autorisation de localisation.
### Récupérer le ConnectionToken
Implémentez l’interface ConnectionTokenProvider dans votre application. Celle-ci définit une fonction unique qui demande un token de connexion à votre back-end.
### Configurer TerminalApplicationDelegate
Pour éviter les fuites de mémoire et garantir un nettoyage approprié des processus Terminal SDK de longue durée, votre application doit disposer de la sous-classe `Application` et appeler `TerminalApplicationDelegate` à partir de la méthode `onCreate`.
### Initialiser le SDK
Pour démarrer, fournissez le contexte d’application actuel, le ConnectionTokenProvider et un objet TerminalListener.
### Détecter les lecteurs
Le SDK Stripe Terminal est livré avec un lecteur de carte de simulation intégré, ce qui vous permet de développer et de tester votre application sans vous connecter à du matériel physique. Pour utiliser le lecteur de simulation, appelez `discoverReaders` pour rechercher des lecteurs, avec l’option de simulation définie sur true.
### Détecter les lecteurs
Le SDK Stripe Terminal est livré avec un lecteur de carte de simulation intégré, ce qui vous permet de développer et de tester votre application sans vous connecter à du matériel physique. Pour utiliser le lecteur de simulation, appelez `discoverReaders` pour rechercher des lecteurs, avec l’option de simulation définie sur true. Pour détecter plus facilement les lecteurs prévus, filtrez par emplacement.
### Se connecter au lecteur de simulation
Lorsque `discoverReaders` renvoie un résultat, appelez le `connectReader` pour vous connecter au lecteur de simulation.
### Créer un PaymentIntent
Créez un objet [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) à l’aide du SDK. Un PaymentIntent suit le cycle de vie de paiement du client, en gardant une trace de toutes les tentatives de paiement échouées et en s’assurant que le client n’est facturé qu’une seule fois.
### Traiter la PaymentIntent
Appeler `processPaymentIntent` avec PaymentIntent pour collecter un moyen de paiement et autoriser le paiement. En cas de connexion au lecteur simulé, l’appel de cette méthode met immédiatement à jour l’objet PaymentIntent avec une [carte bancaire test simulée](https://docs.stripe.com/terminal/references/testing.md#simulated-test-cards). En cas de connexion à un lecteur physique, le lecteur connecté attend qu’une carte soit présentée. Un appel réussi entraîne une PaymentIntent avec un état `requires_capture` pour une capture manuelle, ou `réussi` pour une capture automatique.
### Créer un endpoint pour capturer le PaymentIntent
Créez un endpoint dans votre back-end qui accepte un ID de PaymentIntent et envoie une requête à l’API Stripe pour le capturer.
### Capturer le PaymentIntent
Si vous avez défini `capture_method` sur `manual` lors de la création du PaymentIntent, le SDK renvoie à votre application un PaymentIntent autorisé, mais non capturé. Lorsque l’état du PaymentIntent est `requires_capture`, indiquez à votre back-end de capturer le PaymentIntent.
Pour les comptes connectés, avant de capturer manuellement un paiement, inspectez le `application_fee_amount` du PaymentIntent et modifiez-le si nécessaire.
### Exécuter l’application
Exécutez votre serveur et allez à [localhost:4242](http://localhost:4242).
### Tester l’intégration avec un numéro de carte de test
Vous pouvez configurer le lecteur simulé afin de tester différents flux au sein de votre application de point de vente, par exemple différentes marques de cartes ou des scénarios d’erreur comme un paiement refusé. Afin d’activer ce comportement, insérez cette ligne de code avant d’appeler `collectPaymentMethod`.
| Scenario | Card Number |
| ------------------- | ---------------- |
| Payment succeeds | 4242424242424242 |
| Payment is declined | 4000000000009995 |
### Installer la bibliothèque Node de Stripe
Installez le package et importez-le dans votre code. Si vous partez de zéro et qu’il vous faut un fichier package.json, vous pouvez également télécharger les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### npm
Installez la bibliothèque :
```bash
npm install --save stripe
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque Node de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-node).
### Installer la bibliothèque Ruby de Stripe
Installez le gem Ruby de Stripe et exigez-le dans votre code. Si vous partez de zéro et avez besoin d’un Gemfile, téléchargez les fichiers du projet à l’aide du lien dans l’éditeur de code.
#### Terminal
Installez le gem :
```bash
gem install stripe
```
#### Bundler
Ajoutez cette ligne à votre Gemfile :
```bash
gem 'stripe'
```
#### GitHub
Vous pouvez sinon télécharger le code source du gem Ruby de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-ruby).
### Installer la bibliothèque Java
Ajoutez la dépendance à votre build et importez la bibliothèque. Ou bien, si vous partez de zéro et avez besoin d’un exemple de fichier pom.xml (pour Maven), téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### Maven
Ajoutez la dépendance suivante à votre POM et remplacez {VERSION} par le numéro de version que vous souhaitez utiliser.
```bash
\ncom.stripe\nstripe-java\n{VERSION}\n
```
#### Gradle
Ajoutez la dépendance à votre fichier build.gradle et remplacez {VERSION} par le numéro de version que vous souhaitez utiliser.
```bash
implementation "com.stripe:stripe-java:{VERSION}"
```
#### GitHub
Téléchargez le fichier JAR directement [depuis GitHub](https://github.com/stripe/stripe-java/releases/latest).
### Installer le package Python de Stripe
Installez le package Stripe et importez-le dans votre code. Si vous partez de zéro et qu’il vous faut un fichier requirements.txt, téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### pip
Installez le package via pip :
```bash
pip3 install stripe
```
#### GitHub
Téléchargez le code source de la bibliothèque stripe-python directement [depuis GitHub](https://github.com/stripe/stripe-python).
### Installer la bibliothèque PHP
Installez la bibliothèque avec composer et initialisez-la avec votre clé API secrète. Si vous partez de zéro et que vous avez besoin d’un fichier composer.json, vous pouvez également télécharger les fichiers à l’aide du lien de téléchargement dans l’éditeur de code.
#### Composer
Installez la bibliothèque :
```bash
composer require stripe/stripe-php
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque php de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-php).
### Configurer votre serveur
Ajoutez la dépendance à votre build et importez la bibliothèque. Si vous partez de zéro et avez besoin d’un fichier go.mod, téléchargez les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
#### Go
Veillez à initialiser avec des modules Go :
```bash
go get -u github.com/stripe/stripe-go/v85
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque Go de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-go).
### Installer la bibliothèque Stripe.net
Installez le package avec .NET ou NuGet. Si vous partez de zéro, vous pouvez également télécharger les fichiers qui contiennent un fichier .csproj configuré.
#### .NET
Installez la bibliothèque :
```bash
dotnet add package Stripe.net
```
#### NuGet
Installez la bibliothèque :
```bash
Install-Package Stripe.net
```
#### GitHub
Vous pouvez sinon télécharger le code source de la bibliothèque .NET de Stripe directement [depuis GitHub](https://github.com/stripe/stripe-dotnet).
### Installer les bibliothèques Stripe
Installez les packages et importez-les dans votre code. Si vous partez de zéro et qu’il vous faut un fichier `package.json`, vous pouvez également télécharger les fichiers du projet à l’aide du lien de téléchargement dans l’éditeur de code.
Installez les bibliothèques :
```bash
npm install --save stripe @stripe/stripe-js next
```
> #### Accès à Terminal sur macOS
>
> Le SDK Stripe Terminal nécessite un accès au réseau local. Lorsque vous utilisez macOS, vous devez explicitement autoriser les applications de votre navigateur à accéder aux périphériques du réseau local. Pour en savoir plus, consultez l’[article d’aide Stripe](https://support.stripe.com/questions/ensuring-stripe-terminal-javascript-sdk-functionality-on-macos-15).
### Créer un endpoint ConnectionToken
Pour se connecter à un lecteur, votre back-end doit donner au SDK la permission d’utiliser le lecteur avec votre compte Stripe en lui fournissant la clé secrète d’un [ConnectionToken](https://docs.stripe.com/api/terminal/connection_tokens.md). Créez des tokens de connexion uniquement pour les clients de confiance et [transmettez un ID d’emplacement](https://docs.stripe.com/terminal/fleet/locations-and-zones.md#connection-tokens) lors de la création d’un token de connexion pour contrôler l’accès aux lecteurs. Si vous utilisez Connect, [appliquez le token de connexion](https://docs.stripe.com/terminal/features/connect.md) aux comptes connectés pertinents.
### Installer le SDK
```bash
yarn install @stripe/stripe-terminal-react-native
```
### Créer des emplacements pour vos lecteurs
[Créez des emplacements](https://docs.stripe.com/terminal/fleet/locations-and-zones.md) pour organiser vos lecteurs. Les emplacements regroupent les lecteurs et leur permettent de télécharger automatiquement la configuration du lecteur nécessaire à leur région d’utilisation. Vous devez attribuer un emplacement à chaque lecteur lorsque vous l’[enregistrez](https://docs.stripe.com/terminal/fleet/register-readers.md), ce que vous pouvez faire à l’aide de l’API ou du Dashboard.
### Récupérer le ConnectionToken
Pour permettre au SDK d’accéder à cet endpoint, créez une fonction dans votre application Web qui demande un ConnectionToken à votre back-end et renvoie la clé secrète de l’objet ConnectionToken.
### Configurer les autorisations
#### Android
Ajoutez une vérification pour vous assurer que l’autorisation `ACCESS_FINE_LOCATION` est activée dans votre application.
#### iOS
Pour que votre application puisse fonctionner avec le SDK Stripe Terminal, apportez quelques modifications à votre fichier Info.plist dans Xcode.
#### Location
Activez les services de localisation avec la paire clé-valeur suivante.
```bash
NSLocationWhenInUseUsageDescription\nLocation access is required to accept payments.
```
#### Modes d'arrière-plan
Assurez-vous que votre application fonctionne en arrière-plan et reste connectée aux lecteurs Bluetooth.
```bash
UIBackgroundModes\n\nbluetooth-central\n
```
#### Périphérique Bluetooth
Passez les contrôles de validation de l’application lors de sa soumission à l’App Store.
```bash
NSBluetoothPeripheralUsageDescription\nBluetooth access is required to connect to supported bluetooth card readers.
```
#### Bluetooth systématique
Autorisez votre application à afficher une boîte de dialogue d’autorisation Bluetooth.
```bash
NSBluetoothAlwaysUsageDescription\nThis app uses Bluetooth to connect to supported card readers.
```
### Configurer le fournisseur de contexte
Transmettez la fonction `onFetchConnectionToken` à `StripeTerminalProvider` en tant que propriété.
### Initialiser le SDK
Pour initialiser une instance `StripeTerminal` dans votre application React Native, appelez la méthode initialize à partir du hook `useStripeTerminal`. Vous devez appeler la méthode `initialize` à partir d’un composant imbriqué dans `StripeTerminalProvider`, et non du composant qui contient le `StripeTerminalProvider`.
### Détecter les lecteurs
Le SDK Stripe Terminal est livré avec un lecteur de carte de simulation intégré, ce qui vous permet de développer et de tester votre application sans vous connecter à du matériel physique. Pour utiliser le lecteur de simulation, appelez `discoverReaders` pour rechercher des lecteurs, avec l’option de simulation définie sur true.
### Détecter les lecteurs
Le SDK Stripe Terminal est livré avec un lecteur de carte SIM intégré. Pour utiliser le lecteur de simulation, appelez `discoverReaders` pour rechercher des lecteurs, avec l’option de simulation définie sur true.
### Détecter les lecteurs
Le SDK Stripe Terminal est livré avec un lecteur de carte de simulation intégré, ce qui vous permet de développer et de tester votre application sans vous connecter à du matériel physique. Pour utiliser le lecteur de simulation, appelez `discoverReaders` pour rechercher des lecteurs, avec l’option de simulation définie sur true. Pour détecter plus facilement les lecteurs prévus, filtrez par emplacement.
### Se connecter au lecteur de simulation
Lorsque `discoverReaders` renvoie un résultat, appelez le `connectReader` pour vous connecter au lecteur de simulation.
### Créer un PaymentIntent
Ajoutez un endpoint sur votre serveur qui crée un PaymentIntent. Un PaymentIntent suit le cycle de vie du paiement du client, en gardant trace de toutes les tentatives de paiement échouées et en s’assurant qu’il n’est facturé qu’une seule fois. Renvoyez la clé secrète du client du PaymentIntent dans la réponse. Si vous utilisez Connect, vous pouvez également spécifier des [informations sur le compte connecté](https://docs.stripe.com/terminal/features/connect.md) en fonction de la logique de facturation de votre plateforme.
### Récupérer le PaymentIntent
Envoyez une requête à votre serveur pour obtenir un PaymentIntent afin d’initier le processus de paiement.
### Collecter les informations relatives au moyen de paiement
Appelez `collectPaymentMethod` avec la clé secrète client du PaymentIntent pour collecter un moyen de paiement. Si vous utilisez un lecteur de simulation, l’appel de cette méthode met immédiatement à jour l’objet PaymentIntent en utilisant une [carte de test simulée](https://docs.stripe.com/terminal/references/testing.md#simulated-test-cards). Si vous utilisez un lecteur physique, le lecteur connecté attend qu’une carte lui soit présentée.
### Traiter le paiement
Après avoir collecté les données relatives au moyen de paiement, appelez `processPayment` avec le PaymentIntent mis à jour pour traiter le paiement. Un appel abouti se traduit par un PaymentIntent à l’état `requires_capture` en cas de capture manuelle ou `succeeded` en cas de capture automatique.
### Créer un endpoint pour capturer le PaymentIntent
Créez un endpoint dans votre back-end qui accepte un ID de PaymentIntent et envoie une requête à l’API Stripe pour le capturer.
### Capturer le PaymentIntent
Si vous avez défini `capture_method` sur `manual` lors de la création du PaymentIntent, le SDK renvoie à votre application un PaymentIntent autorisé, mais non capturé. Lorsque l’état du PaymentIntent est `requires_capture`, indiquez à votre back-end de capturer le PaymentIntent.
Pour les comptes connectés, avant de capturer manuellement un paiement, inspectez le `application_fee_amount` du PaymentIntent et modifiez-le si nécessaire.
### Exécuter l’application
Exécutez votre serveur et accédez à [localhost:4242](http://localhost:4242).
### Tester l’intégration avec un numéro de carte de test
Vous pouvez configurer le lecteur simulé afin de tester différents flux au sein de votre application de point de vente, par exemple différentes marques de cartes ou des scénarios d’erreur comme un paiement refusé. Afin d’activer ce comportement, insérez cette ligne de code avant d’appeler `collectPaymentMethod`.
| 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
~~~
## Étapes suivantes
#### [Connexion à un lecteur](https://docs.stripe.com/terminal/payments/connect-reader.md)
Découvrez ce qu’implique la connexion de votre application à un lecteur.
#### [Gestion de parc](https://docs.stripe.com/terminal/fleet/locations-and-zones.md)
Groupez et gérez un parc des lecteurs par emplacement.
#### [Connect](https://docs.stripe.com/terminal/features/connect.md)
Intégrez Stripe Terminal à votre plateforme Connect.