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.
- The consent request (this page): the signed offer a company issues.
- The consent receipt: the Verifiable Credential the citizen receives.
- DID documents: company and citizen.
- Verify a receipt: the four checks an auditor runs.
The consent request (the signed offer)
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. Every value is a string, so the canonical
bytes a verifier re-derives can never diverge.
{
"requestId": "0x4b08245219c0e1a2b3c4d5e6f70819a2b3c4d5e6f70819a2b3c4d5e6f7081234",
"issuer": "did:web:agreely.ca:c:acme",
"subject": {
"ref": "cust_8812",
"status": "known"
},
"consent": {
"action": "grant",
"items": [
{
"itemId": "0x9a2b3c4d5e6f70819a2b3c4d5e6f70819a2b3c4d5e6f70819a2b3c4d5e6f7081",
"category": "phone number",
"purpose": "billing"
}
]
},
"nonce": "0x7081234b3c4d5e6f70819a2b3c4d5e6f70819a2b3c4d5e6f70819a2b3c4d5e6f",
"validUntil": "2031-01-01T00:00:00Z",
"createdAt": "2026-06-26T15:00:00Z",
"expiresAt": "2026-07-26T15:00:00Z",
"companySig": {
"type": "DataIntegrityProof",
"cryptosuite": "eddsa-jcs-2022",
"created": "2026-06-26T15:00:00Z",
"verificationMethod": "did:web: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:agreely.ca:c:{slug}. |
subject.ref |
string | The company's own customer reference. Never a citizen DID. |
subject.status |
string | known or unonboarded (whether the recipient already has a citizen DID). |
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. |
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. |
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, subject, consent, nonce, validUntil, createdAt, and expiresAt. To verify it, drop companySig (and the at-rest status / 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 plus
three envelope fields, which are not covered by companySig:
{
"...": "all offer fields above",
"companySig": { "...": "the proof" },
"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.