---
title: "Start a job"
method: POST
path: "/api/v2/jobs"
tags: ["jobs"]
---

# Start a job

`POST /api/v2/jobs`

Start a new job against a workflow.

Requires a writer role (MEMBER, ADMIN, or OWNER) in the active
organization; VIEWERs are refused. The job is created in
``IN_PROGRESS`` status. The workflow must exist, not be soft-deleted,
and be visible to the active organization (its own workflows plus system
workflows). Members are further restricted to workflows they own, system
workflows, or workflows assigned to a group they belong to. Members in
the virtual "All workflows" group have unrestricted access.
Omit ``workflow_id`` to start an ad-hoc job (requires the org
to have ad-hoc jobs enabled). Submit step results with
``POST /{id}/steps/{sort_order}`` and finalize with ``POST /{id}/analyse``.

## Request body

- JobCreate — Body for `POST /api/v2/jobs`.
  - `workflow_id` string, nullable — Id of the workflow to run. The job captures the workflow's current steps automatically and will always resolve to those exact steps, even if the workflow is edited later. Omit to start an ad-hoc job with no workflow (requires the org to have ad-hoc jobs enabled); steps are then added via extra-steps.
  - `name` string, nullable — Display name for an ad-hoc job. Ignored when workflow_id is set.

## Response `201`

Successful Response

- JobRead — Full job payload including the latest result per step. `steps` is the workflow's steps as they were at the moment the job was started -- not the current workflow. Clients should render the run UI from this list so edits to the workflow after the job started never change historical runs.
  - `id` string, required — Stable job id.
  - `workflow_id` string, required — Id of the workflow this job is running against.
  - `workflow_name` string, nullable — Display name of the workflow this job runs against. Null when the workflow row is unavailable. Additive convenience field so clients need not resolve the name from workflow_id separately.
  - `user_id` string, required — Id of the user who started the job.
  - `is_adhoc` boolean — True when this job runs against a synthetic ad-hoc workflow (no predefined steps). Clients render the workflow column as an ad-hoc placeholder rather than the synthetic workflow name.
  - `organization_id` string, nullable — Owning organization id. Null for personal jobs.
  - `status` 'in_progress' | 'analysing' | 'completed' | 'completed_with_errors' | 'abandoned', required
  - `result` 'pending' | 'passed' | 'failed' — The pass/fail outcome of a job, distinct from its lifecycle status. Lifecycle (``JobLifecycleStatus``) answers "did the run finish, and did any step technically error?". Result answers "did the run pass its checks?". The two are independent: a run can finish cleanly (``COMPLETED``) yet still ``FAILED`` because too few steps passed for the workflow's pass policy. The pass policy is driven by ``allow_step_failure``: - Off: strict. Any errored or failing step makes the result ``FAILED``. - On: threshold. Failures are tolerated until the percentage of evaluable steps that failed exceeds ``fail_threshold_percent``; errored steps count as failures. - ``PENDING``: not yet determined (job still in progress / analysing). - ``PASSED``: the workflow's pass policy is satisfied. - ``FAILED``: the workflow's pass policy is not satisfied.
  - `started_at` string, date-time, required — When the job was created.
  - `analysing_started_at` string, date-time, nullable — When the job transitioned to ANALYSING. Null while still IN_PROGRESS. Used by the stale-analysis recovery sweep to time out crashed analysis tasks.
  - `completed_at` string, date-time, nullable — When the job was completed. Null while in progress.
  - `steps` WorkflowStepRead[] — The workflow's steps as they were at job start.
    - `id` string, required — Stable id of this step. Useful as a React key on edit forms.
    - `step_key` string, nullable — Stable logical-step identity carried across snapshot versions. Reference files attach to this key, so it round-trips: the editor echoes it back on the step-replace save to keep a step's files. Null on job reads, which never edit steps.
    - `sort_order` integer, required — Zero-based position of this step within the workflow.
    - `name` string, required — Human-readable step title shown to the operator.
    - `workflow_note` string, nullable — Optional guidance shown to the operator before they capture the image.
    - `reference_file_paths` string[], nullable — Optional reference files (blob-storage object paths) shown to the operator and fed to the agent. Populated in workflow contexts; null on the job-read endpoint (GET /jobs/{id}), where only ``reference_file_urls`` is returned.
    - `reference_file_urls` string[], nullable — Short-lived signed download URLs for the step's reference files. Best-effort: paths that fail to sign are omitted, so this is not positionally aligned with the underlying paths. Populated only on terminal-status job reads (when the results page renders its report); null in workflow contexts and on in-progress/analysing job polls.
    - `step_type` 'vision_agent' | 'selection' — Discriminator for a workflow step's strategy. Every registered value has a matching :class:`StepTypeSpec` subclass in :mod:`app.workflow_steps` that owns the strategy's config, input, output, submit payload and handlers. Adding a value here is one of the three edits required to register a new step type; see :mod:`app.workflow_steps.registry` for the full checklist.
    - `step_config` object — Per-type configuration for this step. For ``vision_agent`` the blob carries ``agent_id`` and the agent's structured input parameters. For ``selection`` it carries ``options`` and ``use_selection_as_criteria``. Empty ``{}`` when the type has no configuration.
    - `agent_id` string, nullable — Deprecated. Prefer ``step_type`` + ``step_config``. Mirrored from ``step_config.agent_id`` for vision-agent steps; the selection sentinel is emitted for legacy clients on selection steps.
    - `agent_parameters` object, nullable — Deprecated. Prefer ``step_config``. Mirrored from ``step_config`` with the ``agent_id`` key stripped for vision-agent steps.
    - `pass_criteria` PassCriteria
      - `combinator` 'and' | 'or', required — How to aggregate rule outcomes. ``and`` requires every rule to pass; ``or`` requires at least one.
      - `rules` PassCriteriaRule[], required — One or more rules to evaluate against the agent response.
        - `path` string, required — Dotted path into agent response.
        - `op` 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'contains' | 'not_contains' | 'in' | 'not_in' | 'exists' | 'not_exists' | 'length_gte' | 'length_lt', required
        - `value` unknown
    - `notification_rule` StepNotificationRule — Who to tell about one step's outcome, and when. Attached to the step, so it is pinned to the workflow version the job ran against. Null means the step notifies nobody.
      - `recipient_user_ids` string[] — Ids of users to notify, in addition to the job owner when ``notify_job_owner`` is set. Ids outside the job's organisation are dropped at dispatch time rather than failing the run.
      - `notify_job_owner` boolean — Whether the user who ran the job is notified.
      - `on` 'passed' | 'failed' | 'criteria', required — Step outcome that fires a step-level notification.
      - `criteria` PassCriteria
        - `combinator` 'and' | 'or', required — How to aggregate rule outcomes. ``and`` requires every rule to pass; ``or`` requires at least one.
        - `rules` PassCriteriaRule[], required — One or more rules to evaluate against the agent response.
          - `path` string, required — Dotted path into agent response.
          - `op` 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'contains' | 'not_contains' | 'in' | 'not_in' | 'exists' | 'not_exists' | 'length_gte' | 'length_lt', required
          - `value` unknown
    - `allow_multiple_images` boolean — Whether a capture step accepts more than one image per submission (up to the server-enforced cap). Meaningful only for ``vision_agent`` steps; ignored for ``selection`` steps, which never capture images.
  - `allow_adhoc_step` boolean — Whether ad-hoc steps may be appended to this job via `POST /jobs/{id}/extra-steps`. Mirrors the backing workflow's `allow_adhoc_step`. Clients should gate the add-step UI on this flag rather than fetching the workflow, which is unavailable for hidden ad-hoc workflows.
  - `allow_out_of_order_steps` boolean — When True, steps may be captured in any order. When False, they must be captured in ascending sort_order. Mirrors the backing workflow's `allow_out_of_order_steps` so clients can gate step selection without fetching the workflow.
  - `allow_step_skip` boolean — When True, the job may be finalised (analysed) with steps left uncaptured. When False, every step must be captured first. Mirrors the backing workflow's `allow_step_skip` so clients can relax the Analyse gate without fetching the workflow.
  - `extra_steps` JobExtraStepRead[] — Ad-hoc steps appended to this job via `POST /jobs/{id}/extra-steps`. Empty for jobs started against a workflow with `allow_adhoc_step=false`.
    - `id` string, required — Stable id of this extra step.
    - `sort_order` integer, required — Zero-based position after all workflow steps.
    - `name` string, required — Human-readable name shown to the operator.
    - `workflow_note` string, nullable — Optional guidance copy for the operator.
    - `reference_file_paths` string[], nullable — Optional reference files (blob-storage object paths). Null on the job-read endpoint (GET /jobs/{id}), where only ``reference_file_urls`` is returned.
    - `reference_file_urls` string[], nullable — Short-lived signed download URLs for the step's reference files. Best-effort: paths that fail to sign are omitted, so this is not positionally aligned with the underlying paths. Populated only once the job reaches a terminal status (when the results page renders its report); null on the in-progress/analysing polls.
    - `step_type` 'vision_agent' | 'selection' — Discriminator for a workflow step's strategy. Every registered value has a matching :class:`StepTypeSpec` subclass in :mod:`app.workflow_steps` that owns the strategy's config, input, output, submit payload and handlers. Adding a value here is one of the three edits required to register a new step type; see :mod:`app.workflow_steps.registry` for the full checklist.
    - `step_config` object — Per-type configuration for this step. Empty ``{}`` when the type has none.
    - `agent_id` string, nullable — Deprecated. Mirrored from ``step_config.agent_id`` for vision-agent steps; carries the selection sentinel for legacy selection clients.
    - `agent_parameters` object, nullable — Deprecated. Mirrored from ``step_config`` (with ``agent_id`` stripped for vision-agent steps).
    - `pass_criteria` PassCriteria
      - `combinator` 'and' | 'or', required — How to aggregate rule outcomes. ``and`` requires every rule to pass; ``or`` requires at least one.
      - `rules` PassCriteriaRule[], required — One or more rules to evaluate against the agent response.
        - `path` string, required — Dotted path into agent response.
        - `op` 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'contains' | 'not_contains' | 'in' | 'not_in' | 'exists' | 'not_exists' | 'length_gte' | 'length_lt', required
        - `value` unknown
    - `allow_multiple_images` boolean — Whether this ad-hoc capture step accepts more than one image per submission (up to the server-enforced cap). Meaningful only for ``vision_agent`` steps; ignored for ``selection`` steps, which never capture images.
    - `is_extra` boolean — Always true; lets the UI render ad-hoc chips with a single field check.
  - `step_results` JobStepResultRead[] — Latest result per step (one entry per submitted step).
    - `sort_order` integer, required — Zero-based position of the step in the workflow.
    - `workflow_step_id` string, nullable — Id of the workflow step that this result is for. Null when the result belongs to an ad-hoc extra step added during the job -- `extra_step_id` will be set instead.
    - `extra_step_id` string, nullable — Id of the ad-hoc extra step, if this result is for one.
    - `agent_id` string, nullable — Id of the agent that produced this result. Null for non-agent step types (e.g. an operator-picked selection).
    - `step_input` unknown
    - `step_output` unknown
    - `agent_response` unknown
    - `submitted_at` string, date-time, required — When this (most-recent) result was submitted.
    - `analysis_status` 'pending' | 'running' | 'completed' | 'errored' — Per-step analysis lifecycle for the deferred-analysis flow (VA-415). A capture-only POST creates a step row in `pending`. The background completion task transitions it to `running`, then to `completed` or `errored`. The agent verdict (pass/fail) is a separate field on the same row and is only meaningful when `analysis_status == completed`.
    - `passed` boolean, nullable — Verdict from the step's pass-criteria evaluation. Null when the step is informational (no criteria configured) or has not yet been analysed.
    - `pass_explanation` string, nullable — Human-readable summary of which criteria passed / failed.
    - `error_message` string, nullable — Truncated error message when analysis_status == ERRORED.
    - `image_available` boolean — True when an image was captured for this result and can be fetched via `GET /jobs/{id}/steps/{sort_order}/image-url` (which returns a short-lived signed URL).
    - `capture_batch_index` integer — Zero-based position of this image within its capture batch, defines display order.
    - `capture_batch_id` string, nullable — Id grouping the rows submitted together for one step. Null on legacy rows written before batching existed.
    - `original_filename` string, nullable — Original name of the uploaded file, sanitised to its basename. Null when the client never sent one (e.g. a mobile camera capture).

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.net/tiliter/apis/tiliter-vision-ai-public-api.md) · [All operations](https://skmtc.net/tiliter/apis/tiliter-vision-ai-public-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/tiliter/tiliter-vision-ai-public-api/revisions/eef1814ea815/schema)
