API Reference

Base URL: https://api.cynchro.cloud (your ROOT_DOMAIN). All /apps, /deploy, /secrets, /admin routes require a Authorization: Bearer <accessToken> header.

Auth

Method Path Body Notes
POST /auth/register {email, password, name?} Open; creates a user + personal org. Returns tokens.
POST /auth/login {email, password} Returns {user, accessToken, refreshToken, orgId}.
POST /auth/refresh {refreshToken} Rotates tokens (old refresh token is revoked).
POST /auth/logout Revokes all your refresh tokens.
GET /auth/me {user, orgId}.
POST /auth/change-password {currentPassword, newPassword} Revokes other sessions; keeps this one.
  • Access token: JWT, ~15 min TTL. Send as Authorization: Bearer.
  • Refresh token: opaque, ~30 days. Exchange at /auth/refresh for new tokens.
  • /auth is rate-limited (30 requests / 5 min per IP).

Deploy

POST /deploy — create or update (idempotent on name) and queue a deployment.

{
  "name": "myapp",            // required, DNS-safe, unique per org
  // one of:
  "image": "acme/api:1.0",    // prebuilt image
  "repo": "https://github.com/acme/api",  // build from source
  "services": [ /* … */ ],    // multi-service (see Multi-Service Apps)

  "branch": "main",           // repo builds
  "dockerfile": "Dockerfile", // relative path, no "..", no leading "/"
  "context": ".",
  "repoToken": "ghp_…",       // PAT for private repos (encrypted)

  "port": 80,                 // 1–65535
  "domain": "www.x.com",      // valid hostname; default <name>.<ROOT_DOMAIN>
  "cpu": 1,                   // cores, max 8
  "memory": 512,              // MB, 64–16384

  "env": { "K": "V" },        // inline env (encrypted at rest)
  "envFrom": ["secret-name"], // inject secret keys as env vars
  "secretFiles": ["secret-name"] // mount secret keys at /run/secrets/<KEY>
}

Blank optional text fields may be omitted or sent as "" — empty strings are treated as “not provided”.

Response 202:

{ "appId":"…","deploymentId":"…","domain":"…","status":"queued","url":"https://…",
  "webhook": { "url":"…","secret":"…","contentType":"application/json","events":["push"] } }

(webhook only for repo apps.)

Apps

Method Path Notes
GET /apps List your org’s apps.
GET /apps/:id App + webhook + last 20 deployments.
POST /apps/:id/restart Recreate container(s).
POST /apps/:id/stop Stop container(s).
DELETE /apps/:id Remove app, containers, network, images.
GET /apps/:id/logs?tail=N Snapshot logs (N ≤ 2000, default 200).
WS /apps/:id/logs/stream?token=<access> Live log stream.

Secrets

Values are never returned — responses list key names only.

Method Path Body / Query Notes
POST /secrets {name, data:{...}, appId?} Create/replace. appId scopes to one app.
GET /secrets List (names + key names + scope).
GET /secrets/:name ?appId= Metadata + key names.
DELETE /secrets/:name ?appId= Delete (omit appId for shared).

Webhooks

Method Path Notes
POST /webhooks/github/:appId GitHub push events. No JWT; verified by HMAC X-Hub-Signature-256 using the app’s webhook secret. Pushes to the configured branch trigger a rebuild.

Admin (operators only)

Gated by the ADMIN_EMAILS allowlist (a normal login is not enough).

Method Path Notes
GET /admin/seal-status { sealed }.
POST /admin/unseal {key, previous?} (64 hex chars) — load the master key into memory.
POST /admin/seal Drop the key from memory.

Errors

JSON shape: { "error": "<code>", … }. Validation errors include field details:

{ "error":"validation", "details": { "fieldErrors": { "name": ["…"] } } }

Common codes: validation, invalid_credentials, missing_bearer_token, invalid_or_expired_token, quota_exceeded, unknown_secret, sealed, app_not_found, rate_limited. See Troubleshooting.


This site uses Just the Docs, a documentation theme for Jekyll.