Skip to content
emitDocs

API reference

Workflow runs

Start workflow runs, send them signals, read and follow a run's tree, and cancel a run with everything it started.

A workflow run is a job, so the Jobs endpoints work on runs too. The code of a workflow lives in your workers, written with an SDK: these endpoints start runs, signal them and watch them from anywhere.

Start a run

POST /v1/spaces/{space}/jobs · scope create

Create a job with the workflow's name, its input as the payload, and "workflow": true. A worker that serves the workflow picks it up.

Shell
curl -s "$EMIT_URL/v1/spaces/accounts/jobs" \
  -H "Authorization: Bearer $EMIT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "trial", "payload": {"userId": "usr_42", "email": "ada@example.com"}, "key": "trial-usr_42", "workflow": true}'
# {"created":[{"id":"01M3QSR386017JCY0DC11GTG7D","outcome":"NEW","attempt":0}]}

Use key against double starts, or singleton for one open run at a time: see Starting, keys and cancelling. Wait for the result by following the run, or by getting it once it's done.

Send signals

POST /v1/spaces/{space}/jobs:signal · scope create

Send one signal, an array, or {"signals": [...]}. Name the run by exactly one of id, key and singleton.

namestringrequired

The signal's name: what the run waits for. At most 256 bytes.

idstring

The run's id.

keystring

The key the run was started with.

singletonstring

The singleton the run was started with.

dataJSON

What the run receives. At most 4 MiB.

curl -s "$EMIT_URL/v1/spaces/accounts/jobs:signal" \
  -H "Authorization: Bearer $EMIT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"key": "trial-usr_42", "name": "upgraded", "data": {"plan": "pro"}}'
const took = await trial.signal({ key: "trial-usr_42" }, "upgraded", { plan: "pro" });
took, err := trial.Signal(ctx, emit.ByKey("trial-usr_42"), "upgraded", map[string]string{"plan": "pro"})
JSON
{ "delivered": [true], "ids": ["01M3QSR386017JCY0DC11GTG7D"] }

One entry per signal: delivered is true if a run took it, and ids names that run. false, with an empty id, means there's no unfinished run to take it. A signal is never refused for that.

A signal sent before the run waits for it is kept. A signal repeated after a lost answer is delivered again, so send data that can arrive twice safely.

Signal, or start

POST /v1/spaces/{space}/jobs:signalOrStart · scope create

Delivers a signal to the open run under a singleton, or, if there's none, starts a run with job instead. Two calls at once never start two runs.

singletonstringrequired

The run to find, or to start under.

namestring

The signal to send. Leave it out to only start a run if none is open.

dataJSON

The signal's data.

jobobjectrequired

The run to start if none is open, as in Create jobs: its name, payload and "workflow": true. No key. The run it starts doesn't get the signal: its input is how it begins.

Shell
curl -s "$EMIT_URL/v1/spaces/accounts/jobs:signalOrStart" \
  -H "Authorization: Bearer $EMIT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "singleton": "trial-usr_88",
    "name": "upgraded",
    "data": {"plan": "pro"},
    "job": {"name": "trial", "payload": {"userId": "usr_88", "email": "di@example.com"}, "workflow": true}
  }'
# {"id":"01M3QSRDB002NRZ5VBGNQXKT8Q","started":true}

started is true if this call started the run, and false if a run was open and got the signal.

Read a run's tree

GET /v1/spaces/{space}/jobs/{id}/tree · scope read, or a follow token

The run and everything under it: its steps, sleeps and signals, in the order they were made. A step that's itself a workflow run brings its own children. This is what the dashboard's run timeline shows.

Shell
curl -s "$EMIT_URL/v1/spaces/accounts/jobs/01M3QSR386017JCY0DC11GTG7D/tree" -H "Authorization: Bearer $EMIT_TOKEN"
JSON
{
  "id": "01M3QSR386017JCY0DC11GTG7D",
  "name": "trial",
  "status": "COMPLETED",
  "attempt": 3,
  "children": [
    { "name": "send-email", "lane": 0, "status": "COMPLETED", "label": "", "children": [] },
    { "name": "_timeout", "lane": 2, "status": "CANCELLED", "untilMs": "0", "children": [] },
    { "name": "upgraded", "lane": 1, "status": "COMPLETED", "children": [] }
  ]
}

Each node has the job's id, name, status, attempt, maxAttempts, createdAtMs, finishedAtMs, progress and children, plus:

laneinteger

What the node is in its run: 0 a step, 1 a signal (its name is the signal's), 2 a sleep (_sleep) or a wait's timeout (_timeout).

untilMsstring

For a sleep or a timeout, when it ends. For a running step, when its lease ends.

errorstring

For a failed step, or one waiting to be retried, its last error.

notesobject[]

The lines written for people to read (wf.note, job.note), in order.

labelstring

The few words the step was started with.

detachedboolean

The step is waiting on a link.

flowobject

For a run: parked is true while it waits, with no worker holding it, and awaiting names the signals it waits for.

nextNinteger

Set when this node's children were cut to fit: ask for ?from_n= this number to read the rest.

moreinteger

With nextN: how many of its children were cut.

A tree holds at most 20,000 nodes, 14 MiB, and 16 levels of runs. From emit 0.6, ?limit= reads a page of at most that many nodes (up to 500): the run's nextN says where the next page starts, so ask again with ?from_n= that number until there's no nextN. A child run cut by the page has its own nextN: page it by its own id. If the run starts over (flow.gen changes) while you page, start again from the beginning.

To follow a run as it changes, add ?tree=true to Follow a job: each message is then the whole tree, sent again whenever any node in it changes. Someone following with a follow token sees names, statuses, progress and notes, but no inputs, results, errors or labels.

Cancel a run

POST /v1/spaces/{space}/jobs:cancel · scope admin

With "tree": true, cancels each run and everything it started, all the way down: steps, child workflows and their steps, and steps it enqueued.

Shell
curl -s "$EMIT_URL/v1/spaces/accounts/jobs:cancel" \
  -H "Authorization: Bearer $EMIT_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"ids": ["01M3QSR386017JCY0DC11GTG7D"], "tree": true}'

Without tree, the run and the steps it started are cancelled, and steps it enqueued go on.