In modern software development, our applications are rarely monolithic. We rely on a constellation of best-in-class services: Stripe for payments, Twilio for communication, a CRM for customer data, and Slack for internal collaboration. The challenge isn't using these services; it's connecting them. This connecting fabric, often called "glue code," can quickly become a tangled, brittle mess of webhooks, serverless functions, and cron jobs that are difficult to manage, monitor, and scale.
What if you could transform that fragile glue code into a robust, observable, and reusable set of building blocks?
Enter Actions.do. We believe in Actions as Code, Results as Software. By encapsulating every business task—from sending a notification to processing a payment—into a simple API call, you can build powerful, agentic workflows that are as solid as your core application logic.
In this guide, we'll walk through a classic business automation task: posting a real-time notification to a Slack channel for every new high-value subscription processed by Stripe. We'll show you how to leave messy scripts behind and build a resilient workflow with Actions.do.
Let's first look at the traditional approach. You'd likely set up a webhook in your Stripe account that points to a serverless function (e.g., AWS Lambda, Google Cloud Function).
This function would:
While this works, it introduces several points of failure and maintenance headaches:
This approach creates a system that is brittle and hard to maintain. There's a better way.
At Actions.do, we treat every discrete business task as an Action: a versioned, secure, and independently executable API. An Action is the fundamental building block for modern task automation.
For our Stripe-to-Slack workflow, we won't build one monolithic function. Instead, we'll create two distinct and reusable Actions:
This separation is key. The send-slack-message Action can now be called by any part of your system—not just the Stripe webhook handler. This is the power of turning business logic into composable API Actions.
Let's build this workflow using the Actions.do TypeScript SDK.
First, we'll define a generic Action for sending Slack messages. This Action's sole responsibility is to communicate with the Slack API. It knows nothing about Stripe.
// actions/send-slack-message.ts
import { IncomingWebhook } from '@slack/webhook';
// Assume SLACK_WEBHOOK_URL is stored as a secure secret in Actions.do
const webhook = new IncomingWebhook(process.env.SLACK_WEBHOOK_URL);
// The 'define' function from the .do SDK creates your Action
export default defineAction({
name: 'send-slack-message',
// Define the expected inputs for type-safety
input: {
channel: string,
text: string,
},
async handler({ payload }) {
await webhook.send({
channel: payload.channel,
text: payload.text,
});
return { success: true, message: `Message sent to ${payload.channel}` };
},
});
Once you deploy this Action using our SDK, it instantly becomes available as an API endpoint. Anyone on your team can now send a Slack message with a simple API call, without needing to know anything about the Slack API or where the webhook URL is stored.
Next, we create the Action that will act as our webhook endpoint. This Action will contain the business logic specific to processing Stripe events.
// actions/process-stripe-event.ts
import { dotdo } from '@do-sdk';
import Stripe from 'stripe';
// Initialize the Stripe and .do clients
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
const client = dotdo.init({ apiKey: process.env.DOTDO_API_KEY });
const stripeWebhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
export default defineAction({
name: 'process-stripe-event',
async handler({ request }) {
// 1. Verify the webhook signature for security
const event = stripe.webhooks.constructEvent(
request.body,
request.headers['stripe-signature'],
stripeWebhookSecret
);
// 2. Implement business logic
if (event.type === 'invoice.payment_succeeded') {
const invoice = event.data.object as Stripe.Invoice;
const amount = invoice.amount_paid / 100; // Amount is in cents
// Only trigger for high-value payments
if (amount >= 100) {
const message = `🎉 New high-value subscription! Customer: ${invoice.customer_email}, Amount: $${amount}.`;
// 3. Execute the 'send-slack-message' Action!
await client.actions.execute({
name: 'send-slack-message',
payload: {
channel: '#sales',
text: message,
},
});
}
}
return { received: true };
},
});
After deploying both Actions, the final step is to point your Stripe webhook to the secure endpoint URL provided by Actions.do for your process-stripe-event Action.
That's it. Your workflow is live.
What have we accomplished?
You haven't just connected two services. You've created a piece of Services-as-Software—a powerful, automated business process built from composable, code-driven Actions.
Ready to stop writing brittle glue code and start building powerful agentic workflows? Sign up for free at Actions.do and turn your business logic into powerful, reusable API Actions today.