Cloud API¶
The REST API exposed by Repster Cloud. Used by the Repster CLI and the Repster Cloud UI. You can call it directly for automation or integration.
Base URL: https://cloud.repster.online/api — the paths below are relative to it. (The browser UI is served at https://cloud.repster.online/; GET /health lives at the host root, outside /api.)
Auth: API key in the Authorization: Bearer rpk_... header. Keys are org-scoped, so all endpoints automatically scope to the calling key's org.
Client header: X-Repster-Client: <version>, sent automatically by the CLI.
Async runs: POST /runs returns a run_id immediately. Poll GET /runs/{id} or stream logs via GET /runs/{id}/logs?follow=true.
Auth endpoints (no token required)¶
| Method | Path | Body | Returns |
|---|---|---|---|
POST |
/auth/register |
{email, password, org_slug?, org_name?} |
{org, api_key} (raw key shown once), or {needs_org: true} when org_slug is omitted |
POST |
/auth/login |
{email, password, org_slug?} |
{org, api_key} (plus orgs: [...] when the user has multiple orgs) or {needs_org: true} when the user belongs to none |
POST |
/auth/create-org |
{email, password, org_slug, org_name} |
{org, api_key} |
Registering without org_slug creates the account alone. It holds no API key — keys are
org-scoped — so it can reach nothing until it is added to an org or creates one via
POST /auth/create-org. Since POST /orgs/{org_id}/members only ever adds an existing
account, this is how somebody joins an org they were told about.
Passwords must be at least 12 characters, on registration and on change alike.
A failed login returns 401 {"detail": "invalid email or password", "email_known": bool},
so a client can offer registration to a stranger and a password retry to someone who
already has an account.
When a user belongs to multiple orgs and org_slug is omitted from POST /auth/login, the response includes orgs listing all their orgs. Re-POST with org_slug to select one.
The login response also includes must_change_password: true when the account was created with a system-generated temporary password (operator provisioning) and has not yet set its own. Password-authenticated surfaces require the reset first: the browser UI redirects to a change-password screen, and rp login walks the user through it.
User identity¶
| Method | Path | Body | Returns |
|---|---|---|---|
GET |
/users/me |
— | {user_id, email, created_at} |
GET |
/users/me/orgs |
— | [{org_id, slug, name, role, joined_at}] |
POST |
/users/me/password |
{current_password, new_password} |
{org, api_key} — a fresh session key; clears the forced-reset flag and revokes other sessions |
new_password must be at least 12 characters (422 otherwise); a wrong current_password returns 401.
Org management¶
| Method | Path | Body | Returns |
|---|---|---|---|
GET |
/orgs/me |
— | {org_id, slug, name, created_at, terms_required, terms_accepted} |
POST |
/orgs |
{slug, name} |
{org, api_key} |
terms_required is the terms version your org must have accepted (null when none is in force) and terms_accepted says whether it has. The CLI reads them here to detect the gate before running a command — see Terms.
Terms¶
Repster Cloud can require your org to accept its legal terms before it may deploy, run flows, or write secrets.
| Method | Path | Body | Returns |
|---|---|---|---|
GET |
/terms |
— | {required, accepted, accepted_version, accepted_at, accepted_via, can_accept} |
POST |
/terms/accept |
— (admin only) | the updated terms state |
required is the version in force (null when none is), accepted whether your org has accepted it, and can_accept whether the calling key may accept — acceptance is org-level and admin-only, so a member is told to find an admin rather than offered a call that would 403. accepted_via records whether acceptance came from the browser (ui) or the CLI (cli).
POST /terms/accept returns 409 when no version is in force — there is nothing to bind the org to.
While terms are outstanding, POST /deployments, POST /runs and PUT /projects/{project}/secrets return 403. Reads, POST /auth/login and this section stay open, so a gated org can still authenticate, inspect its state, and accept.
The CLI handles all of this for you: any cloud command prompts an admin to accept inline before it does any work, and rp terms show / rp terms accept cover the scripted cases.
Key management (admin only)¶
| Method | Path | Body | Returns |
|---|---|---|---|
POST |
/orgs/{org_id}/keys |
{name} |
{key_id, raw_key, ...} (raw key shown once) |
GET |
/orgs/{org_id}/keys |
— | [{key_id, name, key_prefix, created_at, last_used_at, revoked_at}] |
DELETE |
/orgs/{org_id}/keys/{key_id} |
— | {ok: true} |
Member management (admin only)¶
| Method | Path | Body | Returns |
|---|---|---|---|
GET |
/orgs/{org_id}/members |
— | [{user_id, email, role, created_at}] |
POST |
/orgs/{org_id}/members |
{email, role?} |
{user_id, email, role, created_at} (201), or 404 if the email has no account |
PATCH |
/orgs/{org_id}/members/{user_id} |
{role} |
updated member |
DELETE |
/orgs/{org_id}/members/{user_id} |
— | {ok: true} |
role defaults to "member". Valid values: "admin", "member". Cannot remove or demote the last admin (409). Cannot remove yourself (409).
Deployments¶
| Method | Path | Body | Returns |
|---|---|---|---|
POST |
/deployments |
multipart: manifest + archive |
{deployment_id, code_digest} |
GET |
/deployments?project= |
— | deployments for the caller's org, latest first |
Creating a deployment (POST) is admin only; any org member can list them (GET).
Deployments are immutable and content-addressed, so uploading the same archive twice returns the existing deployment.
POST also returns 403 while your org has terms outstanding.
Flows¶
| Method | Path | Params | Returns |
|---|---|---|---|
GET |
/flows?project= |
optional project filter |
[{project, flow, schedule, entrypoint}] for the caller's org |
The flows across the org's deployments, used by rp list --cloud and the UI Flows page. Available to any org member.
Runs¶
| Method | Path | Body / Params | Returns |
|---|---|---|---|
POST |
/runs |
{project, flow, trigger, retry_of?} |
{run_id, status: "pending"} — the hosted service enqueues the run for the reconciler; it then progresses to running and a terminal state |
GET |
/runs?project=&flow=&limit= |
— | run records for the caller's org |
GET |
/runs/{id} |
— | {run_id, project, flow, status, trigger, deployment_id, started_at, finished_at, rows_loaded, summary, retry_of, duration_seconds, cost_usd, error} |
GET |
/runs/{id}/logs |
?follow=bool |
full log text; SSE stream when follow=true |
POST |
/runs/{id}/cancel |
— (admin only) | the updated run record with status: "cancelled" |
POST /runs returns 404 with a helpful message if the flow has never been deployed. It
also returns 403 while the org has terms outstanding, and enforces spend
guardrails before dispatch: 403 if the org is disabled (kill switch), 429 if the
org has reached its monthly cost cap. A finished run records
duration_seconds (wall-clock) and cost_usd (an estimate from the sandbox's pinned
resources at Modal's published rates); both are null until the run finishes. A failed
run also carries a short error reason (the full output stays in the run logs).
POST /runs/{id}/cancel terminates an in-flight run (Modal sandbox) and marks it
cancelled. Returns 409 if the run has already finished (or is a local inline run with no
detached handle), 404 if it isn't in the caller's org.
Usage¶
| Method | Path | Returns |
|---|---|---|
GET |
/usage |
{org_id, enabled, month, run_count, compute_seconds, cost_usd, monthly_cost_cap_usd, by_flow: [...]} |
Current calendar-month (UTC) usage for the caller's org: run count, wall-clock compute
seconds, estimated spend, and the effective monthly cost cap (null = unlimited).
by_flow breaks the same figures down per (project, flow). Metering only — there is no
billing.
Secrets (admin only)¶
| Method | Path | Body | Returns |
|---|---|---|---|
PUT |
/projects/{project}/secrets |
{KEY: VALUE, ...} |
{ok: true} |
GET |
/projects/{project}/secrets |
— | key names only (values are never returned) |
DELETE |
/projects/{project}/secrets/{key} |
— | {ok: true} |
PUT also returns 403 while your org has terms outstanding.
Health¶
| Method | Path | Returns |
|---|---|---|
GET |
/health |
{ok: true} (no auth required) |