https://api.infery.ai and takes the same
Authorization: Bearer <key> header as the rest of the API.
Run a definition
curl
Send an
Idempotency-Key header to make a retry safe: a second request carrying a key this
workspace has already used returns the original run instead of starting a new one.
For mode: "stream" that replay only applies once the original run has finished. Retry a
key while its run is still going and you get 409 idempotency_in_progress — handle it as
“the first attempt is still alive”, not as a failure to retry.
Missing or wrongly-typed run inputs are reported all at once with the code
invalid_pipeline_input, before anything is executed or charged.
Resuming a failed run
A run that fails half way has still paid for the steps that ran.resume_from_run_id lets you
keep that work: send the failed run’s id, and every step it recorded as succeeded is reused
instead of dispatched. Only the step that failed — and everything downstream of it — runs again,
and a reused step costs nothing.
definition (or pipeline_id) to fix the step that failed — swap the model, change the
params, replace the step. Send neither and the run is resumed against the definition it originally
executed.
What gets re-run is decided by the binding graph: editing a step re-runs that step and everything
that reads it, directly or through a | fallback alternative. A step whose result was never
recorded — including one whose record was lost — simply runs again rather than being assumed
complete.
The reused steps appear in the resumed run as
status: "succeeded" with
skippedReason: "resumed_from_prior_attempt" and creditsUsed: 0 — this run’s result includes
them, and this run did not produce them. That also means a resumed run can itself be resumed.Re-running part of a workflow that already ran
resume_from_run_id answers it broke. rerun_from_step_id, sent alongside it, answers I want a
different result from here on — you changed a prompt, a model or a parameter and want the
consequences recomputed without paying again for the work upstream of the change.
summarise that does not read it
(directly or through another step) could not have produced a different result, so it is neither
re-run nor re-billed. Independent steps also execute concurrently, so “later” is not a well-defined
ordering to bill by in the first place.
Two ways it differs from a bare resume:
- The run may be in any finished state — succeeded, failed or cancelled — not only failed.
- An edit to a step that already produced a result is not refused. A bare resume answers
resume_upstream_definition_changed; here that step and everything below it simply join the set that runs again, and the hold covers the wider set. Editing a step is the reason for the request.
resume_input_changed, resume_artifact_expired and resume_source_definition_unknown apply here
too.
Modes
sync (default)
Blocks until the run finishes, then returns the whole run.
queued, running, succeeded, failed or cancelled.
Each entry of stepRuns carries id, type, status (pending, running, succeeded,
failed, skipped or cancelled), creditsUsed, durationMs, attempt, and — where
they apply — output, outputRef, error, skippedReason and childRunIds.
stream
Returns text/event-stream. Each event is a named SSE event whose data is JSON; the
stream ends with data: [DONE]. Comment lines (: ping) keep the connection alive when a
step is slow.
async
Enqueues the run and returns immediately:
GET /v1/workflows/runs/{id} for the result, or subscribe a
notification channel to the run events. There is no per-run
webhook field — delivery is configured per workspace, and a channel can be scoped to a
single workflow.
Terminal notifications for a run may arrive out of order, and a run may send more than
one: a run reaped as failed whose worker then finishes sends a second, corrected event. For
a given
metadata.runId, a terminal event carrying metadata.correctsPriorStatus
supersedes any that does not, whatever the arrival order. Once you have applied a
correction, discard later terminal events for that run that lack the field.Estimating a run
POST /v1/workflows/estimate prices a definition without executing it. No credits are
held, nothing is persisted.
In the workflow editor the same estimate sits in the run bar and updates as you edit, so you
see what a change costs before you commit to it.


The run bar: what this workflow would cost, and the button that spends it
(canvas) means it priced what is on screen —
your unsaved edits included, not the published version.
curl
definition or pipeline_id; pipeline_version is required
alongside pipeline_id. Anything else is refused with invalid_estimate_request. The
optional input improves the estimate wherever it lets a binding resolve.
step_id, type, min_credits and max_credits, and sometimes a
note explaining a spread. Container entries nest: a parallel entry carries branches, a
foreach entry carries body_steps (each priced for one iteration) plus
max_iterations and items_known, and a sub_pipeline entry carries child_breakdown.
Storing a workflow
Body fields other than
definition are not validated as a shape. definition is parsed
strictly and refuses anything it does not recognise, but name, description and mode are
not: name is bounded by the database column at 120 characters — exceeding it surfaces as a
storage error rather than a clean 400 — description has no runtime limit, and an unknown
mode falls through to sync rather than being rejected.Send mode exactly as sync, stream or async. "SYNC" is not the same thing.pipeline_version on a run when you need a definition frozen — sub_pipeline steps
require it for exactly that reason.
What a finished run looks like


A succeeded run: every step's result, cost and duration, still on the canvas
image.pipeline steps ran at the same time. They each read the same
photo and none reads another’s output, so nothing makes them wait — see
independent steps.
Their durations overlap rather than add up.
The banner names the version. A run records the definition it executed, so
opening an old run shows you what actually ran rather than what is published now.
Here they happen to be the same (v1); when they are not, the banner says so, and
saving the canvas publishes a new version rather than rewriting the one the run
used.
Inspecting and stopping a run
The same facts are on the API, for when the canvas is not where you are looking:
Cancellation is best effort. The runner checks for it between steps, so a step already
in flight is not interrupted; what cancelling stops is everything that has not started yet.
Timeouts
There is no run-level deadline.
pipeline_timeout_seconds used to be accepted and silently
ignored — set it and nothing enforced it — so it is now refused outright at save time,
whatever value you give it: bound a run with per-step timeout_seconds instead.