CLI command reference

Every operation in the platform is available as its own geopera <resource> <action> command, generated directly from the published operation list, so catalog.search becomes geopera catalog search and request fields become first-class --flags you can discover with --help. This page is the complete reference for that command tree: how operation ids map to commands, how request-body fields map to flags (scalars, repeatable arrays, paired booleans, required markers), how the --json fallback composes with flags, the static commands (login, logout, whoami), shell completion, the low-level geopera op escape hatch, and the exit-code contract scripts can rely on. For installation, profiles, and the credential store, see the CLI overview; for the request model behind each command, see operations; for token formats, see authentication.

Synopsis

bash
geopera [COMMAND] [SUBCOMMAND...] [OPTIONS]

Running geopera with no command prints help and lists the top-level resources. Commands fall into two groups:

GroupExamplesPurpose
Generated operation commandsgeopera catalog search, geopera orders archive placeOne command per operation, with typed flags.
Static commandsgeopera login, geopera logout, geopera whoamiAuthentication and identity.

A third, hidden command — geopera op — invokes any operation by raw id and is documented below as an escape hatch.

Global options

Two options are shared by every command that talks to the API. Both fall back to environment variables, then to the value stored in the active profile, then to a built-in default.

OptionEnv varDefaultDescription
--profileGEOPERA_PROFILEdefaultStored identity to use. Profiles namespace separate credentials in ~/.config/geopera/credentials.json.
--api-urlGEOPERA_API_URLhttps://api.geopera.comAPI base URL override. The trailing slash is stripped.

API-URL resolution precedence (highest first): the --api-url flag, then GEOPERA_API_URL, then the api_url stored in the active profile, then https://api.geopera.com.

There is also a credential-free override for CI and short-lived shells:

Env varDescription
GEOPERA_API_TOKENAn opaque Bearer token or gpra_ API key used directly, bypassing the credential store. When set, no profile lookup or token refresh happens — the value is sent as-is on the Authorization header. Use this in CI where you do not want to run geopera login.

Completion and help

These options are provided by the underlying CLI framework and live on the root command.

OptionDescription
--install-completionInstall shell completion for the current shell and exit.
--show-completionPrint the completion script for the current shell (pipe it into your shell config) and exit.
--helpShow help for geopera or any subcommand and exit.
bash
# Install tab completion into your shell profile (bash, zsh, fish, PowerShell)
geopera --install-completion

# Or print the script and place it yourself
geopera --show-completion >> ~/.zshrc

# Per-command help — lists the flags generated for that operation
geopera catalog search --help
geopera orders archive place --help

Completion covers the full generated tree: once installed, geopera ca<TAB> completes to catalog, geopera catalog <TAB> lists the actions under catalog, and flag names complete after --. Because the tree is built from a spec snapshot bundled in the installed package, completion is offline and instant; it refreshes when you upgrade the CLI.

The generated command tree

Every operation has a dotted id like catalog.search or orders.tasking.templates.save. The CLI turns each segment of that id into a level of the command tree, so the command is simply the id with spaces instead of dots:

Operation idCommand
catalog.searchgeopera catalog search
orders.archive.placegeopera orders archive place
orders.tasking.templates.savegeopera orders tasking templates save

This mapping is mechanical and complete: any operation in the published snapshot has a matching command, and the command name always mirrors the operation id. There is nothing to memorise beyond the id itself.

A few properties of the tree are worth knowing:

  • No collisions. Operation ids are guaranteed collision-free as a tree — no id is a prefix of another — so every id is an unambiguous leaf and no name is ever both a group and a runnable command.
  • Underscores become hyphens. A segment like federated_search becomes the command federated-search, so catalog.federated_search is geopera catalog federated-search. The same rule applies to flag names (below).
  • Customer operations only. Admin/internal operations (those requiring an admin: scope) are excluded from the generated tree. They remain reachable through the raw geopera op command for the rare privileged caller.
  • All operations are POST. Every command issues POST /v1/op/<operation_id> with a JSON body. There are no GET-style commands; “reading” the catalog is itself a POST search.

Fields become flags

The request body for each operation is exposed as flags, so for common calls you never write JSON by hand. The flag set is derived from the operation’s request-body schema:

  • Scalar fields (strings, integers, numbers) become --flag value. The flag name is the field name with underscores replaced by hyphens — a field named host_name becomes --host-name. Integers and floats are validated by the CLI, so --limit abc is rejected before any request is sent.
  • Array-of-scalar fields are repeatable — pass the flag once per element: --collections sentinel-2-l2a --collections landsat-c2-l2. Omitting the flag entirely sends no value for that field (it is not sent as an empty array).
  • Boolean fields become a paired switch: --cloud-mask sets it to true, --no-cloud-mask sets it to false. Omitting both leaves the field unset (the server default applies) — the switch is tri-state, not defaulted to false.
  • Required fields are marked [required] in --help and must be supplied, either as a flag or via the --json body below.
  • Complex fields (nested objects, arrays of objects, geometries, filter trees) are not exposed as flags. They are only reachable via --json. --help lists exactly the flags that exist; if a field you need is missing from --help, it is a complex field — supply it through --json.

Field descriptions from the schema are carried through into --help, so each generated flag documents itself:

bash
geopera catalog search --help
Search the catalog for imagery.

Operation: catalog.search

Options:
  --json JSON               Full JSON body (inline, @file, or - for stdin).
                            Flags override its keys.
  --collections TEXT        Collection ids to search. [required]
  --host-name TEXT          STAC host to query.
  --limit INTEGER           Maximum number of results.
  --profile TEXT            Stored identity (env: GEOPERA_PROFILE).
  --api-url TEXT            API base URL override (env: GEOPERA_API_URL).
  --help                    Show this message and exit.

A minimal call using only flags:

bash
geopera catalog search --collections sentinel-2-l2a --limit 10

Complex bodies: —json

Deeply nested fields (geometries, filter trees, line-item lists) are awkward as flags, so every generated command also accepts a full JSON body via --json, supplied three ways:

bash
# Inline JSON
geopera catalog search --json '{"collections": ["sentinel-2-l2a"], "limit": 10}'

# From a file (@ prefix)
geopera catalog search --json @search.json

# From stdin (- )
cat search.json | geopera catalog search --json -

The body must be a JSON object — a top-level array or scalar is rejected with Error: --json must be a JSON object for this command. Malformed JSON is rejected with Error: Invalid --json body: ... before any request is sent. An empty or whitespace-only --json - is treated as {}.

Flags override —json keys

Flags and --json compose: when both are given, individual flags override the matching keys from --json. The body is built by first parsing --json into a dict, then layering each supplied flag on top. This lets you keep a base body in a file and tweak one value on the command line:

bash
# Reuse a saved body but bump the limit for this run
geopera catalog search --json @search.json --limit 25

Precisely:

  • A scalar flag with a value replaces that key in the parsed body.
  • A repeatable flag, given at least once, replaces the whole array for that key (it does not append to a --json array).
  • A boolean given as --x/--no-x replaces that key; omitting both leaves whatever --json provided.
  • An omitted scalar/array flag (no value) does not touch the corresponding --json key — so partial overrides are safe.

Worked examples across domains

Search the catalog, mixing a scalar flag with a repeatable array flag:

bash
geopera catalog search \
  --host-name earthsearch-aws \
  --collections sentinel-2-l2a \
  --collections sentinel-2-l1c \
  --limit 10

Run a federated search across hosts (note the underscore-to-hyphen rule in the action name):

bash
geopera catalog federated-search \
  --collections sentinel-2-l2a \
  --limit 25

Place an archive order whose body is a nested line-item list — supplied via --json because the items are objects:

bash
geopera orders archive place --json @order.json
json
{
	"items": [{ "product_id": "prod_s2_l2a", "scene_id": "S2A_...", "aoi_km2": 120 }]
}

Estimate the cost of a body before placing it, reading from stdin:

bash
geopera orders estimate --json - < order.json

Save a tasking template, showing a deep command path, a scalar flag, a boolean switch, and a nested geometry via --json — with the --name flag overriding the name key in the file:

bash
geopera orders tasking templates save \
  --name "Coastal weekly" \
  --recurring \
  --json @template.json

List your orders (a POST search that takes a body, even when “reading”):

bash
geopera orders list --json '{"status": "active", "limit": 50}'

Every generated command prints pretty-printed JSON on success and renders an errors response on failure (see the exit-code contract). Output is unstyled JSON suitable for piping into jq:

bash
geopera catalog search --collections sentinel-2-l2a --limit 5 \
  | jq '.features[].id'

login

Authenticate the active profile. By default this runs a browser-based device flow; pass --api-key to store a key non-interactively for headless use.

bash
geopera login [OPTIONS]
OptionTypeDefaultDescription
--api-keystringSkip the device flow and store an API key. Use - to read the key from stdin (keeps it out of shell history).
--api-urlstringresolved (see global options)API base URL override.
--no-browserflagfalseDo not auto-open the verification URL in a browser.
--scopestringopenid profileScope to request (device flow only).
--profilestringresolved (see global options)Profile to store the credentials under.

Device flow (default)

With no --api-key, login runs a device authorization flow: it prints a verification URL and a short user code, opens the URL in your browser (unless --no-browser is set), and shows a spinner while it polls until you confirm in the browser. On success it stores the resulting session token for the profile and confirms with a userinfo round-trip.

bash
geopera login
  To sign in, visit:
    https://api.geopera.com/device?user_code=WDJB-MJHT

  And confirm this code:
    WDJB-MJHT

Waiting for authorization... |
Logged in as user-123 (profile 'default').

On a headless machine, pass --no-browser and open the printed URL yourself:

bash
geopera login --no-browser --profile workstation

The session token is short-lived and is refreshed automatically before expiry on subsequent commands, so you do not re-run login until the underlying session itself ends. The session token is sent as a normal Bearer token — it is used exactly like an API key, with no separate exchange step.

API key (headless)

Pass --api-key to store a minted API key without any browser interaction — the right choice for CI and servers. New Geopera keys carry the gpra_ prefix; the CLI validates the key with a userinfo call before saving it, so a bad key fails fast. A key without the gpra_ prefix still works but prints a yellow notice on stderr.

bash
# Read the key from stdin so it never appears in shell history
echo "$GEOPERA_KEY" | geopera login --api-key - --profile ci
Logged in as prn_org_8f2c... (API key, profile 'ci').

You can also pass the key inline (geopera login --api-key gpra_...), but piping via - is recommended so the key stays out of your shell history and process list. In ephemeral CI where you would rather not write to the credential store at all, skip login entirely and set GEOPERA_API_TOKEN (see global options).

Exit behaviour

login exits 0 on success. Any failure — no key provided, key validation failure, device-flow error — exits 1 with an Error: ... line on stderr.

logout

Clear the active profile’s stored credentials. For a device-flow (session) profile this also revokes the session server-side before deleting the local entry; for an API-key profile it simply removes the local entry (the key remains valid until you revoke it in the dashboard).

bash
geopera logout [OPTIONS]
OptionTypeDefaultDescription
--profilestringresolved (see global options)Profile to clear.
bash
geopera logout --profile ci
Logged out (profile 'ci').

If the profile had no stored credentials, it prints No stored credentials for profile '...'. and still exits 0, so logout is safe to run unconditionally in teardown scripts.

whoami

Show the authenticated principal, organisation, and scopes for the active profile. Output is a human-readable key/value listing by default, or raw userinfo JSON with --json.

bash
geopera whoami [OPTIONS]
OptionTypeDefaultDescription
--jsonflagfalsePrint the raw userinfo JSON instead of the formatted listing.
--api-urlstringresolvedAPI base URL override.
--profilestringresolvedProfile to inspect.

Default (human) output

bash
geopera whoami
sub:             user-123
principal_type:  user
org_id:          org_8f2c
scope:           openid profile catalog:read orders:write
api_url:         https://api.geopera.com
profile:         default

The fields map to userinfo keys: sub, geopera_principal_type, geopera_org_id, and scope. The api_url and profile lines reflect the resolved context, not the response body. Missing values render as -.

Raw JSON output

bash
geopera whoami --json
json
{
	"sub": "user-123",
	"geopera_principal_type": "user",
	"geopera_org_id": "org_8f2c",
	"scope": "openid profile catalog:read orders:write"
}

Use raw output to check scopes from a script before attempting a scoped call:

bash
geopera whoami --json | jq -e '.scope | contains("orders:write")'

Exit behaviour

An auth failure (no stored credentials, refresh failure) or an API error exits 1 with an Error: ... line on stderr.

geopera op — escape hatch

The generated command tree covers every customer operation in the published snapshot. For scripting against a dynamic operation id, for an operation newer than your installed CLI, or for a privileged (admin:) operation that is excluded from the tree, the low-level geopera op command invokes any operation directly by id:

bash
geopera op <operation_id> [BODY] [OPTIONS]

It performs the same POST /v1/op/<operation_id> call as the generated command — there is no extra capability, only a generic entry point that takes a raw JSON body instead of typed flags.

Argument / optionDescription
OPERATION_IDThe dotted operation id, e.g. catalog.search or orders.estimate. Required unless --list is given.
BODYPositional JSON request body. Use - to read from stdin. Omit to send {}.
--file, -fRead the JSON body from a file (alternative to the positional BODY).
--listList available operation ids (fetched from the live OpenAPI document) and exit.
--api-urlAPI base URL override (see global options).
--profileStored identity to use (see global options).
bash
# Equivalent to: geopera catalog search --json '{"collections":["sentinel-2-l2a"],"limit":10}'
geopera op catalog.search '{"collections": ["sentinel-2-l2a"], "limit": 10}'

# Body from a file
geopera op orders.archive.place --file order.json

# Body from stdin
cat order.json | geopera op orders.archive.place -

# No body — sends {}
geopera op orders.list

# Discover ids from the live spec (one per line, count on stderr)
geopera op --list

# Drive the operation id from a variable in a script
for OP in catalog.search orders.list; do
  geopera op "$OP" '{}'
done

Unlike the generated tree (built from the bundled snapshot), geopera op --list queries the deployment’s live openapi.json, so it reflects exactly what your configured --api-url currently serves — handy for spotting an operation that shipped after your CLI did.

Prefer the generated geopera <resource> <action> commands for everyday use — they give you typed flags, --help, and completion. Reach for geopera op only when you need a raw, id-driven call.

Exit-code contract

The CLI uses exit codes to distinguish operation failures from everything else, so scripts can react accordingly.

CodeMeaningEmitted by
0Successall commands
1Auth failure, bad input, or any non-operation errorall commands (e.g. login, logout, whoami, invalid JSON, missing operation id)
2The operation call itself failed (the API returned an error)generated operation commands and op

The distinction between 1 and 2 is deliberate: a setup problem (no credentials, malformed --json, a missing required field) exits 1, while a request that reached the API and was rejected exits 2. So an authentication failure exits 1 even on an operation command — only a failed operation invocation against the API yields 2. Every error is written to stderr prefixed with Error:, combining the HTTP status with the problem title/message/detail from the errors response:

Error: [422] Invalid request body — aoi_km2 must be greater than 0

Branch on the code in scripts:

bash
geopera orders estimate --json @order.json
case $? in
  0) echo "estimate ok" ;;
  2) echo "API rejected the order body" >&2; exit 1 ;;
  *) echo "setup/auth error — check credentials and JSON" >&2; exit 1 ;;
esac
bash
geopera orders estimate --json '{}'
echo "exit: $?"   # 2 if the API rejected the body, 0 on success

See also

  • CLI overview — installation, profiles, environment variables, and the credential store.
  • Authentication — Bearer tokens (gpra_ API keys and session tokens).
  • Operations — the request model behind each command.
  • Errors — the problem+json schema rendered on failure.