---
title: "Référence CLI"
weight: 110
description: "Toutes les sous-commandes du binaire difuzio et leurs options."
---

# Référence CLI

Toutes les fonctions passent par le binaire unique difuzio. Les commandes qui
agissent sur un objet suivent la forme `difuzio <groupe> <action> [options]`, par
exemple `difuzio member add` ou `difuzio list set`. Les daemons, les migrations et
les commandes de diagnostic gardent une forme simple : `difuzio serve-web`,
`difuzio migrate up`, `difuzio doctor`.

    difuzio help                 # liste les groupes et les commandes
    difuzio help <groupe>        # actions d'un groupe (ou : difuzio <groupe>)
    difuzio version              # version du binaire et backend de base compilé

Les commandes daemon prennent `--config <chemin>` (et chargent les keyrings). Les
commandes d'administration prennent soit `--dsn <dsn>`, soit `--config <chemin>`
pour la connexion à la base ; `--dsn` l'emporte sur `--config`.

Le DSN (Data Source Name) est la chaîne de connexion à la base. Sa forme dépend du
backend compilé dans le binaire : chaîne go-sql-driver pour MariaDB, chemin de
fichier pour SQLite (voir [Base de données](/difuzio/admin/base-de-donnees)).
`difuzio version` indique le backend lié.

Toute commande qui lit `--config` charge aussi les trois keyrings. Si la
configuration référence `${CREDENTIALS_DIRECTORY}` (le cas par défaut, cf
[Configuration](/difuzio/admin/configuration)), poser la variable sur la commande,
qui échoue sinon en nommant la variable manquante :

    CREDENTIALS_DIRECTORY=/etc/difuzio/secrets difuzio <commande> --config /etc/difuzio/config.yaml

Avec `--dsn`, les keyrings ne sont pas chargés. Quatre commandes exigent donc
`--config` et refusent `--dsn` seul, en l'expliquant : `erase`, `send submit` et
`archive backfill-attachments` (le corps des messages vit hors de la base), et
`digest compile` (la compilation met du courrier en file). `member add` sur une
liste en politique `confirm` a besoin du keyring de tokens et le signale de la
même façon.

## Codes de sortie

- `0` : succès.
- `1` : échec d'exécution (base injoignable, objet introuvable, refus du service).
- `2` : erreur d'invocation (option manquante, valeur inconnue, action inconnue).

`difuzio <commande> --help` sort en `0`. Deux exceptions conservées :
`domain check-dns` sort en `1` tant que le domaine n'est pas prêt pour l'envoi en
masse (c'est un résultat, pas une erreur), et `migrate status` en `1` quand le
schéma est marqué "dirty".

## Daemons

### serve-web

    difuzio serve-web --config /etc/difuzio/config.yaml [--insecure]

Lance l'interface web et l'API REST. `--insecure` envoie les cookies sans le
drapeau `Secure` (développement local uniquement, jamais derrière TLS public).

### serve-lmtp

    difuzio serve-lmtp --config /etc/difuzio/config.yaml

Lance le serveur de réception LMTP (posts, commandes par email, bounces, plaintes).

### worker

    difuzio worker --config /etc/difuzio/config.yaml

Lance le pipeline de traitement, l'envoi sortant, les tâches périodiques, et (si
`metrics.bind` est défini) le serveur `/metrics`. On en lance plusieurs pour le
débit. Rien ne part vers le relais tant qu'aucun worker ne tourne.

## Configuration et diagnostic

### config check

    difuzio config check --config /etc/difuzio/config.yaml

Charge et valide la configuration (keyrings, invariants), puis quitte.

### doctor

    difuzio doctor [--dsn <dsn> | --config /etc/difuzio/config.yaml]

Vérifie que la base répond, que le schéma est à jour et propre, et, avec
`--config`, recoupe la configuration avec la base : domaines déclarés, stockage
des corps, boîtes d'ingestion.

### stats show

    difuzio stats show [--dsn <dsn> | --config <chemin>]

Compteurs de l'instance : domaines, listes, listes dont l'envoi est suspendu,
listes sans VERP, éléments retenus en modération, copies en file.

### queue stats

    difuzio queue stats [--state queued|sending|sent|deferred|failed|cancelled]

Profondeur de la file `outgoing_queue` par état, avec le total. `--state`
restreint le compte à un seul état.

### queue requeue

    difuzio queue requeue [--domain lists.example.org [--list announce]]

Ramène les copies `deferred` en `queued` avec une prochaine tentative immédiate,
pour que le worker les reprenne sans attendre la fin du backoff. Les compteurs de
tentatives restent intacts : la limite de tentatives continue de s'appliquer.

### digest compile

    difuzio digest compile --config /etc/difuzio/config.yaml

Compile une fois les digests en attente, sous le même verrou d'avis que la tâche
périodique du worker. Si un worker compile au même moment, la commande ne fait
rien et le dit (code `1`) plutôt que d'envoyer un digest en double.

### archive backfill-attachments

    difuzio archive backfill-attachments --config /etc/difuzio/config.yaml

Recalcule l'indicateur "pièces jointes" (`messages.has_attachments`) des messages
archivés avant que difuzio ne l'enregistre à la réception. La commande ne lit que
les lignes qui valent encore "non" et dont le corps brut est toujours là : elle
corrige un "non" en "oui", jamais l'inverse.

Ce rattrapage n'est pas fait par une migration : décider si un message porte une
pièce jointe demande de parcourir son arborescence MIME, ce qu'aucun moteur SQL ne
sait faire, et réécrire toute une archive pendant une migration bloquerait la mise
à jour aussi longtemps que dure le parcours. C'est donc une passe de maintenance,
à lancer quand l'instance est calme.

Elle est reprenable et interruptible : elle avance par lots validés au fur et à
mesure, dans l'ordre des identifiants. Un Ctrl-C ne perd que le lot en cours, et
relancer la commande reprend le travail. Un message dont le corps a été purgé par
la rétention est compté comme illisible et laissé tel quel : il n'y a plus rien à
inspecter. Sortie : nombre de messages examinés, corrigés, illisibles, et mal
formés (arborescence MIME partiellement analysable, dont la raison est journalisée).

## Migrations

Les migrations s'appliquent avec le compte DDL (Data Definition Language : le
compte autorisé à faire des `CREATE` / `ALTER` / `DROP`), passé via `--dsn`, ou
via `--config` en repli. Sous SQLite il n'y a pas de comptes : ce sont les droits
POSIX sur le fichier qui font foi.

    difuzio migrate up            [--dsn|--config]   # applique toutes les migrations
    difuzio migrate down [N|all]  [--dsn|--config]   # annule 1, N, ou toutes (all)
    difuzio migrate to <version>  [--dsn|--config]   # va à une version précise
    difuzio migrate status        [--dsn|--config]   # version courante + drapeau dirty
    difuzio migrate force <ver>   [--dsn|--config]   # force la version, efface dirty

`migrate down all` est destructeur (mot-clé `all` requis explicitement). En cas de
schéma "dirty" après un échec, corriger puis `migrate force <version>`.

## bootstrap-admin

    difuzio bootstrap-admin --email vous@example.org --password-stdin [--force]

Crée le premier `super_admin`. Le mot de passe vient de `--password` ou, mieux, de
`--password-stdin` (lu sur l'entrée standard). `--force` permet d'en créer un
autre si un super_admin existe déjà.

## Groupe domain

### domain add

    difuzio domain add --name lists.example.org --base-url https://lists.example.org \
        [--display-name "..."] [--robot difuzio] [--locale fr|en]

Provisionne un domaine (en état `pending_mta`). Voir [Domaines](/difuzio/admin/domaines).
`--locale` fixe la langue des courriers transactionnels du domaine (`fr` par
défaut) : voir [Mails transactionnels](/difuzio/admin/mails-transactionnels).

### domain ls

    difuzio domain ls

Affiche les domaines : id, nom, statut, robot, URL publique.

### domain set-status

    difuzio domain set-status --domain lists.example.org --status active|suspended|pending_mta

Change l'état d'un domaine. Voir [Domaines](/difuzio/admin/domaines).

### domain set-command-addresses

    difuzio domain set-command-addresses --domain lists.example.org --routed=false
    difuzio domain set-command-addresses --domain lists.example.org --routed=true

Déclare si les adresses de service des listes du domaine (`liste-subscribe@`,
`liste-unsubscribe@`, `liste-owner@`, `liste-request@`) sont bien remises à
difuzio. Ce n'est pas une préférence : cela décrit le serveur de messagerie placé
devant.

`--routed=true` (défaut, cas historique) suppose un MTA qui route tout le domaine
vers difuzio. `--routed=false` correspond au profil boîte externe, où seule la
boîte de chaque liste est relevée : difuzio cesse alors d'annoncer ces adresses
dans les en-têtes `List-Help`, `List-Subscribe`, `List-Owner` et
`List-Unsubscribe`, et de les afficher sur les pages publiques. Sans ce réglage,
un abonné qui suit l'un de ces en-têtes écrit à une adresse que l'hébergeur
rejette. Voir [Comptes de messagerie externes](/difuzio/admin/boite-externe).

### domain add-admin

    difuzio domain add-admin --email admin@example.org --domain lists.example.org \
        [--display-name "..."] [--password-stdin]

Crée l'utilisateur s'il n'existe pas et lui octroie `domain_admin` sur le domaine.
Sans mot de passe, le compte reste `unverified` : il ne peut ni se connecter, ni
devenir propriétaire d'une liste.

### domain check-dns

    difuzio domain check-dns --domain lists.example.org [--dkim-selector default]

Vérifie SPF, `_dmarc` et, si un sélecteur est fourni, la clé DKIM publiée. Sort en
`1` tant que le domaine n'est pas prêt pour l'envoi en masse.

La console expose la même vérification par `POST /api/v1/domains/{domaine}/dns-check`
(voir [API REST](/difuzio/admin/rest-api)) : c'est le même code, donc les deux
donnent toujours le même verdict. La commande ne touche pas la base ; l'appel API,
lui, enregistre le résultat sur le domaine (`dns_ok`, `dns_checked_at`).

### domain mta-config

    difuzio domain mta-config --domain lists.example.org [--socket /run/difuzio/lmtp.sock]

Imprime les lignes Postfix qui routent le domaine vers difuzio.

## Groupe list

### list create

    difuzio list create --domain lists.example.org --name announce \
        (--owner proprio@example.org | --owner-id 12) \
        [--display-name "..."] [--description "..."] [--type discussion|newsletter]

Crée une liste et octroie `list_owner` au propriétaire, qui doit être un compte
actif existant. Exactement une des deux désignations de propriétaire est requise :
en préférer une silencieusement confierait la liste à quelqu'un d'autre que celui
qui a été nommé.

### list ls

    difuzio list ls [--domain lists.example.org]

Tableau des listes : id, nom, domaine, type, statut, suspension d'envoi
éventuelle avec sa raison. Voir [Listes](/difuzio/admin/listes).

### list show

    difuzio list show --domain lists.example.org --list announce

Affiche une liste en détail : identité, état d'envoi, et les 27 réglages avec leur
valeur courante.

### list set

    difuzio list set --domain lists.example.org --list announce [<réglages>]

Met à jour les réglages fournis ; ceux qui ne sont pas passés restent inchangés.
Une chaîne vide efface un réglage textuel (`--subject-tag ""`), et `0` rétablit
"conserver indéfiniment" pour `--archive-retention-days`.

`--subject-tag`, `--relay-pool` et `--consent-text-ver` finissent tels quels dans
un en-tête de message : un saut de ligne y est refusé, comme un dépassement de la
longueur de colonne (64, 64 et 32 caractères).

Réglages disponibles :

    --post-policy open|members|moderated|owner
    --subscribe-policy open|confirm|moderated|closed
    --archive-access public|members|owners
    --who-can-see-members public|members|owners
    --reply-to sender|list|both
    --from-munging auto|always|never
    --attachment-policy allow|strip|reject
    --subject-tag "[annonces]"        --subject-tag-enabled=true|false
    --footer-text "..."               --footer-html "..."
    --footer-enabled=true|false       --echo-to-author=true|false
    --max-message-size 10485760       --relay-pool bulk
    --reject-empty-body=true|false    --require-dkim-or-spf=true|false
    --verp-enabled=true|false         --moderation-ttl-hours 168
    --moderate-first-post=true|false  --welcome-text "..."
    --goodbye-text "..."              --privacy-notice "..."
    --consent-text-ver v3             --archive-retention-days 365
    --require-tls-in=true|false       --anonymize-sender=true|false

Voir [Listes](/difuzio/admin/listes).

### list set-policy

    difuzio list set-policy --domain lists.example.org --list announce \
        [--post-policy ...] [--subscribe-policy ...] [--archive-access ...] \
        [--reply-to ...] [--from-munging ...]

Raccourci historique sur les cinq politiques principales. `list set` couvre tous
les réglages.

### list set-status

    difuzio list set-status --domain lists.example.org --list announce \
        --status active|closed|suspended

Change le cycle de vie de la liste. Une liste non active refuse la réception, les
posts et les envois en masse : c'est la suppression douce du produit. À ne pas
confondre avec le kill-switch d'envoi ci-dessous, qui laisse la liste recevoir.

### list suspend / list resume

    difuzio list suspend --domain lists.example.org --list announce [--note "..."]
    difuzio list resume  --domain lists.example.org --list announce

Suspend ou réactive l'émission d'une liste (kill-switch). Voir
[Modération](/difuzio/admin/moderation).

## Groupe member

### member add

    difuzio member add --domain lists.example.org --list announce --email abonne@example.org \
        [--name "..."] [--mode regular|nomail|digest] [--channel web|email|api] \
        [--force --consent-evidence "bulletin papier du 2026-08-10"] \
        [--consent-source web_form|email_confirm|admin_import|api] \
        [--show-confirm-token <fichier>|-]

Abonne une adresse. Le résultat dépend de la politique d'abonnement de la liste :
activation immédiate (`open`), confirmation par mail (`confirm`, le défaut),
attente de modération (`moderated`), ou refus (`closed`).

`--force` crée l'abonnement actif quelle que soit la politique : c'est le chemin
d'import administratif, et il exige `--consent-evidence`, la preuve de
consentement conservée au dossier RGPD. `--show-confirm-token` écrit le jeton de
confirmation dans un fichier créé en mode 0600 (la commande refuse d'écraser un
fichier existant), ou sur la sortie standard avec `-` ; il n'est jamais affiché
sans avoir été demandé.

Quand l'abonnement n'est pas activé immédiatement (politiques `confirm` et
`moderated`), `--mode` et `--name` ne sont pas conservés pendant l'attente : la
demande en instance ne porte pas ces champs, et la confirmation active l'abonné
en `regular` sans nom. La commande le signale. Pour poser un mode, utiliser
`member set-mode` après confirmation, ou abonner directement avec `--force`.

### member ls

    difuzio member ls --domain lists.example.org --list announce \
        [--status pending|active|disabled|unsubscribed|removed] \
        [--mode regular|nomail|digest] [--limit 200] [--offset 0]

Tableau des abonnés : id, adresse, statut, mode, score de bounce, date
d'abonnement, suivi du nombre affiché et du total filtré.

### member rm

    difuzio member rm --domain lists.example.org --list announce --email abonne@example.org \
        [--purge --confirm]

Retire un abonné (statut `removed`, historique de bounces conservé). `--purge`
supprime la ligne définitivement et exige `--confirm`.

### member unsubscribe

    difuzio member unsubscribe --domain lists.example.org --list announce --email abonne@example.org

Enregistre que la personne a demandé à partir (statut `unsubscribed`). C'est un
acte différent de `member rm`, qui est un retrait administratif.

### member disable / enable

    difuzio member disable --domain lists.example.org --list announce --email abonne@example.org
    difuzio member enable  --domain lists.example.org --list announce --email abonne@example.org

Désactive ou réactive la livraison pour un abonné. La réactivation remet aussi le
score de bounce à zéro et repose le plancher de la fenêtre de scoring.

### member set-mode

    difuzio member set-mode --domain lists.example.org --list announce \
        --email abonne@example.org --mode regular|nomail|digest

Change le mode de livraison d'un abonné.

### member import

    difuzio member import --domain lists.example.org --list announce \
        --file abonnes.csv --consent-evidence "formulaires signés, lot 12"

Importe des abonnés depuis un CSV (`-` lit l'entrée standard). La première ligne
est un en-tête : la colonne `email` est obligatoire, `display_name` (ou `name`) et
`delivery_mode` (ou `mode`) sont facultatives, l'ordre des colonnes est libre et
les autres colonnes sont ignorées.

`--consent-evidence` est obligatoire : un import administratif affirme un
consentement que personne n'a confirmé par mail. Le compte rendu donne les lignes
traitées, ajoutées, ignorées et en erreur ; la commande sort en `1` si au moins
une ligne a échoué, les autres restant importées.

### member export

    difuzio member export --domain lists.example.org --list announce \
        [--status ...] [--mode ...] [--file abonnes.csv]

Exporte les abonnés en CSV (`-`, le défaut, écrit sur la sortie standard). Les
colonnes sont `email,display_name,delivery_mode,status,subscribed_at` : c'est
l'aller-retour exact de `member import`. Un fichier est créé en mode 0600. Chaque
export est tracé dans le journal d'audit.

## Groupe send

### send submit

    difuzio send submit --config /etc/difuzio/config.yaml \
        --domain lists.example.org --list announce \
        --from redaction@lists.example.org [--from-name "La rédaction"] \
        --subject "Numéro 1" (--text-file corps.txt | --html-file corps.html | --raw-file message.eml)

Soumet un message à une liste : il suit exactement le même pipeline qu'un post
reçu en LMTP. `--raw-file` porte un message RFC 5322 complet et exclut alors
`--subject`, `--text-file` et `--html-file`. Un seul de ces fichiers peut valoir
`-` (entrée standard). `--config` est obligatoire : le corps est écrit via le
backend de stockage configuré.

Le message est mis en file ; rien ne part tant qu'un worker ne l'a pas traité. La
commande imprime l'identifiant d'envoi et le nombre estimé de destinataires, et
prévient si l'émission de la liste est suspendue.

### send ls

    difuzio send ls --domain lists.example.org --list announce [--limit 50]

Envois récents de la liste : id, date, expéditeur, distribué ou non, copies
encore en file, sujet. C'est ainsi qu'on retrouve un identifiant d'envoi égaré.
La colonne KEPT ne compte que les copies encore présentes dans la file : les
copies remises sont purgées après leur fenêtre de rétention, donc un envoi ancien
et entièrement distribué affiche légitimement 0.

### send status

    difuzio send status --domain lists.example.org --list announce --id 42

Compte des copies par état, dans l'ordre du cycle de vie et zéros compris.

### send cancel

    difuzio send cancel --domain lists.example.org --list announce --id 42

Annule les copies encore en `queued`. Les copies déjà réclamées par un worker
(`sending`) ou différées par le relais (`deferred`) partiront quand même : pour
tout arrêter, suspendre d'abord la liste avec `list suspend`.

## Groupe moderation

    difuzio moderation ls      --domain lists.example.org --list announce
    difuzio moderation approve --domain lists.example.org --list announce --id <id> [--note "..."]
    difuzio moderation reject  --domain lists.example.org --list announce --id <id> [--note "..."]

Liste, approuve ou rejette les éléments retenus (posts et abonnements).
`moderation list` reste accepté comme synonyme de `moderation ls`. Voir
[Modération](/difuzio/admin/moderation).

## Groupe credential

Comptes de messagerie du fournisseur attachés à une liste (profil boîte externe,
voir [Listes](/difuzio/admin/listes)). La saisie se fait dans la console : un mot
de passe passé en argument finirait dans l'historique du shell. Ces commandes
servent au diagnostic et à la reprise d'une configuration existante.

### credential ls

    difuzio credential ls --domain lists.example.org --list membres

Comptes enregistrés pour la liste : type, serveur, identifiant, activation, état.
L'état distingue "jamais testé", "ok" avec la date du dernier succès, "failing"
avec le message de l'hébergeur, et "unreadable" quand la clé de chiffrement qui
protégeait le mot de passe n'est plus disponible. Le mot de passe n'est jamais
affiché.

### credential test

    difuzio credential test --domain lists.example.org --list membres \
        --kind ingest --config /etc/difuzio/config.yaml

Ouvre une vraie session avec le compte enregistré : connexion, TLS,
authentification, et ouverture du dossier pour l'IMAP. Aucun message n'est envoyé
ni relevé. `--kind` vaut `ingest` (boîte IMAP) ou `submission` (compte SMTP).
`--config` est requis : le mot de passe est déchiffré avec le keyring. Le
résultat est enregistré sur la liste, donc visible ensuite dans la console.

### credential rm

    difuzio credential rm --domain lists.example.org --list membres --kind ingest

Supprime un compte enregistré. `--kind` vaut `ingest` (boîte IMAP) ou
`submission` (compte SMTP). C'est la seule écriture disponible en ligne de
commande : ajouter un compte demande un mot de passe, qui n'a rien à faire dans
l'historique du shell, mais le retirer n'expose aucun secret.

Cette commande reste utilisable quand `policy.external_mailboxes` vaut `deny`.
C'est même la sortie prévue dans ce cas : sous cette politique, `serve-web` et
`worker` refusent de démarrer tant qu'un compte subsiste, en nommant les listes
concernées (voir [Configuration](/difuzio/admin/configuration), section
`policy`).

### credential import

    difuzio credential import --config /etc/difuzio/config.yaml
    difuzio credential import --config /etc/difuzio/config.yaml --apply

Verse les entrées `relay.auths` et `ingest.mailboxes` du fichier de configuration
dans la base, pour passer à des comptes gérés depuis la console sans ressaisir un
seul mot de passe. Sans `--apply`, la commande affiche ce qu'elle ferait et
n'écrit rien. Une liste qui a déjà un compte du même type est laissée telle
quelle, sauf `--overwrite`. Le keyring `security.credential_keyring` est requis.

Une fois l'import fait et vérifié, retirer `relay.auths` et `ingest.mailboxes` du
fichier : la base prime, et une entrée YAML devenue inutile n'apparaît plus que
dans un avertissement du journal. `relay.auth` (identité de repli du robot) reste
nécessaire.

## Groupe webhook

### webhook create

    difuzio webhook create [--domain lists.example.org [--list announce]] \
        --url https://exemple.org/hook --events member.added,member.removed

Enregistre un point de terminaison. `--events all` souscrit aux dix événements :
`member.added`, `member.removed`, `member.bounced`, `subscription.pending`,
`subscription.confirmed`, `send.submitted`, `send.completed`, `send.failed`,
`message.held`, `list.suspended`.

L'URL doit être en HTTPS et se résoudre vers une adresse publique : une cible en
loopback, en RFC1918 ou sur une adresse de métadonnées est refusée. Le secret de
signature n'est affiché qu'une seule fois, à la création.

### webhook ls

    difuzio webhook ls

Webhooks visibles : id, portée, actif, URL, événements. Le secret n'est jamais
réaffiché.

### webhook rm

    difuzio webhook rm --id 3

Supprime un webhook.

### webhook test

    difuzio webhook test --id 3

Met en file un ping signé. La requête est émise par un worker en fonctionnement,
et son résultat apparaît dans le journal du worker (`component=webhook`).

## Groupe user

### user create

    difuzio user create --email u@example.org [--display-name "..."] [--locale fr_FR] \
        [--password-stdin]

Crée un compte, sans aucun rôle. Sans mot de passe, le compte reste `unverified`
et ne peut pas être propriétaire d'une liste.

### user ls

    difuzio user ls [--email fragment] [--status unverified|active|disabled] \
        [--limit 200] [--offset 0]

`--offset` exige un `--limit` non nul (SQL n'a pas d'OFFSET seul). Comptes visibles : id, adresse, statut, super_admin, mot de passe posé ou non,
dernière connexion.

### user disable

    difuzio user disable --email u@example.org [--enable]

Désactive un compte, ou le réactive avec `--enable`. Le service refuse de laisser
un domaine sans administrateur.

### user set-password

    difuzio user set-password --email u@example.org --password-stdin

Pose un nouveau mot de passe (haché en argon2id) pour un compte existant.

### user roles

    difuzio user roles --email u@example.org

Rôles détenus par le compte, avec le domaine et la liste concernés.

## Groupe role

    difuzio role grant  --email u@example.org --role moderator --domain lists.example.org --list announce
    difuzio role revoke --email u@example.org --role moderator --domain lists.example.org --list announce

Octroie ou révoque un rôle (`super_admin`, `domain_admin`, `list_owner`,
`moderator`). `--domain` et `--list` selon la portée du rôle. Voir
[Utilisateurs et rôles](/difuzio/admin/utilisateurs-roles).

## Groupe apikey

### apikey create

    difuzio apikey create --email u@example.org --scope user|domain|list \
        [--domain ...] [--list ...] --perms read,members:write,send,moderate,manage [--name ...]

Frappe une clé d'API ; le secret n'est affiché qu'une fois. Voir
[API REST](/difuzio/admin/rest-api).

### apikey ls

    difuzio apikey ls [--all]

Clés administrables : id, propriétaire, nom, portée, permissions, état. Les clés
révoquées ne sont affichées qu'avec `--all`. Le secret n'est jamais réaffiché.

### apikey revoke

    difuzio apikey revoke --id 7

Révoque une clé. L'opération est idempotente : une clé déjà révoquée est signalée
comme telle, sans erreur.

## Groupe audit

    difuzio audit ls [--domain lists.example.org [--list announce]] \
        [--action member.export] [--result ok|denied|error] [--actor "difuzio erase"] \
        [--since 2026-08-01] [--until 2026-09-01] [--limit 100] [--offset 0] [--detail]

Lit le journal d'audit, du plus récent au plus ancien. `--since` et `--until`
acceptent une date `2006-01-02` ou un horodatage RFC3339, en UTC. `--detail`
imprime la charge JSON de chaque entrée.

## erase

    difuzio erase --email personne@example.org --confirm --config /etc/difuzio/config.yaml

Effacement RGPD d'une personne sur toutes les tables. `--confirm` est obligatoire.
`--config` l'est aussi, et `--dsn` seul est refusé : le corps des messages vit hors
de la base (`storage.blob_dir`) et seul le fichier de configuration en donne le
chemin. Sans lui, l'effacement viderait les lignes en laissant les corps sur
disque, en annonçant un succès. Le compte rendu indique le nombre d'objets déliés.
Voir [RGPD](/difuzio/admin/rgpd).

## Anciennes orthographes

Les commandes plates d'avant le passage aux groupes restent acceptées et font
exactement la même chose que leur forme groupée : les scripts existants n'ont pas
besoin d'être réécrits.

| Ancienne forme      | Forme groupée       |
|---------------------|---------------------|
| `add-domain`        | `domain add`        |
| `set-domain-status` | `domain set-status` |
| `add-admin`         | `domain add-admin`  |
| `check-dns`         | `domain check-dns`  |
| `mta-config`        | `domain mta-config` |
| `create-list`       | `list create`       |
| `lists`             | `list ls`           |
| `set-policy`        | `list set-policy`   |
| `list-suspend`      | `list suspend`      |
| `list-resume`       | `list resume`       |
| `set-delivery-mode` | `member set-mode`   |
| `reset-password`    | `user set-password` |
| `grant-role`        | `role grant`        |
| `revoke-role`       | `role revoke`       |
| `create-api-key`    | `apikey create`     |
