Skip to main content

Incorporate Stripe using Squid Webhooks

Use Squid Cloud's webhook decorator to respond to events in Stripe

Webhooks are HTTP requests sent from an app or service when an event occurs. The request's payload includes useful information about the event, which you can use to take actions in your own code. You provide the HTTP endpoint to the service, generally through a product's dashboard. Each product has its own events that can have webhooks, but here's a list of common scenarios:

  • Creating a new user
  • Updating a user's profile
  • Modifying a database or storage
  • Analytics events

In this tutorial, you create a webhook that runs when a Stripe customer's invoice status changes to 'paid'.

What you'll build

  • A Squid backend that adds data to the built-in database in response to Stripe webhooks.

What you'll learn

  • How to create a Squid Service that hooks into Stripe events.
  • How to create a Squid Service that adds security to your chatbot.

What you'll need

Create a Squid project

  1. Navigate to the Squid Cloud Console.
  2. Click Create application.
  3. Name the app "stripe-invoices".
  4. Choose us-east-1.aws as the project region.

Take note of your App ID and Developer ID, as you will need these for the tutorial.

Get the code

  1. Download or clone the squid–samples repo.
  2. Change to the stripe-webhooks/starter directory:
cd stripe-webhooks/starter
  1. Notice that there are two folders in the starter project: stripe-webhook-frontend and squid-webhook-backend. The code we are writing is only on the backend, so we don't need to make any changes to the frontend right now. There is an option at the end of the tutorial to configure the frontend so you can see document updates in realtime.

  2. Change to the stripe-webhook-backend directory, and then install the required NPM packages:

cd stripe-webhook-backend
npm install

Initialize the backend project

To run your backend locally, Squid requires a .env file with attributes that identify your app. The following steps generate the .env file.

  1. In the Squid Console on the Overview page, scroll down to the Backend section.

  2. Click Create .env file. This opens a modal with a terminal command for generating the file. Copy this command. The format of the command is as follows:

squid init-env \
--appId YOUR_APP_ID \
--apiKey YOUR_API_KEY \
--environmentId dev \
--squidDeveloperId YOUR_DEV_ID \
--region us-east-1.aws
  1. In your terminal window, ensure you are in the stipe-webhooks-backend folder, and then paste and run the command. You now have a .env file!

Create the webhook service

The webhook Squid Service we create in this section is designed to add a new invoice with its status or update an existing invoice with the status of 'paid'. The key of each field is the invoice ID from Stripe, and the value is either 'paid' or 'unpaid'.

The document ID is the user's authentication ID. Security rules are configured such that users can only view their own invoices. To help visualize, the structure looks something like the following:

userPayments:
squidUserId123: {
kaglautA235980A: 'paid'
Edg26GH697dk104: 'unpaid'
...
squidUserId456: {
SFHGhg995gja0435: 'unpaid'
...
  1. Navigate to stripe-webhook-backend/src/service/ and open the stripe-webhook-service.ts file.
  2. In the StripeWebhookService class, add the following function:
stripe-webhook-service.ts
async addInvoiceToDatabase(stripeUserId: string, invoiceId: string, paid: boolean): Promise<string | any> {
const paidStatus = paid ? 'paid' : 'unpaid';

try {
// Find user in database
const userDocs = await this.squid.collection('userPayments').query().eq('stripeUserId', stripeUserId).snapshot();

if (userDocs.length === 0) {
console.log('new user found, adding to database');
const newInvoices = { [invoiceId]: paidStatus };
await this.squid
.collection('userPayments')
.doc('squidUserId123')
.insert({ stripeUserId: stripeUserId, invoices: newInvoices });
return 'new user, database update complete';
}

const newInvoices = { ...userDocs[0].data.invoices, [invoiceId]: paidStatus };
await userDocs[0].update({ invoices: newInvoices });
return 'database update complete';
} catch (error) {
console.error(error);
return error.message;
}
}

This helper function takes three parameters: the Stripe customer ID, Stripe invoice ID, and 'paid' status of the invoice. It queries a collection called userPayments to find the document that belongs to the user with the given Stripe customer ID, and then updates their invoices to include the new invoice.

If there is no document found, it adds a new document with the key of squidUserId123. This is just for demonstration purposes since every Stripe customer should have an associated Squid user ID, and thus a document with their user ID as the key. In your app, you will likely handle the scenario as an error that you log in a different location in the database.

  1. After addInvoiceToDatabase function, add the following code:
stripe-webhook-service.ts
@webhook('handleStripePayment')
async handleStripePayment(request: WebhookRequest): Promise<WebhookResponse | any> {
const stripeUserId = request.body.data.object.customer;
const invoiceId = request.body.data.object.id;
const response = await this.addInvoiceToDatabase(stripeUserId, invoiceId, true);
return this.createWebhookResponse(response);
}

This function uses the @webhook decorator, marking it as a Squid webhook. The string handleStripePayment is used in the endpoint URL, so you want to choose a value that clarifies the purpose of the endpoint.

The customer and id properties are available in the body of the request sent by Stripe. View the Stripe documentation on webhooks for details on available properties.

These attributes are passed to the addInvoiceToDatabase function. Then a response is sent to Stripe using Squid's createWebhookResponse function.

  1. In the stripe-webhook-backend folder, run your Squid backend locally using the following command:
squid start

The terminal logs include a URL for the webhook. The log will look similar to the following:

| Available webhooks:
| Webhook URL for handleStripePayment: https://YOUR_APP_ID-dev-YOUR_SQUID_DEVELOPER_ID.us-east-1.aws.squid.cloud/webhooks/SQUID_WEBHOOK_NAME

Keep track of this URL because you will need it in the next section.

Add a Stripe customer

For this section, you need a Stripe account.

  1. In test mode, navigate to the Customers section of the Stripe dashboard.
  2. Click Add customer. Name the customer John Doe or whatever name you prefer.
  3. Click Add customer to save the new customer.

Add the webhook to Stripe

  1. In the Stripe dashboard, click Developers.
  2. On the Developers page, click the Wehooks tab.
  3. Click Add endpoint.
  4. Paste in the endpoint URL from the terminal logs. As a reminder, your Endpoint URL has the following format:
https://YOUR_APP_ID-dev-YOUR_SQUID_DEVELOPER_ID.us-east-1.aws.squid.cloud/webhooks/handleStripePayment
note

The URL format we're using is for the dev environment. The endpoint format for the prod environment is https://YOUR_APP_IDYOUR_SQUID_DEVELOPER_ID.APP_REGION.squid.cloud/webhooks/SQUID_WEBHOOK_NAME.

  1. Click Select events and choose invoice.paid. It's helpful to use the search bar.

  2. Click Add endpoint.

Test the webhook

  1. Open a new terminal window. You should now have two terminal windows open. If you haven't done so already, install the Stripe CLI.

  2. Add an environment variable to store the Stripe customer ID. The Stripe customer ID is available in the details section of the customer you added to your Stripe Customers dashboard.

export customer=YOUR_STRIPE_CUSTOMER_ID
  1. Create a new paid invoice for your customer using the following Stripe command:
stripe trigger invoice.paid --override invoiceitem:customer=$customer --override invoice:customer=$customer --override payment_method:customer=$customer

For the purpose of this tutorial, you don't need to worry too much about what these flags mean. If you would like to know more about the Stripe CLI, check out Stripe's reference docs.

note

This command uses the temporary environment variable you configured. When you want to run this command in another terminal window, you need to add the customer variable again.

  1. In the Stripe dashboard, select the your endpoint from the webhooks tab. You can see the event that took place, Squid's response, and the request body.

  2. In the Stripe dashboard, select the Customers tab and scroll down to the Invoices section of your customer's profile. Notice there is now a paid invoice.

There is also a new unnamed cusotmer in the list of customers. Testing the invoice.paid event with the Stripe CLI creates a new user. This doesn't happen in live events.

You did it!

Congratulations! You just created a Squid Service webhook to respond to an event triggered in Stripe. With the objective completed, you are welcome to stop here, but there is more to add if you choose.

Bonus section: Add a frontend app

To view the updated document data on the backend, we could add a query, get the document, and then log the results. However, to better reflect how you use data in an app, it's best to show the updates on the frontend.

The following bonus steps configure a frontend in which you can view the realtime updates to your database in response to Stripe events.

You will need an Auth0 account with a single-page application configured to use React

Add the Auth0 integration

  1. If you haven't yet made an Auth0 app, set up an Auth0 account and create a single-page application configured to use React. When adding the callback and logout URLs, use http://localhost:5173.
  2. In the Squid Cloud Console in the dev environment, select the Integrations tab.
  3. Click the Available integrations tab to view all integrations.
  4. Scroll to the Auth0 integration and click Add integration.
  5. Enter auth0 for the Integration ID.
  6. Enter the client ID and domain for your Auth0 app. These can be found in the Auth0 console.
  7. Click Add integration.

Add Squid Cloud to the frontend

  1. Navigate to stripe-webhook-frontend/src/main.tsx. Notice there is an Auth0Provider component and a SquidContextProvider component, both of which require configuration:
src/main.tsx
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<Auth0Provider
domain="AUTH0_DOMAIN"
clientId="AUTH0_CLIENT_ID"
authorizationParams={{
redirect_uri: window.location.origin,
audience: 'auth0-api-id',
}}
>
<SquidContextProvider
options={{
appId: 'YOUR_APP_ID',
region: 'YOUR_REGION',
environmentId: 'dev',
squidDeveloperId: 'YOUR_DEVELOPER_ID',
}}
>
<App />
</SquidContextProvider>
</Auth0Provider>
);
  1. Replace the placeholders in the Auth0Provider component with the domain and client ID from your Auth0 application.

  2. Replace the placeholders in the SquidContextProvider component with the App ID, Region and Developer ID for your Squid app. You can find these values in the Squid Console or in your .env file.

  3. Open the stripe-webhook-frontend/src/App.tsx file. Replace the placeholder in the stripeUserId variable with the Stripe Customer ID from the customer you created. You can find this ID in the Stripe dashboard.

App.tsx
...
function App() {
const stripeUserId = '[YOUR_STRIPE_CUSTOMER_ID]'
...
  1. Open a third terminal window. Yes, you should have three different terminal windows open. Change to the stripe-webhook-frontend folder and run the following command:
npm run dev
  1. To view the frontend app, navigate to localhost:PORT where PORT is logged in the terminal. The address will likely be http://localhost:5173.

  2. Log in using the Log in button.

  3. Click Add mock data to generate some imaginary invoices.

  4. In the terminal window you use for Stripe commands, create another paid invoice for your customer. If possible, run the command on a separate screen or shrink the terminal window so you can view the web app as well.

stripe trigger invoice.paid --override invoiceitem:customer=$customer --override invoice:customer=$customer --override payment_method:customer=$customer
  1. Observe in the web app that you have a new paid invoice. Awesome sauce!

Congratulations! 🦑

Nice work! Not only did you create a webhook that responds to events in Stripe, but you also configured a frontend to view changes in real time.

Next steps

Now that you've created an endpoint in Squid, here are some things to try:

  • Add more endpoints in Squid and connect them to other Stripe events.
  • Connect Squid endpoints to other products that use webhooks.
  • Check out the docs to learn about the other types of functionality available in the Squid Backend SDK.