Workflows
Automation workflows with DAG-based execution, scheduling, and webhooks
Workflows enable powerful automation with a DAG (Directed Acyclic Graph) execution model. Unlike simple sequential workflows, Arky workflows can run nodes in parallel, branch conditionally, and trigger from webhooks or schedules.
Key Concepts
Workflow Structure
A workflow consists of nodes and edges:
- Nodes: Individual operations (trigger, HTTP request, condition, wait)
- Edges: Connections between nodes that define execution flow
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Trigger │────▶│ HTTP │────▶│ HTTP │
└─────────┘ │ (fetch) │ │ (notify)│
└─────────┘ └─────────┘
Node Types
| Type | Description |
|---|---|
trigger | Entry point - webhook or scheduled |
http | Make HTTP requests to external APIs |
if | Conditional branching based on expressions |
wait | Pause execution for a duration |
Create Workflow
/v1/businesses/{businessId}/workflows sdk.workflow.createWorkflow() Create a new automation workflow.
const result = await sdk.workflow.createWorkflow({
key: 'order-notification',
status: 'ACTIVE',
nodes: {
trigger: {
type: 'trigger',
event: 'order.created'
},
fetchOrder: {
type: 'http',
method: 'GET',
url: 'https://api.yourapp.com/orders/${trigger.data.orderId}',
headers: {
'Authorization': 'Bearer ${env.API_KEY}'
}
},
sendSlack: {
type: 'http',
method: 'POST',
url: 'https://hooks.slack.com/services/xxx',
body: {
text: 'New order #${fetchOrder.response.orderNumber} - $${fetchOrder.response.total}'
}
}
},
edges: [
{ id: 'e1', source: 'trigger', sourceOutput: 'default', target: 'fetchOrder' },
{ id: 'e2', source: 'fetchOrder', sourceOutput: 'default', target: 'sendSlack' }
]
});Parameters
| Name | Type | Description |
|---|---|---|
key required | string | Unique workflow identifier |
status optional | ACTIVE | DRAFT | ARCHIVED | Workflow status (default: DRAFT) |
nodes required | Record<string, WorkflowNode> | Map of node IDs to node definitions |
edges required | WorkflowEdge[] | Connections between nodes |
schedule optional | string | Cron expression for scheduled execution (e.g., '0 9 * * *' for 9am daily) |
Get Workflow
/v1/businesses/{businessId}/workflows/{id} sdk.workflow.getWorkflow() Retrieve a workflow by ID.
const result = await sdk.workflow.getWorkflow({
id: 'wf_abc123'
});
if (result.ok) {
const workflow = result.val;
console.log(workflow.key, workflow.status);
console.log('Nodes:', Object.keys(workflow.nodes));
}
List Workflows
/v1/businesses/{businessId}/workflows sdk.workflow.getWorkflows() List workflows with filtering and pagination.
const result = await sdk.workflow.getWorkflows({
statuses: ['ACTIVE'],
query: 'notification',
limit: 20,
cursor: null
});
if (result.ok) {
const { items, cursor } = result.val;
items.forEach(workflow => {
console.log(workflow.key, workflow.status);
});
}
Parameters
| Name | Type | Description |
|---|---|---|
ids optional | string[] | Filter by specific workflow IDs |
statuses optional | string[] | Filter by status (ACTIVE, DRAFT, ARCHIVED) |
query optional | string | Search in workflow keys |
limit optional | number | Items per page (max 100) |
cursor optional | string | Pagination cursor |
sortField optional | string | Sort field (createdAt, key) |
sortDirection optional | asc | desc | Sort direction |
Update Workflow
/v1/businesses/{businessId}/workflows/{id} sdk.workflow.updateWorkflow() Update an existing workflow.
const result = await sdk.workflow.updateWorkflow({
id: 'wf_abc123',
key: 'order-notification-v2',
status: 'ACTIVE',
nodes: {
// Updated node definitions
trigger: { type: 'trigger' },
notify: {
type: 'http',
method: 'POST',
url: 'https://api.example.com/notify'
}
},
edges: [
{ id: 'e1', source: 'trigger', sourceOutput: 'default', target: 'notify' }
]
});
Delete Workflow
/v1/businesses/{businessId}/workflows/{id} sdk.workflow.deleteWorkflow() Delete a workflow.
const result = await sdk.workflow.deleteWorkflow({
id: 'wf_abc123'
});
Trigger Workflow
/v1/workflows/trigger/{secret} sdk.workflow.triggerWorkflow() Trigger a workflow execution via webhook. This endpoint does not require authentication - the secret in the URL validates the request.
// The secret comes from your workflow's webhook URL
const result = await sdk.workflow.triggerWorkflow({
secret: 'wh_secret_abc123xyz',
// Pass any data to the workflow
orderId: 'ord_123',
customerEmail: 'customer@example.com',
items: [
{ productId: 'prod_1', quantity: 2 }
]
});Parameters
| Name | Type | Description |
|---|---|---|
secret required | string | Workflow webhook secret from the trigger URL |
[key: string] optional | any | Any additional data to pass to the workflow |
The trigger data is available in your workflow nodes as trigger.data. For example, if you pass orderId, access it as ${trigger.data.orderId}.
Node Types Reference
Trigger Node
The entry point for workflow execution. Every workflow must have exactly one trigger node.
{
type: 'trigger',
event: 'order.created' // Optional: listen for specific business events
}
HTTP Node
Make HTTP requests to external APIs. Supports template variables from previous nodes.
{
type: 'http',
method: 'POST', // GET, POST, PUT, PATCH, DELETE
url: 'https://api.example.com/endpoint',
headers: {
'Authorization': 'Bearer ${env.API_KEY}',
'Content-Type': 'application/json'
},
body: {
userId: '${trigger.data.userId}',
message: 'Hello from Arky!'
},
timeoutMs: 30000 // Optional timeout in milliseconds
}
Available Variables:
${trigger.data.*}- Data passed to the trigger${env.*}- Environment variables configured in your business${previousNodeId.response.*}- Response from a previous HTTP node
If Node
Conditional branching based on JavaScript expressions.
{
type: 'if',
condition: 'trigger.data.amount > 100'
}
If nodes have two outputs:
true- Executed when condition is truthyfalse- Executed when condition is falsy
edges: [
{ id: 'e1', source: 'checkAmount', sourceOutput: 'true', target: 'sendHighValueAlert' },
{ id: 'e2', source: 'checkAmount', sourceOutput: 'false', target: 'sendStandardNotification' }
]
Wait Node
Pause execution for a specified duration.
{
type: 'wait',
duration: '5m' // Supports: 30s, 5m, 2h, 1d
}
Scheduled Workflows
Run workflows on a schedule using cron expressions.
const result = await sdk.workflow.createWorkflow({
key: 'daily-report',
status: 'ACTIVE',
schedule: '0 9 * * *', // Every day at 9:00 AM UTC
nodes: {
trigger: { type: 'trigger' },
generateReport: {
type: 'http',
method: 'POST',
url: 'https://api.yourapp.com/reports/generate'
},
sendEmail: {
type: 'http',
method: 'POST',
url: 'https://api.yourapp.com/email/send',
body: {
to: 'team@company.com',
subject: 'Daily Report',
body: '${generateReport.response.reportUrl}'
}
}
},
edges: [
{ id: 'e1', source: 'trigger', sourceOutput: 'default', target: 'generateReport' },
{ id: 'e2', source: 'generateReport', sourceOutput: 'default', target: 'sendEmail' }
]
});
Common Cron Expressions:
| Expression | Description |
|---|---|
0 9 * * * | Every day at 9:00 AM |
0 */2 * * * | Every 2 hours |
0 9 * * 1 | Every Monday at 9:00 AM |
0 0 1 * * | First day of every month |
*/15 * * * * | Every 15 minutes |
Complete Example: Order Processing
const workflow = await sdk.workflow.createWorkflow({
key: 'process-new-order',
status: 'ACTIVE',
nodes: {
// Entry point
trigger: {
type: 'trigger',
event: 'order.created'
},
// Check order value
checkValue: {
type: 'if',
condition: 'trigger.data.total > 10000' // Over $100
},
// High value: notify sales team
notifySales: {
type: 'http',
method: 'POST',
url: 'https://hooks.slack.com/services/sales-channel',
body: {
text: '🎉 High-value order! $${trigger.data.total / 100} from ${trigger.data.customerEmail}'
}
},
// Always: update inventory
updateInventory: {
type: 'http',
method: 'POST',
url: 'https://api.yourapp.com/inventory/decrement',
body: {
items: '${trigger.data.items}'
}
},
// Send confirmation email
sendConfirmation: {
type: 'http',
method: 'POST',
url: 'https://api.yourapp.com/email/order-confirmation',
body: {
orderId: '${trigger.data.orderId}',
email: '${trigger.data.customerEmail}'
}
}
},
edges: [
// Trigger -> Check Value
{ id: 'e1', source: 'trigger', sourceOutput: 'default', target: 'checkValue' },
// High value -> Notify Sales
{ id: 'e2', source: 'checkValue', sourceOutput: 'true', target: 'notifySales' },
// Both paths -> Update Inventory (runs in parallel with notification)
{ id: 'e3', source: 'trigger', sourceOutput: 'default', target: 'updateInventory' },
// After inventory -> Send Confirmation
{ id: 'e4', source: 'updateInventory', sourceOutput: 'default', target: 'sendConfirmation' }
]
});
Workflows execute nodes in parallel when possible. In the example above, checkValue and updateInventory run simultaneously since they both connect directly to the trigger.