@beel_es/cli
v0.2.2
Published
Agent-first CLI for the BeeL invoicing API. Commands are derived at startup from the embedded OpenAPI spec. Run with npx @beel_es/cli — no install needed.
Maintainers
Readme
@beel_es/cli
Agent-first CLI for the BeeL invoicing API. Every command is derived at startup from the embedded OpenAPI spec — when the API gains an endpoint, the next CLI release gains the command, with zero hand-written wrappers.
npx @beel_es/cli --helpNo install, no brew. Node 20+.
Auth
Three ways to authenticate, resolved per request in this order of precedence: BEEL_API_KEY env var → OAuth session → stored API key.
# Option A — Log in with your browser (OAuth, no key to paste)
npx @beel_es/cli login # sandbox / test (default)
npx @beel_es/cli login --live # production
# Option B (recommended for agents/CI): env var
export BEEL_API_KEY=beel_sk_test_...
# Option C: store an API key in ~/.config/beel/config.json (chmod 600)
npx @beel_es/cli login --api-key beel_sk_test_...
npx @beel_es/cli login --api-key beel_sk_live_... # both can coexistBrowser login (OAuth)
beel login opens your browser against BeeL's authorization server, you approve
the consent screen (and choose Test/Live there), and the CLI stores the resulting
session locally. No API key to copy-paste.
- A short-lived loopback server on
127.0.0.1(an ephemeral OS-assigned port) receives the callback; if the browser doesn't open, the URL is printed to paste manually. - The granted scope decides the environment: a
sandboxscope → test, otherwise → live. - Access tokens (1h) are refreshed automatically with the rotating refresh token (30d) — no re-login until the refresh token expires.
- Request specific scopes with
--scope(repeatable):beel login --scope invoices:read --scope invoices:write. - OAuth uses the dedicated public client
beel-cli(PKCE, no secret). Override it for staging/local withBEEL_OAUTH_CLIENT_ID. Note: browser login requires thebeel-cliclient to be registered on the server; until it ships to production the OAuth flow returnsinvalid_client— use--api-keyin the meantime.
npx @beel_es/cli logout # clear the sandbox session + key
npx @beel_es/cli logout --live # clear the production session + keyThe key prefix decides the slot: beel_sk_test_* → sandbox, beel_sk_live_* → production.
Sandbox is the default. Every command uses the test environment unless you pass --live. A live key in BEEL_API_KEY without --live is an error, not a silent upgrade — production access is always explicit, and beel login (OAuth) likewise requires --live for production.
Usage
npx @beel_es/cli invoices list --status PAID --limit 5
npx @beel_es/cli invoices get <invoice_id>
npx @beel_es/cli invoices create --data @invoice.json
npx @beel_es/cli invoices issue <invoice_id> --wait-for-pdf
npx @beel_es/cli customers create --data '{"fiscal_name":"ACME SL", ...}'
npx @beel_es/cli nif validate --data '{"nif":"B12345678"}'
npx @beel_es/cli invoices export-excel --output invoices.xlsx
npx @beel_es/cli --live invoices list # production--data accepts inline JSON, @file.json, or - for stdin. It is only required for endpoints whose request body is mandatory (e.g. invoices create); for lifecycle actions with an optional body (e.g. invoices mark-paid) it is optional, and verbs with no body (e.g. invoices issue) don't expose it at all. Each command's --help shows whether --data is required or optional. Binary responses (PDF, ZIP, Excel) require --output <path>.
Discover everything with --help at any level: beel --help, beel invoices --help, beel invoices list --help (flags, enums and defaults come from the API spec). For commands that take a --data body, --help also lists the top-level body fields (name, type, required, enums) derived from the spec, plus a pointer to beel docs search <resource> for the full nested schema.
Docs search (no API key needed)
Search docs.beel.es locally — fetches llms-full.txt once (cached 15 min) and prints only the matching sections. An agent gets the relevant ~2KB instead of the full 660KB docs:
npx @beel_es/cli docs list # all pages (JSON)
npx @beel_es/cli docs search idempotency key # top matching sections (markdown)
npx @beel_es/cli docs search rate limit --limit 5
npx @beel_es/cli docs get glossary # one full pageGeneric escape hatch
Any endpoint, even ones this CLI version doesn't know yet:
npx @beel_es/cli request GET /v1/invoices --query status=PAID --query limit=5
npx @beel_es/cli request POST /v1/customers --data @customer.jsonOutput contract (for agents)
- stdout: response JSON, pretty-printed. Nothing else.
- stderr: errors as JSON:
{"error": {"code", "message", "status", "details", "request_id"}}. - Exit codes:
0ok ·1unexpected ·2usage/config ·3auth (401/403) ·4not found ·5validation (400/409/422) ·6rate limit (429) ·7server (5xx).
POST requests get an automatic Idempotency-Key. BEEL_BASE_URL overrides the API host; BEEL_CONFIG_DIR overrides the config location.
How it stays in sync with the API
The OpenAPI spec ships inside the package and the command tree is interpreted from it at startup (src/runtime.ts). When the backend publishes a spec change, a repository_dispatch syncs openapi/public-api.yaml, CI rebuilds, and a patch release is published. Updating the CLI = npx picking the new version.
Development
npm install
npm run dev -- invoices --help # run from source
npm test # vitest
npm run build # single-file bundle in dist/ (zero runtime deps)