FR EN

JSON reference

This section documents the on-the-wire artifacts field by field. Every example is the real shape Agreely's code builds, not an illustration. Read alongside the protocol for the cryptography behind each field.

When a company issues a consent request, Agreely builds a number-free offer, signs its JCS-canonical bytes with the company key, and wraps the signature as a companySig Data Integrity proof. No value is a number (only strings, booleans and objects), so the canonical bytes a verifier re-derives can never diverge.

The company's customer reference is not in the signed offer: it would follow every receipt and every verification bundle, and let them be correlated across organizations. Agreely adds it only to the encrypted copy it keeps (see at rest).

{
  "requestId": "0x4b08245219c0e1a2b3c4d5e6f70819a2b3c4d5e6f70819a2b3c4d5e6f7081234",
  "issuer": "did:web:app.agreely.ca:c:acme",
  "consent": {
    "action": "grant",
    "items": [
      {
        "itemId": "0x9a2b3c4d5e6f70819a2b3c4d5e6f70819a2b3c4d5e6f70819a2b3c4d5e6f7081",
        "category": "phone number",
        "purpose": "billing",
        "sensitive": false,
        "automatedDecision": false,
        "legalBasis": "consent"
      }
    ]
  },
  "nonce": "0x7081234b3c4d5e6f70819a2b3c4d5e6f70819a2b3c4d5e6f70819a2b3c4d5e6f",
  "validUntil": "2031-01-01T00:00:00Z",
  "createdAt": "2026-06-26T15:00:00Z",
  "expiresAt": "2026-07-26T15:00:00Z",
  "document": {
    "code": "acme-billing-v3",
    "name": "Billing consent v3",
    "version": "3",
    "effectiveDate": "2026-01-01"
  },
  "disclosure": {
    "purpose": { "fr": "…", "en": "…" },
    "categories": { "fr": "…", "en": "…" },
    "retention": { "fr": "…", "en": "…" },
    "withdrawal": { "fr": "…", "en": "…" },
    "recipients": { "fr": "…", "en": "…" },
    "rights": { "fr": "…", "en": "…" },
    "responsable": { "name": "…", "contact": "…" }
  },
  "disclosureVersion": "1",
  "disclosureHash": "0x…sha256…",
  "companySig": {
    "type": "DataIntegrityProof",
    "cryptosuite": "eddsa-jcs-2022",
    "created": "2026-06-26T15:00:00Z",
    "verificationMethod": "did:web:app.agreely.ca:c:acme#kms-1",
    "proofPurpose": "assertionMethod",
    "proofValue": "z3Ge8wQ5...base58btc..."
  }
}

Field by field

Field Type Meaning
requestId 0x + 64 hex The protocol handle: 32 fresh random bytes, never derived. The public id everywhere, never an internal uuid.
issuer string The company DID, did:web:app.agreely.ca:c:{slug}.
consent.action string grant.
consent.items[].itemId 0x + 64 hex A fresh random opaque handle for this item.
consent.items[].category string The normalized category key (lowercased canonical), not the display label.
consent.items[].purpose string The normalized purpose key.
consent.items[].sensitive boolean The cell is declared sensitive (its consent must then be express).
consent.items[].automatedDecision boolean The cell feeds a decision based exclusively on automated processing.
consent.items[].legalBasis string The ground the company declares for the cell; consent for a consent ask.
nonce 0x + 64 hex Single-use random nonce, bound into the approval challenge so the answer cannot be replayed.
validUntil RFC 3339 The consent lifespan if approved.
createdAt RFC 3339 When the offer was minted.
expiresAt RFC 3339 The answer deadline (30 days). A pending request past this flips to expired.
document object The consent document descriptor: code, name, nameEn when the document has an English name, version, effectiveDate, and ipfsCid only when the version is pinned to IPFS.
disclosure object The bilingual information the person was given, section by section ({fr, en} per section; responsable is {name, contact}). The means, withdrawal, refusalConsequences, crossBorder, automatedDecision and profiling sections appear only when the document carries them.
disclosureVersion string "1": disclosureHash is over disclosure alone. "2": at least one cell rests on a ground other than consent, and the hash is over {disclosure, legalBasis}.
disclosureHash 0x + 64 hex The SHA-256 of the JCS-canonical preimage disclosureVersion names.
legalBasis object Present only in version "2": for each itemId of a cell that does not rest on consent, {basis, justificationFr, justificationEn?}.
minor object Present only when the person is a minor under 14: {isMinorUnder14: true, parentalConsentObtained}. The guardian's name never enters the signed bytes.
companySig object The eddsa-jcs-2022 Data Integrity proof over the offer.

What companySig signs

The signature covers the offer object before companySig is added, that is: requestId, issuer, consent, nonce, validUntil, createdAt, expiresAt, document, disclosure, disclosureVersion, disclosureHash, and legalBasis and minor when present. To verify it, drop companySig (and the at-rest subject, status and result fields), JCS-canonicalize what remains, and check the Ed25519 signature against the company key.

At rest

The object Agreely stores (encrypted under the tenant DEK) is the offer, its companySig, and three envelope fields that are not covered by companySig: subject (the company's own customer reference, ref, and status, known or unonboarded depending on whether the recipient already has a citizen DID), status and result:

{
  "...": "all offer fields above",
  "companySig": { "...": "the proof" },
  "subject": { "ref": "cust_8812", "status": "known" },
  "status": "pending",
  "result": { "receipts": null, "settledAt": null }
}

status advances to approved, refused, expired, or revoked_before_action; result is populated when the request settles.

The SDK-facing shapes

The /v1 API returns trimmed views of a request rather than the raw signed object. The issuance response (IssuedRequest) and the list/show view (ConsentRequest) are documented in the API reference and the interactive spec.