Following system theme

#Scribo CLI

@causaprima/scribo-cli is the official Scribo terminal client. It wraps the public /api/v1 HTTP API in a commander-based CLI with sysexits-style exit codes, so it's safe to drop into CI pipelines and shell scripts.

#Install

# One-off run
npx @causaprima/scribo-cli <command>

# Global install
npm install -g @causaprima/scribo-cli
scribo <command>

Requires Node.js 20 or later.

#Quickstart

scribo create \
  --jurisdiction DE --currency EUR \
  --sender-name "Example GmbH" --sender-country DE \
  --sender-address "Example Allee 1" --sender-postcode 10115 --sender-city Berlin \
  --sender-tax-id DE123456788 --sender-email billing@example.com \
  --recipient-name "Acme GmbH" --recipient-country DE \
  --recipient-address "Hauptstrasse 1" --recipient-postcode 10117 --recipient-city Berlin \
  --recipient-email ap@acme.example \
  --line "Senior consulting,3,1200,19,DAY,S" \
  --due-date 2026-06-01 \
  -o invoice.pdf

Output:

Invoice created
  invoice_id:  f0b3c1e2-...
  format:      zugferd_comfort
  download:    https://scribo.causaprima.ai/i/f0b3c1e2-.../download
  expires:     2099-12-31T23:59:59Z
  validator:   ok (invopop)
  saved to:    invoice.pdf

On the first invoice for a sender email the CLI prompts on stdin for the 6-digit verification code Scribo emails to --sender-email (suppress with --no-prompt, which prints the challenge and exits 75). An empty answer or a rejected code exits 65 (EX_DATAERR); re-run the command to request a fresh code.

#Commands

#scribo create

Generate an invoice and save the file locally. Two ways to build the payload:

  • Flags — flat CLI flags map onto the CreateInvoiceInput schema. Repeat --line for each line item.
  • JSON file--from invoice.json reads a raw CreateInvoiceInput and ignores most flags.

Line item syntax

--line "<description>,<quantity>,<unit_price>,<tax_rate>[,<unit_code>[,<tax_category_code>[,<tax_exemption_code>]]]"

Escape commas in the description with a backslash: "Hours, Sep \\& Oct,40,100,19,HUR,S". unit_code defaults to EA; tax_category_code defaults to S (standard rated). The optional 7th field, tax_exemption_code, is required for tax_category_code=E (per BR-E-10) and otherwise overrides the auto-applied default for AE/K/G/O — pass a VATEX-EU-* code matching the legal basis (e.g. VATEX-EU-79-C for Kleinunternehmer § 19 UStG). See /docs/tax-codes for the full enum.

Flag reference

Flag Maps to Notes
--from <file> (whole payload) Reads CreateInvoiceInput JSON; overrides other flags.
--idempotency-key <key> Idempotency-Key header Auto-minted from payload hash if omitted.
-o, --output <file> (local write) Default invoice-<id>.pdf.
--json (stdout) Print the InvoiceRecord JSON to stdout after writing the file.
--sender-name, --sender-country, --sender-address, --sender-address2, --sender-postcode, --sender-city, --sender-tax-id, --sender-email, --sender-contact-name, --sender-contact-phone sender.*
--recipient-name, --recipient-country, --recipient-address, --recipient-address2, --recipient-postcode, --recipient-city, --recipient-tax-id, --recipient-email, --recipient-leitweg-id recipient.* --recipient-leitweg-id auto-selects XRechnung UBL.
--currency, --jurisdiction, --format-override, --notes top-level --format-override enum at /docs/api.
--due-date, --payment-terms, --delivery-date, --delivery-start, --delivery-end top-level Dates are YYYY-MM-DD.
--payment-iban, --payment-bic, --payment-account-name payment_means.* (SEPA) --payment-iban is required when the resolved format is XRechnung (Leitweg-ID present or --format-override=xrechnung_*) — BR-DE-1 mandates payment instructions on German B2G invoices. Optional elsewhere.
--payment-account-number, --payment-routing-number, --payment-bank payment_means.* (US) US account number (4–17 digits) + 9-digit ABA routing number, instead of --payment-iban — not both. --payment-bank is the free-text beneficiary bank name + address, rendered on the invoice for wires.
--locale <bcp47> X-Scribo-Locale header Language of the verification email + confirmation page (e.g. de-DE). Defaults to your POSIX locale ($LC_ALL / $LC_MESSAGES / $LANG); unsupported values fall back to English.
--no-prompt (behavior) Skip the interactive stdin prompt for the email verification code — prints the magic-link hint to stderr and exits 75. For CI / unattended runs.
--line (7th field: tax_exemption_code) line_items[].tax_exemption_code Required for tax_category_code=E (per BR-E-10) — pass a VATEX code matching the legal basis. AE/K/G/O get their VATEX codes auto-applied server-side; pass the 7th field only to override.
--base-url <url> env override Overrides SCRIBO_API_BASE_URL.
--api-key <key> env override Overrides SCRIBO_API_KEY.

Common VATEX codes for the 7th --line field:

Code When
VATEX-EU-79-C Kleinunternehmer § 19 UStG (small-business exemption)
VATEX-EU-132 Art. 132 EU VAT Directive — health, education, social services
VATEX-EU-143 Art. 143 — importation exemption
VATEX-EU-AE Reverse charge (auto-applied for category AE)
VATEX-EU-IC Intra-community supply (auto-applied for category K)
VATEX-EU-G Free export (auto-applied for category G)
VATEX-EU-O Outside-scope of VAT (auto-applied for category O)

Example — Kleinunternehmer (§ 19 UStG)

scribo create \
  --sender-name "Friedrich Beratung" --sender-country DE \
  --sender-address "Musterstr. 1" --sender-postcode "10115" --sender-city Berlin \
  --sender-email "f@example.de" \
  --recipient-name "Acme GmbH" --recipient-country DE \
  --recipient-address "Hauptstr. 1" --recipient-postcode "10117" --recipient-city Berlin \
  --recipient-email "ap@acme.de" \
  --currency EUR \
  --line "Beratung,5,80.00,0,HUR,E,VATEX-EU-79-C"

Example — German B2G XRechnung (Leitweg-ID + payment-iban)

scribo create \
  --sender-name "Acme GmbH" --sender-country DE \
  --sender-address "Musterstr. 1" --sender-postcode "10115" --sender-city Berlin \
  --sender-tax-id "DE123456788" --sender-email "billing@acme.de" \
  --sender-contact-name "Erika Beispiel" --sender-contact-phone "+49 30 1234567" \
  --recipient-name "Bundesamt für Beispiele" --recipient-country DE \
  --recipient-address "Wilhelmstr. 1" --recipient-postcode "10117" --recipient-city Berlin \
  --recipient-email "rechnung@bund.de" \
  --recipient-leitweg-id "991-12345-67" \
  --currency EUR \
  --payment-iban "DE89370400440532013000" --payment-account-name "Acme GmbH" \
  --line "Consulting,3,1200.00,19,DAY,S"

#scribo get <invoiceId>

Fetch invoice metadata as JSON on stdout. Useful in scripts that need a fresh signed download URL:

URL=$(scribo get f0b3c1e2-... | jq -r .download_url)
curl -fsSL "$URL" -o invoice.pdf

#scribo download <invoiceId> [-o file]

Stream the invoice bytes only. Default output file: invoice-<id>.pdf.

#scribo jurisdictions

Print the supported-jurisdictions matrix. Use --json for machine-readable output:

scribo jurisdictions --json | jq '.[] | .jurisdiction'

#Configuration

Env var Purpose Default
SCRIBO_API_BASE_URL Public API origin (SCRIBO_BASE_URL is accepted as a fallback — same var the skill uses). https://scribo.causaprima.ai
SCRIBO_API_KEY Optional bearer token (partner quotas). (unset)

CLI flags --base-url and --api-key override env vars.

#Exit codes

The CLI follows BSD sysexits, so callers can branch on the exit code without parsing stderr:

Code Constant Meaning
0 Success.
64 EX_USAGE Missing or malformed CLI flag.
65 EX_DATAERR Server returned 4xx (other than 404).
66 EX_NOINPUT Invoice not found (404).
70 EX_SOFTWARE Server returned 5xx.
75 EX_TEMPFAIL Rate-limited (429) or temporarily soft-blocked (tenant_soft_blocked) — retry after the period printed in the error.
1 Network or unclassified error.

Example CI usage:

scribo create --from invoice.json -o out.pdf || case $? in
  75) echo "rate limited; backing off"; exit 75 ;;
  70) echo "server error; retry later"; exit 1 ;;
  *)  exit 1 ;;
esac

#Contract

The CLI talks to the public /api/v1/* HTTP API. The authoritative contract is the OpenAPI document served at GET {SCRIBO_API_BASE_URL}/api/v1/openapi.json. Any field accepted by the API is accepted by --from <file>.

#See also

  • API — the underlying HTTP contract.
  • MCP server — hosted at scribo.causaprima.ai/mcp for Claude Desktop, Cursor, Cline, ChatGPT App, OpenAI Codex CLI, and other MCP clients.
  • Skillcurl helpers for Claude Code / Codex CLI.
  • Troubleshooting — error codes and recovery.