In modern software development, your application is often the central hub in a constellation of specialized services. You rely on Stripe for payments, Slack for notifications, HubSpot for CRM, and a dozen other third-party APIs to deliver a complete user experience. While this ecosystem provides immense power, it also introduces a significant challenge: integration complexity.
Connecting these disparate services can lead to a web of brittle, hard-to-maintain boilerplate code. Each integration comes with its own authentication method, data format, and error-handling quirks. This is where a paradigm shift is needed—from writing one-off scripts to building a robust system of Actions as Code.
At Actions.do, we believe the fundamental building block for all workflow automation is the Action: a reusable, self-contained, and executable unit of logic. This post dives deep into powerful patterns for using Actions to connect with third-party APIs, transforming integration chaos into a scalable and maintainable process.
Before we explore the patterns, let's revisit what an Action is. As our FAQ states, an Action is the smallest, indivisible unit of work in a workflow. Think of it as a supercharged, reusable serverless function designed specifically for task execution.
This model is uniquely suited for wrapping API calls because it provides:
The most fundamental and common pattern is the Wrapper. The concept is simple: create a dedicated Action for each specific third-party API endpoint you need to interact with.
This pattern isolates the logic for a single task, making it the bedrock of your integration library.
Example: A "Wrapper" Action to create a customer in a CRM.
import { Action } from 'actions.do';
import { crmClient } from './lib/crm-client'; // Your internal SDK for the CRM
// Define a reusable action to create a new contact
const createCrmContact = new Action({
id: 'create-crm-contact',
handler: async (payload: { email: string; name: string; plan: string; }) => {
const { email, name, plan } = payload;
console.log(`Creating contact for ${email} in CRM.`);
// The Action encapsulates the actual API call logic
const contact = await crmClient.contacts.create({
email,
properties: {
fullname: name,
subscription_plan: plan
}
});
return { success: true, crmId: contact.id };
}
});
// This Action can now be used anywhere you need to create a CRM contact.
Wrapper Actions are your core building blocks. Create them for every discrete interaction: send-invoice, fetch-user-profile, create-support-ticket.
While Wrapper Actions are great for single tasks, real business processes are more complex. A "new user onboarding" flow might involve creating a user in three different systems and then sending a welcome email.
This is where the Orchestrator pattern comes in. An Orchestrator Action doesn't call an external API itself. Instead, its job is to execute a sequence of other Actions.
Example: An "Orchestrator" for New User Onboarding.
import { Action, execute } from 'actions.do';
// This Action orchestrates other Actions to perform a business process
const onboardNewUser = new Action({
id: 'onboard-new-user',
handler: async (payload: { userId: string; email: string; name: string; }) => {
const { userId, email, name } = payload;
console.log(`Starting onboarding for user ${userId}.`);
// 1. Execute the Action to create a CRM contact
const crmResult = await execute('create-crm-contact', { email, name, plan: 'free' });
if (!crmResult.success) throw new Error('Failed to create CRM contact.');
// 2. Execute the Action to send a welcome email
const emailResult = await execute('send-welcome-email', { email, name });
if (!emailResult.success) throw new Error('Failed to send welcome email.');
// 3. Execute the Action to notify the team on Slack
await execute('notify-slack-channel', {
channel: 'new-signups',
message: `🎉 New user signed up: ${name} (${email})`
});
return { success: true, completedAt: new Date().toISOString() };
}
});
This pattern brilliantly separates your business logic (the orchestration) from your integration logic (the wrappers). If you decide to switch email providers, you only update the send-welcome-email Action; the onboard-new-user workflow remains untouched.
A common headache in API actions is that the data format from one service rarely matches the format required by another. An API webhook payload might be a complex, nested object, but your Slack notification Action needs a simple string.
The Adapter pattern solves this by dedicating an Action to the sole purpose of data transformation.
Example: An "Adapter" to format a GitHub webhook for Slack.
import { Action } from 'actions.do';
// This Action's only job is to transform data from one shape to another.
const formatGithubPushForSlack = new Action({
id: 'format-github-push-for-slack',
handler: async (payload: any) => { // Takes the raw GitHub webhook payload
const repo = payload.repository.full_name;
const pusher = payload.pusher.name;
const commitCount = payload.commits.length;
const compareUrl = payload.compare;
// Transform the complex object into a simple, human-readable string
const message = `${pusher} just pushed ${commitCount} commit(s) to ${repo}. See changes: ${compareUrl}`;
return { formattedMessage: message };
}
});
Now, you can build a clean workflow:
This decouples your systems beautifully. If GitHub changes its webhook structure, you only need to update one small, focused Adapter Action.
Connecting to third-party APIs means dealing with network failures and transient errors. Actions.do is built for this reality. Each Action can be configured with its own:
By wrapping your API calls in Actions, you get this industrial-strength resilience out of the box.
By adopting these patterns—Wrapper, Orchestrator, and Adapter—you can move beyond fragile, custom-coded integrations. You begin to build a library of reusable, robust, and scalable API Actions that represent your core business processes.
This is the power of Actions.do. It provides the core building blocks to create a true system of workflow automation, allowing you to connect any service and execute any task with confidence and clarity.
Ready to tame your API integration complexity? Explore Actions.do and start building your first reusable Action today.