The Quickest Way to Set Up Stripe in a Web App
This article shows how to get started using Stripe to accept payments in a Next.js application, using the Zero TypeScript SDK to fetch the Stripe API key.
Sam Magura
This article shows how to get started using Stripe to accept payments in a Next.js application, using the Zero TypeScript SDK to fetch the Stripe API key. Zero is a secrets manager which allows you to retrieve API keys and other secrets from the cloud using a single secure token, called a Zero token. Zero makes it so the Next.js application only needs to be configured with the Zero token — the Stripe API key is not stored in the repository or an environment variable.
🔗 The full code for this example is available in the zerosecrets/examples GitHub repository.
Secure your secrets conveniently
Zero is a modern secrets manager built with usability at its core. Reliable and secure, it saves time and effort.
Sign Up for Stripe
To complete this example, you will need an activated Stripe account. Sign up at Stripe.com and follow the wizard for activating your account so that you can accept payments. We won't be doing any real transactions in this example, but it is still necessary to provide the name of your business and your bank account information. You can use your first & last name as the business name, and leave a note in the description field that says you are simply evaluating the Stripe API.
Once your account is activated, make sure to switch to test mode using the toggle in the upper right:
The Stripe publisable key and secret key will be stored in Zero, so please sign up for Zero if you have not done so already. Once you are logged in to the Zero web console, create a new Zero token, and click "Add secret" and select Stripe from the dropdown. Then copy-paste the Stripe publishable and secret keys into Zero. These keys can be found on the homepage of the Stripe dashboard:
To test a payment, we'll need to create a product in Stripe. Click the "Products" link in the navigation bar and then press the "Add product" button. Enter a name for the product and set the cost to a one time payment of $20.00. Once the product is created, you'll be able to copy its price ID which should look similar to price_1LYuqlBzNL28s33DQYwQxFx7
. This price ID is not a secret and can safely be committed to the codebase, which we'll set up in the next section.
Creating the Next.js Web App
Let's create a new Next.js application using TypeScript by running
npx create-next-app nextjs-stripe --ts --use-npm
Start by deleting the boilerplate JSX, CSS, and API route that is part of the default Next.js template so that we can begin from a clean slate. Replace the contents of globals.css
with this stylesheet which is adapted from this example project from the Stripe docs.
Then update index.tsx
to display a product with a checkout link:
// See https://github.com/zerosecrets/examples/tree/main/nextjs-stripe
// for the full source code.
const ProductDisplay: React.FC = () => (
<section>
(product description here)
<form action="/api/createCheckoutSession" method="POST">
<button type="submit">Checkout</button>
</form>
</section>
)
interface HomeProps {
message: string | null
}
export const getServerSideProps: GetServerSideProps<HomeProps> = async (context) => {
let message: string | null = null
// Check to see if this is a redirect back from Checkout
if (context.query['success']) {
message = 'Order placed! You will receive an email confirmation.'
}
if (context.query['canceled']) {
message = "Order canceled -- continue to shop around and checkout when you're ready."
}
return {props: {message}}
}
const Home: NextPage<HomeProps> = ({message}) => {
return (
<div>
<Head>
<title>Next.js + Stripe + Zero</title>
</Head>
<h1>Next.js + Stripe + Zero</h1>
{message ? <p>{message}</p> : <ProductDisplay />}
</div>
)
}
export default Home
There's a fair amount going on here, so let's break it down. The ProductDisplay
component renders the product name, price, and thumbnail image and has a submit button which will post to the API route /api/createCheckoutSession
. This API route doesn't exist yet, but we will create it in a moment. Once complete, the API route should redirect the user to a prebuilt Stripe checkout page.
The other complex part of the code is the getServerSideProps
function. This function inspects the URL search params and sets the message
prop accordingly. Depending on the search params, message
may be set to a "payment successful" message, a "payment canceled" message, or undefined
, which is the default before the user has attempted to make a purchase.
Run the site with npm run dev
and you'll see our simple product page:
Creating a Checkout Session in Stripe
Currently, clicking the "Checkout" button will result in a 404 error. Let's remedy this by creating a new Next.js API route :
const DOMAIN = process.env.DOMAIN
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const stripe = await getStripeClient()
const session = await stripe.checkout.sessions.create({
line_items: [
{
// This is a price ID copied from the Stripe Dashboard
price: 'price_1LYuqlBzNL28s33DQYwQxFx7',
quantity: 1,
},
],
mode: 'payment',
success_url: `${MY_DOMAIN}?success=true`,
cancel_url: `${MY_DOMAIN}?canceled=true`,
})
if (!session.url) {
throw new Error('session.url is null.')
}
res.redirect(303, session.url)
}
This API route is relatively straightforward — it uses a Stripe API client (which we'll create next) to create a new checkout session using the price ID for the product we created earlier in the Stripe Dashboard. It then redirects the user to Stripe, which will render a prebuilt checkout page. If the checkout succeeds, Stripe will redirect back to our site with success=true
in the URL.
Creating the Stripe API Client
We still need to fill in the getStripeClient
function. We'll need the official Stripe npm package as well as the Zero SDK, since the Zero SDK will be used to fetch the Stripe secret key. These packages can be installed with:
npm install stripe @zerosecrets/zero
getStripeClient
could be used by multiple parts of our application, so we'll place it in a new directory named util
. The code looks like this:
import Stripe from 'stripe'
import {zero} from '@zerosecrets/zero'
let stripe: Stripe | undefined
export async function getStripeClient(): Promise<Stripe> {
// Reuse the same Stripe client if one has already been created, so that we
// don't call Zero on every request
if (stripe) {
return stripe
}
if (!process.env.ZERO_TOKEN) {
throw new Error('Did you forget to set the ZERO_TOKEN environment variable?')
}
const secrets = await zero({
token: process.env.ZERO_TOKEN,
pick: ['stripe'],
}).fetch()
if (!secrets.stripe) {
throw new Error('Did not receive an API key for SendGrid.')
}
stripe = new Stripe(secrets.stripe.secret_api_key, {
apiVersion: '2022-08-01',
})
return stripe
}
First, we call Zero with our Zero token to get the Stripe secret key. Then, we instantiate a new instance of the Stripe API client and return it.
You can test the website by locally by running
ZERO_TOKEN=<YOUR_ZERO_TOKEN> npm run dev
This syntax sets your Zero token as an environment variable which can then be accessed from JavaScript as process.env.ZERO_TOKEN
. Don't commit your Zero token to the git repository — your Zero token must remain secret since it provides access to your Stripe account.
If everything is set up correctly, you will be able to "purchase" the mock product. When redirected to the Stripe checkout page, enter 4242 4242 4242 4242
as the card number to simulate a successful payment. The expiration date can be any future date, and the security code can be any three digit number. To test a canceled payment, click the small back button in the upper left of the Stripe checkout page.
Deployment and Next Steps
This article showed how to quickly integrate a Next.js web application with the Stripe API, using the Zero secrets manager to store the Stripe private key. If this were a production application, the next step would be to deploy the app to the cloud. The easiest way to deploy a Next.js application is Vercel — Vercel is the company that makes Next. Vercel has a generous free plan and makes deployment a breeze, especially for Next.js. The application we coded should work on Vercel with no changes, except that the Zero token and your site's domain name must be defined as environment variables in the Vercel dashboard. Happy coding!
Other articles
The Complete Guide to Getting Started with the Braintree GraphQL API
Braintree is one of the world's leading payment platforms. This article provides an in-depth guide to getting started with Braintree, from getting your API token all the way to collecting customer payment information and charging a credit card.
Using Notion as a Human-Readable Database
Capture form submissions from your web app and store them where your team works.
Secure your secrets
Zero is a modern secrets manager built with usability at its core. Reliable and secure, it saves time and effort.