REST API
Every operation of the Rehearsal API, 72 in all, with the access it needs, its parameters and its request body.
The console, the CLI, the Python client and the MCP tools all call this API. You can call it from any
language. Every address starts with your server's address, and every operation is under /v1.
Make a request
Send your key in the Authorization header, and send and expect JSON.
curl https://rehearsal.example.com/v1/me \
-H "Authorization: Bearer <your_key>"curl -X POST https://rehearsal.example.com/v1/evaluations \
-H "Authorization: Bearer <your_key>" -H "Content-Type: application/json" \
-d '{"world_version_id": "<wv_id>", "profile_ids": ["<profile_id>"], "splits": ["dev"], "repeats": 2}'- A request that works answers
200,201when it created something, or202when it started work that continues on the server. - A request that fails answers with a status of
400or above and a JSON body whosedetailsays why: see Errors. - A request with a body that is not valid answers
422, anddetaillists each field that is wrong.
Access
Each operation below shows the least access it accepts. admin is accepted everywhere.
| Shown as | A key needs | In the console |
|---|---|---|
none | No key | |
any key | Any key or console session, whatever its access | |
read | The read scope, which write and evaluator include | Read only |
write | The write scope | Build and evaluate |
evaluator | The evaluator scope | Build and evaluate |
write and evaluator | Both scopes | Build and evaluate |
admin | The admin scope | Full access |
or agent | The agent scope alone is also enough | |
operator admin | A console sign-in by an operator of the server. A key is refused |
Sign in and keys explains the scopes.
All operations
| Operation | Does |
|---|---|
GET /v1/me | Who the key or the session is: the project, the organisation, the scopes and the plan |
GET /v1/health | Whether the server is up, and whether it offers sign-up and Google sign-in |
GET /v1/applications | The applications of the project |
POST /v1/applications | Adds an application |
POST /v1/applications/import-catalog | Registers the pinned third-party applications from the packaged catalog (rehearsal/assets/catalog.yaml) |
DELETE /v1/applications/{app_id} | Removes an application from the console |
GET /v1/applications/{app_id} | One application |
POST /v1/applications/{app_id}/source | Uploads a .tar.gz of the application source (extracted safely by the runner) |
POST /v1/world-builds | Starts a build of a new world version from an application |
GET /v1/jobs | The server jobs of the project, newest first |
GET /v1/jobs/{job_id} | One server job: its status, attempts, spend, finished phases, result and error |
POST /v1/jobs/{job_id}/commands | Pauses, resumes, stops or retries a server job |
GET /v1/worlds | The worlds of the project, each with its versions and their status |
GET /v1/world-versions/{wv_id} | One world version: its manifest of services, roles and tools, its validation report and its provenance |
GET /v1/world-versions/{wv_id}/scenarios | The jobs of a world version, with their split, status and specification |
POST /v1/world-versions/{wv_id}/scenarios | Adds a scenario to a published world; it is validated before it can be approved |
GET /v1/scenarios/{sc_id} | One job, with its specification and validation report |
POST /v1/scenarios/{sc_id}/approve | Approves a job, so that runs use it |
POST /v1/scenarios/{sc_id}/reject | Rejects a job, so that runs do not use it |
POST /v1/world-versions/{wv_id}/validate | Re-checks a published world: replays every job, tries each with a live agent, and withdraws the unfair ones |
GET /v1/agent-profiles | The agent profiles of the project, every version |
POST /v1/agent-profiles | Creates an agent profile |
GET /v1/agent-profiles/{prof_id} | One agent profile |
POST /v1/evaluations | Starts a run: the agents attempt the jobs of a published world version |
GET /v1/runs | The runs of the project, newest first |
GET /v1/runs/{run_id} | One run: its status, its configuration and its summary of scores |
POST /v1/runs/{run_id}/commands | A run is several shard jobs; the command goes to every shard it applies to |
GET /v1/runs/{run_id}/episodes | The episodes of a run, each with its job, split, agent, status, reward and ending |
GET /v1/compare | Compares profiles within one run, or two runs on the same pinned world version |
POST /v1/improvements | Proposes the next version of an agent from its failed train and dev episodes in a run |
GET /v1/episodes/{ep_id} | One episode in full: the job, each action, each message and the result of each check |
POST /v1/episodes/{ep_id}/interventions | Changes a running episode by hand: a message from the customer, a new version of the request, a fault, or a tool taken from or given to a role |
GET /v1/episodes/{ep_id}/observation | The turn that waits for a bring-your-own agent, if one does |
POST /v1/episodes/{ep_id}/actions | Sends the one action of the waiting turn |
GET /v1/episodes/{ep_id}/actions/{key} | The result of an action, by its idempotency key |
GET /v1/jobs/{job_id}/events | The events of a server job, as a stream that stays open until the job ends |
GET /v1/runs/{run_id}/events | The events of a run, as a stream that stays open until the run ends |
GET /v1/streams/{stream}/events/page | Non-streaming page of events (for replay and reconnect snapshots) |
POST /v1/dataset-exports | Exports episodes of runs as a dataset |
POST /v1/world-versions/{wv_id}/bundle | Exports a world version as a bundle file |
GET /v1/artifacts | Exported files: datasets and bundles |
GET /v1/artifacts/{art_id} | One exported file's record |
GET /v1/artifacts/{art_id}/download | The exported file itself |
GET /v1/dashboard | Everything the overview screen needs in one call |
GET /v1/usage | Model spend this month, the workspace allowance, and what is left of it |
GET /v1/billing | The workspace's plan, what it has used this month, and what can be bought |
POST /v1/billing/checkout | A Dodo Payments checkout page for a plan or a top-up; the browser goes there and comes back to the Billing page |
POST /v1/billing/change | Moves an existing subscription to another plan now; Dodo charges or credits the difference for the rest of the period |
POST /v1/billing/portal | Dodo's customer portal: invoices, payment method, cancellation |
POST /v1/billing/sync | Reads the subscription and top-ups back from Dodo now (after checkout, or when a webhook could not reach us) |
GET /v1/pricing | Billing price and market range for every configured model, with sources |
GET /v1/api-keys | The keys of the project: name, prefix, scopes and last use |
POST /v1/api-keys | Creates a key |
DELETE /v1/api-keys/{key_id} | Revokes a key |
GET /v1/credentials | The credential references of the project |
POST /v1/credentials | Registers a credential by reference: the runner reads it from its own environment |
DELETE /v1/credentials/{cred_id} | Removes a credential reference |
POST /v1/auth/signup | Creates an account and signs the browser in; onboarding then creates the workspace |
POST /v1/auth/login | Signs a browser in with an email address and a password, and sets the session cookie |
POST /v1/auth/google | Signs in (registering on first use) with a Google Identity Services ID token |
POST /v1/onboarding/workspace | First step after a new user signs in: the organisation they own and its first project |
DELETE /v1/session | Signs the browser out |
POST /v1/cli/logins | Starts a terminal sign-in |
GET /v1/cli/logins/{code} | What the approval page shows: which terminal asks, from where, and for which workspace |
POST /v1/cli/logins/{code}/{decision} | Approves or denies a terminal sign-in |
POST /v1/cli/logins/poll | The terminal asks whether its request was approved |
GET /v1/admin/organizations | Every workspace on this server with its plan, owner, and this month's use |
PUT /v1/admin/organizations/{org_id} | Puts a workspace on any plan, without payment, and optionally changes single limits (null = no limit) |
POST /v1/admin/organizations/{org_id}/credits | Adds builds or episodes to a workspace for this month |
GET /v1/training-jobs | Training jobs |
POST /v1/training-jobs | Answers that training is coming soon |
GET /v1/training-jobs/{tj_id} | One training job |
Who you are
Check a key and the server.
GET /v1/me
/v1/meNeeds access: any keyWho the key or the session is: the project, the organisation, the scopes and the plan. Use it to check a key.
Answers 200 with project_id, project, organization, key_id, scopes, plan, user, is_admin, needs_onboarding.
GET /v1/health
/v1/healthNeeds access: noneWhether the server is up, and whether it offers sign-up and Google sign-in. Needs no key.
Answers 200 with status, signup, google_client_id, client_wheel.
Applications
The software that worlds are built from. See Add an application.
GET /v1/applications
/v1/applicationsNeeds access: readThe applications of the project.
Answers 200.
POST /v1/applications
/v1/applicationsNeeds access: writeAdds an application. The name must be unique in the project. Adding starts nothing.
Request body, as JSON:
| Field | Type | Default | Meaning |
|---|---|---|---|
name | string, 1 to 200 characters | required | A name, unique in the project. |
source | object | required | Where the source is: see the fields of source below. |
images | object | none | Each service name with its pinned image, image:tag@sha256:.... |
policies | string | "" | Rules the agent must follow, in plain words. |
notes | string | "" | Free text for your own use. |
connection_mode | string | "source" | Only source is accepted. |
Fields of source:
| Field | Type | Default | Meaning |
|---|---|---|---|
kind | one of git, local_path, upload | required | git for a repository, upload for an archive you send afterwards, local_path for a folder on the server's disk. |
url | string | none | For git: an https:// address, or git@host:path. |
ref | string | none | For git: a branch or tag, kept as a note of where the commit came from. |
commit | string | none | For git: the full commit id, 40 or 64 lowercase hexadecimal characters. |
path | string | none | For local_path: a folder inside the server's REHEARSAL_SOURCE_ROOTS. |
Answers 201 with The application: id, name, source, images, policies, notes, connection_mode, created_at.
POST /v1/applications/import-catalog
/v1/applications/import-catalogNeeds access: writeRegisters the pinned third-party applications from the packaged catalog (rehearsal/assets/catalog.yaml). A plan with an application limit gets as many as it has room for, in catalog order (the free plan: the first, Gitea), so a new free workspace can start from a sample instead of being refused.
Answers 201.
DELETE /v1/applications/{app_id}
/v1/applications/<app_id>Needs access: adminRemoves an application from the console. Its builds stop; finished runs stay in the run history.
| Parameter | In | Type | Default |
|---|---|---|---|
app_id | the path | string | required |
Answers 200.
GET /v1/applications/{app_id}
/v1/applications/<app_id>Needs access: readOne application.
| Parameter | In | Type | Default |
|---|---|---|---|
app_id | the path | string | required |
Answers 200.
POST /v1/applications/{app_id}/source
/v1/applications/<app_id>/sourceNeeds access: writeUploads a .tar.gz of the application source (extracted safely by the runner).
| Parameter | In | Type | Default |
|---|---|---|---|
app_id | the path | string | required |
The body is a form upload with one part, file: the archive.
Answers 201.
World builds and server jobs
Start a build, and follow or control any long piece of work. See Build a practice world.
POST /v1/world-builds
/v1/world-buildsNeeds access: write$ Costs moneyStarts a build of a new world version from an application. It spends model budget.
Request body, as JSON:
| Field | Type | Default | Meaning |
|---|---|---|---|
application_id | string | required | The application to build from. |
model | string | none | A model chain for the World Compiler, in place of the server's default. |
budget_usd | number, 0 or more | none | Model spend at which the build stops itself. |
auto_approve | boolean | true | Approve the jobs that pass validation. With false, they wait for you to approve them. |
scenario_target | integer, 1 to 30 | 8 | How many jobs to write. |
max_repair_rounds | integer, 0 to 5 | 2 | How many times the compiler may repair a job that fails validation before it gives the job up. |
check_determinism | boolean | true | Replay each job to prove that it gives the same result twice. |
Answers 202 with job_id, world_id, world_version_id, version.
GET /v1/jobs
/v1/jobsNeeds access: readThe server jobs of the project, newest first. kind narrows the list.
| Parameter | In | Type | Default |
|---|---|---|---|
kind | the query | string | none |
Answers 200.
GET /v1/jobs/{job_id}
/v1/jobs/<job_id>Needs access: readOne server job: its status, attempts, spend, finished phases, result and error.
| Parameter | In | Type | Default |
|---|---|---|---|
job_id | the path | string | required |
Answers 200 with id, kind, status, attempts, spent_usd, budget_usd, completed_phases, result, error.
POST /v1/jobs/{job_id}/commands
/v1/jobs/<job_id>/commandsNeeds access: writePauses, resumes, stops or retries a server job. retry restarts a failed or stopped job from its last saved step.
| Parameter | In | Type | Default |
|---|---|---|---|
job_id | the path | string | required |
Request body, as JSON:
| Field | Type | Default | Meaning |
|---|---|---|---|
command | one of pause, resume, stop, retry | required | What to do with the job or the run. |
Answers 200 with status, pause_requested, cancel_requested.
Worlds and their jobs
Worlds, world versions, and the jobs inside them. The API calls a job a scenario.
GET /v1/worlds
/v1/worldsNeeds access: readThe worlds of the project, each with its versions and their status.
Answers 200.
GET /v1/world-versions/{wv_id}
/v1/world-versions/<wv_id>Needs access: evaluatorOne world version: its manifest of services, roles and tools, its validation report and its provenance.
| Parameter | In | Type | Default |
|---|---|---|---|
wv_id | the path | string | required |
Answers 200.
GET /v1/world-versions/{wv_id}/scenarios
/v1/world-versions/<wv_id>/scenariosNeeds access: evaluatorThe jobs of a world version, with their split, status and specification.
| Parameter | In | Type | Default |
|---|---|---|---|
wv_id | the path | string | required |
Answers 200.
POST /v1/world-versions/{wv_id}/scenarios
/v1/world-versions/<wv_id>/scenariosNeeds access: write and evaluatorAdds a scenario to a published world; it is validated before it can be approved.
| Parameter | In | Type | Default |
|---|---|---|---|
wv_id | the path | string | required |
Request body, as JSON:
| Field | Type | Default |
|---|---|---|
scenario | object | required |
Answers 202.
GET /v1/scenarios/{sc_id}
/v1/scenarios/<sc_id>Needs access: evaluatorOne job, with its specification and validation report.
| Parameter | In | Type | Default |
|---|---|---|---|
sc_id | the path | string | required |
Answers 200.
POST /v1/scenarios/{sc_id}/approve
/v1/scenarios/<sc_id>/approveNeeds access: write and evaluatorApproves a job, so that runs use it.
| Parameter | In | Type | Default |
|---|---|---|---|
sc_id | the path | string | required |
Answers 200.
POST /v1/scenarios/{sc_id}/reject
/v1/scenarios/<sc_id>/rejectNeeds access: write and evaluatorRejects a job, so that runs do not use it.
| Parameter | In | Type | Default |
|---|---|---|---|
sc_id | the path | string | required |
Answers 200.
POST /v1/world-versions/{wv_id}/validate
/v1/world-versions/<wv_id>/validateNeeds access: write and evaluator$ Costs moneyRe-checks a published world: replays every job, tries each with a live agent, and withdraws the unfair ones. It spends model budget.
| Parameter | In | Type | Default |
|---|---|---|---|
wv_id | the path | string | required |
Answers 202.
Agent profiles
Versions of the agents under test.
GET /v1/agent-profiles
/v1/agent-profilesNeeds access: readThe agent profiles of the project, every version.
Answers 200.
POST /v1/agent-profiles
/v1/agent-profilesNeeds access: writeCreates an agent profile. A second profile with the same name becomes the next version.
Request body, as JSON:
| Field | Type | Default | Meaning |
|---|---|---|---|
name | string | required | The agent's name. A second profile with the same name becomes the next version. |
system_prompt | string | "" | The agent's instructions. Empty uses the platform default. |
tool_guidance | object | none | Extra guidance for single tools: tool name to text. It is added to the tool's description. |
model | string | none | A model chain for this agent, in place of the server's default. |
temperature | number | 0.2 | The model's sampling temperature. |
max_turns_per_actor | integer | 25 | How many turns each actor may take in an episode. |
driver | one of llm, external | "llm" | llm: Rehearsal runs a model with these instructions. external: your own agent sends the actions. |
Answers 201.
GET /v1/agent-profiles/{prof_id}
/v1/agent-profiles/<prof_id>Needs access: readOne agent profile.
| Parameter | In | Type | Default |
|---|---|---|---|
prof_id | the path | string | required |
Answers 200.
Evaluations and runs
Start a run, read it, control it and compare it. See Evaluate an agent.
POST /v1/evaluations
/v1/evaluationsNeeds access: write$ Costs moneyStarts a run: the agents attempt the jobs of a published world version. It spends model budget.
Request body, as JSON:
| Field | Type | Default | Meaning |
|---|---|---|---|
world_version_id | string | required | A published world version. |
profile_ids | list of string | required | One or more agent profiles. They get the same jobs. |
splits | list of train, dev, holdout | none | Which splits to run. Without it, all three. |
scenario_ids | list of string | none | Run only these jobs, in place of whole splits. |
repeats | integer, 1 to 20 | 2 | Attempts at each job by each agent. |
default_stress | boolean | true | Add the stress layer to every episode: one refused change, and one repeated request. |
budget_usd | number, 0 or more | none | Model spend at which the run stops itself. |
max_episode_cost_usd | number, 0 or more | none | Model spend at which one episode ends with the ending budget. |
Answers 202 with run_id, job_id, episodes, shards, and starts_at when the run waits for quiet hours.
GET /v1/runs
/v1/runsNeeds access: readThe runs of the project, newest first.
Answers 200.
GET /v1/runs/{run_id}
/v1/runs/<run_id>Needs access: readOne run: its status, its configuration and its summary of scores.
| Parameter | In | Type | Default |
|---|---|---|---|
run_id | the path | string | required |
Answers 200 with The run, with status and summary. summary.profiles has one entry for each agent, named name@vN: see Read results.
POST /v1/runs/{run_id}/commands
/v1/runs/<run_id>/commandsNeeds access: writeA run is several shard jobs; the command goes to every shard it applies to.
| Parameter | In | Type | Default |
|---|---|---|---|
run_id | the path | string | required |
Request body, as JSON:
| Field | Type | Default | Meaning |
|---|---|---|---|
command | one of pause, resume, stop, retry | required | What to do with the job or the run. |
Answers 200.
GET /v1/runs/{run_id}/episodes
/v1/runs/<run_id>/episodesNeeds access: evaluatorThe episodes of a run, each with its job, split, agent, status, reward and ending.
| Parameter | In | Type | Default |
|---|---|---|---|
run_id | the path | string | required |
Answers 200 with A list. Each item has id, scenario, split, profile, status, reward, termination, cost_usd, tokens and oracle.
GET /v1/compare
/v1/compareNeeds access: readCompares profiles within one run, or two runs on the same pinned world version.
| Parameter | In | Type | Default |
|---|---|---|---|
run_a | the query | string | required |
run_b | the query | string | none |
Answers 200 with world_version_id, world_content_hash, and runs: the summary of each run, by run id.
POST /v1/improvements
/v1/improvementsNeeds access: write$ Costs moneyProposes the next version of an agent from its failed train and dev episodes in a run. It spends a little model budget.
Request body, as JSON:
| Field | Type | Default | Meaning |
|---|---|---|---|
profile_id | string | required | The agent profile to improve. |
run_id | string | required | A finished run with train or dev episodes of that profile. |
Answers 202 with job_id. The job's result names the new profile version and gives the reason for each change.
Episodes
One attempt by one agent at one job.
GET /v1/episodes/{ep_id}
/v1/episodes/<ep_id>Needs access: evaluatorOne episode in full: the job, each action, each message and the result of each check.
| Parameter | In | Type | Default |
|---|---|---|---|
ep_id | the path | string | required |
Answers 200 with status, termination, reward, scenario, oracle (with check_results, duplicate_effects, false_completion, environment_error), actions and messages.
POST /v1/episodes/{ep_id}/interventions
/v1/episodes/<ep_id>/interventionsNeeds access: write and evaluatorChanges a running episode by hand: a message from the customer, a new version of the request, a fault, or a tool taken from or given to a role.
| Parameter | In | Type | Default |
|---|---|---|---|
ep_id | the path | string | required |
Request body, as JSON:
| Field | Type | Default | Meaning |
|---|---|---|---|
kind | one of customer_message, goal_change, fault, revoke_tool, grant_tool | required | What to do in the running episode. |
text | string | none | For customer_message and goal_change: what the customer says. |
goal_version | integer | none | For goal_change: the version of the request to move to. |
tool | string | none | For fault, revoke_tool and grant_tool: the tool it applies to. |
fault_mode | one of drop_response, error, timeout_before, rate_limit | none | For fault: how the next call of the tool goes wrong. |
role | string | none | For revoke_tool and grant_tool: the role that loses or gets the tool. |
count | integer | 1 | For fault: how many calls it applies to. |
Answers 202.
Bring your own agent
Read the waiting turn of an episode and send its action. See Bring your own agent.
GET /v1/episodes/{ep_id}/observation
/v1/episodes/<ep_id>/observationNeeds access: read, or agentThe turn that waits for a bring-your-own agent, if one does.
| Parameter | In | Type | Default |
|---|---|---|---|
ep_id | the path | string | required |
Answers 200 with episode_status, awaiting_action, and turn. turn.data has actor, new and tools.
POST /v1/episodes/{ep_id}/actions
/v1/episodes/<ep_id>/actionsNeeds access: write, or agentSends the one action of the waiting turn. The answer comes at once; the result is read with the next operation.
| Parameter | In | Type | Default |
|---|---|---|---|
ep_id | the path | string | required |
Request body, as JSON:
| Field | Type | Default | Meaning |
|---|---|---|---|
actor | string | required | The actor that the waiting turn names. |
tool | string | required | One of the tools that the turn offers. |
args | object | none | The tool's arguments. |
idempotency_key | string, 8 to 64 characters | required | Your own name for this action, different for each action. Sending the same action again with the same key does not carry it out twice. |
Answers 202 with event_id, and duplicate: true when the same action with the same key was sent before.
GET /v1/episodes/{ep_id}/actions/{key}
/v1/episodes/<ep_id>/actions/<key>Needs access: read, or agentThe result of an action, by its idempotency key.
| Parameter | In | Type | Default |
|---|---|---|---|
ep_id | the path | string | required |
key | the path | string | required |
Answers 200 with {"status": "pending"}, or {"status": "done", "result": ...}.
Events
Follow a build or a run as it happens. See The event format at the end of this page.
GET /v1/jobs/{job_id}/events
/v1/jobs/<job_id>/eventsNeeds access: evaluatorThe events of a server job, as a stream that stays open until the job ends.
| Parameter | In | Type | Default |
|---|---|---|---|
job_id | the path | string | required |
cursor | the query | integer | none |
Answers 200.
GET /v1/runs/{run_id}/events
/v1/runs/<run_id>/eventsNeeds access: evaluatorThe events of a run, as a stream that stays open until the run ends.
| Parameter | In | Type | Default |
|---|---|---|---|
run_id | the path | string | required |
cursor | the query | integer | none |
Answers 200.
GET /v1/streams/{stream}/events/page
/v1/streams/<stream>/events/pageNeeds access: evaluatorNon-streaming page of events (for replay and reconnect snapshots).
| Parameter | In | Type | Default |
|---|---|---|---|
stream | the path | string | required |
cursor | the query | integer | 0 |
limit | the query | integer | 500 |
Answers 200.
Exports
Datasets of verified episodes, world bundles, and the files they produce.
POST /v1/dataset-exports
/v1/dataset-exportsNeeds access: writeExports episodes of runs as a dataset. Only train and dev episodes can be exported.
Request body, as JSON:
| Field | Type | Default | Meaning |
|---|---|---|---|
run_ids | list of string | required | The runs to export from. |
splits | list of train, dev | none | train, dev or both. Holdout episodes cannot be exported. Without it, train. |
verified_only | boolean | true | Export only verified episodes. |
Answers 202.
POST /v1/world-versions/{wv_id}/bundle
/v1/world-versions/<wv_id>/bundleNeeds access: write and evaluatorExports a world version as a bundle file.
| Parameter | In | Type | Default |
|---|---|---|---|
wv_id | the path | string | required |
include_images | the query | boolean | false |
Answers 202.
GET /v1/artifacts
/v1/artifactsNeeds access: evaluatorExported files: datasets and bundles. kind narrows the list.
| Parameter | In | Type | Default |
|---|---|---|---|
kind | the query | string | none |
Answers 200.
GET /v1/artifacts/{art_id}
/v1/artifacts/<art_id>Needs access: evaluatorOne exported file's record.
| Parameter | In | Type | Default |
|---|---|---|---|
art_id | the path | string | required |
Answers 200.
GET /v1/artifacts/{art_id}/download
/v1/artifacts/<art_id>/downloadNeeds access: evaluatorThe exported file itself.
| Parameter | In | Type | Default |
|---|---|---|---|
art_id | the path | string | required |
Answers 200.
Usage and billing
Model spend, the plan, and payments.
GET /v1/dashboard
/v1/dashboardNeeds access: evaluatorEverything the overview screen needs in one call.
Answers 200.
GET /v1/usage
/v1/usageNeeds access: readModel spend this month, the workspace allowance, and what is left of it.
Answers 200 with month, spent_usd, by_kind, allowance_usd (null when there is no limit), left_usd, renews.
GET /v1/billing
/v1/billingNeeds access: readThe workspace's plan, what it has used this month, and what can be bought.
Answers 200 with plan (its limits), usage (what is used), month, renews, quiet_hours_utc, next_quiet_start, and the subscription.
POST /v1/billing/checkout
/v1/billing/checkoutNeeds access: adminA Dodo Payments checkout page for a plan or a top-up; the browser goes there and comes back to the Billing page.
Request body, as JSON:
| Field | Type | Default |
|---|---|---|
item | one of pro_monthly, pro_yearly, team_monthly, team_yearly, episodes_1000, build_1 | required |
quantity | integer, 1 to 50 | 1 |
Answers 200.
POST /v1/billing/change
/v1/billing/changeNeeds access: adminMoves an existing subscription to another plan now; Dodo charges or credits the difference for the rest of the period.
Request body, as JSON:
| Field | Type | Default |
|---|---|---|
item | one of pro_monthly, pro_yearly, team_monthly, team_yearly | required |
Answers 200.
POST /v1/billing/portal
/v1/billing/portalNeeds access: adminDodo's customer portal: invoices, payment method, cancellation.
Answers 200.
POST /v1/billing/sync
/v1/billing/syncNeeds access: writeReads the subscription and top-ups back from Dodo now (after checkout, or when a webhook could not reach us).
Answers 200.
GET /v1/pricing
/v1/pricingNeeds access: readBilling price and market range for every configured model, with sources.
Answers 200.
Keys
Create, list and revoke API keys, and the references to credentials that a runner reads from its own environment.
GET /v1/api-keys
/v1/api-keysNeeds access: adminThe keys of the project: name, prefix, scopes and last use. Never the key itself.
Answers 200.
POST /v1/api-keys
/v1/api-keysNeeds access: adminCreates a key. The answer holds the key, once.
Request body, as JSON:
| Field | Type | Default | Meaning |
|---|---|---|---|
name | string | required | A name that says who or what uses the key. |
scopes | list of admin, read, write, evaluator, agent | none | The key's access. The console's "Build and evaluate" is write with evaluator. Without it, admin. |
Answers 201 with api_key, shown once, and a note.
DELETE /v1/api-keys/{key_id}
/v1/api-keys/<key_id>Needs access: adminRevokes a key. It stops working at once.
| Parameter | In | Type | Default |
|---|---|---|---|
key_id | the path | string | required |
Answers 200.
GET /v1/credentials
/v1/credentialsNeeds access: adminThe credential references of the project.
Answers 200.
POST /v1/credentials
/v1/credentialsNeeds access: adminRegisters a credential by reference: the runner reads it from its own environment.
Request body, as JSON:
| Field | Type | Default |
|---|---|---|
name | string | required |
kind | one of model_provider, application, training | required |
env_var | string | required |
Answers 201.
DELETE /v1/credentials/{cred_id}
/v1/credentials/<cred_id>Needs access: adminRemoves a credential reference.
| Parameter | In | Type | Default |
|---|---|---|---|
cred_id | the path | string | required |
Answers 200.
Sign-in
What the console and rehearsal login use. A program with a key does not need these.
POST /v1/auth/signup
/v1/auth/signupNeeds access: noneCreates an account and signs the browser in; onboarding then creates the workspace.
Request body, as JSON:
| Field | Type | Default |
|---|---|---|
name | string, 1 to 200 characters | required |
email | string | required |
password | string, 10 to 200 characters | required |
Answers 201.
POST /v1/auth/login
/v1/auth/loginNeeds access: noneSigns a browser in with an email address and a password, and sets the session cookie.
Request body, as JSON:
| Field | Type | Default |
|---|---|---|
email | string | required |
password | string, 1 to 200 characters | required |
Answers 200.
POST /v1/auth/google
/v1/auth/googleNeeds access: noneSigns in (registering on first use) with a Google Identity Services ID token.
Request body, as JSON:
| Field | Type | Default |
|---|---|---|
credential | string, 20 to 8192 characters | required |
Answers 200.
POST /v1/onboarding/workspace
/v1/onboarding/workspaceNeeds access: any keyFirst step after a new user signs in: the organisation they own and its first project.
Request body, as JSON:
| Field | Type | Default |
|---|---|---|
organization | string, 1 to 200 characters | required |
project | string, 1 to 200 characters | "default" |
Answers 201.
DELETE /v1/session
/v1/sessionNeeds access: noneSigns the browser out.
Answers 200.
POST /v1/cli/logins
/v1/cli/loginsNeeds access: noneStarts a terminal sign-in. Returns the code to show, the page to open, and the secret device code to poll with.
Request body, as JSON:
| Field | Type | Default |
|---|---|---|
client | string | "" |
Answers 201 with user_code, device_code, verification_url, expires_in, interval.
GET /v1/cli/logins/{code}
/v1/cli/logins/<code>Needs access: readWhat the approval page shows: which terminal asks, from where, and for which workspace.
| Parameter | In | Type | Default |
|---|---|---|---|
code | the path | string | required |
Answers 200.
POST /v1/cli/logins/{code}/{decision}
/v1/cli/logins/<code>/<decision>Needs access: adminApproves or denies a terminal sign-in. Only an owner or an admin can approve.
| Parameter | In | Type | Default |
|---|---|---|---|
code | the path | string | required |
decision | the path | one of approve, deny | required |
Answers 200.
POST /v1/cli/logins/poll
/v1/cli/logins/pollNeeds access: noneThe terminal asks whether its request was approved. On the first poll after approval it receives a new API key, exactly once.
Request body, as JSON:
| Field | Type | Default |
|---|---|---|
device_code | string, 20 to 200 characters | required |
Answers 200 with status: pending, approved (with api_key, once), denied or expired.
Operator admin
For the people who run the server. These need a console sign-in by an operator admin, not a key.
GET /v1/admin/organizations
/v1/admin/organizationsNeeds access: operator adminEvery workspace on this server with its plan, owner, and this month's use.
Answers 200.
PUT /v1/admin/organizations/{org_id}
/v1/admin/organizations/<org_id>Needs access: operator adminPuts a workspace on any plan, without payment, and optionally changes single limits (null = no limit).
| Parameter | In | Type | Default |
|---|---|---|---|
org_id | the path | string | required |
Request body, as JSON:
| Field | Type | Default |
|---|---|---|
plan_override | one of free, pro, team, enterprise, internal | none |
limits_override | object | none |
Answers 200.
POST /v1/admin/organizations/{org_id}/credits
/v1/admin/organizations/<org_id>/creditsNeeds access: operator adminAdds builds or episodes to a workspace for this month.
| Parameter | In | Type | Default |
|---|---|---|---|
org_id | the path | string | required |
Request body, as JSON:
| Field | Type | Default |
|---|---|---|
kind | one of episodes, builds | required |
quantity | integer, 1 to 1e+06 | required |
note | string | "" |
Answers 201.
Training
Not built yet: see Not built yet.
GET /v1/training-jobs
/v1/training-jobsNeeds access: readTraining jobs. None can exist yet.
Answers 200.
POST /v1/training-jobs
/v1/training-jobsNeeds access: writeAnswers that training is coming soon.
Request body, as JSON:
| Field | Type | Default |
|---|---|---|
world_version_id | string | required |
base_model | string | "Qwen/Qwen3-1.7B" |
rounds | integer, 1 to 6 | 2 |
rollouts_per_scenario | integer, 1 to 32 | 4 |
serve_base_url | string | "http://127.0.0.1:8001/v1" |
kaggle_gpu | one of NvidiaTeslaT4, NvidiaTeslaP100 | "NvidiaTeslaT4" |
budget_usd | number | none |
Answers 202.
GET /v1/training-jobs/{tj_id}
/v1/training-jobs/<tj_id>Needs access: readOne training job. None can exist yet.
| Parameter | In | Type | Default |
|---|---|---|---|
tj_id | the path | string | required |
Answers 200.
The event format
A build and a run record what happens as events. The two event operations answer with a stream of server-sent events that stays open until the work ends.
curl -N "https://rehearsal.example.com/v1/runs/<run_id>/events?cursor=0" \
-H "Authorization: Bearer <your_key>"Each event is one JSON object in a data: line. Its fields:
| Field | Meaning |
|---|---|
event_id | A number that grows. Pass the last one you saw as cursor to continue after a lost connection |
type | What happened, for example compiler.phase.started, action.succeeded, goal.revised, episode.finished |
summary | One line of text for people |
created_at | When, in UTC |
stream | The id of the server job or the run that the event belongs to |
episode_id, actor_id, goal_version | Set when the event belongs to an episode, an actor, or a version of the request |
data | More fields, by type |
The stream ends with an event named stream.end. The Python client reads the stream and reconnects for you:
rh.jobs.events(job_id) and rh.runs.events(run_id).
To read events without a stream, use GET /v1/streams/<stream>/events/page, which answers one page as a list.
The schema
The server publishes the OpenAPI document of this API at /openapi.json, and a page to try each operation at
/api/docs. rehearsal openapi prints the same document on a machine that has the server installed.
Was this page helpful?