Objective:-France (Bordeaux and Martinique) are using Stripe as payment gateway.
They have
received new payment terminal that we need to connect to POS, The model is BBPOS WisePOS
E
________________________________________________________________________
Stripe terminal overview:-
Stripe terminal provides tools to integratestripe payments into your mobile or web application
to accept in-person payments
There are following below steps to achive objective:-
1. Set up your reader
2. Set up your integration
3. Connect to a reader
4. Collect payments
________________________________________________________________________
1)Set up your reader:-(BBPOS WisePOS E)
Here we are using BBPOS WisePOS E reader Stripe Terminal apps.It connects to the Stripe
Terminal SDK over the internet.
This reader is compatible with the following integrations: JavaScript SDK, iOS SDK, Android SDK,
and server-driven.
There are following below steps to setup BBPOS WisePOS E):-
· Turn the reader on and off
· Access settings:-To open the settings menu, swipe right from the left edge of the reader
screen to reveal a Settings button. Tap the Settings button and enter the admin PIN
07139. From here, you can update your WiFi settings or generate a pairing code for
device registration. Battery status is displayed at the top right of this screen. To close the
settings menu, click the back arrow in the top left corner.
· Connect the reader to the internet:-Because the BBPOS WisePOS E is a smart reader, its
reader software communicates directly with Stripe, managing connectivity through a
LAN. The reader must connect to the same local network as your point of sale
application.it also connect over wifi and ethernet.
· Change the UI appearance:-You can change the appearance of the UI to use a light
theme in the settings menu. Swipe right across the screen to access the settings menu,
and select your appearance.
· Change the default reader language:-The BBPOS WisePOS E supports changing the
reader language in the settings menu. Swipe right across the screen to access the
settings menu, and select your language.
________________________________________________________________________
2)Set up your integration:-
Set up a Stripe Terminal SDK integration to accept in-person payments. the JavaScript SDK
requires three steps:
5. Install the SDK and client library on our checkout page:-
6. Set up the connection token endpoint on our backend and web application
7. Initialize the SDK in our web application
1)Install the SDK and client library:-
Client-side:-
To get started, include this script on our checkout page. This script must always load directly
from https://js.stripe.com for compatibility with the latest reader software. Do not include the
script in a bundle or host a copy yourself; this could break our integration without warning.
<script src="https://js.stripe.com/terminal/v1/"></script>
Server-side:-
Use Strpe official libraries for access to the Stripe API from Our application:
# Install the PHP library via Composer
composer require stripe/stripe-php
2)Set up the ConnectionToken endpoint:-
Server-side:-
To connet to a reader, our backend needs to give the SDk permission to use the reader with our
stripe account,by providing it with the secret key from a ConnectionToken.Our backend should
only create connection tokens for clients that it trusts.
// Set your secret key. Remember to switch to your live secret key in production.
// See your keys here: https://dashboard.stripe.com/apikeys
\Stripe\
Stripe::setApiKey('sk_test_51LKRdTHS7zOaeH1F6W6Y8EJDMBExOSI04NZ1pPBOQ5Ob60CbiPT1
8QrIiTuuK2zA2Md621WMNOy10urMbpiZFP1P00kIgmNb31');
// In a new endpoint on your server, create a ConnectionToken and return the
// `secret` to your app. The SDK needs the `secret` to connect to a reader.
$connectionToken = \Stripe\Terminal\ConnectionToken::create();
Obtain the secret from the ConnectionToken on your server and pass it to the client side.
<?php
$token = # ... Create or retrieve the ConnectionToken
echo json_encode(array('secret' => $token->secret));
?>
Client-side:-
To give the SDK access to this endpoint, create a function in our web application that requests a
ConnectionToken from our backend and returns the secret from the ConnectionToken object.
function fetchConnectionToken() {
// Your backend should call /v1/terminal/connection_tokens and return the JSON response
from Stripe
return fetch('https://{YOUR_BACKEND_URL}/connection_token', { method: "POST" })
.then(function(response) {
return response.json();
})
.then(function(data) {
return data.secret;
});
3)Initialize the SDK(client side):-
The StripeTerminal object made available by the SDK exposes a generic interface for discovering
readers, connecting to a reader, and creating payments. To initialize a StripeTerminal instance in
our JavaScript application, provide the ConnectionToken function implemented in Step 2.
we must also provide a function to handle unexpected disconnects from the reader,
onUnexpectedReaderDisconnect. 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
var terminal = StripeTerminal.create({
onFetchConnectionToken: fetchConnectionToken,
onUnexpectedReaderDisconnect: unexpectedDisconnect,
});
function unexpectedDisconnect() {
// You might want to display UI to notify the user and start re-discovering readers
________________________________________________________________________
3)Connect to a reader:-
Connect Our application to a Stripe Terminal reader.
For smart readers:-
Smart readers run Stripe reader software to communicate directly with Stripe over the internet.
Connecting your app to a smart reader requires three steps:
8. Register a reader to our Stripe account
9. Discover readers with the SDK
10. Connect to a reader with the SDK
1)Register a reader to our Stripe account:-serverside
Before we can connect our application to a smart reader, we must register the reader to our
account.
Register in the Dashboard:-
The simplest way is to add your reader in the Dashboard.
· If you’ve already created a Location, click on it. Otherwise, create one by clicking + New.
· Under the Readers section, click + New.
· If you have a Verifone P400, enter the key sequence 0-7-1-3-9 to display a unique
registration code. If you have a BBPOS WisePOS E, go to the settings then tap Generate
pairing code.
· Enter the code when prompted.
Register using the API:-
For larger deployments, enable users in the field to receive and set up new readers on their
own. In our app, build a flow to register a reader with the Stripe API.
· If we have a BBPOS WisePOS E, go to the settings then tap Generate pairing code.
· The user enters the code in our application.
· our application sends the code to Stripe:
// Set your secret key. Remember to switch to your live secret key in production.
// See your keys here: https://dashboard.stripe.com/apikeys
\Stripe\
Stripe::setApiKey('sk_test_51LKRdTHS7zOaeH1F6W6Y8EJDMBExOSI04NZ1pPBOQ5Ob60CbiPT1
8QrIiTuuK2zA2Md621WMNOy10urMbpiZFP1P00kIgmNb31');
\Stripe\Terminal\Reader::create([
'registration_code' => "{{READER_REGISTRATION_CODE}}",
'label' => "Alice's Reader",
'location' => '{{LOCATION_ID}}',
]);
To confirm that we’ve registered a reader correctly, list all the readers we’ve registered at that
location:
// Set your secret key. Remember to switch to your live secret key in production.
// See your keys here: https://dashboard.stripe.com/apikeys
\Stripe\
Stripe::setApiKey('sk_test_51LKRdTHS7zOaeH1F6W6Y8EJDMBExOSI04NZ1pPBOQ5Ob60CbiPT1
8QrIiTuuK2zA2Md621WMNOy10urMbpiZFP1P00kIgmNb31');
\Stripe\Terminal\Reader::all();
2)Discover readers:-Client-side
After registering the reader to our account, search for previously registered readers to connect
to our point of sale application using the discoverReaders method. we can scope our discovery
using the location we registered the reader to in the previous step.
function discoverReaders() {
const config = {simulated: false, location: '{{LOCATION_ID}}'}
terminal.discoverReaders(config).then(function(discoverResult) {
if (discoverResult.error) {
console.log('Failed to discover: ', discoverResult.error);
} else if (discoverResult.discoveredReaders.length === 0) {
console.log('No available readers.');
} else {
// You should show the list of discoveredReaders to the
// cashier here and let them select which to connect to (see below).
connectReader(discoverResult);
});
3)Connect to a reader:-Client-side
To connect your point of sale application to a reader, call connectReader with the selected
reader.
function connectReader(discoverResult) {
// Just select the first reader here.
var selectedReader = discoverResult.discoveredReaders[0];
terminal.connectReader(selectedReader).then(function(connectResult) {
if (connectResult.error) {
console.log('Failed to connect: ', connectResult.error);
} else {
console.log('Connected to reader: ', connectResult.reader.label);
});
For simulater :-
The Stripe Terminal SDK comes with a built-in simulated card reader, so you can develop and
test your app without connecting to physical hardware. Whether your integration is complete or
you’re just starting out, use the simulated reader to emulate all the Terminal flows in your app.
Note that the simulated reader does not provide a UI. After connecting to it in your app, you
can see it working when calls to the Stripe SDK succeed.
To use the simulated reader, call discoverReaders to search for readers, with the simulated
option set to true. When discoverReaders returns a result, call connectReader to connect to the
simulated reader.
// Handler for a "Connect Reader" button
function connectReaderHandler() {
var config = {simulated: true};
terminal.discoverReaders(config).then(function(discoverResult) {
if (discoverResult.error) {
console.log('Failed to discover: ', discoverResult.error);
} else if (discoverResult.discoveredReaders.length === 0) {
console.log('No available readers.');
} else {
// Just select the first reader here.
var selectedReader = discoverResult.discoveredReaders[0];
terminal.connectReader(selectedReader).then(function(connectResult) {
if (connectResult.error) {
console.log('Failed to connect: ', connectResult.error);
} else {
console.log('Connected to reader: ', connectResult.reader.label);
});
});
Simulated reader configuration
The simulated reader supports a small amount of configuration, enabling you to test different
flows within your point of sale application such as different card brands or error scenarios like a
declined charge.
The simulator configuration accepts either a testCardNumber or a testPaymentMethod options.
To enable this behavior, insert this line of code before you call collectPaymentMethod:
terminal.setSimulatorConfiguration({testCardNumber: '4242424242424242'});
________________________________________________________________________
4)Collect payments:-
Prepare our application and backend to collect payments using Stripe Terminal.
Collecting payments with Stripe Terminal requires writing a payment flow in our application.
Use the Stripe Terminal SDK to create and update a PaymentIntent, an object representing a
single payment session.
Designed to be robust to failures, the Terminal integration splits the payment process into
several steps, each of which can be retried safely:
11. Create a PaymentIntent
12. Collect a payment method
13. Process the payment
14. Capture the payment
1)Create a PaymentIntent:-Server-side
The first step when collecting payments is to start the payment flow. When a customer begins
checking out, our application must create a PaymentIntent object. This represents a new
payment session on Stripe.
The following example shows how to create a PaymentIntent on our server:
// Set your secret key. Remember to switch to your live secret key in production.
// See your keys here: https://dashboard.stripe.com/apikeys
\Stripe\
Stripe::setApiKey('sk_test_51LKRdTHS7zOaeH1F6W6Y8EJDMBExOSI04NZ1pPBOQ5Ob60CbiPT1
8QrIiTuuK2zA2Md621WMNOy10urMbpiZFP1P00kIgmNb31');
\Stripe\PaymentIntent::create([
'amount' => 1000,
'currency' => 'usd',
'payment_method_types' => ['card_present'],
'capture_method' => 'manual',
]);
The PaymentIntent contains a client secret, a key that is unique to the individual PaymentIntent.
To use the client secret, you must obtain it from the PaymentIntent on your server and pass it to
the client side.
<?php
$intent = # ... Create or retrieve the PaymentIntent
echo json_encode(array('client_secret' => $intent->client_secret));
?>
Use the client secret as a parameter when calling collectPaymentMethod
2)Collect a payment method :-Client-side
After you’ve created a PaymentIntent, the next step is to collect a payment method with the
SDK.
In order to collect a payment method, your app needs to be connected to a reader. The
connected reader will wait for a card to be presented after your app calls
collectPaymentMethod.
function checkout() {
// clientSecret is the client_secret from the PaymentIntent you created in Step 1.
terminal.collectPaymentMethod(clientSecret).then(function(result) {
if (result.error) {
// Placeholder for handling result.error
} else {
// Placeholder for processing result.paymentIntent
});
This method collects encrypted payment method data using the connected card reader, and
associates the encrypted data with the local PaymentIntent.
Handle events:-
The JavaScript SDK only supports the Verifone P400 and the BBPOS WisePOS E, which have a
built-in display. Your application doesn’t need to display events from the payment method
collection process to users, as the reader displays them. To clear the payment method on a
transaction, the cashier can press the red X key.
3)Process the payment:-Client-side
After successfully collecting a payment method from the customer, the next step is to process
the payment with the SDK. You can either process automatically or display a confirmation
screen, where the customer can choose to proceed with the payment or cancel (for example, to
pay with cash, or use a different payment method).
When you’re ready to proceed with the payment, call processPayment with the updated
PaymentIntent from Step 2. A successful processPayment call results in a PaymentIntent with a
status of requires_capture.
terminal.processPayment(paymentIntent).then(function(result) {
if (result.error) {
// Placeholder for handling result.error
} else if (result.paymentIntent) {
// Placeholder for notifying your backend to capture result.paymentIntent.id
});
4)Capture the payment:-server-side
Stripe Terminal uses a two-step process to prevent unintended and duplicate payments. When
the SDK returns a processed PaymentIntent to your app, the payment is authorized but not
captured
When your app receives a confirmed PaymentIntent from the SDK, make sure it notifies your
backend to capture the payment. Create an endpoint on your backend that accepts a
PaymentIntent ID and sends a request to the Stripe API to capture it:
// Set your secret key. Remember to switch to your live secret key in production.
// See your keys here: https://dashboard.stripe.com/apikeys
$stripe = new \Stripe\
StripeClient('sk_test_51LKRdTHS7zOaeH1F6W6Y8EJDMBExOSI04NZ1pPBOQ5Ob60CbiPT18QrIiT
uuK2zA2Md621WMNOy10urMbpiZFP1P00kIgmNb31');
$stripe->paymentIntents->capture('{{PAYMENT_INTENT_ID}}', []);
A successful capture call results in a PaymentIntent with a status of succeeded.
________________________________________________________________________
example application :
https://stripe.com/docs/terminal/example-applications
________________________________________________________________________
Simulater code:
<script src="https://js.stripe.com/terminal/v1/"></script>
<?php
require_once('vendor/stripe/stripe-php/init.php');
\Stripe\
Stripe::setApiKey('sk_test_51LKRdTHS7zOaeH1F6W6Y8EJDMBExOSI04NZ1pPBOQ5Ob60CbiPT18QrIiTuuK2
zA2Md621WMNOy10urMbpiZFP1P00kIgmNb31');
$connectionToken = \Stripe\Terminal\ConnectionToken::create();
echo json_encode(array('secret' => $connectionToken->secret));
//echo "<pre>";
//print_r($connectionToken);
//echo "</pre>";
$reader=\Stripe\Terminal\Reader::all();
//echo "<pre>";
//print_r($reader);
//echo "</pre>";
$intent=\Stripe\PaymentIntent::create([
'amount' => 2000,
'currency' => 'eur',
'payment_method_types' => ['card_present'],
'capture_method' => 'manual',
]);
// print_r($intent);
$client_secret=$intent->client_secret;
// echo $client_secret;
?>
<button type="button" onclick="connectReaderHandler()" >Connect Reader</button>
<!--<input id="payment-name" type="text">-->
<input type="hidden" id="payment-button" data-secret="<?= $intent->client_secret ?>"/>
<script>
// var
connection_token="pst_test_YWNjdF8xTEtSZFRIUzd6T2FlSDFGLGp6Q1lsUjhtenZiSE53MG5pd0I5bjUwQ253
ZmE2UG8_00oeZFU2o7";
function fetchConnectionToken() {
// Your backend should call /v1/terminal/connection_tokens and return the JSON response from Stripe
return fetch('https://demo-backend-app.herokuapp.com/connection_token', { method: "POST" })
.then(function(response) {
console.log(response);
return response.json();
})
.then(function(data) {
console.log(data.secret);
return data.secret;
});
}
var terminal = StripeTerminal.create({
onFetchConnectionToken: fetchConnectionToken,
onUnexpectedReaderDisconnect: unexpectedDisconnect,
});
function unexpectedDisconnect() {
// You might want to display UI to notify the user and start re-discovering readers
console.log("rediscover");
}
// Handler for a "Connect Reader" button
function connectReaderHandler() {
var config = {simulated: true};
terminal.discoverReaders(config).then(function(discoverResult) {
if (discoverResult.error) {
console.log('Failed to discover: ', discoverResult.error);
} else if (discoverResult.discoveredReaders.length === 0) {
console.log('No available readers.');
} else {
// Just select the first reader here.
var selectedReader = discoverResult.discoveredReaders[0];
console.log("selected first reader");
terminal.connectReader(selectedReader).then(function(connectResult) {
if (connectResult.error) {
console.log('Failed to connect: ', connectResult.error);
} else {
console.log('Connected to reader: ', connectResult.reader.label);
console.log("payment continiues with card no 4242424242424242")
terminal.setSimulatorConfiguration({testCardNumber: '4242424242424242'});
//var client_secret="<?php //echo $client_secret; ?>//";
//console.log(client_secret);
const paymentbutton = document.querySelector('#payment-button');
console.log("client_secret from the PaymentIntent")
console.log(paymentbutton.dataset.secret);
// clientSecret is the client_secret from the PaymentIntent you created in Step 1.
terminal.collectPaymentMethod(paymentbutton.dataset.secret).then(function(result) {
if (result.error) {
// Placeholder for handling result.error
} else {
console.log("response of collectPaymentMethod")
console.log(result.paymentIntent);
// Placeholder for processing result.paymentIntent
terminal.processPayment(result.paymentIntent).then(function(result) {
if (result.error) {
// Placeholder for handling result.error
} else if (result.paymentIntent) {
console.log("notifying on backend to capture result.paymentIntent.id")
console.log(result.paymentIntent.id);
// document.getElementById("hidden1").value = result.paymentIntent.id;
// Placeholder for notifying your backend to capture result.paymentIntent.id
var paymentintent = result.paymentIntent.id;
$.post("methods.phtml", {
paymentintent: paymentintent,
})
.done(function(response) {
});
}
});
}
});
}
});
}
});
}
</script>
<?php
$payment_intentid = $_POST['paymentintent'];
//echo $payment_intentid;
//exit();
$stripe = new \Stripe\
StripeClient('sk_test_51LKRdTHS7zOaeH1F6W6Y8EJDMBExOSI04NZ1pPBOQ5Ob60CbiPT18QrIiTuuK2zA2
Md621WMNOy10urMbpiZFP1P00kIgmNb31');
//exit();
//$payment_intent=$intent->id;
//echo $intent->id;
//exit();
$stripe->paymentIntents->capture($payment_intentid, []);
?>