> ## Documentation Index
> Fetch the complete documentation index at: https://formbricks.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Retrieve a workflow run

> Returns one workflow run by globally unique run id, including the full debug payload: the
captured `triggerPayload`, the run `data` (per-step results), the persisted `logs` trace,
and retry metadata (`attempt`, `nextAttemptAt`, `lastErrorAt`). Scope 1 deliberately exposes
these as JSON dumps so users and agents can understand exactly what happened in a run.

Poll this endpoint after `POST /api/v3/workflows/{workflowId}/test`: runs execute
asynchronously and transition `queued` → `running` → `completed`/`failed`/`canceled`.

Unknown or inaccessible run ids return `403` rather than `404` to avoid leaking
cross-workspace resource existence.




## OpenAPI

````yaml /api-v3-reference/openapi.yml get /api/v3/workflows/runs/{runId}
openapi: 3.1.1
info:
  title: Formbricks API v3
  description: >
    **Surveys**: **GET /api/v3/surveys**, **POST /api/v3/surveys**, **POST
    /api/v3/surveys/generate**, **POST /api/v3/surveys/validate**, **GET
    /api/v3/surveys/{surveyId}**, **PATCH /api/v3/surveys/{surveyId}**, and
    **DELETE /api/v3/surveys/{surveyId}**.


    **Workflows extension**: **GET /api/v3/workflows**, **POST
    /api/v3/workflows**, **GET /api/v3/workflows/{workflowId}**, **PATCH
    /api/v3/workflows/{workflowId}**, **DELETE /api/v3/workflows/{workflowId}**,
    **POST /api/v3/workflows/{workflowId}/duplicate**, **POST
    /api/v3/workflows/{workflowId}/enable**, **POST
    /api/v3/workflows/{workflowId}/disable**, **POST
    /api/v3/workflows/{workflowId}/archive**, **POST
    /api/v3/workflows/{workflowId}/unarchive**, **POST
    /api/v3/workflows/{workflowId}/test**, **GET /api/v3/workflows/runs**, and
    **GET /api/v3/workflows/runs/{runId}**.


    Authenticate all management endpoints with **session cookie** or
    **`x-api-key`** (management key with access to the workspace).


    **Spec location:** source of truth is the multi-file tree at
    `docs/api-v3-reference/src/` (root `openapi.yml` plus one file per path and
    component); `docs/api-v3-reference/openapi.yml` is the generated single-file
    bundle (alongside v2 at `docs/api-v2-reference/openapi.yml`).


    **workspaceId**

    `workspaceId` is the canonical container identifier for this API. It is a
    **required query parameter on collection read endpoints** (`GET
    /api/v3/surveys`, `GET /api/v3/action-classes`, `GET
    /api/v3/contact-attribute-keys`) because those operate within a workspace.
    **`POST /api/v3/surveys` instead requires `workspaceId` in the request
    body**, not as a query parameter. Single-resource endpoints
    (`GET`/`PATCH`/`DELETE /api/v3/surveys/{surveyId}`) locate the resource by
    its globally-unique id and resolve the workspace from it, so they do **not**
    accept a `workspaceId` query parameter — sending one returns **400**
    (`Unrecognized key: "workspaceId"`).


    **Auth**

    Authenticate with either a session cookie or **`x-api-key`**. In dual-auth
    mode, V3 checks the API key first when the header is present, otherwise it
    uses the session path. Unauthenticated callers get **401** before query
    validation.


    **Pagination**

    Cursor-based pagination with **limit** + opaque **cursor** token. Responses
    return `meta.nextCursor`; pass that value back as `cursor` to fetch the next
    page. Survey list responses also include `meta.totalCount`, the total number
    of surveys matching the current filters across all pages. Workflow list
    responses do not require total counts in Scope 1. There is no `offset` in
    this contract.


    **Filtering**

    Filters use explicit operator-style query parameters under the
    **`filter[...]` family**. The survey list supports `filter[name][contains]`,
    `filter[status][in]`, and `filter[type][in]`. The workflow list supports
    `filter[name][contains]` and `filter[status][in]`; the workflow run list
    supports `filter[status][in]` and `filter[isDryRun][eq]`. Resource-scoping
    identifiers (`workspaceId`, `workflowId`, `responseId`) stay plain query
    parameters. Multi-value filters use repeated keys or comma-separated values
    (e.g. `filter[status][in]=draft&filter[status][in]=inProgress` or
    `filter[status][in]=draft,inProgress`). Sorting remains a flat `sortBy`
    query parameter.


    **Security**

    Missing/forbidden workspace returns **403** with a generic message (not
    **404**) so resource existence is not leaked. Workflow and workflow-run
    detail endpoints also return **403** for unknown IDs or inaccessible IDs to
    avoid IDOR leaks. List responses use `private, no-store`.


    **AI survey creation**

    `POST /api/v3/surveys/generate` returns a draft `POST /api/v3/surveys`
    payload plus validation metadata. It does not create a survey. It generates
    survey content for both `link` and `app` surveys; for `app` it seeds a
    default `distribution` (display once, no triggers, no targeting) that you
    finish configuring before publishing.

    Prompt text is sent to the configured AI provider for generation, but it is
    not stored by this endpoint, not logged by default, and not included in
    audit data.


    **Feedback Records** `/api/v3/feedbackRecords` is served by the **API
    gateway** (Envoy on Formbricks Cloud, Traefik in the one-click Docker
    install), which authorizes each call against the dataset and forwards it to
    the feedback store — not by the application routes that serve the rest of
    v3. Three consequences: the payload is the store's own, so members and
    filters are **`snake_case`** (`tenant_id`, `value_text`) rather than v3's
    camelCase; the dataset is named **`tenant_id`** on the wire and is required
    on every collection operation (it is the feedback dataset id, which the MCP
    `list_feedback_datasets` tool reports as `dataset_id`); and errors come in
    two shapes — gateway refusals (**400**, **401**, **403**, **413**, **503**)
    are `text/plain`, while the store's own problems are
    `application/problem+json` with a stable `code`. These eight operations are
    the whole of the gateway-served surface; any other path it receives under
    the prefix answers **400**. Authenticate with **`x-api-key`**: the key needs
    a permission on a workspace the dataset is assigned to — `read` to list, get
    and search, `write` to create and update, `manage` to delete — and may
    update or delete only in a dataset assigned to exactly one workspace.

    **OpenAPI**

    This spec is **not** produced by `pnpm generate-api-specs` (that script only
    builds v2 → `docs/api-v2-reference/openapi.yml`). When the route contract
    changes, edit the files under `docs/api-v3-reference/src/`, then run `pnpm
    api:v3:bundle` to regenerate the committed single-file bundle. `pnpm
    api:v3:lint` lints the source tree; `pnpm api:v3:check` (CI) fails when the
    bundle is stale.


    **Workflows Scope 1**

    Workflows are a follow-up extension of the existing v3 Survey API work. The
    Survey API establishes API-first survey authoring; Workflows build on that
    same v3 style to automate actions around survey responses through
    workspace-scoped JSON definitions. Scope 1 models the existing Follow-ups
    capability as workflows: one `response.completed` trigger with an optional
    `endingCardIds` filter, and `send_email` actions with Follow-up email field
    parity. The definition and run shapes mirror the shared Zod schemas in
    `packages/workflows` (ENG-1100), which are the implementation source of
    truth for this contract.


    Workflows use `draft`, `enabled`, and `disabled` lifecycle states plus an
    `archived` soft-delete state. Status only changes through the lifecycle
    endpoints (`enable`, `disable`, `archive`, `unarchive`); it is not writable
    via `POST` or `PATCH`. Enabling validates that the definition is executable
    and snapshots an immutable workflow version; runs reference that snapshot
    via `workflowVersionId`. `POST .../test` is a dry run: it validates the
    definition and resolves the trigger's references synchronously, creating no
    run and sending no email, and returns `{ workflowId, ok, problems }`
    directly. Real runs execute asynchronously and are polled via `GET
    /api/v3/workflows/runs/{runId}`.


    **Overview migration note**

    The v3-backed survey overview page intentionally removes actions that are
    not yet exposed by this contract: `Created by` filtering, `Duplicate`,
    `Copy...`, `Preview`, and `Copy link`.


    **Next steps (out of scope for this spec)**

    Additional v3 survey update endpoints, optional ETag/304, field selection,
    translation-specific writes, and survey version history.
  version: 0.1.0
  x-implementation-notes:
    route: apps/web/app/api/v3/surveys/route.ts
    generate-route: apps/web/app/api/v3/surveys/generate/route.ts
    query-parser: apps/web/app/api/v3/surveys/parse-v3-surveys-list-query.ts
    auth: apps/web/app/api/v3/lib/auth.ts
    workspace-resolution: apps/web/app/api/v3/lib/workspace-context.ts
    workflow-contract-ticket: ENG-1101
    workflow-shared-schemas: packages/workflows/src/types (feat/workflows-types)
    workflow-prisma-schema: packages/database/schema/workflows.prisma (feat/workflows-prisma-schema)
    openapi-generated: false
    spec-source: docs/api-v3-reference/src (regenerate bundle with `pnpm api:v3:bundle`)
    pagination-model: cursor
    cursor-pagination: supported
servers:
  - url: https://app.formbricks.com
    description: >-
      Formbricks Cloud. Paths in this spec already include the `/api/v3` prefix;
      self-hosted instances substitute their own origin.
security: []
paths:
  /api/v3/workflows/runs/{runId}:
    get:
      tags:
        - V3 Workflows
      summary: Retrieve a workflow run
      description: >
        Returns one workflow run by globally unique run id, including the full
        debug payload: the

        captured `triggerPayload`, the run `data` (per-step results), the
        persisted `logs` trace,

        and retry metadata (`attempt`, `nextAttemptAt`, `lastErrorAt`). Scope 1
        deliberately exposes

        these as JSON dumps so users and agents can understand exactly what
        happened in a run.


        Poll this endpoint after `POST /api/v3/workflows/{workflowId}/test`:
        runs execute

        asynchronously and transition `queued` → `running` →
        `completed`/`failed`/`canceled`.


        Unknown or inaccessible run ids return `403` rather than `404` to avoid
        leaking

        cross-workspace resource existence.
      operationId: getWorkflowRunV3
      parameters:
        - $ref: '#/components/parameters/WorkflowRunIdPath'
      responses:
        '200':
          description: Workflow run retrieved successfully
          headers:
            X-Request-Id:
              schema:
                type: string
              description: Request correlation ID
            Cache-Control:
              schema:
                type: string
              example: private, no-store
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                properties:
                  data:
                    $ref: '#/components/schemas/WorkflowRunResource'
        '400':
          $ref: '#/components/responses/V3BadRequest'
        '401':
          $ref: '#/components/responses/V3Unauthorized'
        '403':
          $ref: '#/components/responses/V3Forbidden'
        '429':
          $ref: '#/components/responses/V3TooManyRequests'
        '500':
          $ref: '#/components/responses/V3InternalServerError'
      security:
        - sessionAuth: []
        - apiKeyAuth: []
components:
  parameters:
    WorkflowRunIdPath:
      in: path
      name: runId
      required: true
      schema:
        type: string
        format: cuid2
      description: Workflow run identifier.
  schemas:
    WorkflowRunResource:
      description: >
        Full run shape returned by `GET /api/v3/workflows/runs/{runId}` and

        `POST /api/v3/workflows/{workflowId}/test`: the summary fields plus the
        captured trigger

        payload, per-step results, the persisted log trace, and
        retry/idempotency metadata.
      allOf:
        - $ref: '#/components/schemas/WorkflowRunSummary'
        - type: object
          required:
            - triggerPayload
            - data
            - logs
            - idempotencyKey
            - nextAttemptAt
            - lastErrorAt
          properties:
            triggerPayload:
              $ref: '#/components/schemas/WorkflowTriggerPayload'
            data:
              $ref: '#/components/schemas/WorkflowRunData'
            logs:
              type: array
              items:
                $ref: '#/components/schemas/WorkflowRunLog'
              description: >-
                Persisted step-by-step trace, ordered by `sequence`. Empty while
                the run is still `queued`.
            idempotencyKey:
              type:
                - string
                - 'null'
              description: >-
                Deduplication key for this run, unique per workflow. Set from
                the `Idempotency-Key` header on dry runs or from trigger-event
                deduplication.
            nextAttemptAt:
              type:
                - string
                - 'null'
              format: date-time
              description: >-
                When the next retry attempt is scheduled. `null` when no retry
                is pending.
            lastErrorAt:
              type:
                - string
                - 'null'
              format: date-time
    WorkflowRunSummary:
      type: object
      description: >
        Slim run shape embedded as `lastRun` in workflow resources. The runs
        list (`GET /api/v3/workflows/runs`)

        returns `WorkflowRunListItem`, which extends this with `workflowName`.
        Excludes `triggerPayload`, `data`, and `logs`.
      required:
        - id
        - workflowId
        - workspaceId
        - workflowVersionId
        - status
        - isDryRun
        - triggerType
        - surveyId
        - responseId
        - error
        - attempt
        - createdAt
        - updatedAt
        - startedAt
        - finishedAt
      properties:
        id:
          type: string
          format: cuid2
        workflowId:
          type: string
          format: cuid2
        workspaceId:
          type: string
          format: cuid2
        workflowVersionId:
          type:
            - string
            - 'null'
          format: cuid2
          description: >
            Immutable workflow version snapshot the run executes against. `null`
            for dry runs of

            workflows that have never been enabled. Version contents are not
            readable through the

            v3 API in Scope 1.
        status:
          $ref: '#/components/schemas/WorkflowRunStatus'
        isDryRun:
          type: boolean
          description: >-
            `true` for runs created by `POST
            /api/v3/workflows/{workflowId}/test`.
        triggerType:
          type: string
          enum:
            - response.completed
        surveyId:
          type:
            - string
            - 'null'
          format: cuid2
        responseId:
          type:
            - string
            - 'null'
          format: cuid2
          description: >-
            Survey response that triggered the run. `null` for synthesized
            dry-run data or when the response was deleted.
        error:
          type:
            - string
            - 'null'
          description: >-
            Terminal or most recent failure reason. `null` while the run is
            healthy.
        attempt:
          type: integer
          minimum: 0
          description: >-
            Retry attempt counter. `0` on the first execution; retries increment
            it without changing `status`.
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        startedAt:
          type:
            - string
            - 'null'
          format: date-time
        finishedAt:
          type:
            - string
            - 'null'
          format: date-time
    WorkflowTriggerPayload:
      type: object
      description: |
        Trigger payload snapshot captured when a run is created, mirroring
        `ZWorkflowTriggerRunPayload`. Additional runner keys may be present.
      required:
        - type
        - workspaceId
        - surveyId
        - responseId
        - triggeredAt
      properties:
        type:
          type: string
          enum:
            - response.completed
        workspaceId:
          type: string
          format: cuid2
        surveyId:
          type: string
          format: cuid2
        responseId:
          type: string
          format: cuid2
          description: >-
            For dry runs without a `responseId` input, this references the
            synthesized sample response.
        endingCardId:
          type: string
          format: cuid2
          description: >-
            Ending card the respondent reached, when the survey uses ending
            cards.
        data:
          type: object
          description: Response data snapshot used by the runner.
        triggeredAt:
          type: string
          format: date-time
      additionalProperties: true
    WorkflowRunData:
      type: object
      description: >
        Run execution data persisted with the run, mirroring `ZWorkflowRunData`.
        Scope 1 exposes

        this as a debug-oriented JSON dump. Additional runner keys may be
        present.
      required:
        - steps
      properties:
        trigger:
          allOf:
            - $ref: '#/components/schemas/WorkflowTriggerPayload'
          description: >-
            Optional duplicate of the trigger payload snapshot kept inside the
            run data document.
        steps:
          type: array
          items:
            $ref: '#/components/schemas/WorkflowRunStepResult'
      additionalProperties: true
    WorkflowRunLog:
      type: object
      description: >-
        Persisted trace entry for one workflow run step, mirroring the
        `WorkflowRunLog` table row.
      required:
        - id
        - runId
        - sequence
        - stepId
        - stepType
        - status
        - input
        - output
        - error
        - startedAt
        - finishedAt
      properties:
        id:
          type: string
          format: cuid2
        runId:
          type: string
          format: cuid2
        sequence:
          type: integer
          minimum: 0
          description: Order of the entry within the run.
        stepId:
          type: string
          minLength: 1
        stepType:
          type: string
          minLength: 1
        status:
          $ref: '#/components/schemas/WorkflowRunLogStatus'
        input:
          type: object
          description: Step input snapshot. Empty object when nothing was recorded.
        output:
          type: object
          description: >-
            Step output snapshot (mocked for dry runs). Empty object when
            nothing was recorded.
        error:
          type:
            - string
            - 'null'
        startedAt:
          type:
            - string
            - 'null'
          format: date-time
        finishedAt:
          type:
            - string
            - 'null'
          format: date-time
      additionalProperties: false
    Problem:
      type: object
      description: >-
        RFC 9457 Problem Details for HTTP APIs (`application/problem+json`).
        Responses typically include a machine-readable `code` field alongside
        `title`, `status`, `detail`, and `requestId`.
      required:
        - title
        - status
        - detail
        - requestId
      properties:
        type:
          type: string
          format: uri
        title:
          type: string
        status:
          type: integer
        detail:
          type: string
        instance:
          type: string
        code:
          type: string
          enum:
            - ai_features_not_enabled
            - ai_generated_payload_invalid
            - ai_instance_not_configured
            - ai_output_too_long
            - ai_smart_tools_disabled
            - bad_gateway
            - bad_request
            - conflict
            - forbidden
            - internal_server_error
            - invalid_workflow_state
            - not_authenticated
            - not_found
            - payload_too_large
            - service_unavailable
            - too_many_requests
            - unprocessable_content
            - workflow_not_executable
        requestId:
          type: string
        details:
          type: object
        invalid_params:
          type: array
          items:
            $ref: '#/components/schemas/InvalidParam'
    WorkflowRunStatus:
      type: string
      enum:
        - queued
        - running
        - completed
        - failed
        - canceled
      description: >
        Workflow run lifecycle state. `completed`, `failed`, and `canceled` are
        terminal. Valid

        transitions: `queued` → `running`, `running` → `queued` (retry/backoff),
        `queued` →

        `canceled`, and `running` → `completed`/`failed`/`canceled`. Retries do
        not introduce a

        separate status; retry state is exposed via `attempt` and
        `nextAttemptAt`.
    WorkflowRunStepResult:
      type: object
      description: >-
        In-document result for one workflow step, mirroring
        `ZWorkflowStepResult`.
      required:
        - stepId
        - stepType
        - status
      properties:
        stepId:
          type: string
          minLength: 1
          description: Node id of the executed step.
        stepType:
          type: string
          minLength: 1
          description: Node/step type, e.g. `response.completed` or `send_email`.
        status:
          $ref: '#/components/schemas/WorkflowRunLogStatus'
        input:
          type: object
          description: Step input snapshot.
        output:
          type: object
          description: Step output snapshot, or the mocked output for dry runs.
        error:
          type: string
        startedAt:
          type: string
          format: date-time
        finishedAt:
          type: string
          format: date-time
      additionalProperties: false
    WorkflowRunLogStatus:
      type: string
      enum:
        - pending
        - running
        - succeeded
        - failed
        - skipped
      description: Status of one executed (or skipped) workflow step within a run.
    InvalidParam:
      type: object
      description: >
        Field-level validation error. `name` and `reason` are always intended
        for humans.

        Optional machine-readable fields are included when the API can identify
        the semantic error,

        especially for survey locale, identifier, and reference validation used
        by MCP and agent clients.
      required:
        - name
        - reason
      properties:
        name:
          type: string
          description: Dot-path to the invalid request field.
        reason:
          type: string
          description: Human-readable repair guidance.
        code:
          type: string
          enum:
            - dangling_reference
            - duplicate_identifier
            - duplicate_locale
            - forbidden_identifier
            - immutable_identifier
            - invalid_graph
            - invalid_locale
            - invalid_reference
            - missing_required_field
            - missing_translation
            - unsupported_field
            - unsupported_locale
          description: >
            Machine-readable validation category, when available.
            `invalid_graph` covers workflow

            graph-structure violations such as a duplicated trigger edge, an
            unreachable node, or a

            cycle.
        identifier:
          type: string
          description: >-
            Identifier involved in the validation failure, when available. For
            language errors, this can be the normalized language code.
        referenceType:
          type: string
          enum:
            - block
            - element
            - ending
            - hiddenField
            - language
            - variable
            - variableName
            - recall
            - node
            - edge
            - survey
            - endingCard
          description: >-
            Identifier namespace involved in the validation failure. `node`,
            `edge`, `survey`, and `endingCard` are used by workflow validation.
        missingId:
          type: string
          description: Referenced id that does not exist in the submitted survey document.
        firstUsedAt:
          type: string
          description: Dot-path where a duplicate identifier was first used.
        conflictsWith:
          type: string
          description: Dot-path to the existing identifier that conflicts with this field.
      additionalProperties: false
  responses:
    V3BadRequest:
      description: >-
        Bad Request — malformed JSON, invalid query/body/params, duplicate name,
        or unsupported field.
      headers:
        X-Request-Id:
          schema:
            type: string
          description: Request correlation ID
        Cache-Control:
          schema:
            type: string
          example: private, no-store
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    V3Unauthorized:
      description: Not authenticated (no valid session or API key).
      headers:
        X-Request-Id:
          schema:
            type: string
          description: Request correlation ID
        Cache-Control:
          schema:
            type: string
          example: private, no-store
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    V3Forbidden:
      description: >-
        Forbidden — no workspace access, or resource does not exist (404 not
        used; avoids existence leak).
      headers:
        X-Request-Id:
          schema:
            type: string
          description: Request correlation ID
        Cache-Control:
          schema:
            type: string
          example: private, no-store
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    V3TooManyRequests:
      description: Rate limit exceeded.
      headers:
        X-Request-Id:
          schema:
            type: string
          description: Request correlation ID
        Cache-Control:
          schema:
            type: string
          example: private, no-store
        Retry-After:
          schema:
            type: integer
          description: Seconds until the current rate-limit window resets.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    V3InternalServerError:
      description: Internal Server Error.
      headers:
        X-Request-Id:
          schema:
            type: string
          description: Request correlation ID
        Cache-Control:
          schema:
            type: string
          example: private, no-store
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
  securitySchemes:
    sessionAuth:
      type: apiKey
      in: cookie
      name: next-auth.session-token
      description: >
        NextAuth session JWT cookie. **Development:** often
        `next-auth.session-token`.

        **Production (HTTPS):** often `__Secure-next-auth.session-token`. Send
        the cookie your browser receives after sign-in.
    apiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: >
        Management API key; must include **workspaceId** as an allowed workspace
        with read, write, or manage permission.

````