Connecting to the Verifone P400

    Register your Verifone P400 reader and connect your application over the internet

    The Verifone P400 runs Stripe reader software to communicate directly with Stripe over the internet. Connecting your app to an internet-enabled reader requires three steps:

    Registering a reader Server-side

    Before you can connect your application to the Verifone P400, you must register the reader to your account.

    Register in the Dashboard

    The simplest way is to add your reader in the Dashboard.

    1. Click on a location, and under the Readers section, click + New.
    2. On your reader, enter the key sequence 0-7-1-3-9 to display a unique registration code.
    3. 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 your app, build a flow to register a reader with the Stripe API.

    1. On the reader, the user enters the key sequence 0-7-1-3-9 to display a unique registration code.
    2. The user enters the code in your application.
    3. Your application sends the code to Stripe:
    curl https://api.stripe.com/v1/terminal/readers \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d registration_code="{READER_REGISTRATION_CODE}" \ -d label="{OPTIONAL_DISPLAY_NAME}"

    To confirm that you’ve registered a reader correctly, list all the readers you’ve registered:

    curl https://api.stripe.com/v1/terminal/readers \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc:

    Discovering readers Client-side

    After registering the reader to your account, search for readers to connect to your point of sale application using the discoverReaders method.

    function discoverReaders() { const config = {simulated: false} 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); } }); }
    async function discoverReaders() { const config = {simulated: false} const discoverResult = await terminal.discoverReaders(config); 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); } }
    import UIKit import StripeTerminal class ReaderViewController: UIViewController, DiscoveryDelegate, TerminalDelegate { func connectReaderAction() { let config = DiscoveryConfiguration(deviceType: .verifoneP400, discoveryMethod: .internet, simulated: false) self.discoverCancelable = Terminal.shared.discoverReaders(config, delegate: self, completion: { error in if let error = error { print("discoverReaders failed: \(error)") } else { print("discoverReaders succeeded") } }) } }
    #import "APPReaderViewController.h" #import <StripeTerminal/StripeTerminal.h> @interface APPReaderViewController () <SCPDiscoveryDelegate, SCPTerminalDelegate> @property (nonatomic, nullable, strong) SCPCancelable *discoverCancelable; // ... @end @implementation APPReaderViewController // Action for a "Connect Reader" button - (void)connectReaderAction { SCPDiscoveryConfiguration *config = [[SCPDiscoveryConfiguration alloc] initWithDeviceType:SCPDeviceTypeVerifoneP400 discoveryMethod:SCPDiscoveryMethodInternet simulated:NO]; self.discoverCancelable = [[SCPTerminal shared] discoverReaders:config delegate:self completion:^(NSError *error) { if (error != nil) { NSLog(@"discoverReaders failed: %@", error); } else { NSLog(@"discoverReaders succeeded"); } }]; }

    When discovering Verifone P400 readers, the DiscoveryDelegate.didUpdateDiscoveredReaders method will only be called once per call to discoverReaders. didUpdateDiscoveredReaders will return an empty list of readers if no readers are registered or associated with the given location. If you make a subsequent call to discoverReaders to refresh the list, you must first cancel the previous call with the Cancelable returned by discoverReaders.

    Note that only the following DiscoveryConfiguration combinations are allowed. discoverReaders will result in an InvalidDiscoveryConfiguration error if you use an unsupported combination.

    Device Type Discovery Method Location ID Simulated
    verifoneP400 internet string or nil true or false
    chipper2X bluetoothProximity or bluetoothScan nil true or false

    Connecting 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); } }); }
    async function connectReader(discoverResult) { // Just select the first reader here. const selectedReader = discoverResult.discoveredReaders[0]; const connectResult = await terminal.connectReader(selectedReader); if (connectResult.error) { console.log('Failed to connect:', connectResult.error); } else { console.log('Connected to reader:', connectResult.reader.label); } }
    let config = ConnectionConfiguration(failIfInUse: true) Terminal.shared.connectReader(selectedReader, connectionConfig: config, completion: { reader, error in if let reader = reader { print("Successfully connected to reader: \(reader)") } else if let error = error as NSError?, error.code == ErrorCode.connectFailedReaderIsInUse.rawValue { // Ask user if they want to retry connection with ConnectionConfiguration(failIfInUse: false) } else if let error = error { print("connectReader failed: \(error)") } })
    SCPConnectionConfiguration *connectionConfig = [[SCPConnectionConfiguration alloc] initWithFailIfInUse:YES]; [[SCPTerminal shared] connectReader:selectedReader connectionConfig:connectionConfig completion:^(SCPReader *reader, NSError *error) { if (reader != nil) { NSLog(@"Successfully connected to reader: %@", reader); } else if (error.code == SCPErrorConnectFailedReaderIsInUse) { // Ask user if they want to retry connection with [[SCPConnectionConfiguration alloc] initWithFailIfInUse:NO] } else { NSLog(@"connectReader failed: %@", error); } }];

    The Verifone P400 can only connect to one instance of the SDK at a time. When you call connectReader from your app in a different browser tab or device, the new instance breaks the existing reader-to-SDK connection and takes over the Verifone P400, even if the reader’s currently in use. To disable this behavior, pass the fail_if_in_use parameter (named failIfInUse on iOS) when calling connectReader.

    • Regardless of the value of failIfInUse, if your application connects to another application’s reader while the other application is idle, that application’s next attempt to collect payment will fail with an unexpected disconnect.
    • When failIfInUse is set to true, your application does not interrupt a reader that’s currently collecting a payment. Instead, your application’s call to connectReader fails with the connectFailedReaderIsInUse error.
    • When failIfInUse is set to false, your application connects to the other application’s reader immediately. If the other application is currently collecting payment, that payment fails with an unexpected disconnect. Otherwise, that application’s next attempt to collect a payment will fail with an unexpected disconnect.

    We recommend setting failIfInUse: true for the initial connection attempt, and allowing your users to retry the connection with failIfInUse: false if appropriate.

    terminal.connectReader(reader, {fail_if_in_use: true}).then(function(connectResult) { // ... });
    const connectResult = await terminal.connectReader(reader, {fail_if_in_use: true});
    let config = ConnectionConfiguration(failIfInUse: true) Terminal.shared.connectReader(selectedReader, connectionConfig: config, completion: { reader, error in // ... })
    SCPConnectionConfiguration *connectionConfig = [[SCPConnectionConfiguration alloc] initWithFailIfInUse:YES]; [[SCPTerminal shared] connectReader:selectedReader connectionConfig:connectionConfig completion:^(SCPReader *reader, NSError *error) { // ... }

    Handling disconnects

    Your app must implement the UnexpectedReaderDisconnect callback to handle when a reader is disconnected.

    In your implementation of this callback, display a UI to notify the user that the reader disconnected. You may also want to call discoverReaders to begin scanning for readers and reconnect. Your app can attempt to automatically reconnect to the reader that was disconnected, or display a UI for your user to reconnect to another reader.

    The Verifone P400 can disconnect from your app if it loses connection to the internet. To simulate an unexpected disconnect, power off the reader.

    var terminal = StripeTerminal.create({ onFetchConnectionToken: fetchConnectionToken, onUnexpectedReaderDisconnect: unexpectedDisconnect, }); function unexpectedDisconnect() { console.log("Disconnected from reader") }
    const terminal = StripeTerminal.create({ onFetchConnectionToken: fetchConnectionToken, onUnexpectedReaderDisconnect: unexpectedDisconnect, }); function unexpectedDisconnect() { console.log("Disconnected from reader") }
    import UIKit import StripeTerminal class ReaderViewController: UIViewController, TerminalDelegate { override func viewDidLoad() { super.viewDidLoad() Terminal.shared.delegate = self } // ... // MARK: TerminalDelegate func terminal(_ terminal: Terminal, didReportUnexpectedReaderDisconnect reader: Reader) { print("Disconnected from reader: \(reader)") } }
    #import "APPReaderViewController.h" #import <StripeTerminal/StripeTerminal.h> @interface APPReaderViewController () <SCPDiscoveryDelegate, SCPTerminalDelegate> @property (nonatomic, nullable, strong) SCPCancelable *discoverCancelable; // ... @end @implementation APPReaderViewController - (void)viewDidLoad { [super viewDidLoad]; [SCPTerminal shared].delegate = self; } // ... #pragma mark – SCPTerminalDelegate - (void)terminal:(SCPTerminal *)terminal didReportUnexpectedReaderDisconnect:(SCPReader *)reader { NSLog(@"Disconnected from reader: %@", reader); } }

    Next steps

    Congratulations! You've connected your application to the reader. Next, collect your first Stripe Terminal payment.

    The BBPOS and Chipper™ name and logo are trademarks or registered trademarks of BBPOS Limited in the United States and/or other countries. The Verifone® name and logo are either trademarks or registered trademarks of Verifone in the United States and/or other countries. Use of the trademarks does not imply any endorsement by BBPOS or Verifone.

    Was this page helpful?

    Feedback about this page?

    Thank you for helping improve Stripe's documentation. If you need help or have any questions, please consider contacting support.

    On this page