`@refcampaign/cli` is a read-only command-line client for merchant reporting. It reads campaigns, affiliates, conversions, commissions, and payouts; it does not change those resources.

## Installation

The CLI requires Node.js 22, 23, or 24.

Install it globally:

```bash
npm install --global @refcampaign/cli
refcampaign --version
```

Or run the published package without a global install:

```bash
npx @refcampaign/cli --version
npx @refcampaign/cli status --json
```

Run `refcampaign --help` or `refcampaign <group> <command> --help` to inspect the help shipped with your installed version. The examples below use the global executable.

## Authentication

Create a merchant API key in [Settings → API keys](https://app.refcampaign.com/dashboard/settings/api), then start the interactive login:

```bash
refcampaign auth login
```

The prompt masks the key while you type. Login validates the key with RefCampaign before saving it to the operating-system keyring: Keychain on macOS, Secret Service on Linux, or Credential Manager on Windows. The CLI does not create a local credentials file. Surrounding whitespace is rejected.

Inspect or remove the keyring credential with:

```bash
refcampaign auth status
refcampaign auth status --json
refcampaign auth logout
```

`auth status` reports `environment` or `keyring` as the active source. `auth logout` removes only the keyring entry and is safe to repeat.

### CI and environment priority

For CI, add `REFCAMPAIGN_API_KEY` as a masked, protected secret in the CI provider and expose it to the job environment. The CLI uses a non-empty `REFCAMPAIGN_API_KEY` before consulting the keyring, so headless jobs do not need an interactive login. Do not print the variable or write it to a repository file.

```yaml
merchant-report:
  script:
    - refcampaign status --json
    - refcampaign conversions summary --period 30d --json
```

## Commands and filters

Every resource command is read-only. `--json` and `--csv` are mutually exclusive. The global `--debug` option adds redacted diagnostic details to stderr.

| Command                           | Options                                                                                                                                                                                                                                   |
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `refcampaign auth login`          | Interactive masked prompt; validates and saves the keyring credential                                                                                                                                                                     |
| `refcampaign auth status`         | `--json`, `--csv`                                                                                                                                                                                                                         |
| `refcampaign auth logout`         | No command-specific options                                                                                                                                                                                                               |
| `refcampaign status`              | `--json`, `--csv`                                                                                                                                                                                                                         |
| `refcampaign campaigns list`      | Common list options; `--status DRAFT\|ACTIVE\|PAUSED\|COMPLETED\|ARCHIVED`                                                                                                                                                                |
| `refcampaign campaigns get <id>`  | `--json`, `--csv`                                                                                                                                                                                                                         |
| `refcampaign affiliates list`     | Common list options; `--status ACTIVE\|APPROVED_UNASSIGNED\|SUSPENDED\|ARCHIVED`; `--campaign-id <id>`                                                                                                                                    |
| `refcampaign affiliates get <id>` | `--json`, `--csv`                                                                                                                                                                                                                         |
| `refcampaign conversions list`    | Common list options; `--campaign-id <id>`; `--affiliate-id <id>`; `--status PENDING\|APPROVED\|REFUNDED\|REJECTED\|DISPUTED`; `--from <date>`; `--to <date>`; `--min-amount <amount>`; `--max-amount <amount>`                            |
| `refcampaign conversions summary` | `--period 7d\|30d\|mtd\|ytd` (default `30d`); `--group-by status\|campaign`; `--campaign-id <id>`; `--json`; `--csv`                                                                                                                      |
| `refcampaign commissions list`    | Common list options; `--campaign-id <id>`; `--affiliate-id <id>`; `--status PENDING\|APPROVED\|PAID\|REJECTED\|PAYABLE\|LOCKED\|PAID_PENDING\|DISPUTED`; `--from <date>`; `--to <date>`; `--min-amount <amount>`; `--max-amount <amount>` |
| `refcampaign payouts list`        | Common list options; `--affiliate-id <id>`; `--status PENDING\|INVOICE_UPLOADED\|PROCESSING\|APPROVED\|PAID\|REJECTED\|CANCELLED`; `--method PAYPAL\|BANK_TRANSFER\|WISE`; `--from <date>`; `--to <date>`                                 |
| `refcampaign payouts get <id>`    | `--json`, `--csv`                                                                                                                                                                                                                         |

Common list options are `--limit <number>` (1–100, default 50), `--offset <number>` (zero-based, default 0), `--all`, `--json`, and `--csv`. Amount filters accept non-negative decimals with at most two decimal places. Date filters accept a real ISO 8601 date such as `2026-07-01` or a timestamp with seconds and `Z` or a UTC offset.

Example queries:

```bash
refcampaign status
refcampaign campaigns list --status ACTIVE
refcampaign campaigns get camp_123 --json
refcampaign affiliates list --campaign-id camp_123 --all
refcampaign affiliates get aff_123 --json
refcampaign conversions list --status APPROVED --from 2026-07-01 --to 2026-07-31 --csv
refcampaign conversions summary --period 30d --group-by campaign --json
refcampaign commissions list --status PAYABLE --min-amount 10.00 --all
refcampaign payouts list --method BANK_TRANSFER --status PAID --json
refcampaign payouts get pay_123 --csv
```

## Output contracts

The default output is a human-readable table. Dates in tables use the machine's locale and time zone. List tables print `More records are available. Use --offset N to continue.` when another page exists.

Machine-readable modes are stable for scripting:

* `--json` emits one JSON document followed by a newline. Detail and summary commands use `{ "data": ... }`; list commands use `{ "data": [...], "pagination": ... }`.
* `--csv` emits one header row and CRLF-delimited records. Potential spreadsheet formulas in text cells are prefixed with an apostrophe. List and detail columns are the same fields shown below.
* stdout contains successful command output only. Errors, retry notices, and `--debug` diagnostics go to stderr. Secrets are redacted from stderr.

| Command family        | Table/CSV fields                                                                                                                                                                                                     |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `auth status`         | source, merchant, valid                                                                                                                                                                                              |
| `status`              | merchant, active campaigns, Stripe connected, Stripe mode                                                                                                                                                            |
| campaigns             | id, name, status, commission rate/type, start, end                                                                                                                                                                   |
| affiliates            | id, display name, email, status, created                                                                                                                                                                             |
| conversions           | id, campaign, affiliate, amount/currency, commission/currency, status, created                                                                                                                                       |
| `conversions summary` | totals: count, revenue, commissions, period, range; optional status or campaign groups. CSV columns are `scope,key,label,count,revenue,revenue_currency,commissions,commissions_currency,period,range_from,range_to` |
| commissions           | id, affiliate, campaign, amount/currency, status, created                                                                                                                                                            |
| payouts               | id, affiliate, amount/currency, method, status, requested                                                                                                                                                            |

JSON list example:

```bash
refcampaign campaigns list --limit 1 --json
```

```json
{
  "data": [
    {
      "id": "camp_123",
      "name": "Partner program",
      "description": null,
      "status": "ACTIVE",
      "commissionRate": 20,
      "commissionType": "PERCENTAGE",
      "startDate": "2026-07-01T00:00:00.000Z",
      "endDate": null,
      "createdAt": "2026-06-20T08:30:00.000Z"
    }
  ],
  "pagination": {
    "total": 3,
    "limit": 1,
    "offset": 0,
    "hasMore": true,
    "page": 1,
    "totalPages": 3
  }
}
```

CSV example:

```bash
refcampaign campaigns list --limit 1 --csv
```

```csv
id,name,status,commission_rate,commission_type,start,end
camp_123,Partner program,ACTIVE,20,PERCENTAGE,2026-07-01T00:00:00.000Z,
```

## Pagination and retries

Without `--all`, a list command requests one page. Use the displayed next offset, or select another page explicitly with `--limit` and `--offset`. With `--all`, the CLI starts at the requested offset and follows every page until the API reports `hasMore: false`; JSON and CSV then contain the combined rows.

Each HTTP request has a 10-second timeout and at most three attempts. The CLI retries timeouts, transient DNS/connection failures, HTTP 429, and HTTP 5xx responses. It honors a valid `Retry-After` header; otherwise delays are approximately 1 second then 2 seconds plus up to 999 ms of jitter. Retry notices appear on stderr in an interactive terminal or when `--debug` is enabled. Other HTTP 4xx responses are not retried.

## Advanced API URL override

`REFCAMPAIGN_API_URL` is an advanced, process-environment override for the API origin. The selected origin receives the `Authorization: Bearer` header, so it must be an endpoint you trust. The default is `https://app.refcampaign.com`. The value must be an origin root: a trailing `/` is accepted, but a username, password, path, query, or fragment is rejected. HTTPS is mandatory except when the host is exactly `localhost`, `127.0.0.1`, or `[::1]`; ports are allowed. The CLI never persists this override. Never send a production key to an overridden origin.

Use the override only for a controlled non-production environment:

```bash
REFCAMPAIGN_API_URL=https://app.test.refcampaign.com refcampaign status --json
```

## Exit codes

| Code | Meaning                                                                                           |
| ---- | ------------------------------------------------------------------------------------------------- |
| 0    | Success, version, or help                                                                         |
| 1    | API, network, timeout, incompatible-response, keyring, or unexpected failure                      |
| 2    | Invalid command, option, option combination, or local input                                       |
| 3    | Missing, invalid, revoked, or insufficiently scoped credential; scripts may branch on exit code 3 |

## Troubleshooting

* **`No API key configured`**: run `refcampaign auth login`, or expose `REFCAMPAIGN_API_KEY` through the CI secret store.
* **Key reported as invalid or revoked**: without printing its value, check directly whether `REFCAMPAIGN_API_KEY` is defined in the shell or CI secret store. If it is defined, replace or unset it there; `refcampaign auth login` changes only the keyring and cannot override the environment source. If `REFCAMPAIGN_API_KEY` is absent, the keyring is the relevant source: use `refcampaign auth logout` to remove a stale stored entry when needed, then `refcampaign auth login` to validate and save the replacement. Remove surrounding whitespace before submitting it.
* **Key missing the `read` scope**: generate an API key with the `read` scope. Replace or unset `REFCAMPAIGN_API_KEY` when the environment is the active source; otherwise run `refcampaign auth login` with the replacement keyring credential.
* **Secure credential store unavailable**: unlock the OS keyring and retry. On headless CI, use the environment secret instead.
* **HTTP 429 or 5xx**: the CLI already retries up to three total attempts. Wait and retry later if the final attempt fails.
* **Request timed out or network request failed**: verify DNS, proxy, firewall, and the selected API origin. Add the global `--debug` option for redacted diagnostics.
* **Invalid date, amount, page, or filter**: run the exact command with `--help`; usage failures return exit code 2.
* **Unexpected response shape**: update `@refcampaign/cli`; the CLI rejects responses that do not match its shipped contract.
