Tutorials

Implement a Workflow Builder with 3rd-party Actions

Learn how to easily create a workflow builder using xyflow for UI and ActionKit to power 3rd-party actions

Why Workflows

More and more AI SaaS products have embraced workflow features, allowing their users to

  • Visualize and apply deterministic behavior to AI actions

  • Customize automations with language and defined workflow steps that perform actions in 3rd-party platforms

  • Enhance observability and human in the loop interaction to ensure AI actions are reliable and predictable

A few examples:

Copy.ai and Unify GTM are two examples of AI applications using workflow in action.

Copy.ai is an AI-focused workflow tool that automates GTM processes like research and creating marketing assets. Their workflows allow users to use AI to scrape web data as well as automate messaging for when new leads have been researched.

Unify GTM is an AI SDR platform that combines AI functionality (used for manual processes like prospecting) with low-code-like steps in a workflow builder that allow users to see the deterministic automation that occurs in their CRMs.

In both of these AI products, workflows allow their users to express their automations more specifically, with better results. What is also pervasive across these products is the presence of 3rd-party integrations that users can configure to work with their users’ CRMs, messaging, and other platforms.

Building workflow features in your own AI SaaS application doesn’t have to be daunting with large amounts of engineering effort. In this guide on building workflow features, we’ll show you how to implement a workflow builder in two easy steps:

  1. Start with xyflow to build clean workflow interfaces for your frontend

  2. Utilize ActionKit to power workflow integration actions on the backend

(You can find the source code for this sample workflow application in our GitHub repo as well)

xyflow - UI library for workflows

The libraries from xyflow are open source libraries for building workflow UIs that work with the React and Svelte framework (React Flow & Svelte Flow). Our team has worked with the React Flow library to build our very own workflow application with popular 3rd-party integrations like Slack, Salesforce, Gmail, and more. We’ll show you how to build a workflow feature just like this one using xyflow!

The building blocks of a workflow builder like the one above are nodes and edges. Nodes represent the steps or actions in a workflow, while the edges represent the order and direction of the workflow.

Building Nodes

Nodes in React Flow are an object type with id , position , and data (key value pairs with any relevant data that needs to be passed in). In our workflow application sample, we built ActionNodes that take in data needed for an integration action (like the message text for a Slack Send Message action).

export function ActionNode({ data }: { data: any }) {
	...
	return (
		<>
			<Handle type="target" position={Position.Top} />
			<div className='flex flex-col rounded-lg border-2 bg-stone-100 p-4 space-y-2'>
				<div className='flex space-x-2'>
					<img src={data.pic} style={{ maxWidth: "30px" }} />
					<button onClick={() => toggleSidebar(data.id)} className='font-bold text-stone-600'>
					{data.label}
					</button>
				</div>
			</div>
			<Handle type="source" position={Position.Bottom} id="a" />
		</>
	);
}

Like in any React-based UI, you can use tailwind or styled-components to customize the look of your nodes and edges according to your product’s theme.

Connecting Nodes with Edges

Edges connect nodes and visually represent the “flow” of steps and actions in your workflow.

The Edge data type needs an id , source , and target . The source and target strings correspond with the Node ids . You should now get a feel for how nodes and edges relate to one another and how simple it is to create workflow components.

The main workflow UI is rendered with the main <ReactFlow /> component that takes in the arrays of nodes and edges.

<ReactFlow className='min-h-[800px] h-full w-full basis-3/4'
	nodes={nodes} edges={edges} onConnect={onConnect}
	onNodesChange={onNodesChange} onEdgesChange={onEdgesChange}
	nodeTypes={nodeTypes}
	zoomOnScroll={false}>
	<Background />
	<Controls />
</ReactFlow>

Additional xyflow Features

Nodes and edges are the main components of a workflow UI, and xyflow further allows your engineering to add complexity to your workflow features as needed. For example, in React Flow, you can build “sub-flows” where you have a workflow within a node. Another less niche feature your team may want is state management for individual nodes using context or state management.

In our workflow builder example, we’re using zustand, a react state management library, to keep track of form inputs for each ActionNode . That way users can jump from node to node without their inputs changing.

import { create } from 'zustand';
import {
	type Edge,
	type Node,
	type OnNodesChange,
	type OnEdgesChange,
	type OnConnect,
} from '@xyflow/react';
import { addEdge, applyNodeChanges, applyEdgeChanges } from '@xyflow/react';

const useStore = create<AppState>((set, get) => ({
	nodes: [],
	edges: [],
	selectedNode: [],
	onNodesChange: (changes) => {
		set({
			nodes: applyNodeChanges(changes, get().nodes),
		});
	},
	onEdgesChange: (changes) => {
		set({
			edges: applyEdgeChanges(changes, get().edges),
		});
	},
	onConnect: (connection) => {
		set({
			edges: addEdge(connection, get().edges),
		});
	},
	...
}));

export default useStore;

Notice that many of the methods needed for our state change behavior are provided out-of-the-box by the React Flow library!

Programmatic Node Inputs

Because of React Flow’s rich customizability in creating nodes and state management, it’s here that we can use ActionKit - an API that gives developers access to 1000+ 3rd-party actions.

By using the ActionKit API, we get action names, descriptions, data types, and form inputs with no hard coding required. We can use the ActionKit API endpoints to dynamically generate nodes and their inputs.

{
	"name": "GOOGLE_DRIVE_LIST_FILES",
	"description": "Triggered when a user wants to list files in Google Drive",
	"parameters": {
	  "type": "object",
	  "properties": {
	    "includeFolders": {
	      "type": "boolean",
	      "description": "Include Folders"
	    },
	    "parentId": {
	      "type": "string",
	      "description": "Folder"
	    },
	    "pageSize": {
	      "type": "string",
	      "description": "Page Size"

ActionKit - powering workflow integration steps

The React and Svelte Flow library allow UI teams to generate rich, functional workflow UIs; however, how do we “run” workflows and execute these 3rd-party integration actions?

Generally, the workflow execution is handled server-side to perform data manipulation, index to database, and call 3rd-party APIs. In our example, the Run Workflow button triggers the workflow execution by sending nodes (with their form data held in state) and edges to our backend to actually “run” the workflow.

Here’s a basic implementation of a workflow execution method that uses a map to track edges.

{
	"node_1": ["node_2"],
	"node_2": ["node_3", "node_4"

We use the map to traverse our workflow using a breadth-first approach to execute all nodes in our workflow.

export async function POST(request: NextRequest) {
		const contents = await request.json();
		const nodes = contents.nodes;
		const edges = contents.edges;
		const edgeMap = new Map();
		const nodeMap = new Map();
		const resMap = new Map();
		const queue = [];

		for (const edge of edges) {
			if (edgeMap.has(edge.source)) {
				edgeMap.set(edge.source, [...edgeMap.get(edge.source), edge.target]);
			} else {
				edgeMap.set(edge.source, [edge.target]);
			}
		}
		for (const node of nodes) {
			nodeMap.set(node.id, node.data.funcProperties);
		}

		queue.push('0');
		while (queue.length > 0) {
			const nodeId = queue.shift();
			if (nodeId !== '0') {
				const selectedNode = nodeMap.get(nodeId);
				**let res = await performAction(token, selectedNode)**
				resMap.set(nodeId, res);
			}
			if (edgeMap.has(nodeId)) {
				for (const id of edgeMap.get(nodeId)) {
					queue.push(id);
				}
			}
		}
		return NextResponse.json(
			{ status: 200, body: Object.fromEntries(resMap) },
		);
}

Notice the performAction method. It’s here that we can perform integration actions using a simple POST request with the action name and parameters (from the input form) to the ActionKit API.

export async function performAction(jwt: string, contents: { action: string, parameters: any }) {
	const actionsUrl = "<https://actionkit.useparagon.com/projects/>" +
	 process.env.NEXT_PUBLIC_PARAGON_PROJECT_ID;
	 
	const actionHeaders = new Headers();
	actionHeaders.append("Content-Type", "application/json");
	actionHeaders.append("Authorization", "Bearer " + jwt);
	const actionResponse = await fetch(actionsUrl + "/actions", {
		method: "POST",
		headers: actionHeaders,
		body: JSON.stringify({ action: contents.action, parameters: contents.parameters }),
	});
	const actionBody = await actionResponse.json();
	return actionBody;
}

With just a single method implementation, we can perform 1000+ different 3rd-party integration actions server-side, empowering your workflow product to automate processes for your users inside and outside of your product.

We showed a simple implementation of a workflow application triggered with a button, however other “triggers” for workflows could be more applicable to your product. Workflows can be triggered when an event happens in your product (say a user adds a new record) or your user performs an action in one of their integrated 3rd-party applications (i.e. a contact is created in their Salesforce, a message is sent in their Slack, a new page is added in Notion). Paragon can help with the latter with 3rd-party webhook triggers to enable real-time workflow executions. You can explore all of our 3rd-party webhook triggers in our integration catalog.

Wrapping Up

Workflow builders can be a way to allow your users to build and design solutions right in your product’s platform. For AI applications, this leads to more reliable behaviors and more clear, observable processes.

Building this type of workflow feature doesn’t have to be arduous for your engineering team with:

  1. xyflow to simplify the workflow UI building

  2. Paragon’s ActionKit to handle 3rd-party actions in your workflow

With workflow features, your team can build a deeper level of customizability for your users and ultimately a deeper level of love for your product.

TABLE OF CONTENTS
    Table of contents will appear here.
Jack Mu
,

Developer Advocate

mins to read

Ship native integrations 7x faster with Paragon

Ready to get started?

Join 150+ SaaS & AI companies that are scaling their integration roadmaps with Paragon.

Ready to get started?

Join 150+ SaaS & AI companies that are scaling their integration roadmaps with Paragon.

Ready to get started?

Join 150+ SaaS & AI companies that are scaling their integration roadmaps with Paragon.

Ready to get started?

Join 150+ SaaS & AI companies that are scaling their integration roadmaps with Paragon.