Skip to main content

Stripe and Squid Webhooks

Use Squid'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 database.

What you'll need

Environment setup

  1. Install the Squid CLI using the following command:
npm install -g @squidcloud/cli
  1. Download the notes-app code sample:
squid init-sample stripe-webhooks --template stripe-webhooks
  1. Open the project in the IDE of your choice.

Notice that there are two folders in the starter project: frontend and 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 real-time.

Set up the Squid backend

There are two subfolders that make up the stripe-webhooks project: frontend and backend. The backend folder contains the Squid backend for the app.

  1. Navigate to the Squid Console and create a new application named stripe-webhooks.
  1. In the Squid Console, navigate to the application overview page and scroll to the Backend project section. Click Create .env file and copy the command.

Copy Env Command

  1. In the terminal, change to the backend directory:
cd backend
  1. Create the .env file using the command you copied from the console. The command has the following format:
squid init-env --appId YOUR_APP_ID --apiKey YOUR_API_KEY --environmentId dev --squidDeveloperId YOUR_SQUID_DEVELOPER_KEY --region us-east-1.aws
  1. Install the required dependencies:
npm install

The backend is now set up and ready to use with a frontend!

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 backend/src/service/ and open the stripe-webhook-service.ts file.
  2. In the StripeWebhookService class, add the following function:
backend/src/service/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:
backend/src/service/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 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 real-time 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 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 to the frontend

The following steps add configuration parameters to connect the application to Squid.

  1. Open a new terminal window and navigate to the project's frontend. You should now have two open terminal windows: one for the app's backend and one for the frontend.
cd frontend
  1. Install the required dependencies:
npm install
  1. Run the following command to create a .env.local file with the Squid environment configuration needed to initialize Squid:
npm run setup-env
  1. Navigate to frontend/src/main.tsx. Notice there is an Auth0Provider component which requires configuration:
frontend/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: import.meta.env.VITE_SQUID_APP_ID,
region: import.meta.env.VITE_SQUID_REGION,
environmentId: import.meta.env.VITE_SQUID_ENVIRONMENT_ID,
squidDeveloperId: import.meta.env.VITE_SQUID_DEVELOPER_ID,
}}
>
<App />
</SquidContextProvider>
</Auth0Provider>
);
  1. Replace the placeholders in the Auth0Provider component with the domain and client ID from your Auth0 application.

  2. Open the 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.

frontend/src/App.tsx
...
function App() {
const stripeUserId = '[YOUR_STRIPE_CUSTOMER_ID]'
...
  1. In the 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.