Skip to content
flypod
CLI reference

Account commands

Connect the flypod CLI to an account, list owned sites, attach anonymous deploys, and remove the local session.

Accounts are optional. Anonymous deploys still work without one and expire after 14 days. A connected CLI creates owned deploys with no expiry.

flypod login

flypod login

The CLI requests a device code, prints the code and approval URL, and waits for you to approve the request in a signed-in browser. It then saves the returned session token in session.json (mode 0600) inside your per-user flypod config directory. Nothing is written to the project.

If you already hold a Better Auth session token, you can save it directly:

flypod login --token <session_token>

The token is checked against the server before it is saved. A token the server does not accept fails with token_rejected (exit 3) and nothing is saved; if the server cannot be reached, nothing is saved either.

Signing in from an agent

An agent cannot open a browser and must not block for ten minutes waiting for one. Under --json (and when a coding agent runs plain flypod login with no terminal), flypod login starts the device sign-in, hands back everything a person needs to finish it, and exits at once with interactive_login_required (exit 2):

flypod login --json
{
  "ok": false,
  "code": "interactive_login_required",
  "error": "Sign-in needs a browser. Ask the user to open the URL and confirm the code.",
  "fix": "Ask the user to open https://flypod.dev/device?user_code=ABCD-EFGH and confirm code ABCD-EFGH. Once they have, your next flypod command (a deploy, `flypod list`, anything) finishes signing in by itself; to finish it now, run `flypod login --device-code <device_code> --json`, which waits up to 25s for the confirmation.",
  "verification_uri": "https://flypod.dev/device",
  "verification_uri_complete": "https://flypod.dev/device?user_code=ABCD-EFGH",
  "user_code": "ABCD-EFGH",
  "device_code": "…",
  "expires_in": 600,
  "interval": 5
}

Give the person the URL; that is all the agent has to do. The CLI remembers the pending sign-in (pending-login.json in the config directory: a device code, not a credential, worthless after ten minutes). Once the person has confirmed, the next flypod command of any kind (a deploy, flypod update, flypod list, …) checks once, for at most a couple of seconds, finishes signing in, and keeps every site on this machine, exactly as flypod login does. Then it runs signed in. In a terminal it prints one line, ✓ Signed in · 2 sites kept, no expiry; under --json or -q it prints nothing extra.

To finish at once instead:

flypod login --device-code <device_code> --json

It waits up to 25 seconds for the confirmation. Still unconfirmed after that, it fails with authorization_pending (exit 4: run it again, or just carry on, since the next command finishes it); denied is login_denied, an expired code is login_expired, and so is a code that was already used or a user_code passed in place of the device_code. A code that another command already finished answers {"ok": true, "logged_in": true, …}.

If the person had to sign in to flypod first, the approve page sends them back to it once they have, so they confirm the code without hunting for it.

On success, flypod login --json (with --token or --device-code) prints:

{ "ok": true, "logged_in": true, "attached": ["a3f1c2d4e5b60789"], "skipped": [] }

attached lists the temporary sites that became yours; skipped lists the ones that could not be, each with a reason.

FlagDescription
--token <session_token>Check and save this session token instead of opening a browser.
--device-code <code>Wait up to 25 seconds for the approval of a sign-in started with --json.
--jsonEmit JSON on stdout; never blocks waiting for a browser.
-h, --helpPrint usage and exit.

For a stateless agent or CI job, prefer the environment instead of a session file:

FLYPOD_TOKEN=<session_token> flypod ./dist --json

Session tokens act as your account. Store them in a secret manager, never commit them, and do not confuse them with a site's manage_token.

Auto-attach on login

After login, the CLI finds anonymous sites remembered on this machine (for the same server) and sends their stored manage_tokens to POST /account/bulk-attach. Successfully attached sites become owned and permanent: same URLs, same versions. The CLI then drops each attached site's manage_token from the project registry — the server no longer accepts it for an owned site, and your session authorizes instead. If the attach request fails, login still succeeds and the sites stay temporary until you run flypod login again.

flypod logout

flypod logout

Deletes the saved session from session.json, and drops a sign-in still waiting for its person, so it cannot finish after the logout. It does not revoke other browser or CLI sessions and does not delete sites. With --json it prints {"ok":true,"signed_out":true}, or "signed_out":false when there was no saved session.

flypod list

flypod list

Lists owned sites as JSON on stdout, with or without --json: {"ok":true,"sites":[…]}, and {"ok":true,"sites":[]} when there are none yet. Requires a saved login or FLYPOD_TOKEN; without either it fails with not_signed_in (exit 3).

flypod claim

flypod claim <site_id> <claim_token>

Attaches one anonymous deploy to the authenticated account. This is mainly a cross-machine fallback: normal login auto-attaches sites the local CLI already remembers. Requires a saved login or FLYPOD_TOKEN. It prints JSON on stdout:

{ "ok": true, "site_id": "a3f1c2d4e5b60789", "owner_account_id": "…", "expires_at": null }

A site that already belongs to another account fails with already_claimed. Any local link to the site is updated so it no longer expires.

Credential precedence

For account operations and deploys, flypod resolves credentials in this order:

  1. FLYPOD_TOKEN for the current process.
  2. The session saved by flypod login.
  3. FLYPOD_API_KEY, accepted only as a legacy compatibility fallback.
  4. No credential, which produces an anonymous deploy.

The site commands (update, versions, rollback) put two site-scoped credentials in front of that list: an explicit --token <manage_token> first, then the manage_token this machine stored for the site when it deployed it anonymously.

Whatever credential is chosen is the one sent. If the server does not accept it, the command fails (token_rejected on a deploy, unauthorized on a site command); it never silently falls back to anonymous.

The server comes from the saved session's host, then DEPLOY_URL, then https://flypod.dev. flypod login itself always targets DEPLOY_URL (or the default), never an old session's host.

See Tokens and ownership for the difference between account sessions, manage_token, and claim_token.

On this page