Handling payments is a critical part of any online business. Stripe has made accepting payments easier than ever, and their webhooks are essential for automating post-payment workflows like granting service access, sending invoices, or updating CRM records.
But as any developer who has worked with webhooks knows, building a truly reliable webhook handler is deceptively complex. What happens if your server is down? What if Stripe sends a duplicate event? What if one step in your multi-step process fails? These edge cases can lead to inconsistent data, frustrated customers, and late-night debugging sessions.
This is where .do comes in. By leveraging Atomic Actions as Code, you can transform fragile webhook scripts into robust, scalable, and fully auditable business workflows. Let's explore how.
On the surface, handling a Stripe webhook seems simple: create an API endpoint, receive the JSON payload, and execute some business logic. In reality, a production-ready handler must account for several challenges:
The .do platform reimagines workflow automation around the concept of an atomic action. An atomic action is the smallest, indivisible unit of work that is guaranteed to either succeed completely or fail gracefully without any side effects.
Instead of putting all your complex logic inside a fragile API endpoint, you define it as a .do Action. Your API endpoint then becomes incredibly simple: its only job is to receive the webhook and trigger the corresponding Action on the .do platform.
Let's see this in action. Imagine we want to handle Stripe's invoice.paid event. Our workflow should:
Here’s how you would define this as a reusable, atomic action with .do:
import { Action, client } from '@do-sdk/core';
import { db } from './database'; // Your database client
import { email } from './email-service'; // Your email client
// Define an atomic action to handle a successful payment
const processStripePayment = new Action({
name: 'process-stripe-payment',
handler: async (inputs: { stripeEvent: any }) => {
const customerId = inputs.stripeEvent.data.object.customer;
const invoicePdf = inputs.stripeEvent.data.object.invoice_pdf;
// 1. Find user and update subscription
const user = await db.users.findByStripeId(customerId);
if (!user) {
// The action fails cleanly if the user isn't found.
// .do platform handles the error logging and potential alerts.
throw new Error(`User with Stripe ID ${customerId} not found.`);
}
await db.users.update(user.id, { subscriptionStatus: 'active' });
// 2. Send confirmation email
await email.send({
to: user.email,
subject: 'Your payment was successful!',
body: `Hi ${user.name}, thank you for your payment.`,
attachments: [{ filename: 'invoice.pdf', url: invoicePdf }]
});
// The action returns a success result, which is logged and auditable.
return { success: true, userId: user.id };
}
});
With this Action defined, your webhook handler (e.g., in an Express.js app) is trivial:
// In your server code (e.g., Express.js)
app.post('/webhooks/stripe', async (req, res) => {
const stripeEvent = req.body;
// Immediately invoke the .do Action and let the platform handle the rest
if (stripeEvent.type === 'invoice.paid') {
client.action('process-stripe-payment').invoke({ stripeEvent });
}
// Respond to Stripe instantly
res.status(200).send();
});
By shifting the logic to a .do Action, you gain immediate, powerful benefits that are critical for financial operations.
Stop wrestling with fragile webhook handlers. Start building reliable, scalable, and auditable business process automation with .do.
Q: What is an 'atomic action' on the .do platform?
A: An atomic action is the smallest, indivisible unit of work in a workflow, like 'send an email' or 'update a CRM record'. It's designed to either succeed completely or fail without side effects, ensuring process integrity and reliability.
Q: How are .do Actions different from standard API endpoints?
A: While triggered via API, Actions on .do are stateful, auditable, and designed for agentic workflows. They include built-in error handling, retries, and logging, abstracting away boilerplate infrastructure code so you can focus purely on business logic.
Q: What happens if an Action fails during execution?
A: The .do platform provides configurable retry logic and error handling. Because actions are atomic, a failure prevents partial execution, ensuring your system remains in a consistent state. You can also define custom failure handlers and alerts.