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

# List Workflow Runs

> List workflow runs with page-number pagination or reliable completed-run cursor discovery.

Use cursor mode for integrations that must discover every completed run, including runs that finish long after they were created. If you omit `pagination=cursor`, the endpoint preserves its existing page-number response and `created_at DESC` order.

## Authentication and scope

Cursor mode requires both `workspaces-read` and `workflows-read`. The token owner must be an administrator of the workflow workspace.

## Cursor mode request

<ParamField query="pagination" type="string" required>
  Set to `cursor`.
</ParamField>

<ParamField query="status" type="string" required>
  Set to `completed`. Other statuses are rejected in cursor mode.
</ParamField>

<ParamField query="created_after" type="string" required>
  RFC 3339 timestamp. The API returns only runs with `created_at` strictly greater than this activation boundary.
</ParamField>

<ParamField query="cursor" type="string">
  Opaque checkpoint from the previous response's `meta.next_cursor`. Do not decode or modify it.
</ParamField>

<ParamField query="per_page" type="integer" default="100">
  Number of runs to return, from 1 to 100.
</ParamField>

```bash theme={null}
curl --get "https://api.raydocs.com/workspaces/12/workflows/7d3a20e1-1e99-4eb0-9ab7-39ee5028caf4/runs" \
  --header "Authorization: Bearer $RAYDOCS_API_TOKEN" \
  --data-urlencode "pagination=cursor" \
  --data-urlencode "status=completed" \
  --data-urlencode "created_after=2026-07-21T10:00:00.000Z" \
  --data-urlencode "per_page=100"
```

## Cursor mode response

Cursor mode always excludes debug runs and incomplete runs. Results use the stable order `completed_at ASC, id ASC`. The API holds back the current open second so no run can complete later behind an emitted checkpoint.

```json theme={null}
{
  "data": [
    {
      "id": "75058f1e-f44e-46de-93f2-8c6889663be3",
      "workflow_id": "7d3a20e1-1e99-4eb0-9ab7-39ee5028caf4",
      "status": "completed",
      "completed_at": "2026-07-21T12:34:55.000000Z",
      "created_at": "2026-07-21T10:05:00.000000Z"
    }
  ],
  "meta": {
    "server_time": "2026-07-21T12:34:55Z",
    "next_cursor": "eyJjb21wbGV0ZWRfYXQiOi4uLn0",
    "has_more": false
  }
}
```

`next_cursor` is a durable checkpoint, including when `has_more` is `false`. Store it only after you have durably recorded every run on the page. The cursor contains the last `(completed_at, id)` position, encrypted and signed by the API.

Results advance strictly in `completed_at ASC, id ASC` order. Runs created after activation remain eligible until they complete, so a slow run appears on a later poll when its completion time moves beyond the stored checkpoint. Use only `next_cursor` as the client checkpoint and keep `workflow_id:run_id:documentId` as an idempotency key for client retries.

<Warning>
  Keep `created_after` fixed to the workflow activation time. Direct activation boundaries are locked by the first cursor. Do not replace the boundary with the last run's creation or completion time.
</Warning>

## Activate without downloading history

1. Send a bootstrap cursor request with `created_after=1970-01-01T00:00:00Z` and ignore its `data`.
2. Store `meta.server_time` as the workflow's immutable `enabled_at` value.
3. Store `meta.next_cursor` as the initial checkpoint.
4. Use `created_after=enabled_at` and the stored cursor for every later poll. The cursor accepts this one forward movement from the bootstrap boundary and skips the rest of the ignored history.
5. Follow pages while `has_more=true`.

The API chooses a conservative closed whole-second `server_time` before executing the bootstrap query. A run created before `enabled_at` stays excluded even if it finishes later. A run created after `enabled_at` remains eligible and appears when its status becomes `completed`, regardless of how long it takes.

## Page-number compatibility

When `pagination` is omitted, the endpoint keeps the existing behavior:

* page-number pagination with 30 runs per page by default
* newest `created_at` first
* optional status filter
* optional `include_debug=1`
* existing Laravel pagination metadata

Cursor-only fields do not appear in the page-number response.


## OpenAPI

````yaml get /workspaces/{workspaceId}/workflows/{workflowId}/runs
openapi: 3.0.1
info:
  title: Raydocs API
  description: REST API for document extraction with AI-powered data parsing
  version: 1.0.0
servers:
  - url: https://api.raydocs.com
security:
  - bearerAuth: []
tags:
  - name: Workspaces
    description: Create and manage workspaces.
  - name: Workspace Users
    description: Manage users within a workspace.
  - name: Extraction Templates
    description: Define extraction schemas and settings.
  - name: Extraction Sessions
    description: Manage extraction jobs and documents.
  - name: Batch Operations
    description: Bulk operations on sessions.
  - name: Documents
    description: Upload and manage source documents.
  - name: Workflows
    description: Discover workflow runs and read their public outputs.
  - name: Results
    description: Access extraction results.
paths:
  /workspaces/{workspaceId}/workflows/{workflowId}/runs:
    get:
      tags:
        - Workflows
      summary: List Workflow Runs
      description: >-
        List workflow runs. Omit `pagination` for the existing page-number mode,
        or set `pagination=cursor` for reliable completed-run discovery. Cursor
        mode requires `workspaces-read` and `workflows-read`.
      operationId: listWorkflowRuns
      parameters:
        - name: workspaceId
          in: path
          required: true
          schema:
            type: integer
        - name: workflowId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: pagination
          in: query
          description: >-
            Set to `cursor` to activate cursor mode. Omit it to preserve
            page-number pagination.
          schema:
            type: string
            enum:
              - cursor
        - name: page
          in: query
          description: >-
            Page number in the existing page-number mode. Ignored in cursor
            mode.
          schema:
            type: integer
            minimum: 1
        - name: status
          in: query
          description: >-
            Required as `completed` in cursor mode. Other supported statuses
            remain available in page-number mode.
          schema:
            type: string
            enum:
              - pending
              - running
              - paused
              - completed
              - failed
              - cancelled
        - name: created_after
          in: query
          description: >-
            Required RFC 3339 activation boundary in cursor mode. Only runs with
            `created_at` strictly after this value are returned. It is immutable
            after the first cursor, except for the documented one-time
            transition from the epoch bootstrap boundary.
          schema:
            type: string
            format: date-time
        - name: cursor
          in: query
          description: >-
            Opaque checkpoint returned in `meta.next_cursor`. Do not decode or
            modify it.
          schema:
            type: string
        - name: include_debug
          in: query
          description: >-
            Include internal debug runs in page-number mode. Cursor mode always
            excludes them.
          schema:
            type: boolean
        - name: per_page
          in: query
          description: >-
            Number of runs per page. Defaults to 30 in page-number mode and 100
            in cursor mode.
          schema:
            type: integer
            minimum: 1
            maximum: 100
      responses:
        '200':
          description: Workflow runs
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/WorkflowRunCursorPage'
                  - $ref: '#/components/schemas/WorkflowRunOffsetPage'
        '403':
          description: Forbidden
        '404':
          description: Workflow does not belong to the route workspace
        '422':
          description: Invalid cursor-mode parameters
components:
  schemas:
    WorkflowRunCursorPage:
      type: object
      required:
        - data
        - meta
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/WorkflowRunListItem'
        meta:
          type: object
          required:
            - server_time
            - next_cursor
            - has_more
          properties:
            server_time:
              type: string
              format: date-time
              description: >-
                Closed whole-second watermark selected before the query
                executes.
            next_cursor:
              type: string
              description: >-
                Opaque durable checkpoint. Store it only after the page is
                durable.
            has_more:
              type: boolean
              description: True when another page is currently available.
    WorkflowRunOffsetPage:
      type: object
      required:
        - data
        - meta
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/WorkflowRunListItem'
        meta:
          allOf:
            - $ref: '#/components/schemas/PaginationMeta'
            - type: object
              required:
                - current_page
                - last_page
                - per_page
                - total
    WorkflowRunListItem:
      type: object
      required:
        - id
        - workflow_id
        - status
        - created_at
      properties:
        id:
          type: string
          format: uuid
        workflow_id:
          type: string
          format: uuid
        workflow_version_id:
          type: string
          format: uuid
          nullable: true
        trigger_node_id:
          type: string
          nullable: true
        trigger_type:
          type: string
          nullable: true
        status:
          type: string
          enum:
            - pending
            - running
            - paused
            - completed
            - failed
            - cancelled
        completed_at:
          type: string
          format: date-time
          nullable: true
        created_at:
          type: string
          format: date-time
    PaginationMeta:
      type: object
      properties:
        current_page:
          type: integer
        last_page:
          type: integer
        per_page:
          type: integer
        total:
          type: integer
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >
        Personal Access Token created from the Raydocs dashboard.

        Include in the Authorization header: `Bearer <your_token>`

        See [API Keys](/api-reference/api-keys) for token creation and
        management.

````