ReferenceReference by module

Workflows API

Every Workflows action (10) and data model (3): endpoints, scopes, input, preconditions, events and examples.

Automations that react to what happens, or run on a schedule, and do the work for you.

Module code workflows · 10 actions · 3 data models · 10 events. A key or token never does more here than the person behind it can; row-level security applies exactly as in the app. Scopes: workflows (everything), workflows:read (read only) or workflows:<capability>.

Resources

ResourceTableList and readPOSTPATCHDELETE
canvas_run_notescanvas_run_note/api/v1/canvas_run_notes
canvas_triggerscanvas_trigger/api/v1/canvas_triggers
canvas_waitscanvas_wait/api/v1/canvas_waits

Lists take limit (up to 200), cursor, order (e.g. -created_at), fields and q; every other query parameter is a column filter: ?status=paid, ?total[gte]=100, ?id[in]=a,b, ?x=null.

Actions

ActionNeedsWhat it does
workflows.cancel_waitworkflows:writeCancel a waiting workflow run
workflows.decide_waitworkflows:writeApprove or reject a waiting workflow
workflows.draftworkflows:manageDraft a workflow
workflows.install_templateworkflows:manageStart a workflow from a template
workflows.note_undoworkflows:writeRecord an undo of a workflow run
workflows.park_canvasworkflows:writePark a workflow run at a wait
workflows.record_step_keyworkflows:writeRemember a step’s idempotency key
workflows.report_run_failedworkflows:readReport a failed workflow run
workflows.subscribe_canvasworkflows:manageStart a workflow on a module event
workflows.unsubscribe_canvasworkflows:manageStop a workflow listening to events

workflows.cancel_wait

Cancel a waiting workflow run — Stops a canvas execution that is waiting; the blocks that already ran stay done.

Needs workflows:write · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/canvas_waits/{id}/actions/cancel_wait
API key or OAuth token · workflows:write
  • Canonical address: POST /api/v1/actions/workflows.cancel_wait

Input

FieldTypeRequiredNotes
waitIduuidyesFilled from the path {id} · Waiting run · id of canvas_wait

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe waiting run must exist in this workspace.
already_finishedThe run must still be waiting.

Events it publishes: workflows.wait_cancelled

What it writes: canvas_wait (update) — Marks the wait for cancelling

curl -X POST https://app.getera.io/api/v1/canvas_waits/CANVAS_WAIT_ID/actions/cancel_wait \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "workflows.wait_cancelled"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.canvasWaits.cancelWait("CANVAS_WAIT_ID")
era canvas_waits cancel_wait CANVAS_WAIT_ID
tools/call
{
  "name": "era__workflows__cancel_wait",
  "arguments": {
    "waitId": "CANVAS_WAIT_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold workflows:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, already_finished · 429 slow down

workflows.decide_wait

Approve or reject a waiting workflow — Answers an Era approval. Completing its task on the Tasks screen does the same.

Needs workflows:write · changes data

POSThttps://app.getera.io/api/v1/canvas_waits/{id}/actions/decide_wait
API key or OAuth token · workflows:write
  • Canonical address: POST /api/v1/actions/workflows.decide_wait

Input

FieldTypeRequiredNotes
waitIduuidyesFilled from the path {id} · Waiting run · id of canvas_wait
approvebooleanyesApprove
notestringNote · max 500

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_foundThe waiting run must exist in this workspace.
not_waiting_for_approvalThe run must be waiting at an approval.

Events it publishes: workflows.wait_decided

What it writes: canvas_wait (update) — Records the decision

curl -X POST https://app.getera.io/api/v1/canvas_waits/CANVAS_WAIT_ID/actions/decide_wait \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"approve":true}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "workflows.wait_decided"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.canvasWaits.decideWait("CANVAS_WAIT_ID", {
  approve: true
})
era canvas_waits decide_wait CANVAS_WAIT_ID \
  --approve true
tools/call
{
  "name": "era__workflows__decide_wait",
  "arguments": {
    "waitId": "CANVAS_WAIT_ID",
    "approve": true
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold workflows:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, not_waiting_for_approval · 429 slow down

workflows.draft

Draft a workflow — Checks a whole workflow — trigger, conditions and steps — and draws it as a canvas for a person to review and deploy.

Needs workflows:manage · changes data

POSThttps://app.getera.io/api/v1/actions/workflows.draft
API key or OAuth token · workflows:manage

Input

FieldTypeRequiredNotes
namestringyesName · max 160
triggerEventstringWhen this happens · A module event, like crm.lead_won — or crm.* for every event a module publishes. · max 120
triggerKindstring (enum)Trigger · Allowed values: event, schedule, webhook, app_event, manual
triggerConfigobject / arrayTrigger settings · Schedule: { cron, timezone, overlap }. Webhook: { webhookId }. Any: { cancelOn: { event, match } }.
descriptionstringDescription · max 2000
conditionsobject / arrayOnly when
stepsobject / arraySteps · A list of { action, input, options }. { "$event": "payload.id" } reads off the trigger; { "$step": "0", "path": "id" } off an earlier step. Flow steps: flow.branch, flow.filter, flow.delay, flow.wait_until, flow.approval, flow.connector, flow.loop, flow.parallel, flow.era ({ instruction } — one Era turn on the person’s AI subscription; "every day at 9, do X" = a schedule trigger + one flow.era step).

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
empty_nameA workflow needs a name.
unknown_eventThe trigger must be an event some module declares.
bad_triggerA webhook trigger names its endpoint; an app-event trigger is an apps.* event.
bad_scheduleA schedule is a five-field cron in a real time zone.
bad_conditionA condition needs a path and a known comparison.
bad_stepEvery step must be an object naming an action, with a well-formed flow input.
unknown_actionA step may only call an action this platform registers, or a flow step.

Events it publishes: workflows.drafted

curl -X POST https://app.getera.io/api/v1/actions/workflows.draft \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"name":"Name"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "workflows.drafted"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("workflows.draft", {
  name: "Name"
})
era workflows draft \
  --name "Name"
tools/call
{
  "name": "era__workflows__draft",
  "arguments": {
    "name": "Name"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold workflows:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 empty_name, unknown_event, bad_trigger, bad_schedule, bad_condition, bad_step, unknown_action · 429 slow down

workflows.install_template

Start a workflow from a template — Fills a template in for you and draws it as a canvas, ready to review and deploy.

Needs workflows:manage · changes data

POSThttps://app.getera.io/api/v1/actions/workflows.install_template
API key or OAuth token · workflows:manage

Input

FieldTypeRequiredNotes
codestringyesTemplate · max 80
paramsobject / arrayAnswers

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
unknown_templateThe template must exist.
template_needs_moduleEvery module the template uses must be switched on.

Events it publishes: workflows.template_used

curl -X POST https://app.getera.io/api/v1/actions/workflows.install_template \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"code":"Template"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "workflows.template_used"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("workflows.install_template", {
  code: "Template"
})
era workflows install_template \
  --code "Template"
tools/call
{
  "name": "era__workflows__install_template",
  "arguments": {
    "code": "Template"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold workflows:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 unknown_template, template_needs_module · 429 slow down

workflows.note_undo

Record an undo of a workflow run — Records which Era actions of a run were undone through their declared inverse, and which refused.

Needs workflows:write · changes data

POSThttps://app.getera.io/api/v1/canvas_run_notes/actions/note_undo
API key or OAuth token · workflows:write
  • Canonical address: POST /api/v1/actions/workflows.note_undo

Input

FieldTypeRequiredNotes
canvasIdstringyesCanvas workflow · max 128
executionIdstringyesCanvas execution · max 128
statusstring (enum)yesOutcome · Allowed values: done, partial
stepsobject / arrayyesSteps

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
bad_canvasThe canvas id must be a workflow id.
already_undoneA run is undone once.

Events it publishes: workflows.run_undone

What it writes: canvas_run_note (upsert) — Records the undo

curl -X POST https://app.getera.io/api/v1/canvas_run_notes/actions/note_undo \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"canvasId":"Canvas workflow","executionId":"Canvas execution","status":"done","steps":{}}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "workflows.run_undone"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.canvasRunNotes.noteUndo({
  canvasId: "Canvas workflow",
  executionId: "Canvas execution",
  status: "done",
  steps: {}
})
era canvas_run_notes note_undo --data '{"canvasId":"Canvas workflow","executionId":"Canvas execution","status":"done","steps":{}}'
tools/call
{
  "name": "era__workflows__note_undo",
  "arguments": {
    "canvasId": "Canvas workflow",
    "executionId": "Canvas execution",
    "status": "done",
    "steps": {}
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold workflows:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 bad_canvas, already_undone · 429 slow down

workflows.park_canvas

Park a workflow run at a wait — Machine-only: the Era wait / approval block parks the canvas execution until its time, its answer or its expiry.

Needs workflows:write · changes data

Run by Era itself (machine-only). Listed so the reference is complete; an API key or a token is refused (403 machine_only).
POSThttps://app.getera.io/api/v1/canvas_waits/actions/park_canvas
API key or OAuth token · workflows:write
  • Canonical address: POST /api/v1/actions/workflows.park_canvas

Input

FieldTypeRequiredNotes
canvasIdstringyesCanvas workflow · max 128
executionIdstringyesCanvas execution · max 128
contextIdstringyesPause point · max 300
kindstring (enum)yesWaits for · Allowed values: wait, approval
untildate-timeUntil
taskIduuidApproval task · id of ai_task
blockNamestringBlock · max 200
eventobject / arrayTrigger event

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
bad_canvasThe canvas id must be a workflow id.
bad_waitA wait ends at a readable moment within 30 days.

Events it publishes: workflows.canvas_parked

What it writes: canvas_wait (upsert) — Records the parked execution

Errors: 401 no or expired credential · 403 the credential does not hold workflows:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 bad_canvas, bad_wait · 429 slow down

workflows.record_step_key

Remember a step’s idempotency key — Machine-only: an Era block with an idempotency key succeeded, so it does not run again for that key.

Needs workflows:write · changes data

Run by Era itself (machine-only). Listed so the reference is complete; an API key or a token is refused (403 machine_only).
POSThttps://app.getera.io/api/v1/actions/workflows.record_step_key
API key or OAuth token · workflows:write

Input

FieldTypeRequiredNotes
canvasIdstringyesCanvas workflow · max 128
blockIdstringyesBlock · max 128
keystringyesKey · max 500
executionIdstringCanvas execution · max 128
resultobject / arrayResult

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
bad_canvasA step key names its canvas, its block and the key.
already_doneThe block has not already succeeded for this key.

Events it publishes: workflows.step_key_recorded

What it writes: canvas_step_key (insert) — Remembers the key

Errors: 401 no or expired credential · 403 the credential does not hold workflows:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 bad_canvas, already_done · 429 slow down

workflows.report_run_failed

Report a failed workflow run — Machine-only: turns a failed canvas execution into the workflows.run_failed event for its owner, once.

Needs workflows:read · changes data

Run by Era itself (machine-only). Listed so the reference is complete; an API key or a token is refused (403 machine_only).
POSThttps://app.getera.io/api/v1/canvas_run_notes/actions/report_run_failed
API key or OAuth token · workflows:read
  • Canonical address: POST /api/v1/actions/workflows.report_run_failed

Input

FieldTypeRequiredNotes
canvasIdstringyesCanvas workflow · max 128
executionIdstringyesCanvas execution · max 128
namestringWorkflow · max 300
errorstringError · max 2000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
bad_canvasThe canvas id must be a workflow id.
already_reportedA failure is reported once.

Events it publishes: workflows.run_failed

What it writes: canvas_run_note (upsert) — Marks the failure reported

Errors: 401 no or expired credential · 403 the credential does not hold workflows:read · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 bad_canvas, already_reported · 429 slow down

workflows.subscribe_canvas

Start a workflow on a module event — The canvas starts by itself when the event happens — called when a canvas with an Era event trigger is deployed.

Needs workflows:manage · changes data

POSThttps://app.getera.io/api/v1/canvas_triggers/actions/subscribe_canvas
API key or OAuth token · workflows:manage
  • Canonical address: POST /api/v1/actions/workflows.subscribe_canvas

Input

FieldTypeRequiredNotes
canvasIdstringyesCanvas workflow · max 128
eventPatternstringyesWhen this happens · A module event, like crm.lead_won — or crm.* for every event a module publishes. · max 120
enabledbooleanListening
cancelOnobject / arrayStop a waiting run when · { event, match } — e.g. { "event": "inbox.assigned", "match": "payload.id" }.

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
bad_canvasThe canvas id must be a workflow id.
unknown_eventSomething in the platform must publish the event.
bad_triggerA "stop when" names an event and the path it matches.

Events it publishes: workflows.canvas_subscribed

What it writes: canvas_trigger (upsert) — Creates or updates the canvas subscription

curl -X POST https://app.getera.io/api/v1/canvas_triggers/actions/subscribe_canvas \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"canvasId":"Canvas workflow","eventPattern":"When this happens"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "workflows.canvas_subscribed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.canvasTriggers.subscribeCanvas({
  canvasId: "Canvas workflow",
  eventPattern: "When this happens"
})
era canvas_triggers subscribe_canvas \
  --canvas-id "Canvas workflow" \
  --event-pattern "When this happens"
tools/call
{
  "name": "era__workflows__subscribe_canvas",
  "arguments": {
    "canvasId": "Canvas workflow",
    "eventPattern": "When this happens"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold workflows:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 bad_canvas, unknown_event, bad_trigger · 429 slow down

workflows.unsubscribe_canvas

Stop a workflow listening to events — Removes the canvas subscription; the canvas no longer starts on module events.

Needs workflows:manage · removes or cannot be undone

POSThttps://app.getera.io/api/v1/canvas_triggers/actions/unsubscribe_canvas
API key or OAuth token · workflows:manage
  • Canonical address: POST /api/v1/actions/workflows.unsubscribe_canvas

Input

FieldTypeRequiredNotes
canvasIdstringyesCanvas workflow · max 128

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
not_subscribedThe canvas must be subscribed.

Events it publishes: workflows.canvas_unsubscribed

What it writes: canvas_trigger (delete) — Removes the subscription

curl -X POST https://app.getera.io/api/v1/canvas_triggers/actions/unsubscribe_canvas \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"canvasId":"Canvas workflow"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "workflows.canvas_unsubscribed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.canvasTriggers.unsubscribeCanvas({
  canvasId: "Canvas workflow"
})
era canvas_triggers unsubscribe_canvas \
  --canvas-id "Canvas workflow"
tools/call
{
  "name": "era__workflows__unsubscribe_canvas",
  "arguments": {
    "canvasId": "Canvas workflow"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold workflows:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_subscribed · 429 slow down

Data models

CanvasRunNote

Table canvas_run_note · Resource canvas_run_notes

  • GET /api/v1/canvas_run_notes
  • GET /api/v1/canvas_run_notes/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
canvas_idstring · text
execution_idstring · text
failure_reported_atstring (date-time) · timestamptzyes
undo_statusstring · textyes
undoobject · jsonbyes
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

Checks:

  • CHECK (((undo_status IS NULL) OR (undo_status = ANY (ARRAY['done'::text, 'partial'::text]))))

CanvasTrigger

Table canvas_trigger · Resource canvas_triggers

  • GET /api/v1/canvas_triggers
  • GET /api/v1/canvas_triggers/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
canvas_idstring · text
event_patternstring · text
acts_as_user_idstring (uuid) · uuidapp_user
is_enabledboolean · bool
last_run_atstring (date-time) · timestamptzyes
run_countinteger · int4
failure_countinteger · int4
last_errorstring · textyes
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
cancel_onobject · jsonbyes

Primary key: id

Checks:

  • CHECK ((canvas_id ~ '^[A-Za-z0-9_-]{1,128}$'::text))
  • CHECK (((event_pattern = '*'::text) OR (event_pattern ~ '^[a-z][a-z0-9_]*\.([a-z][a-z0-9_]*\|\*)$'::text)))

CanvasWait

Table canvas_wait · Resource canvas_waits

  • GET /api/v1/canvas_waits
  • GET /api/v1/canvas_waits/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
canvas_idstring · text
execution_idstring · text
context_idstring · text
kindstring · textwait, approval
statusstring · textwaiting, resuming, resumed, rejected, expired, cancelled, failed
wake_atstring (date-time) · timestamptzyes
task_idstring (uuid) · uuidyes
decisionstring · textyes
acts_as_user_idstring (uuid) · uuidapp_user
block_namestring · textyes
cancel_keystring · textyes
errorstring · textyes
created_atstring (date-time) · timestamptz
resolved_atstring (date-time) · timestamptzyes

Primary key: id

Checks:

  • CHECK ((canvas_id ~ '^[A-Za-z0-9_-]{1,128}$'::text))
  • CHECK (((decision IS NULL) OR (decision = ANY (ARRAY['approved'::text, 'rejected'::text]))))

Events

Workflows and webhooks react to these events.

EventWhat happensPayload
workflows.canvas_parkedA workflow run is waiting at a wait or an approval.id, canvasId, executionId, kind, wakeAt
workflows.canvas_subscribedA canvas workflow started listening to a module event.id, canvasId, eventPattern
workflows.canvas_unsubscribedA canvas workflow stopped listening to module events.id, canvasId
workflows.draftedA workflow was drafted and drawn as a canvas.name, trigger, steps
workflows.run_failedA workflow run failed. For its owner.id, canvasId, runId, name, error, ownerUserId, recipientUserId
workflows.run_undoneWhat a workflow run did was undone.id, canvasId, runId, status
workflows.step_key_recordedA block with an idempotency key succeeded.id, canvasId, blockId
workflows.template_usedA workflow was started from a template.code, name
workflows.wait_cancelledA person cancelled a waiting workflow run.id, canvasId, executionId
workflows.wait_decidedA person approved or rejected a waiting workflow run.id, canvasId, executionId, decision
Was this page helpful?