API

Cloud

Connect installations to Cloud and use its HTTP control endpoints.

Cloud endpoints connect a self-hosted installation to Openship Cloud and support browser handoffs, managed routing, and transfers. The self-hosted connection routes and Cloud control-plane routes share /api/cloud; the process mode determines which are available.

There is no named native cloud group. To manage Cloud projects through the SDK, use the remote client with the canonical Cloud API and Cloud organization ID. A local owner's Cloud link does not authorize fixed requests or bound/scoped credentials to manage Cloud-stored records; see Cloud compatibility.

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.

Check connection status

GET /api/cloud/status
curl "$OPENSHIP_URL/api/cloud/status" \
  -H "Authorization: Bearer $OPENSHIP_TOKEN"

Connecting itself is a browser flow started from the dashboard (Settings → Cloud): a popup runs the PKCE handshake against Openship Cloud, then posts the result to connect-finalize below. There is no dedicated openship 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 Openship Cloud, not on your self-hosted box. All tenant-scoped operations forward to Oblien through the caller's namespace token; Oblien enforces the namespace boundary natively, so there is no SaaS-side ownership ledger. The public handoff routes are reached by browser redirects and authenticated by a signed, single-use token in the URL.

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 openship 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.

GitHub installation links first open Openship's account selection using flow=select and state. The user can reconnect an existing installation or continue to GitHub for a new one. This also works in the external browser used by self-hosted and desktop instances: the temporary state binds the choice to its initiating user and workspace without requiring a Cloud browser session. Discovery and selection recheck access, and the installation claim uses the same verification and transaction as the dashboard picker.

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

Dashboard product telemetry

POST /api/cloud/telemetry

This optional, first-party endpoint accepts only allowlisted dashboard page and checkout-navigation events. It is separate from the customer traffic analytics relay above and is not an SDK or MCP operation. It returns 404 unless production Cloud telemetry is explicitly configured.

Requests must come from the configured dashboard Origin, use the browser's cookie session when signed in, and omit bearer authorization. The server verifies the current session before associating events with a user or organization. Browser events cannot report payments or other business outcomes; unrecognized properties and bodies larger than 4 KiB are rejected.

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/promote-project

Explicit project promotion uses this receipt-aware variant with { dump, promotionId }. The source persists the transfer ID and original Cloud identity before making the request. Cloud commits the receipt in the same transaction as the project data. A retry with that receipt returns the original import counts, allowing the source to retry local cleanup without importing or overwriting again. Matching project IDs alone do not authorize cleanup; older duplicates without a receipt require review. Both instances must support this endpoint. An older Cloud API rejects it before importing.

Before local cleanup starts, Openship blocks configuration writes and checks the source snapshot again. An edit committed before this check preserves the local copy with TRANSFER_SOURCE_CHANGED; edits attempted during cleanup return PROJECT_TRANSFER_IN_PROGRESS. Failed cleanup releases this guard so the project remains editable. New builds admitted after import are preserved, not cancelled as part of promotion.

Promotion transfers configuration; it does not migrate running workloads or persistent application data. Deploying a local project on a connected Cloud server uses serverId and does not require promotion. See the desktop MCP workflow.

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

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. Oblien returns 409 and Openship 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.

Operations

Managed server connections

OperationREST API
Verify the connected Cloud user's administration of a server in the exact requested organization before linking an installation.POST /api/cloud/servers/:id/authorize
server:admin
Issue namespace-scoped server credentials after ownership checks; work admission also verifies the subscription. Credentials stay on the installation's server and must not be exposed to a browser.POST /api/cloud/servers/:id/connection
server:admin
Claim durable server activity for a linked installation and synchronize its project registry before execution; a disconnected claim does not expire.POST /api/cloud/servers/:id/activity
server:admin
Release the same user's exact controller and activity claim after work finishes, and update its registered projects.POST /api/cloud/servers/:id/activity/release
server:admin
Read a durable deletion receipt using billing administration, the original organization and exact operationId after the server row has been removed.GET /api/cloud/server-deletions/:id
billing:admin

HTTP endpoints

OperationREST API
The connected cloud account (name, email, avatar).GET /api/cloud/account
cloud:read
Proxy Oblien analytics for a hostname in the caller's namespace.POST /api/cloud/analytics
cloud:write
Capture optional hosted dashboard product events with exact-origin and verified cookie identity checks.POST /api/cloud/telemetry
Handler authentication
Consent page mints a one-time handoff code (cookie session checked inline).POST /api/cloud/connect-authorize
Handler authentication
Complete the connect popup: exchange the PKCE code and store the cloud bearer.POST /api/cloud/connect-finalize
cloud:admin · Self-hosted
Validate connect params, then 302 to the dashboard consent page.GET /api/cloud/connect-handoff
Handler authentication
Poll the local Cloud connection handoff.GET /api/cloud/connect-poll
Handler authentication
OAuth → one-time code → redirect to the desktop app callback.GET /api/cloud/desktop-handoff
Handler authentication
Revoke the current cloud session server-side (idempotent).POST /api/cloud/disconnect
cloud:admin
Sync the managed edge proxy (bind a slug to a target).POST /api/cloud/edge-proxy
cloud:write
Remove an authorized Cloud edge-proxy route.POST /api/cloud/edge-proxy/delete
cloud:write
Begin verification for an edge-proxy domain.POST /api/cloud/edge-proxy/verify
cloud:write
Check edge-proxy domain verification.POST /api/cloud/edge-proxy/verify-check
cloud:write
Exchange a one-time code for user + session (rate-limited).POST /api/cloud/exchange-code
Handler authentication
Export an org- or project-scope subgraph dump (rate-limited).POST /api/cloud/export-subgraph
cloud:admin
Select an existing GitHub installation with flow=select, or atomically claim the workspace-bound attempt after GitHub user-token and App-JWT verification.GET /api/cloud/github/install-callback
Handler authentication
Build an Openship installation-selection URL with a one-time workspace state; existing installations can reconnect without another GitHub setup callback.POST /api/cloud/github/install-url
cloud:write
Mint a short-lived (~60min) installation access token.POST /api/cloud/github/installation-token
cloud:write
List the org owner's GitHub App installations.GET /api/cloud/github/installations
cloud:read
Consume the bridge token and redirect the browser into GitHub OAuth.GET /api/cloud/github/oauth-bridge
Handler authentication
Start GitHub OAuth: return a one-time bridge URL.POST /api/cloud/github/oauth-handoff
cloud:write
Friendly "GitHub connected" close-window page.GET /api/cloud/github/oauth-success
Handler authentication
Cloud-resolved GitHub OAuth identity (login, avatar) for the caller.GET /api/cloud/github/user-status
cloud:read
Ingest an org- or project-scope subgraph dump (rate-limited, 50MB cap).POST /api/cloud/ingest-subgraph
cloud:admin
Import a project and its promotion receipt atomically, or acknowledge the same original import on retry (rate-limited, 50MB cap).POST /api/cloud/promote-project
cloud:admin
Create a Cloud Page (proxy Oblien pages.create).POST /api/cloud/pages
cloud:write
Delete a Cloud Page by slug.POST /api/cloud/pages/delete
cloud:write
Disable a Cloud Page by slug.POST /api/cloud/pages/disable
cloud:write
Enable a Cloud Page by slug.POST /api/cloud/pages/enable
cloud:write
Cloud deployment preflight — slug / custom-domain availability.POST /api/cloud/preflight
cloud:write
Run an allowed Pages or routing action after verifying customer namespace ownership.POST /api/cloud/resource-proxy
cloud:write
Read routes or certificates belonging to the caller's Cloud namespace.GET /api/cloud/route-registry
cloud:read
Relay an invitation email via the SaaS mail infrastructure.POST /api/cloud/send-invitation
cloud:write
Openship Cloud connection status for this instance.GET /api/cloud/status
cloud:read · Self-hosted
Delete a project's rows on the SaaS (bring-home / reconcile).POST /api/cloud/teardown-project
cloud:admin
Mint a namespace-scoped Oblien token for the caller's org.POST /api/cloud/token
cloud:write

On this page