Metadata-Version: 2.4
Name: xoople-cli
Version: 0.6.0
Summary: Command-line interface for the Xoople Products API.
License-Expression: LicenseRef-Xoople-Proprietary
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Python :: 3.12
Requires-Dist: xoople-sdk>=0.8.0
Requires-Dist: cyclopts>=4.18,<5
Requires-Dist: rich>=13.7
Requires-Python: >=3.12
Project-URL: Homepage, https://xoople.com
Description-Content-Type: text/markdown

# xoople-cli

Command-line interface for the Xoople Products API, over [`xoople-sdk`](../xoople-sdk).

```console
$ uv tool install xoople-cli
$ export XOOPLE_API_URL=https://api.xoople.com XOOPLE_TOKEN=...
$ xoople analyses list
```

Every command reads `--api-url` and `--token` from `XOOPLE_API_URL` and
`XOOPLE_TOKEN`. `--json` prints the API response verbatim instead of a table, so
output pipes into `jq`.

## Commands

| Group | Commands |
| --- | --- |
| `analyses` | `list` `get` `create` `update` `cancel` `delete` `estimate` |
| `runs` | `list` `get` |
| `outputs` | `list` `get` `access-url` |
| `schedules` | `list` `get` `create` `pause` `resume` `cancel` `run` `estimate-run` |
| `events` | `list` `get` |
| `usage` | `history` `limits` |
| `catalog` | `products` `measures` `designs` |
| `questions` | `list` `show` `ask` |
| `access` | `me` `token` `features` |
| `auth` | `login` `logout` `status` |

## Signing in

`auth login` signs in through the browser with PKCE and stores the session at
`$XDG_CONFIG_HOME/xoople/session.json` (`~/.config/xoople/session.json` by
default), readable only by you. Every later command uses that session when
no `--token` is given, and refreshes it when the
access token is close to expiry.

```console
$ export XOOPLE_API_URL=https://api.xoople.com
$ xoople auth login
$ xoople analyses list
```

`auth login` reads the CIAM client ID from the API. `--ciam-client-id`
(`XOOPLE_CIAM_CLIENT_ID`) overrides it. `auth status` exits `3` when there is no
stored session, so a script can test for a sign-in. `--ciam-redirect-uri` (`XOOPLE_CIAM_REDIRECT_URI`) overrides the
loopback URI the browser returns to; it must match a URI registered for the
CIAM client.

## API keys

An API key lets a script or a CI job run the CLI without a browser sign-in.
Create one on the **API keys** section of your Xoople profile page (`/profile`).
The key starts with `sk_` and is shown once, so store it in a secret manager.

A key belongs to one organization membership. It acts as you, in the
organization that was active when you created it, with that membership's roles.
To work in a different organization, create a key there.

Pass the key as the token. It takes precedence over a stored session:

```console
$ export XOOPLE_API_URL=https://api.xoople.com XOOPLE_TOKEN=sk_...
$ xoople access me
```

The API accepts at most 300 API key requests a minute from one IP address. The
CLI retries rate-limited GETs and replay-safe writes with backoff, then exits
`8`. Any other write exits `8` on the first 429, with no retry. Revoke a key on
the same profile page when you no longer need it.

## Submitting an analysis

The product spec is deeply nested and differs per product, so `create` and
`estimate` take it as JSON rather than as flags:

```console
$ xoople catalog designs --product tabular_time_series --json | jq '.[0].spec_fragment | {product: "tabular_time_series", period: {start: "2024-01-01", end: "2024-06-30"}, aoi: [-1.5, 52.0, -1.0, 52.5], spatial_partition: {type: "h3", target_cells: 5000}, measures}' > spec.json
$ xoople analyses create -f spec.json --display-name "South Wales NDVI" --wait
```

A design's `spec_fragment` holds only what to measure, so the `jq` filter adds the
product, period, area and grid around its `measures`. The cadence defaults to monthly.

The file holds either the bare spec or a whole create request (anything with a
`spec` key). `-f -` reads stdin. `--wait` polls the initial run and exits
non-zero if it does not reach `COMPLETE`.

## Exit codes

`0` success · `1` unexpected CLI error · `2` usage error ·
`3` unauthenticated, including a failed or absent sign-in · `4` forbidden ·
`5` not found · `6` bad request or validation · `7` conflict · `8` rate limited ·
`9` server error · `10` connection failure · `11` unreadable response ·
`12` run finished in a non-`COMPLETE` state · `13` `--wait` timed out ·
`14` the analysis was deleted · `15` the view a question reads is still
being built, ask again shortly · `16` that view's last build failed, refresh
it explicitly; `17` the project was deleted.
