Introducing Stripe Workflows: Customizing Stripe for your needs
Developer craft
Runtime
Complete form to watch full video

Stripe Workflows is a new way to integrate and extend Stripe with zero complex code. See how to build conditional logic that connects Stripe products, so you can automate fraud checks, invoice approvals, compliance, and more.
Speakers
Tanya Boiteau, Product Manager, Stripe
Ben Smith, Staff Developer Advocate, Stripe
BEN SMITH: Hello everyone, good afternoon. My name’s Ben. I’m a developer advocate here at Stripe, and I’m joined by my colleague, Tanya.
TANYA BOITEAU: And I’m a product manager here at Stripe, and this is not the first time Ben and I have been on stage together. In fact, a little fact about us, we actually worked together for close to five years at AWS on serverless. So we worked a lot with step functions and Lambda, and during our time there, we met with a lot of different customers from all sorts of industries, and the same thing kept coming up: that integrations are challenging. It’s complex, and we’re hoping today we can simplify that a little bit more for you.
BEN SMITH: That’s a little bit about who we are and our background, but what’s more interesting to us really is who you are and why you’ve chosen this particular talk. I had an opportunity at the beginning of the session to ask some people why they’re here in this particular talk today, because I know your time’s very valuable at Sessions. And generally speaking, people are here because they’re developers and they’re building integrations and customizations with Stripe already, and they want to understand how they can simplify those integrations with Workflows.
Some people have heard about Stripe Workflows in the keynote, and they’ve just caught their eye and they’re interested to learn more. And some of you are just new to Stripe. You’re developers, and you’re just interested in how you can get more out of Stripe, how you can link products together, and these are all very good reasons to be in this particular talk today. Over the next 30 minutes or so, we’re going to explore how Stripe has evolved from a payments provider into a platform that allows you to run your entire financial infrastructure.
We’ll highlight the types of complexity that come with this type of evolution, and we’ll introduce this new product that Tanya and team have built that’s helped to simplify this problem of complexity. You’ll see a live demonstration in action. And what we’re going to do is, we’re going to build a very simple use case in code, and then Tanya is going to recreate that use case using Stripe Workflows, and we’ll continue to build on that as we go through the talk. And what we hope to show you is how Workflows has implemented some really fundamental concepts under the hood, so that you as a developer, as a builder, don’t have to think about that undifferentiated heavy lifting and you can focus on building your business logic on customizing Stripe to suit your business needs.
And then finally, we want to take you away with a set of best practices and example use cases to kind of spark your imagination that you can take away back to your desks when you leave Sessions. So it all started so simply for Stripe back in 2010. Famously, it was said that with just seven lines of code, you could add Payments to your online applications. And over time, and in response to what our customers were asking for, our product suite grew and grew.
Now, today, you can run your entire financial infrastructure on Stripe, from Payments and Billing to Tax and Identity and finance and many, many more things—just a few listed here. And while that unlocks a huge amount of power and flexibility, it comes with a lot of added complexity. And so that is what Stripe Workflows is looking to solve. You see, when your integration spans Stripe products like Payments and Billing and Tax and Identity, how do you then build and track and visualize and inspect how your integrations are held together?
How do you maintain, reason about, debug, log, catch errors when your integration is spread across multiple Stripe products, maybe hundreds of different API calls and events? That’s the challenge that many teams are facing when they scale up on Stripe, and that’s the problem that Tanya and team have been trying to solve with this new product that is now in public preview today.
It’s called Stripe Workflows. Now, Stripe Workflows allows you to chain together a series of actions, Stripe API actions, and they can run in response to events. It scales automatically, so it’s a fully managed service. There’s nothing to provision, nothing to patch, there’s no code to write, and it allows you to call over 600 of the Stripe actions. And you can use Workflows when you need a series of actions to happen in a particular order reliably, and you can do this to create a number of different customizations.
You see, customers have told us that they want simpler, no-code ways to customize and extend Stripe. They want to build applications in Stripe that allow them to do things like reduce chargeback risk, automate billing runs, route invoices for internal reviews, flagging risky transactions. And we’ll show you some examples of how you can do and build these applications in Workflows in just a moment. You see, a payment isn’t just done.
It moves through multiple states—things like initiated, authorized, captured, refunded, disputed, won and lost. And each one of these states dictates what can happen next. You see, a payment can only be refunded if it was first captured. Now, in Stripe, we use objects to represent the state of a payment or a customer or a product or a dispute. In fact, everything in Stripe is an object. You use the Stripe APIs to create, delete, and update these objects, and when you do this, this produces a new kind of object called an event.
These events contain information about a thing that happened in your Stripe account at a given point in time. And reacting to these events is how we extend and build Stripe integrations. And until today, the only way you could react to these events was with webhooks and event destinations using Amazon EventBridge. From today, though, you can react natively using Stripe Workflows. We’re going to build a little example now in code, and this is going to be a very simple application that just sends an email to an administrator every time a successful transaction happens inside my Stripe Dashboard. And for those of you in the room who are not developers, we’re going to go into the weeds a little bit—but don’t worry.
You don’t have to understand the code here. I’m going to walk you through some of the overhead, some of the mental lifting that developers have to do before they even write any code, and all the different components involved even in writing something so simple as an application that just emails someone. So here’s our first two lines of code, and I’m going to write this in Node.js. And first of all, we have our very first line, which is to bring in the Stripe SDK, because I’m going to communicate with Stripe in this script.
Now, straight away, there’s some things to think about here. I’ve got my Stripe secret key. Now, this contains the entire keys to my Stripe kingdom, right? This is falling into the wrong hands, or accessed by some other script, or accidentally committed to a GitHub repository, all sorts of bad things could happen. You could charge customers. You could refund customers. You can move money. This is a really important API key that I have to make sure I maintain and use at the correct point. I’ve seen customers, for example, hard coding this key in, accidentally leaving it in GitHub repositories, adding it to environment variables, which is one way of doing it, but I wouldn’t recommend that in production.
So, in the end, you end up using some kind of managed service. All the different cloud providers have different ways to manage and rotate keys. But the point is you have to think about how to do this and when to load this key in. Next line here is a library for Node called Nodemailer, which simply sends an email. And I don’t know what this library is. I’m not very familiar with it. It was one of the first things that came up when I did an internet search. But this is what your developers are likely doing, right? I don’t know if there’s any vulnerabilities in this package, if it’s the latest runtime, if it’s patched, if it’s something that I should be really using or not. And so I have to maintain this going forward.
OK. Next line of code. I’m just going to use that Nodemailer function to set it up to send an email. And this is a very common async function that will run synchronously and return a response to send an email using my Gmail account. But again, there’s some issues here. So the email is hard-coded. That could be accidentally committed to a GitHub repo. That person could leave my business or organization. The password is also hard-coded. These are things your developers are accidentally doing in order to move quickly, right?
Unless they’re thinking about it, which I’m sure they are, but then that requires mental overhead. It requires them to really take time on how they’re building these scripts. And this is not differentiating their build from other people. This is not your business logic, right? This is something you don’t really want to be having to think about as a developer. OK. So now we’re into the Stripe part of this script. I’m choosing which Stripe event that I’m going to have my script react in response to. And this is the payment_intent.succeeded. So this is every time there’s a successful payment that happens in my Stripe account, I’m going to send that email.
Now, there’s a few things here that we have to have done behind the scenes. We have to log in to our Stripe Dashboard, configure our Stripe Dashboard to fire on this particular event. We have to make sure we’ve got the correct event. And so we’re taking some things for granted here that it’s the correct event, the correct payload. And the next bit is where it gets really interesting. So now we have to set up a server. This code has to run somewhere, right? We have to have a framework to run this code. So I’m going to use Express. I’m going to enable some JSON parsing. And then finally, I’m going to stand up a webhook endpoint, a public address on the internet, to tell Stripe to send that event object towards.
Now, I have to secure this endpoint by using the Stripe header and this other signature called a webhook signature to make sure that every time there’s a request sent to this endpoint, it’s coming from my Stripe account. And again, I have to make sure that this secret is secured safely, just like my Stripe secret key. I have to make sure that this endpoint is always available. So this code has to exist somewhere. I need to put it on a server. I need to make sure it’s load balanced, it’s performant, it’s available. Maybe I put it on a serverless Lambda function. I need to put that behind API Gateway, and on and on the decisions go.
What I also have here is some error handling. So I’m catching errors, and I’m returning a 400 error. That’s not super useful. I’m not really logging that. I’m not really retrying that error. That’s a whole other thing that I have to think about, how to handle logging and observability, and capture those errors and replay. OK. Tanya now is going to recreate this application using Stripe Workflows.
TANYA BOITEAU: Great. So I’m in the visual builder for Workflows. I’m in a sandbox as well. It’s a safe environment. And we said we’re going to react to payment_intent.succeeded. So again, I have access to over 600 events within Stripe, but I’m going to just look for the payment_intent.succeeded event. There it is. I’ll click it. Perfect. And then all I want to do is send an email. Again, add an action. Top “suggested action” there is email action. We’ll choose myself to send this, and we’ll include a little message. How about a “Woohoo, we got an order.”
Great. I’m going to save those changes, and in, let’s call it 10 seconds or so, I have just created exactly what Ben has just shown us in 30 to 35 lines of code. What we have not yet seen and we’ll get into later in this talk, is all about the other things that we’ve done on your behalf, including observability. So you’ll see those as we continue to progress.
BEN SMITH: I’ve barely had time to have a sip of water, and Tanya’s rebuilt the same application using Workflows with all the other undifferentiated stuff built in. This will run. This is ready to go. There’s no server to spin up, right? This is already available to run. OK, I’m going to come back to my slides. So, I’m going to put these two examples side by side. I have the code version, about 35 lines of code, and I have my workflow version.
The next—imagine that you’re a developer, right? And you’re context switching, you’re building lots of things all the time, different types of applications. Which one of these two examples is going to be easier for you to come back to and continue building from in a day, a week, or a month’s time? Which one is going to be easier for you to explain to your business stakeholders? And remember, this isn’t just a nice diagram in a PowerPoint presentation. This is a screenshot of what Tanya just built. It’s exactly how it looks inside the service itself.
So once this is saved and active, it’s going to start receiving events, and it’s going to start running in response to those events. The next thing I’m going to want to do as a developer is to be able to observe when it successfully executes. I want to see when it’s running. I want to see the data passing through those individual steps. And at some point, one of these steps will fail. Failure is inevitable. We have to build for failure.
It could be a number of different things. It could be a network blip. It could be a syntax error. It could be a wrong input. It could be a service limit that’s been reached. We have to build for failure, right? Now, with Workflows, your workflow step will automatically retry with exponential backoff when a step fails. It’s built into the service. It’s not something you have to think about.
TANYA BOITEAU: Now, like Ben said, things always go wrong, things break. So when we were building Workflows, this was top of mind for us. And what we did was, we wanted to ensure that there was observability across the entire workflow and workflow runs. So to demo this live, let’s take a look at an existing and active workflow that I’ve had running. And it’s to add custom data to high value customers. So on this screen, what you’ll see is that you’ve got a list of its most recent runs. There’s a total of 14. I can see the day in which that run took place, the time. I can also see the status. So whether that particular run was successful or it failed—you can see I’ve got a failed run here.
I can also dive in. I can see the failure reason at a glance. So there’s no such Customer 1, 2, 3. Let’s dig in a little bit more. Just click on a particular run you’re interested in looking in, and now we’ll see the entire execution flow. So this is actually what happened through your whole workflow. So I can see all the steps that were completed, all the way to the one that failed. And what I really love about this service is that when I start to look at any particular step, I can get a lot more information.
So I can see the trigger data—so the payload of that payment intent that succeeded. What did that look like? I can click on any of these other steps that is actually an action. So for example, retrieve customer, and I can see the input and the output of that particular step from one pane of glass. I can go down to this “Update a customer” that had the error. I can find out more information. OK. So I know what I’m going to need to probably fix, but if I needed more information or I’m not familiar with this particular error, I can also choose to hop into Workbench.
And if you’re not familiar, Workbench is Stripe’s developer tool available in the Dashboard. So let’s pop in. Great. I can see more information around the error. So you get information like events, request logs, API calls. For this one, if I needed information about the docs, I can see exactly a resource is missing, and I could go learn about what that particular error is. Now, I’m familiar with this. I know that there’s no customer ID. Here it’s Customer 123, so I likely made a mistake when I was authoring or editing this workflow.
So I’m going to click over to the editor. I’m going to go to that particular step, and of course there I see customer ID is a required field, but I have put in 123. I’m going to delete that, and I’m going to choose to reference the actual customer that’s associated with that successful payment. So we’re just going to click “Customer ID.” I don’t need to know it because it’ll dynamically update based on whatever has kicked off the workflow. I’m going to apply those changes, and I’m going to go back—this is a really neat one.
I’m going to go back to that failed run, and I’m going to say, “Retry run.” And what you’ll see is the workflow will actually run again using that same event payload that was used in that failed run. I can choose to do a refresh—or let me just hop back over here. It’ll refresh. And you can see that that rerun that I just did is now successful. You can check your clocks or your phone to see the time. Today’s May 7th. It’s 2:46 that I’ve now got a successful run just like that.
BEN SMITH: Replaying workflow from the point of failure with steps that are spread across multiple APIs. Things are really difficult and awkward to do when you’re building an application in code. Having it all together in one place is so much more useful. We want to make sure that Stripe Workflows is always the best orchestration tool for you to use when you’re customizing and building with Stripe. And to that end, Tanya and team have gone to some length to get some really important fundamentals in place, both for building and fundamentals that run under the hood, so to speak.
I’m going to quickly go through what some of these things are. So the first is event filtering. Another concept is dynamic fields. And then we’ll talk a little bit about conditional branching. So one of the most common challenges that developers tell me they face when they’re integrating using events coming from their Stripe Dashboard is that they can only really run their scripts in response to a certain event type. So we were using “Payment intent succeeded.”
That’s the type of event we’re running in response to. But people want more granular options over when their customization runs. For example, if you wanted to run your script in response to a “Payment intent succeeded,” but only for charges over a certain amount, well if you’re using webhooks or events, then you would have to first run your script and query that payload before you can decide what to do.
Maybe you just discard it, or maybe you continue down your script. Now, with Workflows, it’s different. We have much more granular event filtering, allowing you to actually check the body of the event payload, the event object, before your workflow runs.
TANYA BOITEAU: So I’ll showcase this relatively quickly, because it is that simple. I’ve clicked on “Payment intent succeeded.” I can simply add a trigger condition. The field that I’m looking for can be any of those things that are included as part of that event payload. In the case that Ben has just been talking about, he wants to filter on the amount of the payment. So let’s say if it’s greater than—and you can see there’s a ton of operators that you can use—$200, this workflow will run, save those changes, and it’s ready to go.
BEN SMITH: The next concept I want to briefly touch on is dynamic values. So Tanya just actually showed you an example of dynamic values. So with dynamic values, it enables you to take some of those fields, some of those values within your objects, and use them further down the workflow. So you can pass these objects down your workflow for use in subsequent steps.
Remember, everything in Stripe is an object. Your event object that triggers your workflow might not have all the data you need in the rest of your workflow, right? So you might need to retrieve objects in addition. You can pass those objects along your workflow and use them for other steps.
TANYA BOITEAU: I’ll walk through the dynamic value piece. So for example, on our “email a team member,” maybe we want to include a bit of information, perhaps the amount of that payment that succeeded. We know it’s over $200, but, like, is it $1,000? Is it $250? Is it $201? So how about we include amount as the key, and the value we’ll actually just reference is amount.
So that’ll dynamically update, and it’ll be included in that email that we send off. But maybe we want to make it a bit more complex. We want to add some more information. How about we include some things about the customer that actually submitted this particular payment? So I’m going to add an API action called “retrieve customer” to get more information about that particular user.
And now I’m going to use dynamic reference, so I’m going to pull in the ID that’s associated with that successful payment. And I can go back to my email, and now I can add information about that customer object. So for example, let’s include the name of that particular customer. We’ll choose fields from the “retrieve a customer.” In this case, we want “Name.” I’ll just search for it. Great. I’ll save the changes. And now that email will dynamically use the data that was available from previous steps.
BEN SMITH: So another way you can use dynamic fields is to make branches. So this means you can create conditions and have different paths taken in your workflow depending on those conditions. And what you do is you grab that object because everything in Stripe is a—
TANYA BOITEAU: Object.
BEN SMITH: Thanks, Tanya. You grab that object, you query the field in that object, and you have it take different paths based on the results of that query.
TANYA BOITEAU: All right. So again, I’ll show you this in action. Let’s say the steps that we had, we want to occur in order. We want these to run every single time, and then we want to make some conditional decision around what should happen next based on a particular condition. So I’m going to add a condition, I’m going to put a field here, and for this example, how about we say, if there’s a payment that intent succeeds, and we are already only triggering this if it’s over $200, but it includes a tip. And so we’re going to choose tip amount, and again, I can use any of these operators. I don’t really care what the tip amount is. I just want to know if you tipped or you didn’t. So I’m just going to say, “is not empty,” meaning this is a tipper.
And then as a result of that, who doesn’t love a great tipper? We’re going to then choose to update a customer. Which customer? Again, using our dynamic reference, we’re going to refer to the customer ID associated with that successful payment. And I’m going to add some custom data, some data that makes sense for my business, but it can be whatever you want for your business. So, you know, tippers are considered a VIP in my world, so I’m going to add a tier, call them “VIP.”
I’m going to save those changes, and now anytime this workflow runs, any customer that was also a tipper and had a payment greater than $200, they’ll be updated as a VIP. So anyone else in my team or my organization that now looks at that customer will see that they’re considered a VIP with that metadata.
BEN SMITH: So that’s some ways the team has gone to some length to make sure there’s some fundamental building blocks when you’re creating your workflows. But I mentioned there’s some fundamentals under the cover as well, and I want to reveal what they are to you, because they’re really important concepts. So the first is that of idempotency, and this is a concept in mathematics or computer science, which is, I guess, simple to understand, but not so simple always to implement. And the idea is that if a function is idempotent, it means whenever it’s run with the same inputs, it will always return the same result. And this is especially important in payments, because if you’re running functions that are not idempotent, you could accidentally charge someone more than once or refund someone more than once, right?
So this is an example written in code of idempotency done wrong, or in fact, not done at all. So here I have a Stripe command that creates a new payment intent. That is a request that gets sent on to Stripe and the fee is charged. A payment intent response is returned to my script, but there’s an error here. Let’s say there’s a network blip and I don’t receive that response in my code. Not to worry. My code catches that, and it retries the same function to create that payment intent.
Stripe receives that, but it doesn’t know that it’s already done this with the same inputs, right, for the same customer. So it does it again and charges your customer twice. Whoops. Really bad. We don’t want to accidentally be charging people or refunding people twice—well, maybe refunding people wouldn’t be too bad for the customer. If we’re doing idempotency right, well, of course, Stripe has a way for you to manage this, right? And that’s by adding something called an idempotency key to the header of the request.
You generate this unique key, you send it along with the request. Stripe will say, “Oh, OK, there’s an idempotency key, that means this is something I need to check if I’ve done before.” There should be a key value stored with the idempotency key and the result. If it’s not there, then it knows that it’s a new request, and it will return the response. But in my little example here, there’s an error with that. I retry. I catch and retry that request with the same idempotency key. So this time, Stripe knows, “OK, there’s an idempotency key. Let’s check if there’s already a response for that.” There is this time, and it simply returns that response, and I haven’t charged someone twice.
Great. So what’s the problem? What’s the challenge? Why are we mentioning this? Well, the challenge is that it’s on you and your development teams to manage when you create your idempotency key and when you apply it, right? There’s some best practices around this, but I often see it done wrong or not done at all, or maybe in the retry it’s missing. This extra overhead that doesn’t differentiate your business logic. It shouldn’t necessarily be something you do if you don’t have to.
And with Stripe Workflows, you don’t have to, right. So every single workflow run and every single step has its own idempotency key automatically applied. You don’t have to think about this. So that means in this example here, the action is fired. There’s no result, so it makes the charge. It stores the result along with the idempotency key. There’s a failure. Stripe Workflows kicks in its automatic retry with that exponential backoff. It retries with the same idempotency key, and we haven’t charged our customer twice by accident.
Wonderful. The next concept is something that Tanya and I came up against a lot when we were working at AWS in the serverless product space, and this was the concept of direct recursion. So at AWS, what we saw most of all, this was the biggest problem that customers would complain about, is that they would write a Lambda function that would accidentally call itself and create these infinitely recursive loops that span up huge bills because Lambda is a pay-per-use service, and maybe they didn’t realize that.
And within seconds, because it scales up so quickly, they’re contacting customer support or us to help them cancel out this bill. So with Stripe, Tanya and team took that learning and thought about how they can prevent that, because what that could do with you in Stripe is you could accidentally exhaust your API limits without really understanding how that happened, right? So, there’s two types of recursion the team have put guardrails against. The first is the idea of direct recursion, where you have a workflow that emits an event that triggers itself infinitely.
The second is indirect recursion, where you can have a workflow that emits an event that triggers another workflow, and so on and so forth. The team wanted to avoid this, and they’ve done this by creating something called an X-Request-Source header that is applied to any event generated from a workflow and persists to subsequent events. What that means, you don’t have to apply this yourself, it just happens, but what that means is, every workflow knows where it is in its ancestry and if it should run or not. So the result is that you can only chain a sequence of workflows to a maximum depth of five, and you can only have a workflow call itself a maximum time of one.
So we’ve stopped infinite loops. We allow self-triggering workflows to run once, because we think there’s some use cases where you might want that. And essentially, the takeaway here is we’re protecting you from API exhaustion. OK. We want to give you some fundamental building blocks, some kind of LEGO bricks to take away when you get back to your desk. It’s an interesting and very seemingly easy way to start building, right?
The most difficult problem is maybe not having a problem or not knowing what you want to build first. So here’s some information to kind of spark those ideas. I expect every single workflow that you build will have one or many of these steps. There will be steps to email users directly from your Stripe account. Steps to retrieve an object, because everything in Stripe is a—
TANYA BOITEAU: Object!
BEN SMITH: I knew that was risky. Everything in Stripe is an object. You’ll want to have steps that retrieve objects to get more data that you can pass down the workflow, right?
That’s our third pattern here, is passing objects down our workflow for subsequent steps. The next is also really powerful. Tanya gave an example of this earlier. It’s automating the metadata in your objects. So these objects allow you to store and retrieve key value pairs, essentially customizing it to actually match your business logic.
We expect you’ll build workflows with conditional branching, with dynamic fields. We expect your nest branches within branches to have really smart paths for individual workloads. I even expect some advanced users to start creating multiple workflows that emit events that trigger other workflows, kind of having a microservice, if you like, of decoupled workflows that are running.
TANYA BOITEAU: Now, one of the examples, if you’re able to catch the developer keynote, I did a demo of this, is around early fraud warnings. So this allows you to act before you actually incur a dispute fee or a chargeback and take some proactive action. So either by refunding the customer for a small charge, or maybe it’s a larger charge, and you actually want to send it to someone on your team to do a bit more digging and determine whether that is actually fraudulent or not. And this entire workflow is really built up of the patterns that Ben just shared.
So object retrieval, we’re actually going to go get the payment intent to get a bit more information about that. We’re then going to use conditional branching. So is that payment intent, is it a large amount or a small amount? If it’s a small amount, then we’re going to take some action, like refunding the customer. But wait, what customer are we refunding? Oh, data passing. I have to refer to that customer ID that was included as part of that payment intent of the charge. So those are sort of three patterns in this example.
BEN SMITH: Another example is to build workflows to automate compliancy. So there’s certain industries like luxury goods or gaming or crypto that face more strict compliance requirements. Businesses might need to flag larger transactions from newer customers. There’s also higher risk regions that need to do this. So here’s a workflow that triggers on a successful payment intent, retrieves the customer object, does some conditional branching to use the metadata to check if it’s a new customer, and the actual amount of that transaction. And then adds or edits some metadata to that custom object, and then sends this on for review to an administrator. You might just build workflows to chain together a sequence of steps, simple workflows to reliably execute API calls in a reliable way with observability every time.
So this example is where I’m running some custom business logic in my own application that generates prices based on multiple variables. Once a customer has accepted their quotation, that will be a request that dumps a bunch of information into a product, into the metadata, and then my workflow runs, retrieves that product metadata, and goes around creating a customer, creating a price, creating a subscription, and so on. And those same patterns you can see here, object retrieval, metadata automation, and data passing.
TANYA BOITEAU: So, you can see we covered a lot of ground today. I’ll say this. We’re just getting started. So we have a super robust roadmap. You can take a look for yourself. I won’t cover it all. I’ll maybe just name the one that I’m most excited about that’s going to come out relatively soon, and that’s third-party actions. We’ve heard—you know, it’s my favorite because we’ve heard from many of you here today and then working with us prior to this, that you want to be able to call other apps and app partners. So we’ll be enabling that soon enough.
BEN SMITH: OK. So today, we announced the public preview of Stripe Workflows, allowing you to automate and orchestrate over 600 API actions in your Stripe account. It scales automatically in response to events, and we think this will open up near infinite amount of customizations for you to run within Stripe. Here’s a QR code for you to learn more information. It’s the release blog, which, of course, links off to all the documentation. Thank you very much, and we hope you enjoy the rest of the time here at Sessions.
TANYA BOITEAU: Thank you.