understudydocs

control plane api

Workloads & routing

The endpoints behind the dashboard's Workloads and Routing pages and the CLI's workloads/routes commands. Routing is always expressed with public model ids from the catalog — provider deployments are never exposed on this surface.

Workloads

method & pathdoes
GET /customer/v1/orgs/:org_id/projects/:project_id/workloadsList the project's workloads.
POST .../workloadsCreate. Body: { "name", "capture_enabled"? }. Names are lowercase alphanumerics/hyphens/underscores, 1–63 chars, unique per project.
PATCH .../workloads/:workload_idRename and/or toggle capture. Body: any of { "name", "capture_enabled" }.

Model catalog

method & pathdoes
GET /admin/v1/orgs/:org_id/modelsList active catalog models: { id, display_name, active, created_at }. The same ids GET /v1/models returns on the gateway.

Routing writes

Two equivalent write surfaces; use whichever fits your shape:

method & pathdoes
PUT /admin/v1/orgs/:org_id/projects/:project_id/workloads/:workload_id/routeSet or clear the route in one call. Body: { "model_id": string | null, "route_traffic_pct"?, "capture_enabled"? }. null clears to passthrough.
PATCH /admin/v1/orgs/:org_id/projects/:project_id/workloads/:workload_idPartial update across all routing + capture fields: { "model_id"?, "route_traffic_pct"?, "capture_enabled"?, "capture_sample_rate"?, "name"? }. model_id is tri-state: omitted = unchanged, null = clear, string = route.
route 10% of a workload to a catalog model
curl -X PUT "https://api.understudylabs.com/admin/v1/orgs/$ORG_ID/projects/$PROJECT_ID/workloads/$WORKLOAD_ID/route" \
  -H "Authorization: Bearer $UNDERSTUDY_API_KEY" \
  -H "content-type: application/json" \
  -d '{"model_id": "glm-5.1", "route_traffic_pct": 10}'
workload object (response shape)
{
  "id": "usp_...",
  "project_id": "proj_...",
  "name": "ad-relevance",
  "capture_enabled": true,        // turned on by the route write above
  "route_model_id": "glm-5.1",
  "route_traffic_pct": 10,
  "capture_sample_rate": 1.0,
  "is_default": false,
  "created_at": "2026-06-12T00:00:00Z"
}

Write semantics worth knowing

rulewhy
Setting a route turns capture on unless you pass capture_enabled: false.Routed traffic is the traffic worth evidence; opting out is explicit.
Omitted route_traffic_pct on a new route defaults to 100 (full cutover).Pass a lower value to canary — e.g. 5 to start small — but the default sends all matching traffic to the route immediately.
Clearing (model_id: null) with capture_enabled omitted leaves capture as-is.Rollback shouldn't silently stop your evidence collection.
The default workload can't be deleted, and exactly one exists per project.Unscoped traffic always has somewhere to land.