> For the complete documentation index, see [llms.txt](https://developer.paddle.com/llms.txt).

# Paddle CLI with scripts and AI agents

Use the Paddle CLI to read data and take actions in your Paddle account from scripts, CI/CD pipelines, scheduled routines, and AI agents.

---

Use the Paddle CLI to run Paddle tasks without you at the terminal, like scheduled routines, scripts, and CI/CD pipelines. Commands return results in the same format every time.

For example, an AI agent routine that runs `paddle subscriptions list --status past_due --output json` every morning gets a list of past-due subscriptions in the same format each time, ready to summarize.

For tasks where you're in the conversation with your agent, checking its work as you go, you can also use the [Paddle MCP server](https://developer.paddle.com/sdks/ai/paddle-mcp.md).

## How it works

You can run the Paddle CLI without being at the terminal in two ways:

- **An AI agent runs it for you**, using the login you've saved on your computer.
- **A CI/CD pipeline or script runs it**, using an API key you set as an environment variable.

The CLI adapts when a program runs it instead of a person: it returns JSON rather than tables and returns an [exit code](#exit-codes) for every command. Commands that delete or cancel something need the entity's ID reconfirmed.

The CLI writes results to stdout and everything else to stderr, like errors, the account line, and next-page hints. You can pipe results to another program or save them to a file:

```sh
paddle customers list | jq '.data[].id'
```

### CLI with AI agents

AI coding agents like [Claude Code](https://developer.paddle.com/get-started/ai/claude-code.md), [Cursor](https://developer.paddle.com/get-started/ai/cursor.md), [Codex](https://developer.paddle.com/get-started/ai/codex.md), and [Gemini CLI](https://developer.paddle.com/get-started/ai/gemini-cli.md) can run the Paddle CLI using your saved login. You don't need to set anything up in the CLI.

To have your agent use the CLI, mention it in your request. For example:

```md
Use the Paddle CLI to create a monthly price for AeroEdit Pro.
```

To make it the default, add a line like this to your project's `CLAUDE.md` or `AGENTS.md` file:

```md
Use the Paddle CLI (`paddle`) for Paddle tasks. Use my sandbox account unless I say otherwise.
```

{% callout type="warning" title="AI agents can make mistakes" %}
Your agent can do everything your saved login allows. Use a sandbox API key while you're testing, and give live API keys only the [permissions](https://developer.paddle.com/api-reference/about/permissions.md) your agent needs.
{% /callout %}

### CLI in CI/CD pipelines

In CI/CD pipelines and other places where you can't log in, set your API key and account using environment variables:

```sh
export PADDLE_API_KEY=YOUR_API_KEY
export PADDLE_ENVIRONMENT=sandbox
paddle products list
```

Store your API key as a secret in your CI/CD system. Don't commit it to your repository. For more, see [API key best practices](https://developer.paddle.com/api-reference/about/authentication.md#best-practices).

## Agent mode

The CLI turns on agent mode on its own when [Claude Code](https://developer.paddle.com/get-started/ai/claude-code.md), [Cursor](https://developer.paddle.com/get-started/ai/cursor.md), [Codex](https://developer.paddle.com/get-started/ai/codex.md), [Gemini CLI](https://developer.paddle.com/get-started/ai/gemini-cli.md), OpenCode, Aider, or a CI/CD system runs it. It detects them from environment variables they set, like `CLAUDECODE` or `CI`.

Agent mode makes the CLI easier for AI agents to use. In agent mode, the CLI returns compact JSON as the output and turns off colors. It still prints which account it used after each command, like `→ sandbox`.

If the CLI doesn't detect your agent, you can turn on agent mode for it. Set the `PADDLE_AGENT` environment variable to `1` in your agent's settings, or ask your agent to add `--agent` to its `paddle` commands.

If you see JSON instead of tables in your own terminal and didn't ask for it, check whether `CI` or `PADDLE_AGENT` is set in your terminal's environment, and unset what you don't need.

## Destructive commands {% id="confirm-destructive-commands" %}

Commands that delete or cancel an entity ask you to confirm the action before they run. In a terminal, you answer a prompt.

In scripts, CI/CD pipelines, and AI agents, you need to pass the entity's [Paddle ID](https://developer.paddle.com/api-reference/about/paddle-ids.md) a second time with `--confirm`. Without it, or if the IDs don't match, the command doesn't run and returns [exit code](#exit-codes) `2`:

```sh
paddle subscriptions cancel sub_01h3h3a9sfpr5syq38tq0sd4sp --confirm sub_01h3h3a9sfpr5syq38tq0sd4sp
```

When a command takes more than one ID, confirm the last one. That's the entity the command deletes:

```sh
paddle payment-methods delete ctm_01hv6y1jedq4p1n0yqn5ba3ky4 paymtd_01hs8zx6x377xfsfrt2bqsevbw --confirm paymtd_01hs8zx6x377xfsfrt2bqsevbw
```

These commands need confirming:

| Command                                  | What it does                                  |
| ---------------------------------------- | --------------------------------------------- |
| `paddle subscriptions cancel`            | Cancels a subscription.                       |
| `paddle notification-settings delete`    | Deletes a notification destination.          |
| `paddle payment-methods delete`          | Deletes a payment method saved for a customer. |
| `paddle checkout-domains delete`         | Deletes a checkout domain.                    |

## Exit codes {% id="exit-codes" %}

Every command returns an exit code. Scripts can use it to check what happened without reading the error message. API errors map to an exit code based on their [HTTP status code](https://developer.paddle.com/api-reference/about/errors.md).

| Code  | Meaning                                                                                       |
| ----- | --------------------------------------------------------------------------------------------- |
| `0`   | Success.                                                                                      |
| `1`   | General error, like a failed request.                                                         |
| `2`   | Usage error, like an unknown command or flag, a missing argument, or a missing `--confirm`.   |
| `3`   | Not found. The API returned `404`.                                                            |
| `4`   | Authentication error. The API returned `401`. Your API key isn't valid. |
| `5`   | Permission error. The API returned `403`. You're not logged in, your API key is for the other account, or it doesn't have permission. |
| `6`   | Rate limited. The API returned `429`.                                                         |
| `7`   | Validation error. The API returned `400` or `422`.                                            |
| `8`   | Conflict. The API returned `409`.                                                             |
| `9`   | Server error. The API returned a `5xx` status.                                                |
| `124` | The request timed out.                                                                        |

When a script or AI agent runs the CLI, errors are a JSON object on stderr. It has the same fields as an [API error](https://developer.paddle.com/api-reference/about/errors.md), all at the top level, plus the HTTP `status` and whether the request is `retryable`:

```json
{
  "status": 404,
  "type": "request_error",
  "code": "not_found",
  "detail": "customer ctm_01hv6y1jedq4p1n0yqn5ba3ky4 not found.",
  "documentation_url": "https://developer.paddle.com/v1/errors/shared/not_found",
  "request_id": "c0913cb1-ed8b-4050-b740-d810504ed8c4",
  "retryable": false
}
```