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 loginThe 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> --jsonIt 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.
| Flag | Description |
|---|---|
--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. |
--json | Emit JSON on stdout; never blocks waiting for a browser. |
-h, --help | Print usage and exit. |
For a stateless agent or CI job, prefer the environment instead of a session file:
FLYPOD_TOKEN=<session_token> flypod ./dist --jsonSession 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 logoutDeletes 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 listLists 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:
FLYPOD_TOKENfor the current process.- The session saved by
flypod login. FLYPOD_API_KEY, accepted only as a legacy compatibility fallback.- 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.