CLI

Access & the raw API

Log in, switch between instances with contexts, manage personal access tokens, and call any API route directly with openship api.

These commands are how the CLI knows which Openship it's talking to and who you are — plus an escape hatch (openship api) for reaching any route that doesn't have its own command yet.

Where auth lives

The CLI keeps its settings in ~/.openship/config.json (mode 0600). That file holds one or more named contexts — each pins an API URL, a dashboard URL, and a personal access token (a opsh_pat_… string). One context is active at a time; every authenticated command reads from it. The default context is called default and points at your local instance (http://localhost:4000).

JSON output

--json is a global flag — put it before the subcommand (openship --json token list). In JSON mode the data is written to stdout as JSON while status messages go to stderr, so a piped stream stays clean. Setting OPENSHIP_JSON=1 in the environment does the same thing. openship api always prints the response body.

openship login

Authenticate against an instance and save the token into a context. Run with no --token and it opens the dashboard's Settings page — where Personal Access Tokens live — and waits for you to paste one; pass --token to log in non-interactively (CI, scripts). The token is validated against the API before it's stored, and it must start with opsh_pat_.

# Interactive — opens the dashboard, prompts for a pasted token
openship login

# Non-interactive — against a remote self-hosted instance, stored as a named context
openship login \
  --token opsh_pat_xxxxxxxx \
  --api-url https://openship.example.com \
  --dashboard-url https://openship.example.com \
  --context prod
FlagPurposeDefault
--token <token>Personal access token (opsh_pat_…) for non-interactive login.(prompted)
--api-url <url>API base URL to authenticate against.http://localhost:4000
--dashboard-url <url>Dashboard base URL (used to open the token page).http://localhost:3001
--context <name>Name of the context to store this login under.default

Can't reach the API?

If login reports it couldn't reach the API, the host in --api-url isn't responding. Point it at the right instance — for a remote self-hosted box that's the same URL you open in the browser.

openship logout

Remove the stored token from a context. The endpoints stay saved, so a later login just re-adds the token.

openship logout                 # active context
openship logout --context prod  # a specific one
FlagPurposeDefault
--context <name>Log out of a specific context.(active context)

openship context

Manage the named connections in ~/.openship/config.json. This is pure local config editing — no API calls. Use it to keep several instances side by side (local, staging, production) and switch between them. Alias: openship ctx. Running it bare prints the active context and the full list (the active row is starred).

openship context           # show active + list all
openship context use prod  # switch the active context
SubcommandPurpose
list (alias ls)List configured contexts.
use <name>Switch the active context.
add <name>Create or update a context's endpoints/token.
rm <name> (alias remove)Remove a context (can't remove the active one — switch away first).

The list shows one row per context: current (* marks the active one), name, apiUrl, dashboardUrl, and auth (token when a token is stored, - when not).

context add

Register an instance without logging in interactively. add only writes config — use login when you want the token checked against the API first.

openship context add staging \
  --api-url https://staging.example.com \
  --dashboard-url https://staging.example.com \
  --token opsh_pat_xxxxxxxx \
  --use
FlagPurpose
--api-url <url>API base URL.
--dashboard-url <url>Dashboard base URL.
--token <token>Personal access token to store.
--useSwitch to this context after adding.

openship token

Create and manage the personal access tokens that authenticate the CLI and the API. Tokens are self-scoped — every call operates on your own tokens. In the dashboard these live under Settings → Personal Access Tokens.

SubcommandPurpose
listList your personal access tokens.
create <name>Mint a new token (the secret is shown once).
revoke <id>Revoke one of your tokens.

token create

# A full-access, non-expiring token
openship token create "laptop"

# A read-only token that expires in 30 days
openship token create "ci-reader" --read-only --expires 30

# Scope a token to one project with specific permissions (repeatable)
openship token create "deploy-bot" --grant project:abc123:read,write
FlagPurposeDefault
--read-onlyReject mutation methods (POST/PUT/PATCH/DELETE).off
--expires <days>Expire after N days (1–365); omit for a non-expiring token.never
--grant <type:id:perms>Scope the token to a resource. Repeatable. Format type:id:perm1,perm2, e.g. project:abc123:read,write.(full access)

Copy the secret immediately

token create prints the full opsh_pat_… secret once and never again. token list only ever shows a short prefix. If you lose it, revoke the token and mint a new one.

The list table shows: id, name, prefix, readOnly, scoped, expires, lastUsed, and revoked. Pass a token's id (they look like pat_…) to revoke:

openship token list
openship token revoke pat_abc123

openship api

The escape hatch. Make an authenticated request to any API route using the active context's token — much like gh api. This is what keeps the CLI small: anything without a dedicated command (audit log, one-off reads, routes added after your CLI version) is still reachable here.

The <path> argument is relative to /api, so openship api /projects calls <your-api-url>/api/projects. The method defaults to GET, or POST when you pass --data.

# GET a collection
openship api /projects

# GET a single resource
openship api /deployments/dep_abc123

# POST with a JSON body (method defaults to POST when --data is given)
openship api /domains -d '{"projectId":"proj_123","hostname":"app.example.com"}'

# DELETE with an explicit method
openship api /tokens/pat_abc123 -X DELETE

# Add query parameters (repeatable)
openship api /domains -q projectId=proj_123
FlagPurposeDefault
-X, --method <method>HTTP method.GET, or POST when --data is set
-d, --data <json>Request body as a JSON string.(none)
-q, --query <kv...>Query parameter key=value. Repeatable.(none)

The response body is printed to stdout — pretty-printed when it's JSON, raw otherwise. On a non-2xx response the body is still printed and the command exits non-zero, so you can pipe it into jq and still detect failures in scripts.

Which routes exist?

Browse the API reference for paths, methods, and required permissions. The resource commands (project, service, domain, and friends) wrap the common ones in a friendlier form — reach for openship api when there's no dedicated command.

On this page