TypeScript — CLI (@paylera/cli)
@paylera/cli reads a paylera.config.ts and applies it to a Paylera tenant idempotently via the admin upsert API. Inspired by Autumn’s autumn deploy.
Install
npm install --save-dev @paylera/cli# or run ad-hoc:npx paylera --helpGetting started
-
Get an API token from the Paylera admin console:
https://admin.paylera.dev/settings/api-keys. -
Capture credentials.
Terminal window npx paylera login# Paste your token at the prompt. Saved to ~/.paylera/credentials.The token can also be supplied via the
PAYLERA_API_TOKENenv var. -
Bootstrap a config from your tenant (or write one by hand):
Terminal window npx paylera pull # writes paylera.config.ts in the cwd -
Edit
paylera.config.tsto taste, then deploy:Terminal window npx paylera deploy --dry-run # show the plannpx paylera deploy # diff + confirm + apply
Example config
import { defineConfig } from "@paylera/cli";
export default defineConfig({ apiVersion: "2026-05-01", features: [ { code: "api_calls", kind: "metered", billableMetric: "api_call_count" }, { code: "seats", kind: "numeric" }, { code: "premium_support", kind: "boolean" }, ], plans: [ { code: "starter", name: "Starter", prices: [{ amount: 1900, currency: "USD", interval: "month" }], features: { api_calls: { includedUsage: 10_000, usageCycle: "calendar_month" }, seats: { value: 5 }, premium_support: { value: false }, }, }, ],});The schema is locked in the relay protocol — “CLI declarative config schema”. Zod validation runs at every command invocation.
Commands
| Command | What it does |
|---|---|
paylera deploy | Diff local config against the tenant, prompt, apply via PUT upsert. |
paylera diff | Show drift only. Exit code 0 when matched, 2 when drift exists. |
paylera pull | Inverse of deploy — write tenant state to paylera.config.ts. |
paylera login | Capture an API token into ~/.paylera/credentials. |
paylera --version | Print the CLI version. |
paylera deploy
paylera deploy [--config <path>] [--dry-run] [--yes]--config <path>— path to the config file (default:paylera.config.tssearched in the cwd, then.mts,.mjs,.js).--dry-run— show the diff and exit; no upserts performed.--yes— skip the interactive confirmation (CI mode). Against apl_live_*token,--yesadditionally requiresPAYLERA_ALLOW_PRODUCTION_DEPLOY=1to acknowledge production impact.
paylera diff
paylera diff [--config <path>]Prints the same diff deploy would apply, then exits 2 if any changes were detected. Use this in CI to fail builds on drift.
paylera pull
paylera pull [--output <path>] [--force]Fetches the current feature + plan catalog and writes a canonical paylera.config.ts (sorted, deterministic). Refuses to overwrite an existing file unless --force is passed.
paylera login
paylera login [--token <pl_*>] [--base-url <url>] [--credentials-path <path>]Writes ~/.paylera/credentials (JSON: {"api_token": "...", "base_url": "..."}). If --token is omitted, the CLI reads it from stdin. v1 is a token-paste flow; a full OAuth device-flow lands once the admin console exposes the device-authorisation endpoint.
Environment variables
| Variable | Purpose |
|---|---|
PAYLERA_API_TOKEN | Overrides the credentials file when set. |
PAYLERA_API_BASE_URL | Self-hosted / staging override (otherwise derived from the token prefix). |
PAYLERA_ALLOW_PRODUCTION_DEPLOY=1 | Required for --yes against a pl_live_* token. |
NO_COLOR=1 / FORCE_COLOR=1 | Disable / enable ANSI colour output. |
Idempotency
Every upsert call carries a stable Idempotency-Key of the form paylera-cli:upsert:{kind}:{code}. Replays — CI re-runs, network blips — collapse to a single backend mutation. The key is stamped onto the @paylera/sdk typed admin methods (client.admin.upsertFeatureByCode, upsertPlanByCode, upsertProductByCode, upsertBillableMetricByCode), which were added in SDK Round 2A.
Optional optimistic-concurrency: the facade forwards an ifMatch option (integer or RFC-7232 ETag) onto the typed methods — a stale version yields 412 PreconditionFailed.
CI usage
Fail on drift in pull requests, deploy on merge:
- name: Check drift if: github.event_name == 'pull_request' run: npx paylera diff env: PAYLERA_API_TOKEN: ${{ secrets.PAYLERA_TEST_TOKEN }}
- name: Deploy if: github.ref == 'refs/heads/main' run: npx paylera deploy --yes env: PAYLERA_API_TOKEN: ${{ secrets.PAYLERA_LIVE_TOKEN }} PAYLERA_ALLOW_PRODUCTION_DEPLOY: "1"Programmatic use
The package also exports the schema + diff/apply engine for programmatic use (e.g. building a custom deploy pipeline):
import { defineConfig, diffConfig, applyConfig, fetchRemoteState,} from "@paylera/cli";