API

Cloud API

Connect a self-hosted instance to Alaf Server Cloud, and the cloud control-plane endpoints (handoff, edge proxy, pages, subgraph transfer, GitHub App proxy) that back it.

The Cloud API links a self-hosted Alaf Server instance to Alaf Server Cloud (the managed control plane) so it can deploy to cloud runtimes, use managed domains and pages, and borrow the central GitHub App. It has two disjoint halves and which one is mounted depends on the process mode:

  • Self-hosted set (cloud-local) — connect/disconnect, status, and the workspaces/drift listing. Mounted only when the instance is not in cloud mode. This is what you call on your own box.
  • Cloud control-plane set (cloud-saas) — handoff/OAuth, namespace token minting, edge-proxy/pages/analytics proxies, subgraph transfer, and the GitHub App proxy. Mounted only in cloud mode (CLOUD_MODE). Your self-hosted instance calls these machine-to-machine over its stored cloud session; you rarely call them by hand.

Both halves share the base path /api/cloud, but only one is present in any given process.

Base path & auth

All paths are relative to your instance, under /api — e.g. https://your-host/api/cloud/status. The self-hosted endpoints take a personal access token as a bearer header (Authorization: Bearer <token>, from alaf server token create); the dashboard uses your session cookie. The cloud control-plane endpoints authenticate with the cloud session bearer minted during connect (or a signed one-time token in the URL for the public handoff routes) — not a self-hosted PAT. See the API overview and auth model.

Self-hosted endpoints

Present only on a self-hosted instance (not in CLOUD_MODE). The cloud connection is org-owned: it belongs to the organization owner, so every member sees the same verdict. Disconnect and connect-finalize require the owner role, not merely a cloud:admin grant.

Method & pathPermissionWhat it does
GET /api/cloud/statuscloud:readAlaf Server Cloud connection status for this instance.
GET /api/cloud/workspacescloud:readList the org's Alaf Server Cloud (Mtntasci) workspaces, with drift (orphaned cloud/local).
POST /api/cloud/connect-finalizecloud:admin + ownerComplete the connect popup: exchange the PKCE code and store the cloud bearer.
POST /api/cloud/disconnectcloud:admin + ownerClear the org's stored cloud session and prune member GitHub grants.

Check connection status

GET /api/cloud/status
curl https://your-host/api/cloud/status \
  -H "Authorization: Bearer $ALAFSERVER_TOKEN"
# The CLI surfaces the same connection state in its status readout:
alaf server status

Connecting itself is a browser flow started from the dashboard (Settings → Cloud): a popup runs the PKCE handshake against Alaf Server Cloud, then posts the result to connect-finalize below. There is no dedicated alaf server cloud connect CLI verb.

Finalize a connection

The dashboard popup reads its PKCE verifier from localStorage and posts the returned code here to store the org's cloud bearer.

POST /api/cloud/connect-finalize

Prop

Type

Owner only

connect-finalize and disconnect take over the org's cloud bearer, so they are gated by requireRole("owner") on top of the cloud:admin tag. A non-owner with a cloud:admin grant still gets 403.

Cloud control-plane endpoints

Present only in cloud mode (CLOUD_MODE) — i.e. these run on Alaf Server Cloud, not on your self-hosted box. All tenant-scoped operations forward to Mtntasci through the caller's namespace token; Mtntasci enforces the namespace boundary natively, so there is no SaaS-side ownership ledger. The public routes carry no session — they are reached by browser redirects and authenticated by a signed, single-use token in the URL.

Method & pathPermissionWhat it does
GET /api/cloud/desktop-handoffpublicOAuth → one-time code → redirect to the desktop app callback.
GET /api/cloud/connect-handoffpublicValidate connect params, then 302 to the dashboard consent page.
POST /api/cloud/connect-authorizepublicConsent page mints a one-time handoff code (cookie session checked inline).
POST /api/cloud/exchange-codepublicExchange a one-time code for user + session (rate-limited).
POST /api/cloud/tokencloud:writeMint a namespace-scoped Mtntasci token for the caller's org.
GET /api/cloud/accountcloud:readThe connected cloud account (name, email, avatar).
POST /api/cloud/disconnectcloud:adminRevoke the current cloud session server-side (idempotent).
POST /api/cloud/preflightcloud:writeCloud deployment preflight — slug / custom-domain availability.
POST /api/cloud/edge-proxycloud:writeSync the managed edge proxy (bind a slug to a target).
POST /api/cloud/analyticscloud:writeProxy Mtntasci analytics for a hostname in the caller's namespace.
POST /api/cloud/pagescloud:writeCreate a Cloud Page (proxy Mtntasci pages.create).
POST /api/cloud/pages/enablecloud:writeEnable a Cloud Page by slug.
POST /api/cloud/pages/disablecloud:writeDisable a Cloud Page by slug.
POST /api/cloud/pages/deletecloud:writeDelete a Cloud Page by slug.
POST /api/cloud/send-invitationcloud:writeRelay an invitation email via the SaaS mail infrastructure.
POST /api/cloud/ingest-subgraphcloud:adminIngest an org- or project-scope subgraph dump (rate-limited, 50MB cap).
POST /api/cloud/export-subgraphcloud:adminExport an org- or project-scope subgraph dump (rate-limited).
POST /api/cloud/teardown-projectcloud:adminDelete a project's rows on the SaaS (bring-home / reconcile).
POST /api/cloud/github/oauth-handoffcloud:writeStart GitHub OAuth: return a one-time bridge URL.
GET /api/cloud/github/oauth-bridgepublicConsume the bridge token and redirect the browser into GitHub OAuth.
GET /api/cloud/github/oauth-successpublicFriendly "GitHub connected" close-window page.
POST /api/cloud/github/install-urlcloud:writeBuild the App install URL with a one-time state token.
GET /api/cloud/github/install-callbackpublicGitHub install callback — attribute the install to the starting user.
GET /api/cloud/github/installationscloud:readList the org owner's GitHub App installations.
POST /api/cloud/github/installation-tokencloud:writeMint a short-lived (~60min) installation access token.
GET /api/cloud/github/user-statuscloud:readCloud-resolved GitHub OAuth identity (login, avatar) for the caller.

These are mostly internal

Your self-hosted instance calls the control-plane endpoints for you via its cloud client — you don't wire them up by hand, and there is no alaf server CLI verb that maps to them one-to-one. The request shapes below are documented so integrators can reason about the traffic.

Handoff & code exchange

The connect and desktop-login flows never hand the local instance a browser cookie. Instead a short-lived, PKCE-bound handoff code is minted (connect-authorize), then swapped for a dedicated session (exchange-code).

POST /api/cloud/connect-authorize

Prop

Type

POST /api/cloud/exchange-code

Prop

Type

The public GET handoff routes take query params, not a body — desktop-handoff and connect-handoff expect redirect, state, and code_challenge; github/install-callback expects installation_id, setup_action, and state; github/oauth-bridge expects token.

Deploy proxies (preflight, edge proxy, analytics)

POST /api/cloud/preflight

Prop

Type

POST /api/cloud/edge-proxy

Prop

Type

POST /api/cloud/analytics

Prop

Type

Pages

pages creates a managed static page; the enable/disable/delete actions each take just a slug.

POST /api/cloud/pages

Prop

Type

POST /api/cloud/pages/disable   (also /enable, /delete)

Prop

Type

Invitation relay

Used when a self-hosted operator sets invitationMailSource = "cloud" — the SaaS sends the email from its own infrastructure. Capped at 20/hour per org inside the service.

POST /api/cloud/send-invitation

Prop

Type

Subgraph transfer & teardown

The ingest/export pair moves an org's or a single project's rows between a self-hosted instance and the SaaS (team-mode migration and project transfer). Instance-scope dumps are refused.

POST /api/cloud/ingest-subgraph

Prop

Type

POST /api/cloud/export-subgraph

Prop

Type

POST /api/cloud/teardown-project

Prop

Type

GitHub App proxy

Cloud holds the GitHub App private key; self-hosted instances never do. Local hands off (userId, request) and gets resolved data back — it never signs a JWT or sees the App credentials.

POST /api/cloud/github/installation-token

Prop

Type

installationId is never accepted from the body

installation-token resolves the installation from the caller's org, not from a client-supplied id — passing one has no effect. This prevents a caller from minting a token for an installation it doesn't own.

Errors you might see

403 — owner required (self-hosted connect/disconnect)

connect-finalize and disconnect require the org owner role. A member with only a cloud:admin grant is rejected.

409 — slug already taken (edge proxy / pages)

The requested slug is owned by another tenant on the shared cloud zone. Mtntasci returns 409 and Alaf Server forwards it. Choose a different slug.

412 — dump format mismatch (ingest)

ingest-subgraph rejects dumps whose formatVersion doesn't match the SaaS (code: INGEST_FORMAT_MISMATCH). Update your local instance and re-dump.

413 — dump too large (ingest)

ingest-subgraph caps the request body at 50MB (code: PAYLOAD_TOO_LARGE) before auth even runs.

401 — invalid or expired code / session

Handoff codes are single-use and time-bound; exchange-code returns 401 once consumed or expired. The control-plane cloud:* endpoints return 401 when the cloud session bearer is missing or revoked — reconnect from the dashboard.

On this page