This content originally appeared on flaviocopes.com and was authored by flaviocopes.com
This post is part of a new series where we build a clone of Airbnb with Next.js. See the first post here.
- Part 1: Let’s start by installing Next.js
- Part 2: Build the list of houses
- Part 3: Build the house detail view
- Part 4: CSS and navigation bar
- Part 5: Start with the date picker
- Part 6: Add the sidebar
- Part 7: Add react-day-picker
- Part 8: Add the calendar to the page
- Part 9: Configure the DayPickerInput component
- Part 10: Sync the start and end dates
- Part 11: Show the price for the chosen dates
- Part 12: Login and signup forms
- Part 13: Activate the modal
- Part 14: Send registration data to the server
- Part 15: Add postgres
- Part 16: Implement model and DB connection
- Part 17: Create a session token
- Part 18: Implement login
- Part 19: Determine if we are logged in
- Part 20: Change state after we login
- Part 21: Log in after registration
- Part 22: Create the models and move data to the db
- Part 23: Use the database instead of the file
- Part 24: Handle bookings
- Part 25: Handle booked dates
- Part 26: Prevent booking if already booked
- Part 27: Adding Stripe for payments
Now we must implement the Stripe webhook handler. A webhook is an HTTP call in response to something, and in our case that’s sent to us when the payment is successful.
Using Webhooks locally
When the app will be “live” on a real server, you’d go to https://dashboard.stripe.com/account/checkout/settings and click “Configure webhooks” in the “Checkout client & server integration” section to configure the real webhook.
But since we are running the app locally, what can we do? Stripe does not let us use localhost
as a valid domain, and for a good reason: they must be able to access your app, and if it’s running on localhost it’s just not possible - unless you set up an ip tunnel using ngrok for example.
Luckily for us, Stripe has this great tool called Stipe CLI that can provide a way to automatically get webhooks to our local server.
See here how to install it. In my case, on macOS, it’s
brew install stripe/stripe-cli/stripe
Once installed I run
stripe login
and follow the instructions to log in.
Then run
stripe listen --forward-to localhost:3000/api/stripe/webhook
This command will return a webhook signing secret code, which you’ll need to put in the .env
file:
STRIPE_WEBHOOK_SECRET=whsec_SOMETHING
and it will keep running in the background.
Important: you now need to stop the Next.js npm run dev
command, and start it again, to apply the .env
setting.
The Webhook handler
Now let’s create the Webhook POST handler.
Create a file pages/api/stripe/webhook.js
We return a { received: true }
JSON response to Stripe, to tell them “we got it!”:
export default async (req, res) => {
res.writeHead(200, {
'Content-Type': 'application/json'
})
res.end(JSON.stringify({ received: true }))
}
Before doing so however, we can use this code (which I found on the Stripe documentation) that we use to analyze the Webhook:
const sig = req.headers['stripe-signature']
let event
try {
event = stripe.webhooks.constructEvent(rawBody, sig, endpointSecret)
} catch (err) {
res.writeHead(400, {
'Content-Type': 'application/json'
})
console.error(err.message)
res.end(
JSON.stringify({
status: 'success',
message: `Webhook Error: ${err.message}`
})
)
return
}
See that I use the rawBody
variable. This is not a property available by default to us, but stripe.webhooks.constructEvent()
wants the raw request body passed to it, to verify for security purposes.
We must tell Next.js to avoid parsing the body:
export const config = {
api: {
bodyParser: false
}
}
Then we can install the raw-body
library:
npm install raw-body
and we have access to the raw body using
const rawBody = await getRawBody(req, {
encoding: 'utf-8'
})
Since we get lots of various Webhook notifications from Stripe we need to filter out the one we need, which is called checkout.session.completed
.
When this happens we get the session id from the event and we use that to update the booking with the same session id assigned (remember? we added it into the table) and it sets the paid
column to true:
if (event.type === 'checkout.session.completed') {
const sessionId = event.data.object.id
try {
Booking.update({ paid: true }, { where: { sessionId } })
} catch (err) {
console.error(err)
}
}
This is the complete code:
import { Booking } from '../../../model.js'
import dotenv from 'dotenv'
dotenv.config()
import getRawBody from 'raw-body'
export const config = {
api: {
bodyParser: false
}
}
export default async (req, res) => {
if (req.method !== 'POST') {
res.status(405).end() //Method Not Allowed
return
}
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY)
const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET
const sig = req.headers['stripe-signature']
const rawBody = await getRawBody(req, {
encoding: 'utf-8'
})
let event
try {
event = stripe.webhooks.constructEvent(rawBody, sig, endpointSecret)
} catch (err) {
res.writeHead(400, {
'Content-Type': 'application/json'
})
console.error(err.message)
res.end(
JSON.stringify({
status: 'success',
message: `Webhook Error: ${err.message}`
})
)
return
}
if (event.type === 'checkout.session.completed') {
const sessionId = event.data.object.id
try {
Booking.update({ paid: true }, { where: { sessionId } })
console.log('done')
} catch (err) {
console.error(err)
}
}
res.writeHead(200, {
'Content-Type': 'application/json'
})
res.end(JSON.stringify({ received: true }))
}
This is a central part of our application.
As soon as the user is back from the payment from Stripe, if all goes well the booking has already been marked as paid in our database.
Testing Webhooks
As with every entity that’s introduced in your application that you don’t have full control over, testing webhooks is complicated.
Luckily Stripe provides us the stripe
CLI tool we already used to allow local webhooks to run.
If you open another window, you can invoke it again like this:
stripe trigger checkout.session.completed
This lets you test the Webhook code without having to follow the payments workflow manually over and over again.
You can now try the whole workflow, and ideally you should get a booking marked as paid in the database!
This content originally appeared on flaviocopes.com and was authored by flaviocopes.com

flaviocopes.com | Sciencx (2021-12-28T05:00:00+00:00) Airbnb clone, handling Stripe webhooks. Retrieved from https://www.scien.cx/2021/12/28/airbnb-clone-handling-stripe-webhooks/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.