Skip to content

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

Terminal window
npm install --save-dev @paylera/cli
# or run ad-hoc:
npx paylera --help

Getting started

  1. Get an API token from the Paylera admin console: https://admin.paylera.dev/settings/api-keys.

  2. 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_TOKEN env var.

  3. Bootstrap a config from your tenant (or write one by hand):

    Terminal window
    npx paylera pull # writes paylera.config.ts in the cwd
  4. Edit paylera.config.ts to taste, then deploy:

    Terminal window
    npx paylera deploy --dry-run # show the plan
    npx 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

CommandWhat it does
paylera deployDiff local config against the tenant, prompt, apply via PUT upsert.
paylera diffShow drift only. Exit code 0 when matched, 2 when drift exists.
paylera pullInverse of deploy — write tenant state to paylera.config.ts.
paylera loginCapture an API token into ~/.paylera/credentials.
paylera --versionPrint the CLI version.

paylera deploy

paylera deploy [--config <path>] [--dry-run] [--yes]
  • --config <path> — path to the config file (default: paylera.config.ts searched 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 a pl_live_* token, --yes additionally requires PAYLERA_ALLOW_PRODUCTION_DEPLOY=1 to 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

VariablePurpose
PAYLERA_API_TOKENOverrides the credentials file when set.
PAYLERA_API_BASE_URLSelf-hosted / staging override (otherwise derived from the token prefix).
PAYLERA_ALLOW_PRODUCTION_DEPLOY=1Required for --yes against a pl_live_* token.
NO_COLOR=1 / FORCE_COLOR=1Disable / 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:

.github/workflows/paylera.yml
- 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";