DocsREST API

REST API

The Ruust REST API: log in for a bearer token, then list, lay and inspect your Eggs over HTTPS.

The Ruust REST API is what the CLI and the dashboard talk to, and you can talk to it directly too. Every endpoint lives under /api/v1/ on the control plane and speaks JSON over HTTPS. You authenticate once to get a bearer token, then send it on each call. This page documents the endpoints that exist today. Nothing here is a placeholder. Call POST /api/v1/auth/login with your email and password to exchange them for a token: the response gives you a token, its expiresAt (an ISO 8601 timestamp in UTC) and the email it belongs to. A token lasts 30 days. Send it on every other call as an Authorization: Bearer <token> header. A failed login always returns an identical 401, so the endpoint never discloses which accounts exist.

bash
# Log in, then reuse the token on every call.
RUUST_TOKEN=$(curl -s https://ruust.run/api/v1/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"email": "[email protected]", "password": "..."}' | jq -r .token)

curl -s https://ruust.run/api/v1/me -H "Authorization: Bearer $RUUST_TOKEN"
# => {"id": "cus_...", "email": "[email protected]"}
Exchange an email and password for a bearer token, then confirm it with /api/v1/me.

Deploy it

  1. Log in with POST /api/v1/auth/login and keep the token.
  2. Pick a region with GET /api/v1/regions (no token needed): eu-west is London, us-east is Virginia.
  3. Lay a new Egg with POST /api/v1/eggs, passing a repo, a branch (defaults to main), a region and a tier (nano, small, standard or large).
  4. Poll GET /api/v1/eggs/:id/status until the lifecycle reaches hatched.
bash
# Lay a new Egg from a repository. Returns 201 with the created Egg.
curl -s https://ruust.run/api/v1/eggs \
  -H "Authorization: Bearer $RUUST_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"repo": "you/app", "branch": "main", "region": "eu-west", "tier": "standard"}'

# List every Egg you own.
curl -s https://ruust.run/api/v1/eggs -H "Authorization: Bearer $RUUST_TOKEN"
# => {"eggs": [ ... ]}
POST /api/v1/eggs lays an Egg; GET /api/v1/eggs lists them.

The port

The API lays an Egg for you, but the Egg still has to hatch, and that comes down to the port contract. Ruust sets a PORT env var in the container and your app must listen on it and bind to 0.0.0.0, not localhost. Binding to localhost is the top reason an Egg builds but never hatches, and GET /api/v1/eggs/:id/status will sit at hatching rather than reaching hatched. The API cannot fix this for you; it is your code that must read PORT.

javascript
const port = process.env.PORT || 3000;
app.listen(port, '0.0.0.0', () => {
  console.log('listening on', port);
});
Whatever the API lays, the app inside must listen on PORT and bind to 0.0.0.0.

Inspecting your Eggs

  • GET /api/v1/eggs/:id returns one Egg in full detail: its domains, its latest deployment and the KEYS of its environment variables (never the values). A missing or unowned Egg returns an identical 404, so the Egg of another customer is never disclosed.
  • GET /api/v1/eggs/:id/status polls the lifecycle (incubating, hatching, hatched, cold, cracked) plus the short git sha and finish time of the latest deployment. Ideal for watching a hatch land.
  • GET /api/v1/eggs/:id/logs returns the recent container log tail as { lines: [{ ts, level, text }] }. These are real stdout and stderr lines shipped by the agent; stderr surfaces as warn.
  • GET /api/v1/eggs/:id/build-log returns the redacted build output of the latest deployment. Secrets are stripped before storage, so it is safe to read.
  • GET /api/v1/eggs/live returns the volatile state of every Egg you own (lifecycle plus the latest reported RAM and CPU) in one batched call.
  • Errors are consistent: 401 when the token is missing or invalid, 400 with a human-readable error for a bad body, 404 when you cannot see the Egg.