Stripe is a great platform for running an online business, especially on account of the developer-centric API that makes it easy to collect payments, set up subscriptions and more.
Many of these APIs result in Stripe generating one or more events that you can subscribe to via a webhook. These events could represent a successful payment, or perhaps a new subscriber to your SaaS platform. In total, there are well over 100 different types of events that you can subscribe to, so how can we build a loosely-coupled cloud-native event-driven architecture to handle these events? How can we make this serverless?
It's easy, we'll use AWS EventBridge.
Why AWS EventBridge?
For those of you just learning about AWS EventBridge, it is a serverless event bus supporting event-driven architectures, released July 2019. An event bus is a central location where business events can be published and routing rules can be configured to send those events to downstream functions or services that operate on them. By using an event bus as an intermediate layer, this decouples services from needing direct knowledge of how to communicate with each other, which allows development teams to build and operate independently.
One reason, among many, why AWS EventBridge should be considered is the cost. With AWS EventBridge, you have a fully managed cloud-native event bus, requiring no effort to set up and no servers to pay for - and it costs a very reasonable $1 per million events. Latency is typically about half a second. By going with a fully managed solution, you're saving your team from spending time on 'undifferentiated heavy lifting' associated with infrastructure, giving them more time to focus on delivering customer value.
The solution
We'll show here how we can set up AWS EventBridge so that it can begin ingesting events from Stripe. As part of that ingestion, we'll check that the event is truly from Stripe by verifying the signature on the event. Let's get started.
Using an an open-source project we created called stripe-eventbridge, you can quickly set up the plumbing to connect Stripe events to AWS EventBridge via a Lambda function that will then validate the authenticity of incoming events (so that downstream functions won't have to). This allows for the events that are published on the event bridge to be routed to various downstream functions through simple routing rules which we show at the end of the post.
With this deployed, you can set up many downstream Lambda functions to handle the wide array of events generated by Stripe and configure the routing to these event handlers with AWS EventBridge based on the Stripe event type. All of this without having to worry about event signatures, since events are only placed on the EventBridge if they pass validation.
The stripe-eventbridge project creates an endpoint that you configure in the Stripe Dashboard as the destination for the webhook events. When an event arrives, the endpoint will invoke a Lambda that we provide which has these responsibilities:
to validate that the event has a valid signature (i.e. that it was generated by Stripe)
to place validated events (only) on the AWS EventBridge
to notify an SNS topic if an event fails to validate (e.g. due to an invalid signature)
Solution overview
stripe-eventbridge uses the Serverless Framework to generate the infrastructure in the AWS section of the diagram above. The Serverless Framework allows us to automatically create and deploy the CloudFormation stacks needed to realize the above configuration. The stacks can be deployed via sls deploy and rolled back via sls remove using the command line client.
Serverless components in stripe-eventbridge
Let's walk through what stripe-eventbridge creates:
A Lambda - this function validates incoming events, and if they are from Stripe (i.e. signed correctly) then they are relayed to the AWS EventBridge where downstream services can read from them.
An API Gateway endpoint - this is the webhook endpoint that the Lambda above is listening to for new events.
An AWS SecretManager secret - this secret is created with an empty value, and you populate this with the signing key assigned to your webhook endpoint in the Stripe Dashboard
An SNS topic - if the webhook fails validation or processing, then a notification is sent to a topic called stripe-webhook-event-failed-to-validate. You can configure subscriptions to this topic, so that you are emailed (for example) whenever an event fails processing.
If you'd like to get started, you can visit the GitHub project here:
https://github.com/rangle/stripe-eventbridge
Routing by event type
Now that you have events being published to the EventBridge, you can configure routing based on the event type using Rule patterns like this. The detail-type values are exactly the values of the underlying Stripe events - you can see a full list here: https://stripe.com/docs/api/events/types
{
"detail-type": [
"payment_intent.succeeded"
],
"source": [
"Stripe"
]
}
Alternately, if you are creating your event handlers using the Serverless Framework, then you can declare the same routing in your infrastructure code (this is really good practice) in your serverless.yml as follows:
handler: handler.myLambdaFunction
events:
- eventBridge:
pattern:
source:
- Stripe
detail-type:
- payment_intent.succeeded
And that's all!
I hope you have found this valuable. Stay tuned, we'll be exploring more with Serverless in upcoming posts.
Top comments (4)
EventBridge is a rebranding of CloudWatch Events with some new additional features added (creating additional event buses and approved third-party integration).
I think what this article highlights the best is the fact that you can publish events directly to the event bus is the AWS SDK. It's not obvious since most people using CloudWatch Events/EventBridge use the AWS Console limits the utility of this service offering. So here in this article you can see the event being published:
What this article is lacking is showing you the tail-end of integration. If you open up EventBridge these are all your possible targets.
So you may be asking, why use the AWS SDK to call the EventBridge API only for it to call SNS or Lambda when you can directly invoke these using the AWS SDK.
The reason is that it's forcing you to conventionalize you're inputs and outputs as a data object (events) for better usability. So maybe you only want to use Lambda for the target today but if you force your output to event then tomorrow you might want to use something else.
I think one very important thing the article highlighted was the added latency. In my research, I couldn't figure out yet what additional latency.
The article suggestions 500ms which in my opinion is very high, so maybe that's "worst case".
Another consideration does EventBridge force you into vendor lock-in or does it make it hard to migrate layer or go cross-cloud. I'm not building events bus's on daily basis but I would think migration might not be bad. I could see a way of moving containerized microservices onto NATS.
The only thing I'm not a fan of the codebase is it's written using serverless.yml instead of a CloudFormation template. It's nitpicking of me, but since this is such an AWS specific implementation and there so little in the template as is, it's nice when these projects choose more vanilla options.
Hi Andrew,
Lots of good considerations here! If you're looking for a CloudFormation version of this project, Adrienne Dreyfus at Stripe has recently ported this to use SAM (the Serverless Application Model extension of CloudFormation), so that we can have the best of both worlds:
github.com/adreyfus-stripe/stripe-...
Enjoy! :)
So here I did a bit of digging.
Looks like the is a limit of 50 per API call for SDK. You can increase it via Service Limits but being such a small number, looks the EventBus is low traffic for custom integration.
You can see using the Console with Event Rules and Schedule there are no such limits
Also, there is a throttling limit for invocations.
All very interesting. I'll have to give a thought on how the utility of this should work.
I'm working on an application where mongodb atlas and my aws are tied through VPC peering. As soon as I do that, Stripe is blocked because I'm not able to reach Stripe endpoints due to VPC - can you suggest what could be the best solution to this conundrum.