CLI
@agreely/cli est la barrière de consentement sous forme d'outil en ligne de
commande. Un seul binaire, deux modes :
- Les humains obtiennent une sortie en couleur et un assistant interactif (à un TTY).
- Les agents obtiennent du JSON pur sur stdout et des codes de sortie stables
(un tube ou
--json).
C'est une fine coquille par-dessus @agreely/sdk : elle ne
réimplémente jamais la logique HTTP, de décision ou de normalisation. Elle résout
l'authentification, choisit un mode, appelle le SDK, et traduit le résultat en
code de sortie.
Paquet @agreely/cli 0.5.1 (la version publiée que décrit cette page), binaire
agreely, ESM, Node >=18, licence MIT. Il dépend de @agreely/sdk ^0.6.1 et
partage donc les limites du SDK 0.6.1 :
voir Ce que 0.5.1 ne couvre pas.
Installer
npm install -g @agreely/cli
agreely --help
agreely --version # -> 0.5.1
Agent-native : une variable d'environnement + --json
export AGREELY_API_KEY=agr_live_xxx # le seul réglage dont un agent a besoin
agreely check cust-42 "Email Address" "Marketing Outreach" --json
# -> {"decision":"allow","status":"active","consentRef":"0x…","assurance":"citizen_signed","tier":"full"} exit 0
Définissez la clé une fois via AGREELY_API_KEY (aucune invite, aucun
trousseau requis), passez --json (ou redirigez simplement par un tube : un stdout
qui n'est pas un TTY déclenche automatiquement le mode agent), et branchez sur le
code de sortie. category / purpose sont envoyés bruts; le serveur les
apparie.
Drapeaux globaux
Acceptés avant ou après la sous-commande :
--json: force le mode agent (JSON pur sur stdout).--api-key <key>: déconseillé, visible dansps.--base-url <url>: remplace l'URL de base de l'API.-v,--version: affiche la version.
Variables d'environnement
AGREELY_API_KEY: le chemin d'authentification agent.AGREELY_BASE_URL: l'URL de base de l'API.AGREELY_RPC_URL: l'URL RPC deverify --onchain.XDG_CONFIG_HOME: relocalise le dossier de configuration.
Le tableau des codes de sortie (le contrat agent)
Le code de sortie est le contrat. Il sépare proprement une panne d'un refus et une vérification échouée d'une panne, ce qui est tout l'intérêt d'une barrière de consentement agent-native.
| code | signification |
|---|---|
0 |
succès, une vérification ALLOW, ou un verify qui rend verified (un dossier ou un reçu sur papier) ou partial (un reçu téléphonique); avec --onchain, seulement quand la chaîne lit aussi le consentement en vigueur (withdrawal: "active"). Jamais pour un reçu par clé d'accès seul |
1 |
un échec inattendu / non catégorisé |
2 |
usage ou validation : arguments mauvais ou manquants, entrée invalide (un 422, un 413), aucun identifiant, une erreur de configuration, un 404, ou un 409 de conflit d'état |
3 |
authentification : la clé est absente, invalide, révoquée ou dépourvue de la portée requise |
4 |
indisponible : une panne d'Agreely ou une expiration (distincte d'un refus), un request wait à court de temps, ou un verify dont un contrôle n'a pu aboutir : un DID irrésolvable, un contrôle demandé avec --onchain ou --ipfs, ou un retrait que --onchain n'a pu lire (un reçu sur papier ou par téléphone, ou un dossier qui ne nomme pas chaque consentement accepté) |
5 |
limite de débit : la fenêtre par entreprise et par minute a été dépassée (réessayez après le délai) |
6 |
vérification échouée : un dossier ou un reçu a été vérifié et n'a pas été validé, ou le fichier est malformé (aucun contrôle n'a eu lieu). Un verdict, pas une erreur; un fichier qui n'est pas du JSON sort en 2 |
7 |
facturation inactive : l'abonnement Agreely de l'entreprise est échu (HTTP 402, code d'enveloppe billing_inactive). Un refus par défaut comme un DENY, mais actionnable et distinct d'une panne |
8 |
plafond quotidien (HTTP 429 withdrawal_daily_cap, verbal_daily_cap, hold_budget_exhausted, hold_release_cap_reached). Pas une fenêtre de débit : réessayer aujourd'hui ne peut pas réussir, ne bouclez donc pas dessus |
9 |
l'écriture a réussi mais sa sortie n'a pu être enregistrée (consent-sheet create : la feuille a été émise, le fichier n'a pu être écrit). La référence et le lien de réclamation ont tout de même été imprimés. Ne réessayez pas |
10 |
une vérification DENY propre, un négatif attendu, pas une erreur |
11 |
verify : incomplet, un reçu par clé d'accès seul ne peut pas être relié à l'offre à laquelle il répond. Vérifiez plutôt son dossier de vérification. Ni une falsification, ni un succès |
12 |
verify --onchain : retiré. Le reçu est authentique, mais la chaîne consigne le retrait du consentement, pour toutes ses finalités ou certaines (consentAnchorRecords dit lesquelles, avec revokedAt). Ni une falsification, ni un succès |
check résout ALLOW vers 0 et DENY vers 10. La CLI fonctionne en refus par
défaut : lors d'une panne, le SDK lève une exception et la CLI sort avec 4, de
sorte qu'un appelant peut toujours distinguer « panne » de « refusé ». Le JSON d'un
DENY va tout de même sur stdout; une véritable erreur garde stdout propre et écrit
une enveloppe sur stderr :
{"error":{"code":"invalid_request","message":"…","reason":"other_consents_running","field":"otherConsents"}}
reason et field apparaissent quand le serveur les a envoyés. Branchez sur
code et reason, jamais sur message. Un 409 garde son code précis
(identity_held, already_released, already_minted, citizen_consent_at_gate,
...). Sans code, il retomberait sur retry, ce qui n'arrive pas aujourd'hui puisque l'API en envoie toujours un. Une erreur d'usage côté CLI porte le code usage.
Modes (détectés automatiquement)
| condition | mode | comportement |
|---|---|---|
stdout est un TTY et pas de --json |
humain | couleurs, l'assistant, confirmations |
stdout n'est pas un TTY, ou --json |
agent | jamais d'invite, JSON pur sur stdout, journaux/erreurs sur stderr |
En mode agent, stdout ne transporte que du JSON pur et rien d'autre; chaque
journal, indice ou erreur va sur stderr. En mode humain, la sortie est colorée avec
assistants et confirmations. picocolors désactive automatiquement la couleur hors
TTY. Un argument requis manquant en mode agent est une erreur claire assortie d'une
sortie d'usage (2); il ne reste jamais bloqué à attendre une invite.
Commandes
agreely check <customerId> <category> <purpose>
agreely check --batch <file.json>
agreely catalog [--document <code>]
agreely whoami
agreely requests list [--customer <ref>] [--status <s>] [--limit <n>] [--cursor <id>]
agreely request create [--customer <id> --to <email> (--document <versionId> | --document-code <code>) --valid-until <YYYY-MM-DD>] [--idempotency-key <k>]
agreely request show <requestId>
agreely request cancel <requestId>
agreely request wait <requestId> [--interval <ms>] [--timeout <ms>]
agreely documents list | show <code> | pdf <documentVersionId> --out <file.pdf> [--locale fr|en] [--force]
agreely manual-consent create --customer <id> --document-version <id> --effective-date <YYYY-MM-DD> --valid-until <YYYY-MM-DD> [--item <item>]... --pdf <path> [--upload] [--sensitive-express-attested] [--version-attested] [--idempotency-key <k>]
agreely manual-consent claim-link --customer <id> [--reference <ref>]
agreely manual-consent revoke <consentRef> [--reason <text>] [--other-consents keep|withdraw]
agreely manual-consent erase <consentRef> [--reason <text>] [--other-consents keep|withdraw]
agreely consent-sheet create <customerRef> --document-version <id> --out <file.pdf> [--locale fr|en] [--idempotency-key <k>] [--force]
agreely verbal-consent record | show <consentId> | paper <consentId> ...
agreely withdraw <customerRef> <consentRef> --channel <c> --operator <id> [--requested-at <instant>] [--reason <text>] [--other-consents withdraw|keep | --also-withdraw <ref,...>] [--idempotency-key <k>]
agreely customer get <customerRef>
agreely customer set <customerRef> [--display-name <n>] [--email <e>] [--notice-locale fr|en]
agreely retention show <customerRef>
agreely retention dispose <customerRef> --disposition <kind> [--reason <text>] [--retention-until <YYYY-MM-DD>] [--schedule-ref <ref>]
agreely holds place <customerRef> --ground <g> [--provision <text>] [--rule <key>]... [--cell <id>]... [--started-on <date>] [--review-on <date>] [--idempotency-key <k>]
agreely holds release <customerRef> <holdId> --reason <text> [--idempotency-key <k>]
agreely holds list [--changed-since <cursor>] [--page-token <t>]
agreely holds sync [--changed-since <cursor>] [--max-pages <n>]
agreely relationship end <customerRef> --reason <text>
agreely relationship revert <customerRef> --reason <text>
agreely verify <file.json> [--did-doc <file>]... [--onchain --rpc-url <url>] [--ipfs]
agreely login
agreely config set [--api-key <k>] [--base-url <url>]
Chaque commande accepte aussi les drapeaux globaux. Un agreely requests ... nu
reste un alias de agreely requests list.
Écritures : délais et nouvelles tentatives
Les commandes d'écriture disposent de 15 secondes et les lectures de 5 secondes,
sauf check, qui garde les 800 ms du SDK, calibrées pour la barrière de
consentement. Ces commandes envoient une Idempotency-Key, la vôtre
(--idempotency-key) ou une que la CLI génère : request create (qui envoie un
courriel à une personne), manual-consent create, verbal-consent record et
paper, withdraw, holds place et holds release. Si l'une d'elles se termine
par une expiration ou une panne (sortie 4), ou par un 409 de code retry,
l'enveloppe d'erreur porte idempotencyKey : réessayez avec cette même clé et
le serveur rejoue la première réponse au lieu d'écrire deux fois. Une nouvelle clé
est une nouvelle écriture.
consent-sheet create fait exception : sa clé est un verrou, donc une clé répétée
est un 409 already_minted. Les autres écritures (customer set,
retention dispose, relationship end|revert,
manual-consent claim-link|revoke|erase, request cancel) n'envoient aucune clé
propre et n'en impriment aucune.
Dates, instants et category:purpose
--valid-untilestYYYY-MM-DDet signifie jusqu'à la fin de ce jour dans le fuseau horaire de votre entreprise, au plus 10 ans plus tard (un plafond de produit d'Agreely, pas un plafond prévu par la loi). Pour un consentement téléphonique, ce peut aussi être un instant RFC 3339 avec décalage. Les expressions relatives comme « +1 year » sont refusées.- Les instants (
--obtained-at,--signed-at,--requested-at) doivent porter un décalage ouZ. --itemet--answers'écriventcategory:purpose, coupés au premier deux-points, les deux côtés épurés. Une catégorie qui contient elle-même un deux-points ne peut pas s'écrire ainsi : utilisez l'id du catalogue avec--item.--outdoit être un chemin de fichier ordinaire : un PDF n'est jamais écrit sur stdout (/dev/stdoutest refusé), et un fichier existant est refusé sans--force.
La barrière de consentement
check
Décision synchrone. Sortie 0 = ALLOW, 10 = DENY, 4 = panne.
agreely check cust-42 "Email Address" "Marketing Outreach" --json
# {"decision":"allow","status":"active","consentRef":"0x…","assurance":"citizen_signed","tier":"full"} exit 0
# {"decision":"deny","status":"revoked","consentRef":"0x…","assurance":"company_attested","tier":"manual"} exit 10
# {"decision":"allow","status":"necessity","basis":"necessary_for_service"} exit 0
En mode agent, le JSON est {decision, status, consentRef?, assurance?, tier?, basis?}.
Les étiquettes sont bilingues et tolèrent les accents. category et purpose
peuvent être donnés en français ou en anglais, avec ou sans accents, et sont
appariés sans égard à la casse ni aux espaces. L'anglais ne se résout que si
l'entreprise a divulgué une étiquette anglaise pour cette cellule. Une étiquette
ambiguë ou non déclarée refuse par défaut (deny none) : passez l'étiquette telle
que déclarée au catalogue quand vous le pouvez.
Un allow n'est pas toujours un consentement. status: "necessity" signifie
qu'il n'y a aucun enregistrement de consentement : l'autorisation repose sur un
fondement autre que le consentement, déclaré par l'entreprise sur la cellule du
catalogue, et basis le nomme. Une telle décision n'a ni consentRef ni
assurance : si vous versez ce résultat dans un rapport, lisez basis, sans
quoi un allow de nécessité est indiscernable d'un allow consenti. Agreely consigne
le fondement déclaré; il ne se prononce pas sur sa validité juridique.
Lisez le niveau de preuve, pas seulement la décision. Une décision appuyée sur
un enregistrement porte assurance et tier, la même preuve sous deux noms :
citizen_signed / full (la personne a signé avec une clé d'accès),
company_attested / manual (un papier signé à la main) et
company_documented / verbal (un consentement donné par téléphone et consigné
par votre organisation, sans document signé). Un consentement téléphonique
autorise exactement comme les autres; c'est votre système qui décide de ce que
chaque niveau peut débloquer, alors traitez une assurance ou un tier que vous
ne reconnaissez pas comme non acceptable.
Une ligne d'information n'est pas un consentement. Une ligne que le document
donne à titre d'information, dont la personne a pris acte sur une feuille papier
ou lors d'un appel, répond comme s'il n'y avait aucun enregistrement (necessity
avec son basis, ou le refus habituel), sans consentRef ni assurance.
Les statuts de refus sont none, revoked, expired, erased,
relationship_ended (l'entreprise a consigné la fin de la relation, P-39.1,
art. 12 al. 1; A-2.1, art. 65.1 al. 1), requires_depersonalization et basis_not_in_regime.
Traitez tout statut inconnu comme un refus et lisez decision, qui ne vaut jamais
que allow ou deny. Les statuts sont détaillés dans la
référence de l'API.
Mode lot : --batch <file.json> lit un tableau JSON d'objets
{customerRef, category, purpose} et les envoie en une seule requête. La
sortie agent est un tableau JSON, un objet
{customerRef, category, purpose, decision, status, consentRef?, assurance?, tier?, basis?}
par cellule. La sortie est 0 quand toutes les cellules autorisent, 10 dès
qu'une refuse, 4 en cas de panne. Le serveur plafonne un lot à
500 cellules : un fichier plus grand est refusé avant l'envoi (sortie 2, avec
le nombre dans le message), alors découpez vous-même les gros fichiers. L'API
permet 120 requêtes par minute par entreprise (par entreprise, pas par clé), et
une exécution --batch compte pour une requête.
agreely check --batch ./cells.json --json
# [{"customerRef":"cust-42","category":"Email Address","purpose":"Marketing Outreach","decision":"allow","status":"active","consentRef":"0x…","assurance":"citizen_signed","tier":"full"}]
catalog
Liste le catalogue actif de l'entreprise : JSON {catalog: entries}. Avec
--document <code>, seulement les cellules actives d'un document publié, avec son
documentVersionId. Ne décidez jamais d'un consentement à partir du catalogue :
seul check dit à quoi une personne a consenti.
whoami
Vérifie la clé côté serveur en appelant GET /v1/whoami : la commande rapporte
les portées que le serveur accorde réellement, et non une déduction locale. Une
clé invalide sort avec 3. La commande n'imprime jamais le secret (masqué : les
8 premiers + les 4 derniers caractères). JSON :
{authenticated, apiKeyMasked, apiKeySource, baseUrl, scopes}.
Demandes de consentement et documents
requests list
Liste les demandes (métadonnées seulement), pagination par curseur. --status
accepte pending, approved, asks_declined, refused, expired ou
revoked_before_action (une valeur invalide est une erreur d'usage). --limit
vaut 50 par défaut côté serveur, au plus 100. Le JSON est la page brute
{items, nextCursor}.
request create
Chaque demande est émise sous un document de consentement publié : passez
--document <versionId> ou --document-code <code> (l'un ou l'autre, pas les
deux; trouvez-les avec agreely documents list). Les items (catégorie, fin)
demandés découlent du document côté serveur : cette commande n'a pas de drapeau
--item.
agreely request create \
--customer cust-42 --to [email protected] \
--document-code privacy-2026 \
--valid-until 2030-01-01 --idempotency-key issue-2026-001 --json
# -> l'IssuedRequest : {"requestId":"0x…","status":"pending","deepLink":"…","document":{…},…}
Réutilisez --idempotency-key pour rendre une nouvelle tentative sûre : un rejeu
renvoie la demande d'origine, sans double émission ni double courriel.
À un TTY humain sans drapeau, un assistant recueille la référence du document, le client, le courriel du destinataire et la date d'échéance, valide chacun et confirme avant d'émettre. En mode agent, ou dès qu'un drapeau scriptable est présent, chaque drapeau requis doit être fourni.
Le statut d'une demande est pending, approved, asks_declined, refused,
expired ou revoked_before_action. asks_declined signifie que la personne a
confirmé avoir reçu l'information mais a décliné toutes les demandes de
consentement : aucun consentement n'a été obtenu. Elle n'apparaît jamais sous
--status approved, et approved signifie qu'au moins une demande a été acceptée.
request show
requestId doit correspondre à ^0x[0-9a-f]{64}$. JSON : l'enregistrement brut.
request cancel
Annule une demande en attente par son requestId (portée issue). L'appel est
idempotent : une demande déjà terminale n'est pas une erreur, la sortie reste
0 avec cancelled: false. JSON : {requestId, status, cancelled}.
agreely request cancel 0x… --json
# {"requestId":"0x…","status":"revoked_before_action","cancelled":true} exit 0
request wait
Sonde jusqu'à ce que la demande ne soit plus pending (tout autre statut,
asks_declined compris). Un délai épuisé sort avec 4. --interval vaut
2000 ms par défaut, --timeout vaut 120000 ms. JSON : l'enregistrement réglé
brut.
agreely request wait 0x… --timeout 300000 --json
documents
agreely documents list --json
agreely documents show <code> --json # la divulgation publiée complète
agreely documents pdf <documentVersionId> --out ./info.pdf --locale fr
Découverte en lecture seule des documents de consentement publiés. Retenez le
code stable, pas l'id de version, qui change à chaque publication. pdf écrit le
document d'information dans un fichier; le récupérer ne consigne rien et ne prouve
pas que quiconque a été informé.
Consentements papier et téléphoniques
manual-consent
Portée attest. Consigne un consentement recueilli sur papier (un PDF signé) sous
l'attestation de votre entreprise. Le résultat porte
assurance: "company_attested" (le parcours en ligne donne citizen_signed).
agreely manual-consent create \
--customer cust-42 --document-version 4b08… \
--effective-date 2026-06-01 --valid-until 2031-01-01 \
--item "Email Address:Marketing Outreach" --item 4b082452-… \
--pdf ./signed-consent.pdf --json
# -> {"consentId":"…","merkleRoot":"0x…","consentRefs":["0x…"],"assurance":"company_attested","anchored":false,"acknowledged":[…],"asksDeclined":false}
- create :
--customer,--document-version,--effective-date,--valid-untilet--pdfsont requis.--itemnomme les demandes de consentement cochées sur la feuille (un id de catalogue oucategory:purpose); omettez-le entièrement pour une feuille qui a répondu « non » à toutes les demandes. Le serveur ajoute chaque ligne que le document donne à titre d'information comme une prise d'acte (jamais un consentement); la réponse les liste dansacknowledgedet metasksDeclinedquand aucune demande n'a été consentie. Un document qui ne demande aucun consentement (un avis de collecte) est refusé (sortie2).--valid-untilest au plus 10 ans après--effective-date.--sensitive-express-attestedet--version-attestedne sont envoyés que s'ils sont donnés. - Le PDF est haché localement (
0x+ SHA-256); seul cet engagement est envoyé. Les octets ne quittent la machine qu'avec--upload, et le serveur les vérifie alors contre le hash. Un fichier vide est refusé, tout comme un téléversement qui n'est pas un PDF. - Un
409(sortie2) signifie que la requête contredit le registre : une fin déjà couverte par un consentement actif que la personne a signé avec une clé d'accès, un consentement téléphonique pour le même client et le même document qui attend encore son papier signé, ou une relation terminée. - claim-link :
--customerrequis. JSON : leClaimLinkbrut{claimUrl, token, expiresAt}. Un client inconnu est un404, une relation terminée un409, les deux en sortie2. - revoke : retire un consentement consigné par votre organisation (papier ou
téléphone; une clé qui ne détient que
attest_verbalatteint les consentements téléphoniques). JSON :{consentRef, revoked, alreadyRevoked, gate}.gatedit ce quecheckrépond désormais pour cette fin :denied(ce consentement l'appuyait),superseded(un autre consentement avait déjà pris le relais et reste intact) ouunchanged(une répétition idempotente). - erase : efface (crypto-broyage) un consentement consigné par votre
organisation. C'est irréversible, d'où la seule portée
attest. JSON :{consentRef, erased, alreadyErased, gate}. Une conservation active le refuse (409 hold_active, sortie2).
Quand la personne a aussi signé la même fin en ligne, avec une clé d'accès, et que
ce consentement est en vigueur, revoke et erase sont refusés (409 citizen_consent_at_gate, sortie 2) : ces commandes n'y mettent jamais fin,
consignez plutôt le retrait demandé par la personne avec withdraw.
--other-consents keep ne met fin qu'à cet enregistrement et laisse ce
consentement en vigueur, et la sortie porte alors stillInForce.
--other-consents withdraw est refusé comme l'absence de déclaration.
consent-sheet
agreely consent-sheet create cust-42 --document-version 4b08… --out ./sheet-cust-42.pdf
Émet la feuille de signature d'une version publiée pour un client (portée
attest) avec une nouvelle réclamation. Le PDF est écrit dans --out (jamais
sur stdout; un fichier existant est refusé avant l'émission sans --force). La
référence imprimée et le lien de réclamation ne sont rendus qu'une fois et ne
sont stockés nulle part : rien ne peut les retrouver plus tard. Une
--idempotency-key rejouée est un 409 already_minted.
- N'envoyez jamais le lien de réclamation dans la même enveloppe que la feuille : la référence imprimée en est le second facteur.
- N'envoyez jamais le hash de la feuille vierge comme preuve d'un consentement papier : la preuve est le papier signé, une fois revenu.
verbal-consent
Un consentement que la personne a donné par téléphone, consigné par votre
organisation : le niveau le plus faible (tier: "verbal",
assurance: "company_documented"). L'enregistrement exige la portée
attest_verbal, le papier exige attest, show accepte l'une ou l'autre.
agreely verbal-consent record --customer cust-42 --document-version 4b08… \
--answer "Email Address:Marketing Outreach=yes" --answer "Phone:Surveys=no" \
--obtained-at 2026-10-09T10:15:00-04:00 --obtained-by agent-7 --script-version v3 \
--consented-by self --valid-until 2027-10-09 --paper-expected --json
# -> {"consentId":"…","tier":"verbal","assurance":"company_documented","consentRefs":["0x…"],"acknowledged":[…],"asksDeclined":false,…}
agreely verbal-consent show <consentId> --json # ce qui a été dit, ce que le papier a dit, ce qui est en vigueur
agreely verbal-consent paper <consentId> --signed-at 2026-10-12T09:00:00-04:00 \
--answer "Email Address:Marketing Outreach=yes" --pdf ./signed.pdf --json
- Chaque
--answerest leyesou lenoexplicite de la personne, sous la formecategory:purpose=yes|no. --obtained-atdate d'au plus 7 jours et n'est jamais dans le futur.--consented-byvautself,self_with_assistantourepresentative. Un représentant exige--capacity(tutelle,mandat_protection_homologue,representation_temporaire,curatelle,titulaire_autorite_parentale,tuteur_mineur,otherouundeclared).- Pour un mineur de moins de 14 ans, passez
--minor,--consented-by representative, une--capacitytitulaire_autorite_parentaleoututeur_mineur, et le nom du représentant dans--respondent-name. --sensitive-express-attestedest requis quand un « oui » couvre une fin sensible qui repose sur le consentement.paperconsigne le papier signé qui confirme l'appel; son PDF est haché localement exactement comme pourmanual-consent create.- Retirez un consentement téléphonique avec
manual-consent revokeouwithdraw. Le plafond quotidien des consentements téléphoniques sort avec8.
withdraw
Consigne le retrait que la personne a demandé, en son nom (portée withdraw,
jamais sur une clé par défaut). --channel vaut phone, email, mail,
in_person ou other; --operator est votre identifiant opaque du membre du
personnel, jamais un courriel. --requested-at est le moment où la personne l'a
demandé; --reason compte au plus 1 000 caractères.
agreely withdraw cust-42 0x… --channel phone --operator agent-7 --reason "demandé par téléphone" --other-consents keep --json
# -> {"consentRef":"0x…","withdrawn":true,"alreadyWithdrawn":false,"recordedOnBehalf":true,"assurance":"company_documented","gate":"denied","alsoWithdrawn":[],"stillInForce":["0x…"]}
Le JSON est la réponse du serveur telle que reçue : assurance vaut
company_documented, quel que soit le niveau du consentement. Lisez gate avant
de dire à quiconque que l'utilisation a cessé. Le retrait est accepté après la fin
de la relation et pendant une suspension de facturation. Le plafond quotidien
(50 par période glissante de 24 heures) sort avec 8 : consignez les retraits
suivants depuis la page du client dans Agreely.
Quand un autre consentement de la même fin est en vigueur pour ce client, le
retrait dit ce qu'il en advient : --other-consents withdraw les retire tous,
--other-consents keep les laisse en vigueur, et --also-withdraw <ref,...> nomme
ceux à retirer (des consentRef séparées par des virgules, au plus 50, répétable).
Donnez l'un des deux drapeaux, jamais les deux : les deux ensemble, une portée
inconnue, une référence qui n'est pas une consentRef ou plus de 50 références
sortent en 2 avant tout appel. Sans l'un ni l'autre, la commande sort avec 2,
le code invalid_request et la raison other_consents_running, rien n'est écrit,
et l'enveloppe d'erreur liste ces consentements dans otherConsentRefs : demandez à
la personne, puis réessayez avec une portée. alsoWithdrawn liste les
consentements retirés avec celui-ci, stillInForce ceux encore en vigueur.
Clients, conservation et mises en conservation
customer
Portée registry.
agreely customer get cust-42 --json # métadonnées seulement : des booléens, jamais le nom ni le courriel
agreely customer set cust-42 --display-name "Ada Lovelace" --email [email protected] --notice-locale fr
agreely customer set cust-42 --email "" # une fusion : un drapeau absent reste intact, une valeur vide l'efface
409 identity_held ou identity_erased signifie que l'identité ne peut pas être
modifiée maintenant.
customer set ne prend ni --legal-basis ni --basis-note : le registre ne
consigne pas de raison de détenir un client (le fondement est documenté par cellule
du catalogue), et un drapeau inconnu sort en 2.
retention et holds
agreely retention show cust-42 --json
agreely retention dispose cust-42 --disposition legal_hold --reason "Loi X, art. 12" --retention-until 2031-01-01
agreely holds place cust-42 --ground other_law --provision "Loi X, art. 12" --rule <ruleKey> --cell <catalogId>
agreely holds place cust-42 --ground rights_request # sans --rule/--cell : couvre tout
agreely holds release cust-42 <holdId> --reason "demande close"
agreely holds list [--changed-since <cursor>] [--page-token <t>] # UNE page
agreely holds sync [--changed-since <cursor>] [--max-pages <n>] # TOUTES les pages (borne par défaut 1000)
retentionutilise la portéeregistry.--dispositionvautdestroyed,anonymizedoulegal_hold;legal_holdexige--reason(la loi qui impose le délai).disposeexige que la relation soit terminée (409 relationship_active); le résultat dit ce qu'il est advenu de la copie de l'identité chez Agreely (agreelyIdentity) et avertit parhold_activequand une mise en conservation tient.- Une mise en conservation
other_lawexige--provision; unerights_requestla refuse.--started-onvaut aujourd'hui par défaut;--review-onn'est qu'un rappel. holds listetholds syncexigent la portéeholds. Le flux se pagine avecpageToken/nextPageToken, et seule la dernière page portecursor.holds syncparcourt toutes les pages et imprime le curseur à garder (en--json:{"mode","holds","cursor"}) : conservez-le et passez-le comme prochain--changed-since. Sans--changed-since, le résultat est un instantané de toutes les mises en conservation actives (remplacez tout votre ensemble); avec, un delta (mise à jour parid). La livraison est au moins une fois. Atteindre--max-pageséchoue plutôt que d'imprimer un flux partiel.
Relation
relationship end
Portée relationship. Consigne qu'une relation client est terminée, au sens de
l'article 23 de P-39.1 (article 73 de A-2.1 pour un organisme public) : « les fins
[...] sont accomplies ». <customerRef> est votre propre référence client (la même
que pour check), rattachée à l'entreprise de la clé. --reason est requis et
vérifié avant tout appel réseau : un motif absent ou vide sort avec 2, jamais
une fin silencieuse. L'appel est idempotent (re-finir une relation déjà
terminée est un succès; endedAt et endedBy d'origine sont préservés). C'est une
surcouche de cycle de vie : elle ne révoque ni n'efface aucun consentement. JSON :
la réponse du serveur.
agreely relationship end cust-42 --reason "Compte fermé, fins accomplies" --json
# {"customerRef":"cust-42","status":"ended","endedAt":"…","endedRecordedAt":"…","endedBy":"company"} exit 0
La CLI 0.5.1 date toujours la fin par l'appel : l'endedAt passé facultatif de
l'API, pour un système qui déclare la fin en retard, n'a pas de drapeau en 0.5.1.
relationship revert
Portée relationship. Annule une fin de relation prématurée ou erronée : une
correction d'une inscription inexacte (P-39.1, art. 11; A-2.1, art. 72), jamais une
résurrection d'un consentement mort. --reason est requis.
L'annulation n'est admissible que si la fin a été consignée par l'entreprise, que
rien n'a été détruit, et qu'on est dans la fenêtre de 30 jours (une règle
de produit d'Agreely, pas un délai prévu par la loi). Une relation non admissible
sort avec 2 (un 404 propre côté serveur, sans rien écrire) : une personne qui
revient est une nouvelle relation, qui exige une nouvelle demande de consentement.
JSON : {customerRef, status, reverted}.
agreely relationship revert cust-42 --reason "Fin enregistrée par erreur" --json
# {"customerRef":"cust-42","status":"active","reverted":true} exit 0
verify
Vérification hors ligne d'abord d'un dossier de vérification (le reçu, l'offre
signée et la racine de Merkle qu'émet un consentement par clé d'accès) ou d'un reçu
sur papier ou par téléphone. Une fine enveloppe autour de la méthode statique
Agreely.verifyReceipt du SDK 0.6.1, qui expose les mêmes statuts : elle ne
redérive pas les verdicts. Elle n'exige aucune clé d'API.
agreely verify ./agreely-verification-bundle.json --did-doc ./issuer.did.json --did-doc ./citizen.did.json
agreely verify ./agreely-verification-bundle.json --onchain --rpc-url https://base-rpc.publicnode.com --json
En mode humain, verify imprime le verdict global (VERIFIED, PARTIAL,
INCOMPLETE, UNAVAILABLE, WITHDRAWN, MALFORMED ou FAILED) avec le type de
reçu, puis une ligne par contrôle (companySignature, receiptIntegrity,
citizenAssertion, disclosureCopy, documentAnchor, consentAnchor,
cellLabelBinding), la ligne withdrawal, et les notes. La ligne
cellLabelBinding est celle à lire avant de faire confiance à une étiquette
affichée. En mode agent, elle émet le ReceiptVerification brut, avec withdrawal
et, quand la chaîne le consigne, withdrawnAt.
| global | sortie | signification |
|---|---|---|
verified |
0 |
les contrôles énumérés tiennent, sur un dossier ou un reçu sur papier; ce n'est pas une preuve juridique. Avec --onchain, 0 seulement quand la chaîne lit aussi le consentement en vigueur, sinon 4 |
partial |
0 |
un reçu téléphonique dont la signature de l'entreprise se vérifie : la parole de l'organisation. partial ne montre pas à lui seul que cette personne a consenti; app.agreely.ca/verify lit en plus, avec son dossier de vérification, si un reçu de version 4 est encore en vigueur. Avec --onchain, 4 |
incomplete |
11 |
un reçu par clé d'accès seul : vérifiez son dossier de vérification. Ni une falsification, ni un succès |
withdrawn |
12 |
avec --onchain : le reçu est authentique et la chaîne consigne le retrait du consentement, pour toutes ses finalités ou certaines (consentAnchorRecords dit lesquelles). Il n'est plus en vigueur; ce n'est pas une contrefaçon |
unavailable |
4 |
un contrôle n'a pu aboutir (un DID irrésolvable, un sujet qui n'est pas did:agreely:citizen:, un registre inconnu) : peu concluant, pas une contrefaçon |
malformed |
6 |
un fichier que le vérificateur ne peut pas lire : aucun contrôle n'a eu lieu, ce verdict ne dit rien d'une altération. Un fichier qui n'est pas du JSON sort en 2 |
failed |
6 |
un contrôle a activement échoué : une altération, une mauvaise clé, ou un document DID qui ne confirme pas la clé (voir plus bas) |
Drapeaux :
--did-doc <file>(répétable) : installe un résolveur de document DID local, rendant la résolution DID hors réseau. Un DID inconnu se résout alors versunavailable(sortie4) plutôt que d'atteindre le réseau. Un document--did-docest cru tel que fourni : qui le fournit fournit la clé. Prenez-le chez l'émetteur et au palier citoyen, jamais dans le fichier vérifié; lesdidDocumentsdu dossier ne sont jamais crus. Sans--did-doc, les contrôles de signature et d'assertion effectuent une résolution DID par HTTPS.--ipfs: active le contrôledisclosureCopy(récupère la copie IPFS et la compare àdisclosureHash); autrementskipped.--onchain: lit aussi les ancrages du document et du consentement, et le retrait, et exige une URL RPC via--rpc-urlouAGREELY_RPC_URL(sinon erreur d'usage). Il ne lit que le registre de Base, le réseau principal. Un dossier dont la délégation de la clé de l'émetteur nomme un autre registre ou une autre chaîne (un dossier ancré sur Base Sepolia, par exemple) est refusé avant tout appel quand un contrôle lirait la chaîne : ces contrôles rendentunavailable, une note ditunknown registry, et la sortie est4. Ce n'est pas une contrefaçon, et réessayer n'y change rien.
Un contrôle demandé avec --onchain ou --ipfs qui n'a pu aboutir sort en 4,
jamais en 0 ni en 6.
Le retrait
Le verdict dit si le reçu est authentique; withdrawal dit si le consentement est
encore en vigueur : active, withdrawn (sortie 12) ou not_checked. Sans
--onchain, il vaut toujours not_checked, et un consentement vérifié sort en 0
avec la ligne WITHDRAWAL NOT CHECKED : un consentement retiré, vérifié hors
ligne, rend encore verified. Pour n'accepter un consentement que tant qu'il est
en vigueur, vérifiez son dossier avec --onchain et n'acceptez que la sortie 0.
Ce vérificateur lit l'enregistrement sur la chaîne d'un dossier par clé d'accès
seulement : sous --onchain, un reçu sur papier ou par téléphone sort en 4.
Le détail de chaque contrôle se trouve dans Vérifier un ConsentReceipt.
Sortie 4 (indisponible) contre sortie 6 (échec)
C'est le cœur honnête du vérificateur. Un contrôle qui n'a pas pu aboutir (un DID irrésoluble, un RPC ou une passerelle en échec, un registre inconnu) sort en 4 (indisponible), pas en 6. La sortie 6 est réservée à un échec actif (une altération, une mauvaise clé, une chaîne qui contredit le fichier) et au fichier malformé. Un reçu valide, durant une panne, ne doit jamais ressembler à une contrefaçon.
Les clés viennent des documents DID que lit le vérificateur. Un --did-doc
citoyen sans authentication ni validFrom, ou un document d'émetteur qui ne
liste pas la clé sous assertionMethod, fait sortir un reçu authentique en 6. Un
failed seul n'est donc pas une preuve de falsification : lisez le contrôle qui a
échoué et les notes, vérifiez les documents --did-doc fournis, ou vérifiez le
reçu à app.agreely.ca/verify avec son dossier de
vérification.
Identifiants
login
Interactif uniquement. En mode agent, login échoue et vous renvoie vers
config set ou AGREELY_API_KEY. Il demande la clé et une URL de base optionnelle,
vérifie la clé contre l'API en direct avant de la persister (il ne stocke jamais
une clé qui ne fonctionne pas), puis la range dans le trousseau du système
d'exploitation, avec repli vers le fichier de configuration 0600.
config set
Non interactif : il ne demande jamais rien et ne vérifie rien. Il exige au moins un
drapeau parmi --api-key et --base-url, et stocke les identifiants.
agreely config set --api-key agr_live_xxx --base-url https://api.agreely.ca
Préséance d'authentification
La CLI ne demande jamais de clé en dehors de login. Ordre de résolution :
--api-key flag (déconseillé, visible dans `ps`)
> AGREELY_API_KEY env (le chemin agent : une variable, aucune invite)
> trousseau du SE (keytar)
> ${XDG_CONFIG_HOME|~/.config}/agreely/config.json (mode 0600)
Une clé absente est une erreur d'usage (sortie 2) : « No API key. Set
AGREELY_API_KEY, run agreely login, or pass --api-key. »
URL de base : --base-url > AGREELY_BASE_URL > configuration stockée > valeur
par défaut du SDK (https://api.agreely.ca). Si le module natif optionnel keytar
est indisponible, login / config set se rabattent sur le fichier de
configuration 0600.
La dégradation est omise (à dessein)
La CLI fonctionne en refus par défaut et traduit une panne en code de sortie
4. La politique de dégradation (ouverture en cas de panne / double barrière /
bris de glace) est intentionnellement omise de la CLI : c'est une
préoccupation d'intégration application/SDK de longue durée (avec un collecteur
d'audit et une fenêtre bornée), pas quelque chose qu'une invocation ponctuelle de
CLI peut persister ou auditer sensément. Configurez-la là où le
SDK est intégré.
Ce que 0.5.1 ne couvre pas
L'API accepte ces membres; la CLI 0.5.1 n'a pas de drapeau pour eux. Ces cas passent par l'application Agreely ou un appel direct à l'API :
- Un
endedAtpassé surrelationship end. - Sur un consentement papier : qui a consenti (
capacity),isMinoretageBracket. - Sur un consentement téléphonique :
ageBracket(14_to_17en particulier;--minorcouvre un mineur de moins de 14 ans). - Les routes de la politique de confidentialité et l'inventaire.
Ouverte et vérifiable
Sous licence MIT, sans télémétrie, sans analytique et sans appel de retour : chaque
requête passe par @agreely/sdk vers l'URL de base de l'API que vous configurez.
Une clé d'API n'est envoyée que dans l'en-tête Authorization: Bearer vers cette
API; elle n'est jamais journalisée (elle est masquée à l'affichage). Dépendances :
@agreely/sdk, commander, @clack/prompts, picocolors, et un keytar
optionnel.