This is the API view of workflows. For the visual editor, templates, and per-step product reference, see
the Workflows product guide. Both drive the same underlying workflow — a plan you
publish over the API opens and runs identically in the app.
What you work with
The graph model
A plan is a directed acyclic graph. Every node has a stable stringid and a next array of the node ids it points to. The empty string "" marks an unwired slot (a dangling branch a draft can tolerate but a publish cannot).
The entry node is the single node that no other node points to. It must be a selector or import block — the step that brings records into the workflow.
Node kinds
BLOCK — one workflow step
BLOCK — one workflow step
blockIdcomes fromGET /v1/workflows/blocks.inputsare the block’s configured inputs — discover them withGET /v1/workflows/blocks/{blockId}.- A
BLOCKhas exactly onenextslot, exceptWAIT_FOR_APPROVAL, which has two:[approvedTargetId, rejectedTargetId].
CONDITIONAL — branch on record data
CONDITIONAL — branch on record data
nexthas exactlyconditions.length + 1entries: one target per condition (in order), then the fallback target last.- Discover fields and operators with
GET /v1/workflows/condition-fields. - At most 20 conditions on a single node.
percentageis an integer 1–100; sibling split percentages on one node must sum to ≤ 100.- Any remainder falls through to the fallback branch (so one
RANDOM_SPLITof 50 is a 50/50 A/B split). - Each record gets a stable roll per run — re-running a step never reshuffles records between branches.
KING — dedupe / group the stream
KING — dedupe / group the stream
nextis[leftTargetId, rightTargetId].- Use it to collapse duplicates or keep one record per group before an expensive step.
Wiring rules
- The
nextslot count is fixed per node kind:BLOCK→ 1 (or 2 forWAIT_FOR_APPROVAL),CONDITIONAL→conditions.length + 1,KING→ 2. - Every id in a
nextarray must reference an existing node id, or be""for an unwired slot. - No cycles. A plan may hold at most 60 nodes.
- The entry node is inferred (the node nothing points to) — you don’t flag it.
Plan anatomy
A complete, publishable plan for import a list → check email deliverability → add to a campaign:importis the entry node — nothing points to it, and it’s a selector block.verifyleavesinputsempty: itsleadIdinput is the record flowing from the previous step, so you omit it. Only selector/standalone steps carry an explicit entity id.campaignis terminal — its singlenextslot is"".- Every required input a publish needs is present (
SELECT_LEADS_FROM_LIST.leadsGroupId,ADD_LEADS_TO_CAMPAIGN.campaignId).
Triggers
The optionaltrigger decides when a run starts. It defaults to MANUAL. All five types:
A
WEBHOOK trigger that declares inputs can’t be started with POST /v1/workflow/{id}/run — deliver
its payload to the webhook URL instead. A webhook trigger with no declared inputs can still be run manually.Drafts, published versions, and concurrency
Every workflow has one editable draft and, once published, one live published version.- Create / update always writes the draft. Nothing runs off a draft.
- Publish snapshots the draft into a new immutable version (
v1,v2, …) and reconciles the trigger (e.g. arms a schedule). Runs execute the published version. - Editing a published workflow is safe: the live version keeps running until you publish again.
GET /v1/workflow/{workflowId} returns a revision token (the workflow’s updatedAt, ISO-8601). Pass it back on PATCH …/draft and POST …/publish for optimistic concurrency:
1
Read
GET /v1/workflow/4021 → revision: "2026-07-19T10:15:30.000Z".2
Write with the revision
PATCH /v1/workflow/4021/draft with "revision": "2026-07-19T10:15:30.000Z".3
Handle 409
If someone else edited the draft in between, you get 409 Conflict — re-read, reconcile, retry with the
new revision. Omit
revision to force last-write-wins (not recommended for shared workflows). POST …/publish can also return 409 when another publish is mid-flight (its trigger is already being
updated) — that one isn’t a revision conflict; just retry shortly.Runtime input contract
A published workflow declares what a run needs viaruntimeInputContract on GET /v1/workflow/{workflowId}. It has one of three statuses, and — for EMPTY and SUPPORTED — a ready-to-send exampleBody you can copy straight into the run call:
To make an entry step accept a run-time id, set its entity input to the sentinel
"__MANUAL_INPUT":
SUPPORTED contract whose acceptedKeys include the public alias (contactListId) and the raw key (leadsGroupId); the runner also accepts leadIds / leadId as a fallback. You’d then run it with, for example, { "input": { "contactListId": 55762 } } or { "input": { "leadIds": [101, 102] } }.
The same sentinel drives WEBHOOK-triggered entry steps: declare an entity-typed webhook input (e.g. { "key": "contacts", "type": "leadIds" }) and set the entry step’s entity input to "__MANUAL_INPUT" — the run is seeded from the webhook payload at delivery time. Entity-typed webhook inputs are never wired with a { "webhookInputKey": … } binding; that binding style is only for non-entity fields (e.g. a profileUrl input filling a profileUrl field). For example, an IMPORT_COMPANY_FROM_PAYLOAD entry step with a declared { "key": "companyPayload", "type": "companyPayload" } webhook input must set inputs.companyPayload to { "webhookInputKey": "companyPayload" }. Put only configured values or bindings in node inputs — never copy the catalog’s key, type, required, valueShape, or resolution metadata into the plan. Also note the delivery credentials (trigger.webhookUrl + trigger.webhookSecret) are issued on publish — a draft has none yet.
Credits and limits
maxCreditsPerRun— an optional integer ceiling on credits a single run may spend. Enrichment and AI steps consume credits; a run stops once it hits the ceiling. Set it on create orPATCH …/draft.- 60 nodes max per plan.
- 20 conditions max per
CONDITIONALnode.
Access, scopes, and rate limits
Every request is authenticated with your API key in thex-api-key header (see Authentication). The base URL is https://openapi.enginy.ai.
Granting
WORKFLOWS_WRITE implies WORKFLOWS_READ. A workflow is only visible to a key whose creating user can access it (workspace admins see all; other users see workflows they own or were granted access to).
Where to next
Endpoints
The interactive reference for every workflow endpoint, generated from the OpenAPI spec.
Cookbook
Four end-to-end builds you can copy and run.
MCP agent guide
The recommended tool flow for AI agents.