ultrarouter docs
API reference

Workspaces

Workspace tenancy management.

Workspace tenancy management.

This page is GENERATED from the OpenAPI spec (openapi.yaml) — it can never drift from the served API. Set UR_BASE_URL (required: your gateway’s URL) and UR_API_KEY (an ur_sk_* key); secrets are always the $UR_API_KEY placeholder.

Read the workspace model policy

GET /v1/workspaces/{id}/model-policy

The workspace MODEL POLICY (which models this workspace may run): a preset (us_only | global | custom) plus per-model/per-provider/per-lab allow-deny rules and the US-hosted open-weight exception. Default global when unset. RBAC model_policy.read.

Auth: Session cookie + workspace RBAC.

curl -sS -X GET "$UR_BASE_URL/v1/workspaces/req_0000000000000000/model-policy" \
  -H "Cookie: better-auth.session_token=$UR_SESSION"

Replace the workspace model policy

PUT /v1/workspaces/{id}/model-policy

REPLACE the workspace MODEL POLICY. Enforced everywhere a model is picked (routing/fallbacks, eval/bench candidates, recommendations, flywheel/eval replays) through the ONE versioned-config snapshot; a denied model is a pre-dispatch model_denied_by_policy refusal. owner|admin, audited, bumps config_version.

Auth: Session cookie + workspace RBAC.

curl -sS -X PUT "$UR_BASE_URL/v1/workspaces/req_0000000000000000/model-policy" \
  -H "Cookie: better-auth.session_token=$UR_SESSION" \
  -H "Content-Type: application/json" \
  -d '{
    "preset": "us_only"
  }'

Read the workspace native-passthrough routing policy

GET /v1/workspaces/{id}/passthrough-policy

The per-workspace NATIVE-PASSTHROUGH routing policy: stage-keyed rules that let the gateway swap a POST /v1/responses / POST /v1/messages request’s model from its call tags (X-UR-Call-Type / X-UR-Trace.stage / body model), optionally injecting Anthropic prefix caching — the product form of moving a cheap stage off the frontier model with no code change. Default disabled when unset. RBAC passthrough_policy.read.

Auth: Session cookie + workspace RBAC.

curl -sS -X GET "$UR_BASE_URL/v1/workspaces/req_0000000000000000/passthrough-policy" \
  -H "Cookie: better-auth.session_token=$UR_SESSION"

Replace the workspace native-passthrough routing policy

PUT /v1/workspaces/{id}/passthrough-policy

REPLACE the per-workspace native-passthrough routing policy. Applied on POST /v1/responses and POST /v1/messages: the FIRST matching rule rewrites the body’s model to its served model (SAME provider family only — a cross-family rule is refused here by name), which must be priced and active in the catalog; everything else in the body is left verbatim. owner|admin, audited, bumps config_version (visible within one 5 s cache window).

Auth: Session cookie + workspace RBAC.

curl -sS -X PUT "$UR_BASE_URL/v1/workspaces/req_0000000000000000/passthrough-policy" \
  -H "Cookie: better-auth.session_token=$UR_SESSION" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "rules": [
      {
        "id": "string"
      }
    ]
  }'

List the workspace live-injection experiment packs

GET /v1/workspaces/{id}/experiment-packs

LIST the workspace experiment packs, newest first — ids / module_hash / token count / source / created + revoked timestamps only (never the module text). owner|admin session (flywheel.write).

Auth: Session cookie + workspace RBAC.

curl -sS -X GET "$UR_BASE_URL/v1/workspaces/req_0000000000000000/experiment-packs" \
  -H "Cookie: better-auth.session_token=$UR_SESSION"

Load a live-injection experiment pack

POST /v1/workspaces/{id}/experiment-packs

Load a small, experiment-labeled learned PLAYBOOK (a ur:learned reference block ≤ 800 tokens) that a passthrough rule’s inject can bind to a (call type × api key). A matching POST /v1/messages / POST /v1/responses request gets the pack inserted into the learned reference slot, stamped, bounded and fail-safe. The module TEXT is stored in encrypted blob storage under corrections_consent — a create is REFUSED when consent is off, when the text exceeds 800 tokens by the core estimator, or when it is not a ur:learned shape. NOT a product lever adoption, NOT a holdout arm. owner|admin session (flywheel.write), audited (ids / hashes only); never returns the text.

Auth: Session cookie + workspace RBAC.

curl -sS -X POST "$UR_BASE_URL/v1/workspaces/req_0000000000000000/experiment-packs" \
  -H "Cookie: better-auth.session_token=$UR_SESSION" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "string",
    "call_type_id": "string",
    "module_text": "string"
  }'

Revoke a live-injection experiment pack

DELETE /v1/workspaces/{id}/experiment-packs/{packId}

REVOKE an experiment pack (set revoked_at). A revoked pack is no longer injected on any matching request — the gateway serves verbatim with a recorded skip — within one 5 s config window (a revoke bumps config_version). The module body rides the corrections-body retention sweep. owner|admin session (flywheel.write), audited.

Auth: Session cookie + workspace RBAC.

curl -sS -X DELETE "$UR_BASE_URL/v1/workspaces/req_0000000000000000/experiment-packs/{packId}" \
  -H "Cookie: better-auth.session_token=$UR_SESSION"

Preview a proposed model policy against the live catalog

POST /v1/workspaces/{id}/model-policy/preview

Evaluate a PROPOSED policy against the LIVE catalog WITHOUT mutating anything: allow/deny counts by lab and by provider, the denied logical models, and the input-price range lost. Exactly what the dashboard onboarding wizard shows. RBAC model_policy.read.

Auth: Session cookie + workspace RBAC.

curl -sS -X POST "$UR_BASE_URL/v1/workspaces/req_0000000000000000/model-policy/preview" \
  -H "Cookie: better-auth.session_token=$UR_SESSION" \
  -H "Content-Type: application/json" \
  -d '{
    "preset": "us_only"
  }'

Create a workspace

POST /v1/workspaces

Auth: Session cookie + workspace RBAC.

curl -sS -X POST "$UR_BASE_URL/v1/workspaces" \
  -H "Cookie: better-auth.session_token=$UR_SESSION" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "string"
  }'

Rename a workspace

PATCH /v1/workspaces/{id}

Auth: Session cookie + workspace RBAC.

curl -sS -X PATCH "$UR_BASE_URL/v1/workspaces/req_0000000000000000" \
  -H "Cookie: better-auth.session_token=$UR_SESSION" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "string"
  }'

Soft-delete a workspace

DELETE /v1/workspaces/{id}

Auth: Session cookie + workspace RBAC.

curl -sS -X DELETE "$UR_BASE_URL/v1/workspaces/req_0000000000000000" \
  -H "Cookie: better-auth.session_token=$UR_SESSION"