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://repster.online/api — the paths below are relative to it. (The browser UI is served at https://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) |
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} |
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 or a member invite) 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} |
POST |
/orgs |
{slug, name} |
{org, api_key} |
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, temp_password?} (201) |
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.
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 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} |
Health¶
| Method | Path | Returns |
|---|---|---|
GET |
/health |
{ok: true} (no auth required) |