Get Paid IRL (Part 2) Building your app for accepting payments
Tags: tutorial, payments, stripe, webdev
Published: 2022-05-23 18:44:10

*Did you know that you can accept in-person payments with Stripe? In this series, we’re going to dive headfirst into building an in-person payments integration using [Stripe Terminal](https://stripe.com/docs/terminal).*  

*In [our last post](https://dev.to/stripe/get-paid-irl-how-to-accept-money-with-stripe-terminal-part-14-1ljd), we learned how to register a physical or simulated WisePOS E using the Stripe dashboard, so that we could build a point-of-sale application to take in-person payments.* 

*In this blog post, we’re going to start building our application using a scaffolded Node.js project in [Replit](https://replit.com/~), a service you can use to build, compile and host projects–or repls–from the comfort of your browser. That’s right, we’re leaving the Stripe dashboard and breaking out our web-based IDE!*

*New to this series? Be sure to check out [our previous post](https://dev.to/stripe/get-paid-irl-how-to-accept-money-with-stripe-terminal-part-14-1ljd) on how to set up a physical or simulated card reader for testing and development.*  

# Building your point-of-sale app
## Setting up the project

We’re going to start building our web app using a scaffolded [Node.js](https://nodejs.org/en/about/) project in [Replit](https://replit.com/), a free service you can use to build and host projects (repls) from the comfort of your favorite browser. If you don’t already have a Replit account, you can sign up for a free one [here](https://replit.com/signup).   

To save time, be working off [this starter repl](https://replit.com/@charlesw-dev/terminal-starter#.replit). The repl has Node.js backend running the [Express.js](https://expressjs.com/) micro framework. We’ve scaffolded the project ahead of time to include the HTML templates and app server, so that we can focus on building against the [Stripe Terminal](https://stripe.com/docs/terminal) APIs instead of writing boilerplate.  

[**Fork the starter Repl**](https://replit.com/@charlesw-dev/terminal-starter#.replit) to create a copy to your account, if you’d like to follow along with the tutorial and remix the application. 

[**Add your Stripe secret key**](https://dashboard.stripe.com/test/apikeys) as a project environment variable by navigating to the repl’s **Secret** store and adding  `STRIPE_SECRET_KEY`  as a key and your actual Secret key as its value.  

**Click the Run button** to start your project. This will install the project’s required dependencies and start the app. Your starter point-of-sale app is live 🎉

![Click the Run button in your repl to start the project and notice it has no readers in the reader-select](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dtw7hdj01v9vo39a80jh.gif)

You’ll notice that we have a dropdown field for selecting a reader. You’ll also notice that our dropdown list doesn’t actually list any readers.

To fill out our list, we’ll be creating a backend route for retrieving our Terminal readers from our Stripe account in **`server/server.js`** and use it in **`client/index.js`**.

----------
## Creating a route for listing readers (backend)

To list our readers in our frontend, we’ll need to first retrieve them from Stripe in our backend. 

In `/server/server.js`, add a route for retrieving your Terminal readers from all locations around line 30. Be sure to add your code *after* instantiating your Express `app` and `stripe`  but *before* running `app.listen()`.  

Here we’ll create a `GET` endpoint on our backend at `/list-readers`. In the `app.get()` callback, add a try-catch. We’ll call `stripe.terminal.readers.list()`. In our case, we’ll `limit` our results to five readers with a status of `online`.  In addition to status, we could also filter the results by [`location`](https://stripe.com/docs/api/terminal/readers/list#list_terminal_reader-location), [`device_type`](https://stripe.com/docs/api/terminal/readers/list#list_terminal_reader-device_type) , and even device [`serial_number`](https://stripe.com/docs/api/terminal/readers/list#list_terminal_reader-serial_number). But for testing, filtering by `status` will do.

{% embed https://gist.github.com/charlesw-stripe/3ade1136707b5cc6dce4de83b7419495 %}


Now if we create a `GET` request to our `/list-readers` route, which we can do via [`cURL`](https://curl.se/), [Postman](https://www.postman.com/), or by visiting the URL in our browser, we’ll get an array that contains a list of Terminal Reader objects, which represent the current state of our registered card readers.

{% embed https://gist.github.com/charlesw-stripe/daef2591212188ec338c581aa5bb61eb %}

Retrieving our readers will give us a variety of information about the reader, including its name (`label`), `status`, and most recent `action`. We’ll dive into how to use the `action` property in our next post on creating and processing payments. For now, let’s focus on rendering our readers to the page and making them selectable. 

----------
## Retrieving and rendering readers (frontend)

Now that we have a way to retrieve our readers, let’s render them in our web app.  

In `client/index.js`, we have an event listener for when our DOM loads, `DOMContentLoaded`. In the callback, use fetch to make a `GET` request to our newly created list-readers endpoint.  We’ll destructure the results to get a `readers` (success) or an `error` (failure). 

If we get an error, we’ll handle the error by adding a message to our `#messages` div just below our form and logging out to the console using our addMessage helper from `utils.js`. Otherwise, we’ll loop through our `readersList`, adding each one to our `reader-select` dropdown.

{% embed https://gist.github.com/charlesw-stripe/f677e12f271221cb23721ebd17184b99 %}

Let your repl save and reload.  Your Terminal app is now able to list any online readers. 

![The register Terminal readers in the Stripe dashboard are now listed in our app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8hm8gh0utgrway9vozb2.gif)

If you don’t see any readers or errors, make sure that you’ve set up at least one simulated reader to at least one Stripe Terminal Location. You can learn how in our [previous post on registering readers](https://dev.to/stripe/get-paid-irl-how-to-accept-money-with-stripe-terminal-part-14-1ljd). 

Otherwise, your app’s dropdown list should now contain up to five online simulated or real WisePOS E’s.

Just having a list of online readers along with their IDs brings you half-way to processing in-person payments with Stripe’s Terminal server-driven integration. 

----------
## Next up: Creating and collecting payments with Stripe Terminal

In our next post, we’ll learn how to create and hand-off payments to the Stripe Terminal readers listed in our app using the [Payment Intents](https://stripe.com/docs/payments/payment-intents) and [Terminal Reader](https://stripe.com/docs/api/terminal/readers) APIs.  


## Stay connected

Want to stay up to date on Stripe’s latest integrations, features, and open-source projects?
  
📣 Follow us on [Twitter](https://twitter.com/StripeDev)
💬 Join the official [Discord server](https://stripe.com/go/developer-chat)
📺 Subscribe to our [Youtube channel](https://www.youtube.com/StripeDevelopers)
📧 Sign up for the [Dev Digest](https://go.stripe.global/dev-digest)


## About the author

![The author, Charles Watkins](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aqzlent7mkotc9hnl8k7.png)

[Charles Watkins](https://charleswatkins.dev/) is a Developer Advocate at Stripe where he writes, codes, and livestreams about online payments. In his spare time, he enjoys drawing, gaming, and rewatching the first five seasons of Game of Thrones.