`@refcampaign/cli` est un client en ligne de commande en lecture seule pour le reporting merchant. Il consulte les campagnes, affiliés, conversions, commissions et paiements sans modifier ces ressources.

## Installation

Le CLI nécessite Node.js 22, 23 ou 24.

Installez-le globalement :

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

Vous pouvez aussi exécuter le package publié sans installation globale :

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

Exécutez `refcampaign --help` ou `refcampaign <groupe> <commande> --help` pour consulter l'aide livrée avec la version installée. Les exemples suivants utilisent l'exécutable global.

## Authentification

Créez une clé API merchant dans [Paramètres → Clés API](https://app.refcampaign.com/dashboard/settings/api), puis lancez la connexion interactive :

```bash
refcampaign auth login
```

Le prompt masque la clé pendant la saisie. La connexion valide la clé auprès de RefCampaign avant de l'enregistrer dans le keyring du système : Trousseau sur macOS, Secret Service sur Linux ou Gestionnaire d'informations d'identification sur Windows. Le CLI ne crée aucun fichier local d'identifiants. Les espaces en début ou fin de clé sont refusés.

Consultez ou retirez l'identifiant du keyring avec :

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

`auth status` indique `environment` ou `keyring` comme source active. `auth logout` retire uniquement l'entrée du keyring et peut être relancé sans risque.

### Priorité en CI et dans l'environnement

Pour la CI, ajoutez `REFCAMPAIGN_API_KEY` comme secret masqué et protégé chez le fournisseur CI, puis exposez-le à l'environnement du job. Le CLI utilise un `REFCAMPAIGN_API_KEY` non vide avant de consulter le keyring ; les jobs headless n'ont donc pas besoin de connexion interactive. N'affichez pas la variable et ne l'écrivez pas dans un fichier du dépôt.

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

## Commandes et filtres

Toutes les commandes de ressources sont en lecture seule. `--json` et `--csv` sont incompatibles. L'option globale `--debug` ajoute des diagnostics expurgés sur stderr.

| Commande                          | Options                                                                                                                                                                                                                                                |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `refcampaign auth login`          | Prompt interactif masqué ; valide et enregistre l'identifiant dans le keyring                                                                                                                                                                          |
| `refcampaign auth status`         | `--json`, `--csv`                                                                                                                                                                                                                                      |
| `refcampaign auth logout`         | Aucune option spécifique                                                                                                                                                                                                                               |
| `refcampaign status`              | `--json`, `--csv`                                                                                                                                                                                                                                      |
| `refcampaign campaigns list`      | Options de liste communes ; `--status DRAFT\|ACTIVE\|PAUSED\|COMPLETED\|ARCHIVED`                                                                                                                                                                      |
| `refcampaign campaigns get <id>`  | `--json`, `--csv`                                                                                                                                                                                                                                      |
| `refcampaign affiliates list`     | Options de liste communes ; `--status ACTIVE\|APPROVED_UNASSIGNED\|SUSPENDED\|ARCHIVED` ; `--campaign-id <id>`                                                                                                                                         |
| `refcampaign affiliates get <id>` | `--json`, `--csv`                                                                                                                                                                                                                                      |
| `refcampaign conversions list`    | Options de liste communes ; `--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` (défaut `30d`) ; `--group-by status\|campaign` ; `--campaign-id <id>` ; `--json` ; `--csv`                                                                                                                                |
| `refcampaign commissions list`    | Options de liste communes ; `--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`        | Options de liste communes ; `--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`                                                                                                                                                                                                                                      |

Les options de liste communes sont `--limit <number>` (1–100, défaut 50), `--offset <number>` (indexé à partir de zéro, défaut 0), `--all`, `--json` et `--csv`. Les filtres de montant acceptent un nombre décimal positif ou nul avec deux décimales au maximum. Les filtres de date acceptent une date ISO 8601 réelle comme `2026-07-01`, ou un timestamp avec les secondes et `Z` ou un décalage UTC.

Exemples de requêtes :

```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
```

## Contrats de sortie

La sortie par défaut est un tableau lisible. Les dates des tableaux utilisent la locale et le fuseau de la machine. Les listes affichent `More records are available. Use --offset N to continue.` lorsqu'une autre page existe.

Les modes machine-readable sont stables pour les scripts :

* `--json` émet un document JSON suivi d'un saut de ligne. Les commandes de détail et de synthèse utilisent `{ "data": ... }` ; les listes utilisent `{ "data": [...], "pagination": ... }`.
* `--csv` émet un header puis des enregistrements séparés par CRLF. Les textes pouvant être interprétés comme des formules de tableur sont préfixés par une apostrophe. Les champs des listes et détails sont indiqués ci-dessous.
* stdout contient uniquement la sortie réussie de la commande. Les erreurs, notifications de retry et diagnostics `--debug` vont sur stderr. Les secrets sont expurgés de stderr.

| Famille de commandes  | Champs tableau/CSV                                                                                                                                                                                                                         |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `auth status`         | source, merchant, valid                                                                                                                                                                                                                    |
| `status`              | merchant, campagnes actives, connexion Stripe, mode Stripe                                                                                                                                                                                 |
| campaigns             | id, nom, statut, taux/type de commission, début, fin                                                                                                                                                                                       |
| affiliates            | id, nom affiché, e-mail, statut, création                                                                                                                                                                                                  |
| conversions           | id, campagne, affilié, montant/devise, commission/devise, statut, création                                                                                                                                                                 |
| `conversions summary` | totaux : nombre, revenu, commissions, période, intervalle ; groupes facultatifs par statut ou campagne. Les colonnes CSV sont `scope,key,label,count,revenue,revenue_currency,commissions,commissions_currency,period,range_from,range_to` |
| commissions           | id, affilié, campagne, montant/devise, statut, création                                                                                                                                                                                    |
| payouts               | id, affilié, montant/devise, méthode, statut, demande                                                                                                                                                                                      |

Exemple de liste JSON :

```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
  }
}
```

Exemple CSV :

```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 et retries

Sans `--all`, une commande de liste demande une seule page. Utilisez l'offset suivant affiché, ou choisissez une page avec `--limit` et `--offset`. Avec `--all`, le CLI part de l'offset demandé et suit toutes les pages jusqu'à ce que l'API renvoie `hasMore: false` ; les sorties JSON et CSV contiennent alors les lignes combinées.

Chaque requête HTTP a un timeout de 10 secondes et trois tentatives au maximum. Le CLI retente les timeouts, les échecs DNS/connexion transitoires, HTTP 429 et HTTP 5xx. Il respecte un header `Retry-After` valide ; sinon, les délais sont d'environ 1 seconde puis 2 secondes, avec jusqu'à 999 ms de jitter. Les notifications de retry apparaissent sur stderr dans un terminal interactif ou lorsque `--debug` est actif. Les autres réponses HTTP 4xx ne sont pas retentées.

## Surcharge avancée de l'URL API

`REFCAMPAIGN_API_URL` est une surcharge avancée de l'origine API par l'environnement du processus. L'origine sélectionnée reçoit le header `Authorization: Bearer` : elle doit donc être digne de confiance. La valeur par défaut est `https://app.refcampaign.com`. La valeur doit viser la racine de l'origine : un `/` final est accepté, mais un nom d'utilisateur, un mot de passe, un path, une requête ou un fragment est rejeté. HTTPS est obligatoire sauf si l'hôte est exactement `localhost`, `127.0.0.1` ou `[::1]` ; les ports sont autorisés. Le CLI ne persiste jamais cette surcharge. N'envoyez jamais une clé de production vers une origine surchargée.

Utilisez la surcharge uniquement pour un environnement hors production contrôlé :

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

## Codes de sortie

| Code | Signification                                                                                                      |
| ---- | ------------------------------------------------------------------------------------------------------------------ |
| 0    | Succès, version ou aide                                                                                            |
| 1    | Échec API, réseau, timeout, réponse incompatible, keyring ou inattendu                                             |
| 2    | Commande, option, combinaison d'options ou saisie locale invalide                                                  |
| 3    | Identifiant absent, invalide, révoqué ou sans scope suffisant ; les scripts peuvent traiter le libellé exit code 3 |

## Résolution des problèmes

* **`No API key configured`** : exécutez `refcampaign auth login` ou exposez `REFCAMPAIGN_API_KEY` depuis le coffre de secrets de la CI.
* **Clé indiquée comme invalide ou révoquée** : sans afficher sa valeur, vérifiez directement si `REFCAMPAIGN_API_KEY` est défini dans le shell ou le coffre CI. S'il est défini, remplacez-le ou retirez-le à cet endroit ; `refcampaign auth login` modifie uniquement le keyring et ne peut pas remplacer la source d'environnement. Si `REFCAMPAIGN_API_KEY` est absent, le keyring est la source à traiter : utilisez `refcampaign auth logout` pour retirer une ancienne entrée si nécessaire, puis `refcampaign auth login` pour valider et enregistrer la nouvelle clé. Retirez les espaces autour de la clé avant de la soumettre.
* **Clé sans le scope `read`** : générez une clé API avec le scope `read`. Remplacez ou retirez `REFCAMPAIGN_API_KEY` lorsque l'environnement est la source active ; sinon, exécutez `refcampaign auth login` avec la nouvelle clé destinée au keyring.
* **Stockage sécurisé indisponible** : déverrouillez le keyring du système et réessayez. Dans une CI headless, utilisez le secret d'environnement.
* **HTTP 429 ou 5xx** : le CLI effectue déjà trois tentatives au maximum. Attendez avant de réessayer si la dernière échoue.
* **Timeout ou échec réseau** : vérifiez le DNS, le proxy, le pare-feu et l'origine API sélectionnée. Ajoutez l'option globale `--debug` pour des diagnostics expurgés.
* **Date, montant, page ou filtre invalide** : relancez la commande exacte avec `--help` ; les erreurs d'usage renvoient le code de sortie 2.
* **Format de réponse inattendu** : mettez `@refcampaign/cli` à jour ; le CLI refuse les réponses qui ne respectent pas son contrat livré.
