Stripe Tap to Pay Integration
August 7, 2025 · AI Conversations
—
### ✅ Prerequisites
1. **Stripe Account** with Terminal access & Tap to Pay on Android enabled.
2. A **certified Android device** with NFC & Google Play Services.
3. A **connected account** or **merchant account** in Stripe.
4. Stripe **secret key** (for backend) and **connection token endpoint**.
—
### 🧱 Native Android Integration Overview
1. **Add Stripe Terminal SDK to Android app:**
// In build.gradle (app)
dependencies {
implementation 'com.stripe:stripeterminal:2.19.0' // latest as of July 2025
}
2. **Initialize Stripe Terminal:**
Terminal.initTerminal(
getApplicationContext(),
LogLevel.VERBOSE,
new TokenProvider() {
@Override
public void fetchConnectionToken(@NonNull ConnectionTokenCallback callback) {
// Call your backend to create a connection token
fetchFromBackend(callback);
}
}
);
3. **Discover Tap to Pay Reader:**
DiscoveryConfiguration config = new DiscoveryConfiguration(
0, // no specific simulated reader
DeviceType.INTEGRATED,
0
);
terminal.discoverReaders(config, new DiscoveryListener() {
@Override
public void onUpdateDiscoveredReaders(@NonNull List<Reader> readers) {
if (!readers.isEmpty()) {
terminal.connectReader(readers.get(0), new ReaderCallback() {
@Override
public void onSuccess(@NonNull Reader reader) {
Log.d("Stripe", "Connected to reader: " + reader.getLabel());
}
@Override
public void onFailure(@NonNull TerminalException e) {
Log.e("Stripe", "Connection failed: " + e.getMessage());
}
});
}
}
});
4. **Create & Collect Payment Intent:**
// From backend: create PaymentIntent and pass client_secret
PaymentIntentParameters params = new PaymentIntentParameters.Builder()
.setAmount(5000L) // $50.00
.setCurrency("usd")
.build();
terminal.createPaymentIntent(params, new PaymentIntentCallback() {
@Override
public void onSuccess(@NonNull PaymentIntent intent) {
terminal.collectPaymentMethod(intent, new PaymentIntentCallback() {
@Override
public void onSuccess(@NonNull PaymentIntent collectedIntent) {
terminal.processPayment(collectedIntent, new PaymentIntentCallback() {
@Override
public void onSuccess(@NonNull PaymentIntent processedIntent) {
// Show success UI
}
@Override
public void onFailure(@NonNull TerminalException e) {
// Handle failure
}
});
}
@Override
public void onFailure(@NonNull TerminalException e) {
// Handle error
}
});
}
@Override
public void onFailure(@NonNull TerminalException e) {
// Handle error
}
});
—
### 🔄 Backend: Connection Token Endpoint (PHP Example)
require_once 'vendor/autoload.php';
StripeStripe::setApiKey('sk_test_...');
$connectionToken = StripeTerminalConnectionToken::create();
echo json_encode([
'secret' => $connectionToken->secret
]);
—
### 🌉 Next Step (if using Cordova):
– Create a **Cordova plugin wrapper** for the native Stripe Terminal SDK.
– Use `cordova-plugin-nativestorage` or equivalent for passing token/session securely.
– Bridge all needed Java methods from the Android SDK to JS (I can help build this plugin step-by-step if needed).
—
### 📦 Final Notes
– Tap to Pay only works on supported Android hardware (Pixel 5+, etc.).
– Requires Stripe's approval to enable Tap to Pay.
– You must use the **Stripe-connected reader flow** (not simulated).
– Cannot test real payments in development mode; use test card/NFC simulator.
—
Would you like me to:
1. Generate a custom Cordova plugin for this?
2. Help you bridge this into Framework7?
3. Provide a test APK for Tap to Pay prototype?
Let me know how deep you want to go.
1. Creating a custom Cordova plugin for Stripe Terminal SDK (Tap to Pay).
2. Bridging the native Android SDK to Framework7.
3. Building a test APK for Tap to Pay prototype.
—
## ✅ **1. Create a Custom Cordova Plugin for Stripe Terminal SDK (Tap to Pay)**
### Folder Structure:
cordova-plugin-stripe-terminal/
├── plugin.xml
├── src/
│ └── android/
│ └── StripeTerminalPlugin.java
└── www/
└── StripeTerminal.js
### 🧩 `plugin.xml`
<plugin id="cordova-plugin-stripe-terminal" version="1.0.0" xmlns="http://apache.org/cordova/ns/plugins/1.0">
<name>StripeTerminal</name>
<js-module src="www/StripeTerminal.js" name="StripeTerminal">
<clobbers target="StripeTerminal" />
</js-module>
<platform name="android">
<config-file target="AndroidManifest.xml" parent="/*">
<uses-permission android:name="android.permission.NFC"/>
<uses-feature android:name="android.hardware.nfc" android:required="true"/>
</config-file>
<source-file src="src/android/StripeTerminalPlugin.java" target-dir="src/com/yourcompany/stripeterminal"/>
</platform>
</plugin>
—
### 🧠 `StripeTerminalPlugin.java` (Basic Structure)
package com.yourcompany.stripeterminal;
import org.apache.cordova.*;
import org.json.JSONArray;
import org.json.JSONException;
import android.util.Log;
import android.content.Context;
import com.stripe.stripeterminal.Terminal;
import com.stripe.stripeterminal.external.callable.*;
import com.stripe.stripeterminal.external.models.*;
public class StripeTerminalPlugin extends CordovaPlugin {
private CallbackContext callbackContext;
private Context appContext;
@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
this.callbackContext = callbackContext;
this.appContext = this.cordova.getActivity().getApplicationContext();
if (action.equals("initialize")) {
initializeTerminal();
return true;
}
return false;
}
private void initializeTerminal() {
Terminal.initTerminal(
appContext,
LogLevel.VERBOSE,
new TokenProvider() {
@Override
public void fetchConnectionToken(@NonNull ConnectionTokenCallback callback) {
fetchFromBackend(callback); // implement HTTPS call to your backend
}
}
);
callbackContext.success("Terminal Initialized");
}
}
—
### 🧩 `www/StripeTerminal.js`
var exec = require('cordova/exec');
exports.initialize = function (success, error) {
exec(success, error, 'StripeTerminal', 'initialize', []);
};
—
## ✅ **2. Bridge to Framework7 in Cordova App**
In your `app.js` or main Framework7 view:
StripeTerminal.initialize(
function (msg) {
console.log('Stripe Terminal Initialized:', msg);
},
function (err) {
console.error('Error initializing Stripe Terminal:', err);
}
);
—
## ✅ **3. Build Test APK for Tap to Pay**
### Steps:
1. Clone your Cordova app and add the plugin:
cordova plugin add ../cordova-plugin-stripe-terminal
2. Add Android platform:
cordova platform add android
3. Build debug APK:
cordova build android
4. Install on supported Android device with NFC + Google Play Services:
adb install platforms/android/app/build/outputs/apk/debug/app-debug.apk
—
## 🔄 Backend Endpoint for Connection Token (PHP)
StripeStripe::setApiKey('sk_test_...');
$token = StripeTerminalConnectionToken::create();
echo json_encode(['secret' => $token->secret]);
Make sure this endpoint is called in your Java code using `HttpsURLConnection` or a library like Retrofit.
—
## ✅ Next Steps
Would you like me to:
– Create and upload the full Cordova plugin repo for you?
– Help you implement the complete `connectReader`, `collectPayment`, and `processPayment` flow?
– Provide the `.apk` build to test on a real Android device?
Let me know what you'd like to do first — I can prepare the plugin ZIP or set up your test APK build next.
**Download it here:**
[📦 cordova-plugin-stripe-terminal.zip](sandbox:/mnt/data/cordova-plugin-stripe-terminal.zip)
—
### 📥 To Use the Plugin
1. Unzip and add it to your Cordova project:
cordova plugin add ./cordova-plugin-stripe-terminal
2. Call the init function in Framework7:
StripeTerminal.initialize(
(msg) => console.log('Initialized:', msg),
(err) => console.error('Failed:', err)
);
—
### 🚀 Next Steps
Let me now:
– ✅ Build `connectReader`, `collectPayment`, and `processPayment` methods in the plugin.
– ✅ Help you create a test APK with the full Tap to Pay flow.
– ✅ Guide you to replace `"REPLACE_WITH_YOUR_CONNECTION_TOKEN"` with your real backend call.
Would you like me to build the next version of the plugin with the full payment flow and upload that too?
—
### ✅ 1. In your app-level `platforms/android/app/build.gradle`
Inside the `dependencies` block, add:
dependencies {
// ... your existing dependencies
implementation 'com.stripe:stripeterminal:2.19.0' // Use latest available version
}
> 💡 If you're not sure which version is current, [check here on Maven](https://mvnrepository.com/artifact/com.stripe/stripeterminal).
—
### ✅ 2. In your `platforms/android/build.gradle`
Make sure the `mavenCentral()` repository is present:
allprojects {
repositories {
google()
mavenCentral() // Required for Stripe Terminal SDK
}
}
—
### ✅ 3. Optional — Min SDK version
In `config.xml` or the plugin itself, you may want to enforce:
<preference name="android-minSdkVersion" value="21" />
Stripe Tap to Pay requires:
– **Android 8.1+**
– **NFC-enabled device**
– **Google Play Services**
—
### Final Reminder: After plugin is added, always run:
cordova platform remove android
cordova platform add android
cordova build android
Would you like me to generate a pre-configured `build.gradle` file for you with this already added?
**📦 Download:**
[cordova-plugin-stripe-terminal-updated.zip](sandbox:/mnt/data/cordova-plugin-stripe-terminal-updated.zip)
—
### 🧠 Methods Exposed
| JavaScript Call | Description |
|———————————-|——————————————–|
| `StripeTerminal.initialize()` | Initializes Stripe Terminal SDK |
| `StripeTerminal.connectReader()`| Discovers and connects to Tap to Pay NFC reader |
| `StripeTerminal.collectPayment(amount)` | Creates, collects, and processes a payment of specified amount (in cents) |
—
### 🧪 Usage Example (in Framework7 app.js)
// Initialize Stripe Terminal
StripeTerminal.initialize(
(res) => console.log('Initialized:', res),
(err) => console.error('Init failed:', err)
);
// Connect reader
StripeTerminal.connectReader(
(res) => console.log('Reader connected:', res),
(err) => console.error('Reader failed:', err)
);
// Collect & process $50.00
StripeTerminal.collectPayment(
5000, // amount in cents
(res) => console.log('Payment successful:', res),
(err) => console.error('Payment error:', err)
);
—
### 🔐 IMPORTANT
– Replace the token string in:
callback.onSuccess("REPLACE_WITH_YOUR_CONNECTION_TOKEN");
with a **real HTTPS call to your backend** that returns a `connection_token` from Stripe.
Would you like me to help write that backend PHP (or CodeIgniter) endpoint next?