TofuPilotTofuPilot
API Reference (v2)Runs

List and filter runs

Retrieve a paginated list of test runs with filtering by unit, procedure, date range, outcome, and station.

Access

API KeyAccess LevelDescription
UserFullUsers can read runs
StationLimitedStations cannot read runs

Endpoint

GET/v2/runs
AuthorizationBearer <token>

API key for authentication. Use format: Bearer YOUR_API_KEY

In: header

Query Parameters

search_query?string

Search query to filter runs by run ID (partial match) or unit serial number.

ids?array<string>

Filter by specific run IDs.

outcomes?array<string>

Filter by run outcomes.

procedure_ids?array<string>

Filter by procedure IDs.

procedure_versions?array<string>

Filter by procedure versions.

serial_numbers?array<string>

Filter by unit serial numbers.

part_numbers?array<string>

Filter by component part numbers.

revision_numbers?array<string>

Filter by revision identifiers.

batch_numbers?array<string>

Filter by batch numbers.

duration_min?string

Filter for runs with duration greater than or equal to this value (ISO 8601 duration).

Match^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$
Formatduration
duration_max?string

Filter for runs with duration less than or equal to this value (ISO 8601 duration).

Match^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$
Formatduration
started_after?string

Filter for runs started at or after this time.

Match^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
Formatdate-time
started_before?string

Filter for runs started at or before this time.

Match^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
Formatdate-time
ended_after?string

Filter for runs ended at or after this time.

Match^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
Formatdate-time
ended_before?string

Filter for runs ended at or before this time.

Match^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
Formatdate-time
created_after?string

Filter for runs created at or after this time.

Match^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
Formatdate-time
created_before?string

Filter for runs created at or before this time.

Match^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
Formatdate-time
created_by_user_ids?array<string>

Filter by user IDs who created the runs.

created_by_station_ids?array<string>

Filter by station IDs that created the runs.

operated_by_ids?array<string>

Filter by user IDs who operated the runs.

limit?integer

Maximum number of runs to return per page.

Default50
Range1 <= value <= 100
cursor?integer

Offset position for pagination. Use the next_cursor from the previous response to get the next page.

Range-9007199254740991 <= value <= 9007199254740991
sort_by?string

Field to sort results by.

Default"started_at"
Value in"started_at" | "created_at" | "duration" | "outcome" | "serial_number" | "part_number" | "revision_number"
sort_order?string

Sort order direction.

Default"desc"
Value in"asc" | "desc"

Response Body

from tofupilot.v2 import TofuPilot
from datetime import datetime, timedelta, timezone

# Initialize the TofuPilot client
client = TofuPilot()

# Execute the operation
result = client.runs.list(
    limit=20,
    search_query="SN-001234",
    ids=["550e8400-e29b-41d4-a716-446655440000"],
    outcomes=["PASS", "FAIL"],
    procedure_ids=["550e8400-e29b-41d4-a716-446655440000"],
    procedure_versions=["v1.0.0", "v2.0.0"],
    serial_numbers=["SN-001234", "SN-005678"],
    part_numbers=["PCB-V1.2", "PCB-V1.3"],
    revision_numbers=["REV-A", "REV-B"],
    batch_numbers="BATCH-2024-Q1-001,BATCH-2024-Q1-002",
    duration_min="PT5M",
    duration_max="PT30M",
    started_after=datetime.fromisoformat("2024-01-15T10:30:00Z"),
    started_before=datetime.fromisoformat("2024-01-15T11:30:00Z"),
    ended_after=datetime.fromisoformat("2024-01-15T10:30:00Z"),
    ended_before=datetime.fromisoformat("2024-01-15T11:30:00Z"),
    created_after=datetime.fromisoformat("2024-01-15T10:30:00Z"),
    created_before=datetime.fromisoformat("2024-01-15T11:30:00Z"),
    created_by_user_ids=["550e8400-e29b-41d4-a716-446655440000"],
    created_by_station_ids=["550e8400-e29b-41d4-a716-446655440000"],
    operated_by_ids=["550e8400-e29b-41d4-a716-446655440001"],
    cursor=50,
    sort_by="started_at",
    sort_order="desc"
)

# Handle response
print(result)
{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "created_at": "2024-01-15T10:30:00Z",
      "started_at": "2024-01-15T10:35:00Z",
      "ended_at": "2024-01-15T10:37:30Z",
      "duration": "PT2M30S",
      "outcome": "PASS",
      "docstring": "Test run for production validation",
      "created_by_user": {
        "id": "550e8400-e29b-41d4-a716-446655440001",
        "name": "John Doe",
        "email": "john.doe@example.com"
      },
      "created_by_station": {
        "id": "550e8400-e29b-41d4-a716-446655440002",
        "name": "Test Station 01"
      },
      "operated_by": {
        "id": "550e8400-e29b-41d4-a716-446655440001",
        "name": "John Doe",
        "email": "john.doe@example.com"
      },
      "procedure": {
        "id": "550e8400-e29b-41d4-a716-446655440003",
        "name": "PCB Functional Test",
        "version": {
          "id": "550e8400-e29b-41d4-a716-446655440010",
          "tag": "v2.1.0"
        }
      },
      "unit": {
        "id": "550e8400-e29b-41d4-a716-446655440004",
        "serial_number": "SN-2024-001234",
        "part": {
          "id": "550e8400-e29b-41d4-a716-446655440007",
          "number": "PCB-MAIN-001",
          "name": "Main Control Board",
          "revision": {
            "id": "550e8400-e29b-41d4-a716-446655440006",
            "number": "REV-A"
          }
        },
        "batch": {
          "id": "550e8400-e29b-41d4-a716-446655440005",
          "number": "BATCH-2024-Q1-001"
        }
      }
    }
  ],
  "meta": {
    "has_more": true,
    "next_cursor": 100
  }
}
{
  "message": "Bad request",
  "code": "BAD_REQUEST",
  "issues": []
}
{
  "message": "Unauthorized",
  "code": "UNAUTHORIZED",
  "issues": []
}
{
  "message": "Internal server error",
  "code": "INTERNAL_SERVER_ERROR",
  "issues": []
}

How is this guide?