API Reference
The REST API behind the CLI and console
The rh CLI and the console are both clients of the same REST API — there's nothing they can
do that this API doesn't expose. Base URL defaults to http://localhost:8787 in development
(REMOTEHOST_API_URL for the CLI, NEXT_PUBLIC_API_URL for the console).
Authentication
Every /v1 request requires an Authorization: Bearer <token> header, using the same token
rh login stores at ~/.config/remotehost/config.json. There is no separate API-key auth for
/v1 today — org API keys (visible via GET /v1/orgs/:orgId/api-keys) exist
as a concept but authenticate a different surface, not this REST API directly.
curl https://<api-host>/v1/me/orgs \
-H "Authorization: Bearer $REMOTEHOST_TOKEN"Health check
GET /healthUnauthenticated. Returns { "ok": true, "service": "remotehost-api" }.
Orgs
| Method & path | Description |
|---|---|
GET /v1/me/orgs | List orgs the caller belongs to |
POST /v1/orgs | Create an org |
GET /v1/orgs/:orgId/members | List org members |
GET /v1/orgs/:orgId/subscription | Current plan and status |
PATCH /v1/orgs/:orgId/subscription/usage-guardrails | Set sandbox usage cap and overage policy |
GET /v1/orgs/:orgId/usage | Machine-hour usage against allowance and hard cap |
GET /v1/orgs/:orgId/usage?projectId=:projectId | Project-scoped machine-hour usage against project cap |
GET /v1/orgs/:orgId/activity | Org activity feed (lifecycle events) |
GET /v1/orgs/:orgId/api-keys | List org API keys |
POST /v1/orgs/:orgId/billing/checkout | Start a Stripe checkout session for a plan |
Usage guardrails
PATCH /v1/orgs/:orgId/subscription/usage-guardrailsOrg admins can set a hard sandbox machine-hour cap and whether overage is allowed.
{
"sandboxMachineHourLimit": 250,
"sandboxOverageEnabled": false
}For project-level blast-radius control, org admins can set a project cap:
PATCH /v1/orgs/:orgId/projects/:projectId/usage-guardrails{
"sandboxMachineHourLimit": 50
}Set sandboxMachineHourLimit to null to remove the project cap. A project
cap is enforced inside the org cap and uses the same billing period as the
subscription. Add ?projectId=:projectId to the usage endpoint to return
project-scoped usage and alert state.
Set sandboxMachineHourLimit to null to fall back to the catalog included
allowance when overage is disabled. When overage is enabled and no explicit cap
is set, usage may continue without a catalog cap for custom contracts.
The usage response exposes both the effective cap and the explicit override.
sandboxMachineHourLimit is the cap enforced for the current period, while
sandboxMachineHourLimitOverride is null when the subscription is using its
default included allowance.
{
"includedMachineHours": 200,
"sandboxMachineHourLimit": 200,
"sandboxMachineHourLimitOverride": null,
"sandboxOverageEnabled": false,
"usedMachineHours": 12.5,
"remainingMachineHours": 187.5,
"usageAlert": {
"percentUsed": 6.25,
"status": "normal",
"message": "Sandbox machine-hour usage is within the current cap."
}
}Invitations
| Method & path | Description |
|---|---|
GET /v1/orgs/:orgId/invitations | List pending invitations |
POST /v1/orgs/:orgId/invitations | Invite a member by email |
DELETE /v1/orgs/:orgId/invitations/:invitationId | Revoke a pending invitation |
GET /v1/invitations/:token | Look up an invitation by its token |
POST /v1/invitations/:token/accept | Accept an invitation as the authenticated user |
Projects
| Method & path | Description |
|---|---|
GET /v1/orgs/:orgId/projects | List projects |
POST /v1/orgs/:orgId/projects | Create a project |
PATCH /v1/orgs/:orgId/projects/:projectId | Update project metadata |
PATCH /v1/orgs/:orgId/projects/:projectId/usage-guardrails | Set project sandbox cap |
Sandboxes
| Method & path | Description |
|---|---|
GET /v1/orgs/:orgId/sandboxes | List sandboxes (excludes deleted) |
POST /v1/orgs/:orgId/sandboxes | Create and provision a sandbox |
POST /v1/sandboxes/:sandboxId/stop | Stop a running sandbox |
POST /v1/sandboxes/:sandboxId/resize | Set an exact sandbox allocation |
POST /v1/sandboxes/:sandboxId/metrics/sample | Sample Firecracker sandbox CPU, memory, and disk pressure |
Create a sandbox
POST /v1/orgs/:orgId/sandboxes{
"agent": "claude",
"projectId": "proj_123",
"name": "my-sandbox",
"repository": "org/repo",
"branch": "main",
"profile": "auto",
"sshPublicKey": "ssh-ed25519 AAAA... remotehost-cli"
}agent and projectId are required (agent is "claude" or "codex") — every other field
falls back to the project's defaults, a selected sandbox profile, or a server-generated value.
profile can be "auto", "agent-small", "agent-standard", "build-heavy",
"browser-heavy", "repo-large", or "long-running". If machineSize is also provided, it
overrides the profile's initial machine tier. Without either field, profile is inferred from
the requested machine size for backward compatibility. Region and infrastructure tier are chosen
server-side from the org's plan and are not client inputs. Returns 201 with
{ "sandbox": { ... } }; the sandbox payload includes sandbox_profile so clients can display
and meter the selected workload profile, plus allocated_vcpu, allocated_memory_gb, and
allocated_disk_gb for the concrete resource shape. Returns 400 if projectId is missing or
unknown, or 409 if the org is at its concurrent-sandbox limit.
List sandboxes
GET /v1/orgs/:orgId/sandboxesReturns { "sandboxes": [...] }, newest first, excluding sandboxes with status: "deleted".
Stop a sandbox
POST /v1/sandboxes/:sandboxId/stopStops the sandbox and ends its machine-time billing.
Resize a sandbox
POST /v1/sandboxes/:sandboxId/resize{
"vcpu": 4,
"memoryGb": 8,
"diskGb": 80
}Sets an exact allocation target. Stopped sandboxes update their persisted allocation immediately.
Running sandboxes apply live only when the provider can verify the resource update; otherwise the
requested shape is stored as pendingAllocation and used on the next resume.
Sample sandbox metrics
POST /v1/sandboxes/:sandboxId/metrics/sampleSamples CPU, memory, and disk pressure from a running Firecracker sandbox, records a
sandbox_metrics_sample event, and returns the current allocation plus the recommended allocation.
For auto sandboxes, a changed recommendation is stored as pendingAllocation and promoted the
next time the sandbox is provisioned or resumed. Live in-place resize still requires an
orchestrator resource-update primitive.
Errors
Error responses are { "error": { "message": "<message>" } } with a matching HTTP status code
— 400 for invalid input, 401/403 for auth and membership failures, 402 for billing
issues, 404 for missing resources, 409 for plan/limit conflicts, 429 for rate limits,
500 for provisioning or database failures.