npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@getpeppr/cli

v0.12.3

Published

CLI tool for Peppol e-invoice validation and development

Readme

@getpeppr/cli

Developer toolkit for Peppol e-invoicing. Scaffold invoices, run offline pre-flight checks, convert to UBL XML, look up participants in the Peppol Directory, and send invoices to the Peppol network — all from the command line.

Installation

# Run directly (no install)
npx @getpeppr/cli validate invoice.json

# Or install globally
npm install -g @getpeppr/cli
getpeppr --help

Commands

getpeppr init — Scaffold an invoice

Generate a starter JSON file suitable for local validation and UBL conversion:

getpeppr init                        # creates invoice.json
getpeppr init my-invoice.json        # custom filename
getpeppr init --credit-note          # credit note template
getpeppr init --force                # overwrite existing file

The generated template includes a Belgian seller, the sandbox test receiver as buyer, and two invoice lines — ready to edit, validate, convert, and send from a sandbox account.

getpeppr validate — Validate an invoice

Run partial offline pre-flight checks before the network applies the complete Peppol BIS 3.0 rulebooks:

getpeppr validate invoice.json

Output:

Validating: invoice.json

── Structure ──────────────────────────────
  ✓ No errors

── Offline Checks (partial) ───────────────────
  ✓ No findings

── Country Rules ────────────────────────────
  ⚠ No structured communication reference (BE-02)

── Summary ──────────────────────────────────
  ✓ Pre-flight checks passed (1 warning)

| Flag | Description | |------|-------------| | --json | Machine-readable JSON output | | --quiet | Exit code only, no output |

getpeppr convert — Convert to UBL XML

Convert a getpeppr JSON invoice to Peppol BIS 3.0 UBL 2.1 XML:

getpeppr convert invoice.json                     # XML to stdout
getpeppr convert invoice.json -o invoice.xml      # write to file
getpeppr convert invoice.json --validate           # validate first, convert only if valid

Automatically detects credit notes ("isCreditNote": true) and produces the correct UBL CreditNote document.

| Flag | Description | |------|-------------| | -o, --output <file> | Write XML to file instead of stdout | | --validate | Validate before converting (errors block conversion) |

getpeppr lookup — Peppol Directory search

Look up any participant registered on the Peppol network:

# Direct lookup by Peppol ID
getpeppr lookup 0208:0685660237

# Search by company name
getpeppr lookup --name "Dupont"

# Filter by country
getpeppr lookup --name "GmbH" --country DE

# JSON output
getpeppr lookup 0208:0685660237 --json

| Flag | Description | |------|-------------| | --name <name> | Search by company name (min 3 characters) | | --country <code> | Filter by ISO 2-letter country code | | --json | Output results as JSON | | --limit <n> | Max results for search (default: 10) |

getpeppr login — Save your API key

Store a getpeppr API key in $XDG_CONFIG_HOME/getpeppr/credentials.json~/.config/getpeppr/credentials.json by default, %APPDATA%\getpeppr\credentials.json on Windows. On Unix-like systems the file is created and checked with mode 0600; Windows has no POSIX mode. Sandbox and live keys can coexist.

# Interactive (recommended) — prompts for the key with masked input
getpeppr login

# Explicit env (required in CI / non-TTY)
getpeppr login --key sk_sandbox_... --sandbox
getpeppr login --key sk_live_...    --live

| Flag | Description | |------|-------------| | --key <key> | API key. CI use only — visible in ps/shell history. Prefer the prompt or GETPEPPR_API_KEY. | | --sandbox | Store as sandbox key (default) | | --live | Store as live (production) key |

API key resolution order: --key flag → GETPEPPR_API_KEY env var → stored credentials.

getpeppr send — Send an invoice to Peppol

Send an invoice through the getpeppr API to the Peppol network. Targets sandbox by default; pass --prod for production.

getpeppr send runs a JSON preflight aligned with POST /v1/invoices. That endpoint currently ignores invoiceTypeCode and lets the provider generate the UBL, so the send preflight does not apply P0100, P0101, or P0112 to that inert field. Structure checks including BR-CL-01, plus every other applicable offline and country check, remain active. Use getpeppr validate or getpeppr convert --validate for full local-UBL semantics; both retain those profile checks because they validate or build the UBL locally.

# Send a JSON file
getpeppr send invoice.json

# Quick test — synthesize an invoice from flags (no file needed)
getpeppr send --to 9925:BE0314595348 --amount 100 --desc "Test invoice"

# Watch delivery status until terminal (60s timeout)
getpeppr send invoice.json --watch

# Production send — requires confirmation (skip with -y)
getpeppr send invoice.json --prod

| Flag | Description | |------|-------------| | [file] | Path to invoice JSON (mutex with --to/--amount/...) | | --prod | Target production (uses live key + confirmation prompt) | | --local | Target http://localhost:3001 (dev server) | | --key <key> | Override stored API key | | --to <peppol-id> | Recipient Peppol ID (when no file) | | --amount <number> | Line amount in major currency units | | --currency <iso> | ISO 4217 code (default EUR) | | --country <iso> | Recipient country (ISO 3166-1 alpha-2) when no file | | --desc <text> | Line description | | --attachment | Attach the bundled test PDF | | --watch | Poll status until terminal (60s timeout) | | -y, --yes | Skip the --prod confirmation prompt | | --no-validate | Skip the JSON send preflight | | --json | Machine-readable JSON output | | --quiet | Exit code only, no output |

When sending through the API, getpeppr determines the seller from the API key. A from party can still be present for local validation and UBL conversion, but the gateway ignores it for delivery.

getpeppr whoami — Show your Peppol identity

Read the Peppol identity of the account behind your API key: the environment the key operates in, your legal entity as the gateway holds it, and every Peppol identifier registered for it with its status. Works with any key — standard keys included. This is the fastest way to check "is my identifier registered and verified?" without opening the console.

# Sandbox identity (default)
getpeppr whoami

# Production identity (uses your live key)
getpeppr whoami --prod

# Machine-readable
getpeppr whoami --json

| Flag | Description | |------|-------------| | --prod | Use the live API key (default: sandbox) | | --local | Target http://localhost:3001 (dev server) | | --key <key> | Override API key. CI use only — visible in ps/shell history. Prefer GETPEPPR_API_KEY. | | --json | Output the identity as JSON |

If no legal entity exists in the environment yet, whoami says so and points to the console page where you create one.

getpeppr logout — Remove stored credentials

getpeppr logout

Removes the credentials file. No-op if the file doesn't exist.

Exit codes

| Code | Meaning | |------|---------| | 0 | Success (valid invoice, participant found, conversion OK) | | 1 | Failure (invalid invoice, participant not found) | | 2 | Input error (file not found, invalid JSON, bad arguments) |

send --watch is two outcomes, not one

Since 0.7.0, a watch that fails because the API answered something the CLI cannot honestly read exits 1. Before 0.7.0 it printed a warning and exited 0, which meant an automation could read a broken API as a confirmed delivery.

A watch that runs out of time still exits 0, and that is a different fact: the document was accepted, and the watch stopped without having seen a terminal status. It does not follow that the document is still in flight. The deadline is checked between polls, so a status can turn terminal during the final wait and never be read — the status printed on a timeout may already be stale. Poll again or use a webhook rather than treating a timeout as a failure.

⚠️ The 60 seconds bound when the last poll starts, not when the command ends. The deadline is checked before each request, so a slow or retried call carries the run past it. If a pipeline needs a hard ceiling, impose your own.

CI/CD integration

# Fail pipeline if invoice is invalid
getpeppr validate invoice.json --quiet || exit 1

# Validate + convert in one step
getpeppr convert invoice.json --validate -o output.xml

# Send via API key in env (no login state needed)
GETPEPPR_API_KEY=$SANDBOX_KEY getpeppr send invoice.json --json

What it validates

getpeppr validate and getpeppr convert --validate run three validation engines from the @getpeppr/sdk:

  1. Structure — Required fields, type checks, format validation
  2. Offline Checks — 40 registered partial pre-flight checks: exact network-rule equivalents plus explicit GETPEPPR-* diagnostics. The legacy provider-capability diagnostic unsupported_vat_category can also appear, but is outside that count. This is not a Peppol conformance verdict.
  3. Country Rules — Belgium (BE), France (FR), Italy (IT), Netherlands (NL), Germany (DE)

Scaffolding (init), validation, and conversion run fully offline — no API key or network connection required. Only lookup, send, and whoami need a network connection. Before a sandbox send, the CLI reads GET /v1/identity: its own generated fixture is adapted to the returned O/0 or AE/0 profile, while a user-edited file is never rewritten silently and is refused locally if its tax mode conflicts with the sender.

Invoice format

The input file must be a JSON object matching the getpeppr InvoiceInput type. number, to, and lines are required for API sends. The from party is included in the scaffold because offline validation and UBL conversion need seller metadata; API sends use the legal entity linked to your key. The generated file starts as an O/0 integration fixture. At send time the CLI verifies it against the actual sender profile and never forwards an incompatible tax mode.

{
  "number": "INV-2026-001",
  "date": "2026-01-15",
  "dueDate": "2026-02-15",
  "currency": "EUR",
  "buyerReference": "PO-2026-042",
  "from": {
    "name": "Dupont & Fils SPRL",
    "peppolId": "0208:0685660237",
    "street": "Avenue Louise 54",
    "city": "Bruxelles",
    "postalCode": "1050",
    "country": "BE"
  },
  "to": {
    "name": "SPF Economie (test receiver)",
    "peppolId": "9925:BE0314595348",
    "street": "Rue du Progrès 50",
    "city": "Brussels",
    "postalCode": "1210",
    "country": "BE"
  },
  "lines": [
    {
      "description": "Conseil en transformation numérique",
      "quantity": 10,
      "unitPrice": 950,
      "vatRate": 0,
      "vatCategory": "O",
      "taxExemptReason": "Integration test"
    },
    {
      "description": "Software license — annual subscription",
      "quantity": 1,
      "unitPrice": 2400,
      "vatRate": 0,
      "vatCategory": "O",
      "taxExemptReason": "Integration test"
    }
  ],
  "paymentTerms": "Net 30 days",
  "paymentReference": "+++000/0000/00097+++"
}

This is the exact template generated by getpeppr init. See the full type reference for all available fields.

Ready to send?

When your invoice JSON is ready, send it to the Peppol network — straight from the CLI:

getpeppr login                       # store your sandbox key once
getpeppr send invoice.json --watch   # send + poll delivery status

Or, for programmatic use inside an app, install the SDK:

npm install @getpeppr/sdk
import { Peppol } from "@getpeppr/sdk";

const peppol = new Peppol({ apiKey: "your-api-key" });
const result = await peppol.invoices.send(invoice);

Sign up at getpeppr.dev to get your API key.

Release notes

validate runs the Peppol rules bundled into the version you installed, so its verdict can change between releases — which matters most if you gate a pipeline on its exit code. Two places tell you what moved:

  • CHANGELOG.md, shipped inside the package (node_modules/@getpeppr/cli/CHANGELOG.md).
  • getpeppr.dev/news for the same notes on the web, alongside gateway and SDK changes.

License

MIT