Documentation

DocsAPI ReferenceWorkflows API

Workflows API

GET/v1/workflows

List workflows.

TypeScript
const workflows = await client.listWorkflows();
curl
curl https://api.outreachagent.dev/v1/workflows \
  -H "Authorization: Bearer $OUTREACHAGENT_API_KEY"
POST/v1/workflows

Create a new workflow.

ParameterTypeRequiredDescription
namestringYesWorkflow name
triggerstringYes"manual", "api", or "event"
nodesWorkflowNode[]YesArray of workflow nodes
exitCriteriaExitCriterion[]NoConditions that automatically exit enrolled contacts
optOutModestringNo"link", "reply" (default), or "header_only". Controls how opt-out is presented in emails.
TypeScript
const wf = await client.createWorkflow({
  name: "Drip Campaign",
  trigger: "api",
  nodes: [
    { id: "n1", type: "send_email", label: "Intro", templateId: "tmpl_1", nextNodeId: "n2" },
    { id: "n2", type: "delay", label: "Wait 1 day", delayAmount: 1, delayUnit: "days", nextNodeId: "n3" },
    { id: "n3", type: "send_webhook", label: "Notify CRM", webhookUrl: "https://crm.example.com/api", webhookBody: "{\"contact\": \"{{ contact.email }}\"}", nextNodeId: "n4" },
    { id: "n4", type: "exit", label: "End", nextNodeId: null }
  ],
  exitCriteria: [{ trigger: "reply" }, { trigger: "bounce" }]
});
curl
curl -X POST https://api.outreachagent.dev/v1/workflows \
  -H "Authorization: Bearer $OUTREACHAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Drip Campaign",
    "trigger": "api",
    "nodes": [
      {"id":"n1","type":"send_email","label":"Intro","templateId":"tmpl_1","nextNodeId":"n2"},
      {"id":"n2","type":"delay","label":"Wait 1 day","delayAmount":1,"delayUnit":"days","nextNodeId":"n3"},
      {"id":"n3","type":"send_webhook","label":"Notify CRM","webhookUrl":"https://crm.example.com/api","webhookBody":"{\"contact\": \"{{ contact.email }}\"}","nextNodeId":"n4"},
      {"id":"n4","type":"exit","label":"End","nextNodeId":null}
    ],
    "exitCriteria": [{"trigger":"reply"},{"trigger":"bounce"}]
  }'
GET/v1/workflows/:workflowId

Get workflow definition.

TypeScript
const wf = await client.getWorkflow("wf_abc");
curl
curl https://api.outreachagent.dev/v1/workflows/wf_abc \
  -H "Authorization: Bearer $OUTREACHAGENT_API_KEY"
PATCH/v1/workflows/:workflowId

Update workflow name, trigger, nodes, exitCriteria, or optOutMode.

TypeScript
await client.updateWorkflow("wf_abc", { name: "Updated Campaign" });
curl
curl -X PATCH https://api.outreachagent.dev/v1/workflows/wf_abc \
  -H "Authorization: Bearer $OUTREACHAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Updated Campaign"}'
DELETE/v1/workflows/:workflowId

Delete a workflow.

TypeScript
await client.deleteWorkflow("wf_abc");
curl
curl -X DELETE https://api.outreachagent.dev/v1/workflows/wf_abc \
  -H "Authorization: Bearer $OUTREACHAGENT_API_KEY"
POST/v1/workflows/:workflowId/publish

Publish a draft workflow (draft → active).

TypeScript
await client.publishWorkflow("wf_abc");
curl
curl -X POST https://api.outreachagent.dev/v1/workflows/wf_abc/publish \
  -H "Authorization: Bearer $OUTREACHAGENT_API_KEY"
POST/v1/workflows/:workflowId/pause

Pause an active workflow.

TypeScript
await client.pauseWorkflow("wf_abc");
curl
curl -X POST https://api.outreachagent.dev/v1/workflows/wf_abc/pause \
  -H "Authorization: Bearer $OUTREACHAGENT_API_KEY"
POST/v1/workflows/:workflowId/resume

Resume a paused workflow.

TypeScript
await client.resumeWorkflow("wf_abc");
curl
curl -X POST https://api.outreachagent.dev/v1/workflows/wf_abc/resume \
  -H "Authorization: Bearer $OUTREACHAGENT_API_KEY"
GET/v1/workflows/:workflowId/analytics

Get aggregate analytics for a workflow: enrollment counts, email stats, and rates.

TypeScript
const analytics = await client.getWorkflowAnalytics("wf_abc");
// analytics.totalEnrollments, analytics.completionRate, analytics.emailsSent, ...
curl
curl https://api.outreachagent.dev/v1/workflows/wf_abc/analytics \
  -H "Authorization: Bearer $OUTREACHAGENT_API_KEY"
POST/v1/workflows/:workflowId/nodes/:nodeId/pause

Pause a specific node. Paused nodes are skipped during execution. The node ID is added to the workflow's pausedNodeIds array.

TypeScript
await client.pauseNode("wf_abc", "n3");
curl
curl -X POST https://api.outreachagent.dev/v1/workflows/wf_abc/nodes/n3/pause \
  -H "Authorization: Bearer $OUTREACHAGENT_API_KEY"
POST/v1/workflows/:workflowId/nodes/:nodeId/resume

Resume a paused node, removing it from pausedNodeIds.

TypeScript
await client.resumeNode("wf_abc", "n3");
curl
curl -X POST https://api.outreachagent.dev/v1/workflows/wf_abc/nodes/n3/resume \
  -H "Authorization: Bearer $OUTREACHAGENT_API_KEY"
GET/v1/workflow-templates

List pre-built workflow templates. Built-in templates: Cold Outreach, Onboarding Drip, Re-engagement.

TypeScript
const templates = await client.listWorkflowTemplates();
// templates = [{ id, name, description, category, trigger, nodes, exitCriteria? }]
curl
curl https://api.outreachagent.dev/v1/workflow-templates \
  -H "Authorization: Bearer $OUTREACHAGENT_API_KEY"
POST/v1/workflows/from-template

Clone a template into a new draft workflow.

ParameterTypeRequiredDescription
templateIdstringYesTemplate ID to clone
namestringNoOptional name for the new workflow
TypeScript
const wf = await client.cloneFromTemplate("wftpl_cold", "My Cold Outreach");
await client.publishWorkflow(wf.id);
curl
curl -X POST https://api.outreachagent.dev/v1/workflows/from-template \
  -H "Authorization: Bearer $OUTREACHAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"templateId": "wftpl_cold", "name": "My Cold Outreach"}'
GET/v1/send-limits

List send limits for the organization. Returns per-inbox and org-wide limits.

TypeScript
const limits = await client.listSendLimits();
curl
curl https://api.outreachagent.dev/v1/send-limits \
  -H "Authorization: Bearer $OUTREACHAGENT_API_KEY"
PUT/v1/send-limits

Create or update a send limit. Omit inboxId for org-wide limit. Workflows automatically throttle email sends when the limit is reached.

ParameterTypeRequiredDescription
inboxIdstringNoInbox to limit (omit for org-wide)
dailyLimitnumberYesMaximum emails per day
TypeScript
// Org-wide limit
await client.upsertSendLimit({ dailyLimit: 500 });

// Per-inbox limit
await client.upsertSendLimit({ inboxId: "inb_abc", dailyLimit: 100 });
curl
curl -X PUT https://api.outreachagent.dev/v1/send-limits \
  -H "Authorization: Bearer $OUTREACHAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"dailyLimit": 500}'
POST/v1/workflows/:workflowId/test-send

Send a test email for a specific workflow node. Renders the template with optional contact data and enrollment variables, then delivers to the specified address.

ParameterTypeRequiredDescription
nodeIdstringYesID of a send_email node in the workflow
tostringYesEmail address to send the test to
contactIdstringNoContact ID to use for template rendering (populates {{ contact.* }} variables)
variablesobjectNoPer-enrollment variable overrides (populates {{ vars.* }} in templates)
TypeScript
const result = await client.testSendWorkflow("wf_abc", {
  nodeId: "n1",
  to: "you@yourteam.com",
  contactId: "con_xyz",
  variables: { hook: "your recent product launch" }
});
// result = { subject: "...", html: "...", to: "you@yourteam.com" }
curl
curl -X POST https://api.outreachagent.dev/v1/workflows/wf_abc/test-send \
  -H "Authorization: Bearer $OUTREACHAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"nodeId": "n1", "to": "you@yourteam.com", "variables": {"hook": "your recent product launch"}}'
POST/v1/workflows/:workflowId/simulate

Dry-run a workflow without sending real emails. Returns a step-by-step trace showing which nodes would execute and why.

TypeScript
const sim = await client.simulateWorkflow("wf_abc", {
  contactId: "con_xyz"
});
// sim.trace = [{ nodeId, nodeType, label, outcome, message }, ...]
// sim.terminalStatus = "completed" | "would_wait" | "blocked" | ...
curl
curl -X POST https://api.outreachagent.dev/v1/workflows/wf_abc/simulate \
  -H "Authorization: Bearer $OUTREACHAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contactId": "con_xyz"}'