@capacitor-pay/stripe
v0.0.1
Published
Capacitor plugin wrapping the Stripe Terminal SDK for card reader and Tap to Pay checkout. Stripe provider for capacitor-pay.
Maintainers
Readme
capacitor-pay-stripe
Stripe provider plugin for @capacitor-pay/core, wrapping the Stripe Terminal SDK for card reader and Tap to Pay checkout. Can also be used standalone without @capacitor-pay/core.
⚠️ Verification status
Unlike @capacitor-pay/sumup (whose native code was compiled and verified against the real SumUp SDK), the native iOS and Android code in this plugin has not been compiled against the real Stripe Terminal SDKs - those SDK artifacts aren't available in this environment. The TypeScript layer (src/) builds and type-checks cleanly.
The overall structure, method names, and call flow (connection token → discover → connect → create/collect/confirm PaymentIntent) follow Stripe's documented SDK patterns. The parts most likely to need small fixes when you first build against the real SDKs are called out with NOTE: comments in:
ios/Plugin/StripePlugin.swift- Tap to Pay class/enum names (TapToPayDiscoveryConfigurationBuilder,TapToPayConnectionConfigurationBuilder,TapToPayReaderDelegate,DeviceType.appleBuiltIn,DiscoveryMethod.tapToPay), which have been renamed across SDK major versions (formerly "Local Mobile").android/src/main/java/com/capacitorpay/stripe/StripePlugin.java-DiscoveryMethod.LOCAL_MOBILE,DeviceType.COTS_DEVICE,ConnectionConfiguration.LocalMobileConnectionConfiguration, and the fullBluetoothReaderListenermethod set.
Treat this as a solid starting point to iterate on with a real Stripe test account, following the same approach used for capacitor-pay-sumup/test-app (a minimal Capacitor app with both platforms added, building until the native SDKs compile cleanly).
How this differs from @capacitor-pay/sumup
SumUp's SDK presents its own checkout UI and handles reader pairing internally - one checkout() call does everything. Stripe Terminal is lower-level: you must explicitly discover and connect to a reader before calling checkout(), and Stripe requires your own backend to issue "connection tokens" (short-lived credentials the SDK uses to talk to Stripe).
Install
npm install @capacitor-pay/stripe
npx cap syncBackend requirement: connection token endpoint
Stripe Terminal SDKs never use your secret key directly - they authenticate via a connection token that your backend creates server-side:
POST /v1/terminal/connection_tokens (using your Stripe secret key)Expose an endpoint in your own backend that calls this and returns the result as-is, e.g.:
{ "secret": "pst_test_..." }Pass this endpoint's URL as connectionTokenUrl in setup(). The plugin calls it itself (with any headers you provide, e.g. for your app's auth) every time the SDK needs a new token.
iOS setup
Add to your ios/App/Podfile:
pod 'CapacitorPayStripe', :path => '../../node_modules/@capacitor-pay/stripe'Then run pod install. This pulls in the StripeTerminal pod (~> 3.7, see CapacitorPayStripe.podspec).
Tap to Pay on iPhone
Tap to Pay on iPhone requires:
- The
com.apple.developer.proximity-reader.payment.acceptanceentitlement (granted by Apple on request). - iPhone XS or later, iOS 16.7+.
NSLocationWhenInUseUsageDescriptioninInfo.plist(the SDK uses location to verify the device is in a supported region).
discoverReaders({ method: 'tapToPay' }) (the default) looks for the device's own NFC reader; connectReader then connects to it directly - no separate hardware is needed.
Android setup
The Stripe Terminal Android SDK is on Maven Central, so no extra repository is needed beyond google()/mavenCentral() (already present in a default Capacitor project).
Like @capacitor-pay/sumup, consuming apps need core library desugaring enabled in android/app/build.gradle:
android {
compileOptions {
coreLibraryDesugaringEnabled true
}
}
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
}Add the runtime permissions Stripe Terminal needs to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.NFC" />BLUETOOTH_SCAN/BLUETOOTH_CONNECT/ACCESS_FINE_LOCATION are runtime ("dangerous") permissions on Android 12+ - your app must request them before calling discoverReaders({ method: 'bluetoothScan' }).
Tap to Pay on Android
Tap to Pay on Android (method: 'tapToPay', internally a "local mobile"/COTS reader) requires Android 11+ (API 30) and a device on Stripe's supported list, plus Stripe enabling Tap to Pay for your account.
API
setup(...)discoverReaders(...)connectReader(...)getConnectionStatus()disconnectReader()checkout(...)cancelCheckout()checkTapToPay()
setup(...)
setup(options: StripeSetupOptions) => Promise<{ success: boolean }>Configure the SDK with your publishable key and connection token endpoint. Call once on startup.
| Param | Type |
| ------------- | -------------------------------------------------------------- |
| options | StripeSetupOptions |
discoverReaders(...)
discoverReaders(options?: DiscoverReadersOptions) => Promise<{ readers: StripeReader[] }>Scan for nearby readers. Resolves once the scan finishes (after timeout, default 5000ms) with whatever readers were found.
| Param | Type |
| ------------- | -------------------------------------------------------------------------------- |
| options | DiscoverReadersOptions |
connectReader(...)
connectReader(options: ConnectReaderOptions) => Promise<{ success: boolean; reader?: StripeReader; }>Connect to a reader returned by discoverReaders.
| Param | Type |
| ------------- | ---------------------------------------------------------------------- |
| options | ConnectReaderOptions |
getConnectionStatus()
getConnectionStatus() => Promise<StripeConnectionStatus>Get the currently connected reader, if any.
disconnectReader()
disconnectReader() => Promise<{ success: boolean }>Disconnect from the currently connected reader.
checkout(...)
checkout(options: StripeCheckoutOptions) => Promise<StripeCheckoutResult>Create a PaymentIntent for amount/currency, collect a payment method from the connected reader, and confirm the payment. Requires a reader to be connected via connectReader first.
| Param | Type |
| ------------- | ---------------------------------------------------------------------- |
| options | StripeCheckoutOptions |
cancelCheckout()
cancelCheckout() => Promise<{ success: boolean }>Cancel an in-progress checkout (e.g. while waiting for a card tap).
checkTapToPay()
checkTapToPay() => Promise<StripeTapToPayStatus>Check whether Tap to Pay is available on this device and whether a Tap to Pay reader is currently connected.
Interfaces
StripeSetupOptions
| Prop | Type | Description |
| ------------------------ | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| publishableKey | string | Stripe publishable key, e.g. "pk_live_...". |
| connectionTokenUrl | string | URL of your backend endpoint that creates and returns a Stripe Terminal connection token, e.g. { "secret": "pst_test_..." }. |
| headers | Record<string, string> | Optional extra headers sent with the connection token request, e.g. for authentication. |
DiscoverReadersOptions
| Prop | Type | Description |
| --------------- | -------------------------------------------------------- | --------------------------------------------------------------------------------- |
| method | StripeReaderDiscoveryMethod | Defaults to tapToPay. |
| simulated | boolean | Discover simulated readers instead of real hardware. Defaults to false. |
| timeout | number | How long to scan for readers, in milliseconds. Defaults to 5000. |
StripeReader
| Prop | Type |
| ------------------ | --------------------- |
| id | string |
| label | string | null |
| serialNumber | string | null |
| deviceType | string | null |
| batteryLevel | number | null |
| simulated | boolean |
ConnectReaderOptions
| Prop | Type | Description |
| ---------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| readerId | string | The id of a reader returned by discoverReaders. |
| locationId | string | The Stripe Location ID (tml_...) this reader belongs to. Required for tapToPay/bluetoothScan readers. |
StripeConnectionStatus
| Prop | Type |
| --------------- | ------------------------------------------------------------ |
| connected | boolean |
| reader | StripeReader |
StripeCheckoutOptions
| Prop | Type | Description |
| -------------- | ------------------------------- | ------------------------------------------------------------------------------- |
| amount | number | Amount to charge, in the major currency unit (e.g. 12.50 for €12.50). |
| currency | string | ISO 4217 currency code, e.g. "EUR". |
| title | string | Optional description, attached to the PaymentIntent's metadata.title. |
| metadata | Record<string, string> | Arbitrary key/value pairs attached to the PaymentIntent. |
StripeCheckoutResult
| Prop | Type | Description |
| ------------------- | --------------------- | --------------------------------------------------------------------------- |
| success | boolean | |
| paymentIntentId | string | ID of the PaymentIntent (pi_...) created for this checkout. |
| status | string | Final PaymentIntent status, e.g. "succeeded" or "requiresCapture". |
StripeTapToPayStatus
| Prop | Type | Description |
| --------------- | --------------------- | ----------------------------------------------------------- |
| available | boolean | |
| activated | boolean | Whether a Tap to Pay reader is currently connected. |
Type Aliases
StripeReaderDiscoveryMethod
How the SDK should look for a reader. tapToPay uses the phone's own NFC reader.
'tapToPay' | 'bluetoothScan'
