> ## Documentation Index
> Fetch the complete documentation index at: https://docs.e-invoice.be/llms.txt
> Use this file to discover all available pages before exploring further.

# peppol CLI

> Install the peppol command-line tool and validate, create and send Peppol documents from a terminal or a script.

`peppol` is the command-line tool for the e-invoice.be API. Use it to send a test invoice without code, to examine received documents, or to automate tasks in a shell script. The source is in the repository [e-invoice-be/peppol-cli](https://github.com/e-invoice-be/peppol-cli).

The CLI calls the single API host `https://api.e-invoice.be`. The API key selects the mode: a key of a sandbox company runs the commands in test mode.

## Install

<Tabs>
  <Tab title="macOS">
    ```bash theme={null}
    brew tap e-invoice-be/tap
    brew install e-invoice-be/tap/peppol-cli
    ```
  </Tab>

  <Tab title="Linux">
    Use Homebrew:

    ```bash theme={null}
    brew tap e-invoice-be/tap
    brew install e-invoice-be/tap/peppol-cli
    ```

    As an alternative, download the `linux_amd64` or `linux_arm64` archive from [GitHub Releases](https://github.com/e-invoice-be/peppol-cli/releases), extract it, and move the `peppol` file to a directory in your `PATH`.
  </Tab>

  <Tab title="Windows">
    Download the `.zip` file for Windows from [GitHub Releases](https://github.com/e-invoice-be/peppol-cli/releases), extract it, and add `peppol.exe` to your `PATH`.
  </Tab>
</Tabs>

Make sure that the installation is correct:

```bash theme={null}
peppol version
```

## Authenticate

The CLI can get the API key from two sources.

<Tabs>
  <Tab title="Interactive">
    ```bash theme={null}
    peppol auth
    ```

    The command opens the API settings page of the app in your browser and asks you to paste the API key. It calls `GET /api/me/` to make sure that the key is valid, and then stores the key in a workspace.

    ```bash theme={null}
    # Show the authentication status
    peppol auth status

    # Remove the stored key of the active workspace
    peppol auth logout
    ```
  </Tab>

  <Tab title="Environment variable">
    ```bash theme={null}
    export PEPPOL_API_KEY="your-api-key"
    ```

    Use this method in scripts and in CI. The CLI stores nothing.
  </Tab>
</Tabs>

Show the account of the key:

```bash theme={null}
peppol me
```

<Warning>
  `PEPPOL_API_KEY` has priority over all stored keys. While the variable is set, the `--workspace` flag and the active workspace do not change the key that the CLI uses.
</Warning>

## Workspaces

A workspace is a name for one stored API key. Each company has its own API key, thus you use one workspace for each company. The CLI stores workspaces in `~/.config/peppol-cli`, or in `$XDG_CONFIG_HOME/peppol-cli` if that variable is set.

| Command | Function |
| - | - |
| `peppol workspace add <name>` | Asks for an API key, makes sure that it is valid, and stores it with this name |
| `peppol workspace list` | Shows all workspaces and the active workspace |
| `peppol workspace use <name>` | Makes a workspace the active workspace |
| `peppol workspace remove <name>` | Removes a workspace and its stored key |

`peppol auth` also makes a workspace. Its name comes from the company name, or from the `--workspace` flag if you give it.

### Use a sandbox company and a production company together

<Steps>
  <Step title="Add a workspace for each company">
    Paste the API key of the related company when the command asks for it.

    ```bash theme={null}
    peppol workspace add sandbox
    peppol workspace add production
    ```
  </Step>

  <Step title="Make the workspace of the sandbox company the active workspace">
    ```bash theme={null}
    peppol workspace use sandbox
    ```

    All commands now use the sandbox company.
  </Step>

  <Step title="Use the production company for one command">
    The global flag `--workspace` (short form `-w`) applies to one command only. The active workspace does not change.

    ```bash theme={null}
    peppol outbox list -w production
    ```
  </Step>
</Steps>

<Tip>
  Keep the workspace of the sandbox company as the active workspace. Then a command without `-w` cannot send a document on the Peppol network.
</Tip>

## Validate, create and send an invoice

This procedure uses a file `invoice.json` with the invoice JSON. The [Quickstart](/quickstart) shows how to make this file.

<Note>
  Validation is not a separate mandatory call. `POST /api/documents/` rejects a payload that does not pass the same rules. Use `POST /api/validate/json` while you develop, because it returns all rule failures and the generated UBL.
</Note>

<Steps>
  <Step title="Validate the JSON file">
    ```bash theme={null}
    peppol validate json invoice.json
    ```

    The command shows `Validation: PASSED`, or `Validation: FAILED` with the number of errors and warnings and a table with the columns `SEVERITY`, `RULE ID`, `MESSAGE` and `LOCATION`. If the document is not valid, the exit code is `3`.

    To read the JSON from standard input, use `--file -`:

    ```bash theme={null}
    cat invoice.json | peppol validate json --file -
    ```
  </Step>

  <Step title="Create the document">
    ```bash theme={null}
    peppol document create json invoice.json
    ```

    The command creates a document in the `DRAFT` state and shows its details. Record the document ID. Add `--construct-pdf` to let the API make a PDF from the document.
  </Step>

  <Step title="Send the document">
    ```bash theme={null}
    peppol document send <document-id>
    ```

    With a sandbox company, the send does not use the Peppol network. See [Test mode and sandbox companies](/environments).
  </Step>

  <Step title="Examine the result">
    ```bash theme={null}
    peppol document get <document-id>
    peppol document timeline <document-id>
    ```
  </Step>
</Steps>

In a script, use `--json` and get the document ID from the output. This sample uses `jq`:

```bash theme={null}
DOCUMENT_ID=$(peppol document create json invoice.json --json | jq -r '.id')
peppol document send "$DOCUMENT_ID" --json
```

### Set the Peppol IDs for a send

`peppol document send` accepts flags that give the sender and the receiver explicitly:

<ParamField path="--sender-peppol-scheme" type="string">
  Peppol scheme of the sender, for example `0208`.
</ParamField>

<ParamField path="--sender-peppol-id" type="string">
  Peppol ID of the sender.
</ParamField>

<ParamField path="--receiver-peppol-scheme" type="string">
  Peppol scheme of the receiver.
</ParamField>

<ParamField path="--receiver-peppol-id" type="string">
  Peppol ID of the receiver.
</ParamField>

<ParamField path="--email" type="string">
  Email address for the `email` parameter of the send call.
</ParamField>

## Other common tasks

### Create a document from UBL or PDF

```bash theme={null}
# From a UBL XML file
peppol document create ubl invoice.xml

# From a PDF file
peppol document create pdf invoice.pdf --vendor-tax-id BE1018265814 --customer-tax-id BE0848934496
```

The flags `--vendor-tax-id` and `--customer-tax-id` are optional. See [Send UBL documents](/guides/ubl-documents) and [Create documents from PDF](/guides/pdf-documents).

### Validate

```bash theme={null}
# A UBL XML file
peppol validate ubl invoice.xml

# A document that is already in your account
peppol document validate <document-id>

# A Peppol ID: format and registration on the network
peppol validate peppol-id 0208:0848934496
```

For the Peppol ID check, see [Look up Peppol participants](/guides/lookup-participants).

### Look up a participant

```bash theme={null}
peppol lookup 0208:0848934496
peppol lookup search "OpenPeppol" --country BE
```

### List documents

```bash theme={null}
peppol inbox list
peppol inbox invoices
peppol inbox credit-notes
peppol outbox list
peppol drafts list
```

The list commands accept the flags `--page`, `--page-size`, `--from`, `--to`, `--search`, `--type`, `--sort-by` and `--sort-order`. The inbox commands also accept `--sender`. `peppol outbox list` also accepts `--receiver`.

### Download, delete and attach

```bash theme={null}
# Download the UBL XML of a document
peppol document ubl <document-id> -o invoice.xml

# Delete a draft document
peppol document delete <document-id>

# Attachments
peppol document attachment list <document-id>
peppol document attachment add <document-id> terms.pdf
peppol document attachment get <document-id> <attachment-id> -o terms.pdf
```

### Usage statistics

```bash theme={null}
peppol stats
peppol stats --from 2026-01-01 --to 2026-03-01 --aggregation MONTH
```

`--aggregation` accepts `DAY`, `WEEK` or `MONTH`. See [Usage statistics and credits](/guides/usage-statistics).

### Back up all documents

```bash theme={null}
peppol backup ./peppol-archive
```

The command writes each document, its attachments, its UBL XML and its timeline to the directory.

## Automation

### Global flags

These flags are available on all commands:

| Flag | Short form | Function |
| - | - | - |
| `--json` | `-j` | Writes the output as JSON |
| `--quiet` | `-q` | Does not write output that is not essential |
| `--verbose` | `-v` | Writes more information |
| `--no-color` | | Does not use colours in the output |
| `--workspace <name>` | `-w` | Uses this workspace for the command |

### Confirmation prompts

`peppol document delete` and `peppol document attachment delete` ask for a confirmation. In a script, add `--yes` to these two commands. `--yes` is not a global flag.

```bash theme={null}
peppol document delete <document-id> --yes
```

### Exit codes

| Code | Meaning |
| - | - |
| `0` | The command was successful |
| `1` | General error, for example a file that does not exist or an error response from the API |
| `2` | Authentication error: no API key is available, or the API does not accept the key |
| `3` | Validation failed: `peppol validate json` or `peppol validate ubl` found that the document is not valid |
| `4` | Not found: the document or the attachment does not exist |

<Warning>
  With `--json`, `peppol validate json` and `peppol validate ubl` write the validation result and stop with exit code `0`, also when the document is not valid. In a script that uses `--json`, read the field `is_valid` from the output. `peppol document validate` does not use exit code `3` in any mode.
</Warning>

When a command fails and `--json` is set, the CLI writes the error as JSON to standard error:

```json theme={null}
{
  "error": "document not found",
  "code": 4
}
```

### Sample script

```bash theme={null}
#!/usr/bin/env bash
set -euo pipefail

# PEPPOL_API_KEY is set in the environment

if ! peppol validate json invoice.json --quiet; then
  echo "The invoice is not valid" >&2
  exit 1
fi

DOCUMENT_ID=$(peppol document create json invoice.json --json | jq -r '.id')
peppol document send "$DOCUMENT_ID" --json
```

### Shell completion

`peppol completion bash`, `peppol completion zsh`, `peppol completion fish` and `peppol completion powershell` write a completion script for your shell.

## Use with AI agents

An AI agent that can run shell commands can use the CLI with `--json`, `--yes` and the exit codes. To connect an AI assistant directly to your account without the CLI, use the MCP server. See [Model Context Protocol (MCP)](/essentials/mcp).

## Report a problem

Report a problem with the CLI in the [issues of the repository](https://github.com/e-invoice-be/peppol-cli/issues).

## Next Steps

<CardGroup cols={2}>
  <Card title="SDKs" icon="cubes" href="/sdks">
    Call the API with a typed client in your language
  </Card>

  <Card title="Test mode and sandbox companies" icon="flask" href="/environments">
    Learn how a sandbox company runs in test mode
  </Card>

  <Card title="Validation during development" icon="circle-check" href="/guides/validation">
    Understand the validation result
  </Card>

  <Card title="Model Context Protocol (MCP)" icon="robot" href="/essentials/mcp">
    Connect an AI assistant to your account
  </Card>
</CardGroup>
