Encaisser un paiement
Encaissez un paiement en personne avec Stripe Terminal : enregistrez les écouteurs dès le démarrage, initialisez le plugin, connectez un lecteur et confirmez un PaymentIntent.
Prérequis pour le premier test
Avant la première tentative d’encaissement, préparez :
- Les réglages de plateforme décrits dans Configuration, y compris les autorisations Android nécessaires
- Un point de terminaison authentifié fournissant des jetons de connexion, que votre application peut appeler
- Un PaymentIntent de test avec
card_present, créé sur votre serveur - Un
locationIdStripe Terminal adapté au type de connexion à rechercher
Le premier résultat à obtenir est : connecter un lecteur → recueillir un moyen de paiement → confirmer le PaymentIntent et recevoir ConfirmedPaymentIntent. L’exécution de la commande doit toujours attendre votre webhook Stripe. Pour les lecteurs simulés, utilisez un type de connexion pris en charge avec isTest: true, comme indiqué dans Configuration : TerminalConnectTypes.Simulated n’est pas universel.
Enregistrer les écouteurs au niveau de l’application
Enregistrez les écouteurs d’événements Terminal une seule fois par démarrage de l’application JavaScript, le plus tôt possible pendant l’amorçage — par exemple dans main.ts, un initialiseur d’application ou un service singleton initialisé au démarrage — et avant toute initialisation ou opération. Conservez-les pendant toute la durée de vie du composant qui en est responsable au niveau de l’application.
enum TerminalEventsEnum
| Membre | Valeur |
|---|---|
Loaded |
'terminalLoaded' |
DiscoveredReaders |
'terminalDiscoveredReaders' |
DiscoveringReaders |
'terminalDiscoveringReaders' |
CancelDiscoveredReaders |
'terminalCancelDiscoveredReaders' |
ConnectedReader |
'terminalConnectedReader' |
DisconnectedReader |
'terminalDisconnectedReader' |
ConnectionStatusChange |
'terminalConnectionStatusChange' |
UnexpectedReaderDisconnect |
'terminalUnexpectedReaderDisconnect' |
ConfirmedPaymentIntent |
'terminalConfirmedPaymentIntent' |
CollectedPaymentIntent |
'terminalCollectedPaymentIntent' |
Canceled |
'terminalCanceled' |
Failed |
'terminalFailed' |
RequestedConnectionToken |
'terminalRequestedConnectionToken' |
ReportAvailableUpdate |
'terminalReportAvailableUpdate' |
StartInstallingUpdate |
'terminalStartInstallingUpdate' |
ReaderSoftwareUpdateProgress |
'terminalReaderSoftwareUpdateProgress' |
FinishInstallingUpdate |
'terminalFinishInstallingUpdate' |
BatteryLevel |
'terminalBatteryLevel' |
ReaderEvent |
'terminalReaderEvent' |
RequestDisplayMessage |
'terminalRequestDisplayMessage' |
RequestReaderInput |
'terminalRequestReaderInput' |
PaymentStatusChange |
'terminalPaymentStatusChange' |
ReaderReconnectStarted |
'terminalReaderReconnectStarted' |
ReaderReconnectSucceeded |
'terminalReaderReconnectSucceeded' |
ReaderReconnectFailed |
'terminalReaderReconnectFailed' |
Les surcharges typées de addListener couvrent la plupart de ces membres. DiscoveringReaders et CancelDiscoveredReaders sont émis au démarrage et à l’annulation de la recherche native, mais n’ont pas de surcharge dédiée ; consultez la page API.
Initialiser
Privilégiez une requête authentifiée côté application via RequestedConnectionToken et setConnectionToken. Votre application peut ainsi joindre ses identifiants d’autorisation habituels et contrôler les erreurs. Enregistrez l’écouteur avant initialize ; le SDK Terminal demande un nouveau jeton de connexion à usage unique chaque fois qu’il en a besoin. Activez isTest pendant le développement.
method initialize(...)
Initialise le SDK Stripe Terminal et son fournisseur de jetons de connexion.
Appelez cette méthode une fois avant de découvrir les lecteurs.
Lorsque tokenProviderEndpoint est fourni, le plugin envoie une requête POST et attend { secret: string }. Si ce paramètre est omis, gérez plutôt RequestedConnectionToken et appelez setConnectionToken().
initialize(options: StripeTerminalInitializationOptions) => Promise<void>
Sur le Web, initialize nécessite une nouvelle instance du plugin : un nouvel appel après une initialisation réussie lève Stripe Terminal has already been initialized.
Fournir un jeton de connexion de manière sécurisée
Omettez tokenProviderEndpoint et enregistrez RequestedConnectionToken avant initialize. Lorsque le SDK a besoin d’un jeton, le plugin émet cet événement et attend setConnectionToken({ token }).
Effectuez la requête avec votre mécanisme d’autorisation habituel, exigez une réponse réussie, validez secret, puis transmettez-le comme token. Appelez setConnectionToken uniquement pendant qu’une demande de jeton est en attente ; Android et iOS rejettent les appels supplémentaires avec Stripe Terminal do not pending fetchConnectionToken. Ne journalisez jamais la réponse ni le jeton.
method setConnectionToken(...)
Fournit un secret de jeton de connexion après l’émission de RequestedConnectionToken. Créez chaque jeton sur votre serveur et utilisez-le une seule fois.
setConnectionToken(options: SetConnectionTokenOptions) => Promise<void>
Mode de compatibilité tokenProviderEndpoint
tokenProviderEndpoint convient aux déploiements simples, mais les clients natifs v8.2.1 envoient un POST HTTP minimal : l’appelant ne peut ajouter ni en-tête d’autorisation ni corps de requête. Utilisez-le uniquement si votre serveur peut authentifier et protéger cette requête par d’autres moyens. N’exposez jamais un point de terminaison public de création de jetons sans restriction.
Lorsque tokenProviderEndpoint est défini, le plugin envoie un POST HTTP avec un corps vide. La réponse doit être un objet JSON contenant une chaîne secret :
{ "secret": "pst_..." }
Cette valeur est un jeton de connexion Stripe Terminal. Créez-le sur le serveur avec votre clé API secrète (stripe.terminal.connectionTokens.create()). Ne placez jamais la clé secrète, des clés restreintes permettant de créer des jetons ou des jetons de connexion bruts dans le binaire de l’application, les journaux ou une configuration cliente publique.
La démo officielle expose POST /connection/token et renvoie { secret } ; adaptez son authentification et son autorisation à votre application.
Créer un PaymentIntent sur votre backend
Créez le PaymentIntent sur votre serveur. La démo officielle utilise POST /connection/intent et renvoie { paymentIntent } en tant que secret client.
Exigences correspondant au plugin et à la démo :
payment_method_typesdoit inclurecard_present- Conservez la clé secrète Stripe sur le serveur
- Transmettez uniquement le secret client à
collectPaymentMethod({ paymentIntent }) - Ne créez ni ne confirmez de PaymentIntents pour paiements en présence de la carte avec une clé publique dans l’application
Exemple côté serveur tiré de la démo :
await stripe.paymentIntents.create({
amount: 1000,
currency: 'usd',
payment_method_types: ['card_present'],
capture_method: 'automatic',
});
Rechercher des lecteurs
Recherchez des lecteurs à proximité ou simulés. Fournissez une valeur TerminalConnectTypes et un locationId Stripe Terminal lorsque le type de connexion l’exige.
locationId est utilisé lors de la recherche Internet et requis pour connecter les lecteurs Tap to Pay, Bluetooth et USB Android. La recherche Internet peut filtrer par emplacement ; Tap to Pay et Bluetooth transmettent l’emplacement à la configuration de connexion.
Points particuliers :
- Web prend uniquement en charge
Internet. Tout autretypeest indisponible. - Bluetooth sur iOS signale les lecteurs via
DiscoveredReadersà plusieurs reprises à mesure que la recherche évolue. Consultez Stripe : connecter un lecteur Bluetooth (iOS). DéfinissezbluetoothScanWaitTime(en millisecondes) pour quediscoverReadersattende avant de se terminer avec la liste actuelle. La valeur0, ou l’absence de valeur, renvoie le premier résultat de recherche. - iOS émet aussi
DiscoveringReadersau démarrage de la recherche. USB, HandOff etSimulatedcommetypene sont pas implémentés. - Android exige
ACCESS_FINE_LOCATIONà l’exécution, sinondiscoverReadersest rejeté.Simulatedest traité comme une recherche Bluetooth.HandOffcorrespond à Apps on Devices. - Appelez
cancelDiscoverReaderssi l’utilisateur quitte l’interface de recherche. Sur le Web, l’annulation est sans effet. Donnez toujours à l’utilisateur un moyen d’arrêter une longue recherche Bluetooth.
Écoutez DiscoveredReaders en plus d’attendre la promesse. Sur iOS avec Bluetooth, l’écouteur fournit la liste actualisée ; la promesse peut se terminer avant le dernier événement.
method discoverReaders(...)
Découvre les lecteurs avec le mode de communication demandé. Les lecteurs renvoyés sont des instantanés ; écoutez DiscoveredReaders lorsque la découverte continue peut produire des résultats supplémentaires.
discoverReaders(options: DiscoverReadersOptions) => Promise<{ readers: ReaderInterface[]; }>
interface DiscoverReadersOptions
| Propriété | Type | Description | Depuis |
|---|---|---|---|
type |
TerminalConnectTypes |
Méthode de découverte et mode de communication avec le lecteur à utiliser. | 5.1.0 |
locationId |
string |
Identifiant Stripe Terminal Location utilisé pour limiter la découverte des lecteurs Internet et leur enregistrement lorsqu’il est requis. | 5.1.0 |
bluetoothScanWaitTime |
number |
S’applique uniquement à la découverte par balayage Bluetooth (iOS uniquement). Pendant la découverte, les lecteurs sont signalés via DiscoveryDelegate.didUpdateDiscoveredReaders. Ce délai détermine le temps d’attente avant de résoudre la méthode discoverReaders avec la liste courante. Si ce paramètre n’est pas fourni ou vaut 0, les résultats du balayage initial sont renvoyés. |
7.2.0 |
enum TerminalConnectTypes
| Membre | Valeur |
|---|---|
Simulated |
'simulated' |
Internet |
'internet' |
Bluetooth |
'bluetooth' |
Usb |
'usb' |
TapToPay |
'tap-to-pay' |
HandOff |
'hand-off' |
Connecter un lecteur
Connectez un des lecteurs découverts avant de recueillir les données de paiement. L’objet reader doit provenir du résultat de recherche actuel (serialNumber est l’identifiant principal du plugin).
autoReconnectOnUnexpectedDisconnect vaut false par défaut et s’applique à Tap to Pay et Bluetooth. Pour USB sur Android, la configuration de connexion native active actuellement la reconnexion automatique. Les connexions Internet n’utilisent pas ce paramètre.
merchantDisplayName et onBehalfOf s’appliquent à Tap to Pay sur iOS (LocalMobileReader). Sur Android, définissez plutôt les valeurs de compte connecté et d’affichage sur le PaymentIntent.
method connectReader(...)
Se connecte à un lecteur renvoyé par discoverReaders().
connectReader(options: ConnectReaderOptions) => Promise<void>
Recueillir un moyen de paiement
Transmettez le secret client du PaymentIntent fourni par votre backend à collectPaymentMethod. Le plugin récupère ce PaymentIntent, puis recueille le moyen de paiement sur le lecteur connecté.
method collectPaymentMethod(...)
Recueille un moyen de paiement pour un PaymentIntent créé sur le serveur. Confirmez l’intent recueilli avec confirmPaymentIntent().
collectPaymentMethod(options: CollectPaymentMethodOptions) => Promise<void>
Confirmer le PaymentIntent
Traitez et confirmez le PaymentIntent dont le moyen de paiement a été recueilli. confirmPaymentIntent est rejeté si cette collecte n’a pas préalablement réussi (PaymentIntent not found for confirmPaymentIntent).
method confirmPaymentIntent()
Confirme le PaymentIntent recueilli le plus récemment par le lecteur.
confirmPaymentIntent() => Promise<void>
ConfirmedPaymentIntent est un signal pour l’interface cliente, pas une autorisation d’exécuter la commande. N’exécutez celle-ci qu’après vérification, par votre backend, d’un webhook Stripe tel que payment_intent.succeeded.
Gérer l’annulation et les erreurs
cancelCollectPaymentMethodannule une collecte en cours. En cas de réussite, la promesse est résolue etCanceledest émis.Failedest émis sicollectPaymentMethodouconfirmPaymentIntentéchoue. La promesse de cet appel est également rejetée. La charge utile peut contenirmessage,codeetdeclineCode.- N’utilisez pas
ConnectionStatusChangepour détecter une déconnexion inattendue. UtilisezUnexpectedReaderDisconnect, ainsi queDisconnectedReaderpour Bluetooth/USB. Consultez Cycle de vie du lecteur.
method cancelCollectPaymentMethod()
Annule un appel à collectPaymentMethod() en cours.
cancelCollectPaymentMethod() => Promise<void>
Déconnecter le lecteur
Déconnectez le lecteur lorsque le parcours de paiement est terminé ou que le lecteur n’est plus nécessaire.
method disconnectReader()
Déconnecte le lecteur actif. Se résout immédiatement si aucun lecteur n’est connecté.
disconnectReader() => Promise<void>
Après le premier succès
Consultez Cycle de vie du lecteur pour la déconnexion, la reconnexion et les mises à jour. Pour accepter les paiements avec un téléphone comme lecteur, consultez Tap to Pay. Les signatures formelles restent sur la page API.
import {
StripeTerminal,
TerminalConnectTypes,
TerminalEventsEnum,
} from '@capacitor-community/stripe-terminal';
const paymentStatusListener = await StripeTerminal.addListener(
TerminalEventsEnum.PaymentStatusChange,
({ status }) => console.log(status),
);
const confirmedListener = await StripeTerminal.addListener(
TerminalEventsEnum.ConfirmedPaymentIntent,
() => console.log('Payment processed; waiting for the server webhook'),
);
const failedListener = await StripeTerminal.addListener(
TerminalEventsEnum.Failed,
(error) => console.error(error),
);
// Register the authenticated RequestedConnectionToken provider first.
await StripeTerminal.initialize({ isTest: true });
const { readers } = await StripeTerminal.discoverReaders({
type: TerminalConnectTypes.TapToPay,
locationId: '**************',
});
const reader = readers[0];
if (!reader) throw new Error('No compatible reader found');
await StripeTerminal.connectReader({
reader,
});
try {
const response = await fetch('https://example.com/connection/intent', {
method: 'POST',
headers: { Authorization: `Bearer ${accessToken}` },
});
if (!response.ok) throw new Error(`PaymentIntent request failed: ${response.status}`);
const { paymentIntent } = (await response.json()) as { paymentIntent: string };
await StripeTerminal.collectPaymentMethod({ paymentIntent });
await StripeTerminal.confirmPaymentIntent();
} finally {
await StripeTerminal.disconnectReader();
}
// Remove the three listeners when their application-level owner is destroyed.
import { StripeTerminal, TerminalEventsEnum } from '@capacitor-community/stripe-terminal';
await StripeTerminal.addListener(
TerminalEventsEnum.RequestedConnectionToken,
async () => {
try {
const response = await fetch('https://example.com/connection/token', {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
});
if (!response.ok) throw new Error(`Connection token request failed: ${response.status}`);
const data = (await response.json()) as { secret?: unknown };
if (typeof data.secret !== 'string' || !data.secret) {
throw new Error('Connection token response is missing secret');
}
await StripeTerminal.setConnectionToken({ token: data.secret });
} catch (error) {
// An empty token fails the pending native callback instead of leaving it hanging.
try {
await StripeTerminal.setConnectionToken({ token: '' });
} finally {
console.error('Unable to supply a connection token', error);
}
}
},
);
await StripeTerminal.initialize({
isTest: true,
});