MCP is live.Set upAsk the community
OmniDimension

Build with the API

Create and run workflows over the REST API, the same workflows the dashboard builds. The rules an integration or an AI agent needs to get it right.

Everything the visual builder does, the API does too. You build a workflow as a graph of nodes, join them with edges, test it, then publish it. The dashboard and the API read and write the same workflow, so a graph the API creates opens in the canvas, and a workflow a person drew can be edited by the API.

Base URL https://omnidim.io/api/v1  ·  All routes live under /api/v1/workflows and /api/v1/workflow-node-types.

The tools, in the order you use them

  1. listWorkflowNodeTypes with q (for example whatsapp) to find node types.
  2. getWorkflowNodeType for the fields one type needs. Ask for detail=full only when you want the examples.
  3. listWorkflowFieldOptions for any field of type ref (a number, an integration, a template, an agent). Never guess an id. If it returns no_options, ask the user for the value.
  4. createWorkflow with a name. It starts with one trigger node. You may pass a complete first graph instead, in the shape getWorkflow returns under draft.
  5. editWorkflow with the revision from your last read and a list of ops.
  6. validateWorkflow, then fix what it reports with another editWorkflow.
  7. testWorkflow only after the user agrees (see Test runs are real).
  8. publishWorkflow, then activateWorkflow or deactivateWorkflow.

Draft and published

  • You always edit the draft. A published workflow is never changed in place.
  • Real events and webhooks always run the published version. A test runs the draft.
  • publishWorkflow copies the draft to the live version and leaves a fresh draft for the next round of edits. It refuses while validateWorkflow has errors.
  • deactivateWorkflow pauses the live version. activateWorkflow resumes it.

Connecting nodes

An edge runs from one node's output to the next node. Plain nodes have one output, default. Branching nodes have named outputs, and you must say which. getWorkflowNodeType lists each type's outputs. A summary:

NodeOutputs
conditionalTrue, False
switch_conditioneach case id, plus else
time_conditionYes, No
photo_analyzerpass, fail
voice_aiCompleted, Not Completed
zoho_biginCreated, Found, Ambiguous, Failed, Success
  • One output can feed several nodes. They all run.
  • add_node with after and handle places and connects a node in one step.
  • Every node except notes must be reachable from the trigger, or publish is refused.

Ops

OpFields
add_nodeid, type, config?, label?, position?, after?, handle?
update_nodeid, config (merged; null removes a key), label?
move_nodeid, position {x, y}
delete_nodeid (its edges go too)
connectfrom, to, handle? (default default)
disconnectfrom, to, handle?

A batch applies completely or not at all. A failing op returns 422 invalid_op with its op_index, and nothing is saved.

Passing data between nodes

{{ context.<node id>.<field> }} reads an earlier node's output. The engine also provides {{ context.webhook }} (the trigger payload) and {{ context.execution_link }}. Only nodes that run earlier have output.

Node ids appear in these references, so pick readable ones: check_interest, wa_followup, notify_sales. Use lowercase letters, digits and underscores, starting with a letter. These names are reserved: webhook, execution_id, execution_link, get, items, keys, values.

Node rules worth knowing

  • code runs a sandboxed Python snippet and must assign its output to a result variable. A dict in result becomes the node's output. Without it, the node has no output.
  • sub_workflow starts another of your workflows and continues at once. The target must be published and active. A paused target fails the run.
  • wait, wait_for_time, voice_ai and send_email pause the run and resume it later. There is no end node: a branch ends at a node with no outgoing edge, and the run finishes when every branch has ended.
  • notes never connects and never runs. Add one that says what the workflow is for, so the next person to open the canvas understands it.

Credentials

Never put secrets in config when an integration exists. Pick integrations, numbers and templates from listWorkflowFieldOptions. Secret fields (a Slack webhook URL, API headers and body params) read back as ********. Send ******** back unchanged and the stored value is kept. If the user has no matching integration, tell them to connect one in the dashboard first.

Test runs are real

Errors you will see

ErrorMeaningWhat to do
409 revision_conflictThe draft changed since you read it, often the user saved in the dashboardgetWorkflow, then retry with the new revision
422 validation_failed with not_foundAn id is not in this workspacePick from listWorkflowFieldOptions
422 validation_failed on publishMissing fields, an unconnected node, or a bad handleFix each one, then publish again
422 invalid_opAn op is malformed or names a missing nodeFix the op at op_index
422 validation_failed with templated_refAn id field holds a {{ }} templatePut a literal id from listWorkflowFieldOptions
400 no_optionsThe field holds an id from another systemAsk the user for the value

Worked example

"After a call, if the lead is interested, send our follow-up WhatsApp template and tell #sales in Slack."

Create

createWorkflow { "name": "Interested lead follow-up" } gives you a trigger node and a revision.

Find the ids

listWorkflowFieldOptions for whatsapp.phone_number_id, then for whatsapp.template_id with depends set to that number. Confirm both with the user.

Build the graph

One editWorkflow batch, using the revision from step 1:

{
  "revision": "3f9a1c07be2d",
  "ops": [
    {"op": "add_node", "id": "check_interest", "type": "conditional", "after": "trigger",
     "config": {"conditions": [{"variable": "{{ context.trigger.extracted_variables.interested }}", "operator": "==", "value": "yes"}]}},
    {"op": "add_node", "id": "wa_followup", "type": "whatsapp", "after": "check_interest", "handle": "True",
     "config": {"phone_number_id": 8265, "message_type": "template", "template_id": 3676, "to_number": "{{ context.trigger.customer_number }}"}},
    {"op": "add_node", "id": "notify_sales", "type": "slack", "after": "wa_followup",
     "config": {"slack_webhook_url": "<from the user>", "message": "Follow-up sent to {{ context.trigger.customer_number }}"}},
    {"op": "add_node", "id": "about", "type": "notes",
     "config": {"note_text": "Follows up interested leads after a call."}}
  ]
}

The phone_number_id and template_id are literal ids from step 2. The to_number and message are free text, so they take {{ }}.

Validate, publish, attach

validateWorkflow, fix anything reported, then publishWorkflow. Tell the user to point the agent's post-call action at this workflow.

On this page