The problem
You give an agent a card mandate. The mandate says the agent can spend up to a ceiling over a month, up to a maximum number of transactions, in one currency. The agent runs for thirty days. At the end of the month somebody asks the obvious question: did the agent stay inside the ceiling?
Right now that question is answered by whoever owns the database. The platform runs a query, sums a column, and produces a number. If the account holder disputes it, the platform runs the query again and produces the same number, because it is the same query against the same database. The account holder has no way to check the arithmetic, no way to check that the rows summed were the rows belonging to this mandate, and no way to check that a row was not quietly excluded. The platform's word counts because nothing else is on offer.
That was tolerable when a human authorised each purchase. A human remembers roughly what they bought. When the acting party is an agent running unattended at machine speed, nobody on the account holder's side has an independent memory of the month. The only record is the platform's record, and the platform is also the party with an interest in the total looking reasonable.
Name the parties and what each would assert without evidence. The platform asserts a total and a count and says the agent stayed within its mandate. The account holder asserts that the total looks wrong and that transactions outside the mandate window were folded in. A merchant acquirer, brought in later, asserts nothing useful because it only ever saw its own transactions. An auditor asked to sign off asserts that it reviewed the platform's report, which is a statement about reading a report rather than about the underlying arithmetic.
There are three specific ways the summing goes wrong, and none requires anyone to be dishonest. A transaction from a neighbouring mandate gets included because both mandates belong to the same customer. A transaction that settled a day after the window closed gets counted in the window it was authorised near. Two records for the same transaction, one from the authorisation feed and one from the settlement feed, both get counted. Each produces a total that is wrong in a way no reader of a report can detect.
The dishonest case is simpler. A platform that is one transaction over a ceiling can drop that transaction from the set before reporting. Nothing in a report format prevents that. This receipt does not prevent it either, and it says so in the boundary. What it does is make every other kind of error detectable, and it makes the presented set permanently fixed. Once the receipt is signed, the platform is committed to that exact list of member receipt identifiers and body digests. If a transaction is later produced that clearly belonged in the window and is absent from the list, the platform cannot claim it was included.
The question moves from whether you believe the platform's total to here is the set, here is the arithmetic, check it yourself.
What the receipt binds
The signed body carries these fields. All of them are required by the schema at https://thehiveryiq.com/.well-known/schemas/mandate-aggregate-v1.json.
| Field | Meaning |
|---|---|
receipt_type | Fixed to mandate.aggregate. Pins the instrument type inside the signed bytes. |
schema | Fixed to r1.0.0. The receipt schema revision the body conforms to. |
aggregate_id | Caller chosen identifier for this aggregation, one to 256 characters. |
tenant_id | The tenant the aggregation belongs to, one to 256 characters. |
mandate_ref | Reference to the one delegated authority receipt all members must share, carrying receipt_id, payload_sha256 and delegation_id. |
window | The accounting window, with opens_at and closes_at as UTC instants. |
cumulative_constraint | The ceiling being tested, with max_total_minor, a three letter currency code, and max_count. |
members | One to 1000 member entries. Each carries the member receipt_id, its payload_sha256, its amount_minor, its currency and its authorized_at. |
totals | The claimed aggregate, with total_minor, count and currency. |
outcome | One of within_cumulative, exceeds_cumulative or indeterminate. |
evaluated_at | The UTC instant the aggregation was evaluated. |
boundary | The fixed non attestation string, checked as a schema constant. |
Two shapes are worth reading closely. The member entry holds a digest of the member receipt body but not the body. The cumulative_constraint holds max_total_minor as an integer in minor units, so there is no floating point anywhere in the ceiling comparison.
What is deliberately not in the signed body
The member receipts are not in the signed body. The aggregate carries only each member's receipt_id and payload_sha256, plus the three transaction facts needed for the arithmetic. The full conformance receipts, with their merchant identifiers, their transaction fingerprints, their initiator records and their display bindings, stay with the party holding them.
The commitment that makes this safe is the Hive typed receipt digest in src/typed/canon.js, in four steps.
First, canonicalisation. The signed body is serialised to JSON with object keys sorted recursively, arrays left in order because order is significant, no whitespace, and every code unit above U+007F escaped as a lowercase \uXXXX sequence. That escape exists so the bytes match Python json.dumps(body, sort_keys=True, separators=(",", ":")) with its default ensure_ascii=True. Without it, a body containing one non ASCII character would digest differently in a JavaScript verifier and a Python verifier.
Second, the digest. payload_sha256 is the lowercase hex SHA-256 over the UTF-8 bytes of that canonical string.
Third, domain separation. The bytes an Ed25519 signature covers are the ASCII string
hive-receipt <receipt_id> <payload_sha256> <ts>
The literal prefix hive-receipt is the domain separation label. A signature over a Hive receipt cannot be replayed as a signature over any other message that does not begin with those bytes and that exact spacing.
Fourth, the signature. sig_b64u is unpadded base64url Ed25519 over that signing string. The envelope declares algorithm as the constant Ed25519.
One numeric encoding constraint binds an interoperating producer. An integral value has to be encoded as a JSON integer. Writing it as 1.0 canonicalises to 1.0 in Python and 1 in JavaScript, which changes payload_sha256. Receipts minted here always satisfy the constraint because JSON.stringify never emits a trailing .0.
The member link uses the same digest function. member.payload_sha256 is payloadDigest(member_receipt.signed_body), so the aggregate commits to the exact bytes of every member body without carrying any of them.
The gates
Verification runs the gates in this order and stops at the first failure, so no later gate reads a field an earlier gate has already shown to be untrustworthy.
- SCHEMA. Validates the whole envelope against the mandate aggregate v1 schema, including
additionalProperties: falseat every level and theboundaryconstant. A failure means the receipt is not a well formed instrument of this type. - ISSUER_KEY_MATCH. Resolves
envelope.key_idin the trusted keyring. A failure means the key does not resolve, or that no trusted keyring resolver was supplied to the verifier at all. - PAYLOAD_DIGEST, RECEIPT_ID, SIGNATURE and SIGNER_IDENTITY. The shared envelope layer. The canonical digest over
signed_bodyis recomputed againstpayload_sha256,receipt_idhas to parse into ther_<type>_<unix_seconds>_<12 hex>form with a type segment equal tosigned_body.receipt_type, and the Ed25519 signature has to verify against the trusted key forkey_idor, failing that, a caller supplied key. SIGNER_IDENTITY fails in the second case, reporting internally consistent bytes from a signer this service does not trust. - MEMBER_LINKS. For every member, requires that a conformance envelope was supplied and that
member.payload_sha256equals the recomputed digest of that supplied body. A failure means a member was named without being produced, or the produced body is not the body the aggregate committed to. - MEMBER_INTEGRITY. Runs the full
mandate.conformanceverification over every supplied member receipt, against the same delegation and resolver. A failure names the member and the conformance gate it tripped, so a broken aggregate points at the specific broken member. - MEMBER_MANDATE_MATCH. Requires each member's own
mandate_refto equal the aggregatemandate_refon all three ofreceipt_id,payload_sha256anddelegation_id. A failure means the set mixes spending under different delegated authorities. - NO_DUPLICATE_MEMBERS. Requires the member receipt identifiers to be unique and sorted ascending. A failure means either the same transaction was counted twice or the body is not in the deterministic order the aggregate form requires.
- MEMBERS_IN_WINDOW. Parses the window, requires it to be valid and non decreasing, and requires every member's linked
transaction.authorized_atto fall at or insideopens_atandcloses_at. A failure names the member and the offending instant. - CURRENCY_UNIFORM. Requires each member's declared currency and its linked transaction currency to equal
cumulative_constraint.currency. A failure means a mixed currency set was presented as if one ceiling applied, and the service performs no conversion. - TOTALS_RECOMPUTE. Requires each member's
amount_minor,currencyandauthorized_atto equal the linked receipt's transaction values, then recomputes the integer minor unit sum, the count and the currency and compares them tototals. A failure means the stated totals are not the totals the members produce. - OUTCOME_RECOMPUTE. Derives the outcome as
exceeds_cumulativewhentotal_minorexceedsmax_total_minororcountexceedsmax_count, andwithin_cumulativeotherwise, then compares it to the statedoutcome. A failure means the caller asserted a finding the arithmetic does not support.
The boundary
This receipt attests that the supplied set of mandate conformance receipts all reference the same delegated authority, all fall inside the stated window, share one currency, contain no duplicate, and that their cumulative total and count were recomputed by this service in integer minor units and compared against the stated cumulative constraint. This service cannot know whether the supplied set is complete. A transaction that was never presented here does not appear in these totals, so a within cumulative outcome is a statement about the receipts supplied and not a statement about everything the mandate holder spent. It performs no currency conversion, is not a payment authorisation, shifts no liability under any card network rule, and does not limit any right a consumer holds under Regulation E, Regulation Z, or any equivalent rule.
That paragraph is a schema constant. It is inside the signed bytes and it is checked at verification, so a receipt cannot be minted with a softer version of it.
Enumerating what the instrument does not prove makes it more useful in an argument. Consider what happens without the enumeration. The platform hands over a signed total. The account holder's lawyer reads "signed" and hears "complete". Six months later a transaction surfaces that was never in the set. Now the whole receipt is in question, because it was allowed to imply something it never checked.
With the enumeration, the same surfaced transaction changes nothing about the receipt's standing. The receipt said in its own signed body that it speaks only about the receipts supplied. The argument moves immediately to the real point, which is why that transaction was not presented.
The same holds for the currency clause and the regulatory clause. A reader who wants to argue that an exchange rate was applied unfairly learns from the receipt itself that no conversion happened here. A reader who wants to argue that this receipt overrode a consumer protection learns that it did not and cannot. Every sentence of non attestation closes a line of argument before it starts.
Adversarial cases
These are the real cases in test/mandate-aggregate.test.mjs.
A duplicate member fails NO_DUPLICATE_MEMBERS. The obvious way to pad a count is to list the same conformance receipt twice. The gate builds a set of the member identifiers and compares its size to the array length, so the duplicate is caught before any arithmetic runs. Renaming one copy does not help either, since the identifier is part of the member's own signed receipt and MEMBER_LINKS checks the digest.
A mixed currency set fails CURRENCY_UNIFORM. Two hundred in a weak currency and two hundred in a strong one are not four hundred of anything. A caller who sums across currencies and presents one ceiling comparison trips this gate, which checks both the member's declared currency and its linked transaction currency against cumulative_constraint.currency. The service performs no conversion, so there is no rate to argue about.
A member outside the window fails MEMBERS_IN_WINDOW. This is the case of pulling a transaction from an adjacent month into a month with room left. The gate reads authorized_at from the linked conformance receipt rather than from the aggregate's own member entry, so editing the aggregate does not move the transaction.
A forged total fails TOTALS_RECOMPUTE. The direct attack is to write a smaller total_minor. The gate first requires each member's amount_minor, currency and authorized_at to equal the linked receipt's transaction values, then recomputes the sum, the count and the currency from those verified members. The stated totals are never used as an input.
A forged outcome fails OUTCOME_RECOMPUTE. The subtler attack is to leave the arithmetic honest and simply write within_cumulative over a total that exceeds the ceiling. The gate derives the outcome from the recomputed totals and the stated constraint and compares. Both the count ceiling and the amount ceiling are checked, so a set that stays under the amount but overruns max_count still comes out as exceeds_cumulative.
A member under another delegation fails MEMBER_MANDATE_MATCH. This is authority laundering. A transaction made under a wide mandate gets folded into an aggregate reported against a narrow one. The gate compares the member's own mandate_ref against the aggregate's on all three fields, and the payload_sha256 component means two delegations with the same identifier but different terms stay distinguishable.
Two positive cases are worth naming as well. A valid supplied conformance set verifies, and a valid excess cumulative outcome verifies. An aggregate that honestly reports exceeds_cumulative is a valid receipt. The instrument is not a pass stamp.
Performance
From hive-verifier-api/benchmarks/results-latest.json, measured at 2026-08-09T22:28:01.099Z at commit e167719f7d815809c6f55c5dde4495edf1c5615f over 200 iterations:
| Measure | Value |
|---|---|
| Mint p50 | 6.928 ms |
| Mint p95 | 10.33 ms |
| Verify p50 | 6.261 ms |
| Verify p95 | 6.795 ms |
| Artifact size | 2043 bytes |
The hardware caveat, stated plainly. This is a local harness measurement on one machine and one Node version, recorded on Node v20.20.1, linux/x64, a two core Intel Xeon at 2.90 GHz. It is a reproducible measurement of this code, not a production latency guarantee. Verify cost here scales with member count, because MEMBER_INTEGRITY runs a full conformance verification per member.
How to run it
Verification is open. It needs no credentials, so it is the fastest honest check available.
- Host:
https://thehiveryiq.com/v1 - Verify route:
/verify/mandate-aggregate - Mint route:
/mint/mandate/aggregate, which requiresAuthorization: Bearer $HIVE_TYPED_MINT_TOKEN
curl -sS -X POST https://thehiveryiq.com/v1/verify/mandate-aggregate -H 'content-type: application/json' -d '{"receipt": <a receipt of this type>}'
Mint fails closed with 401 when the token is missing or wrong. There is no unsigned path and no simulated path in the signer: a caller without a seed cannot mint.
Where it sits in the canon
Family: authority. Category: typed receipt contract.
It composes upward from mandate.conformance. Every member of an aggregate is a conformance receipt, and MEMBER_INTEGRITY re-verifies each one rather than trusting its presence in the list. Both point at the same authority.delegation receipt through mandate_ref, and the aggregate requires that reference to be identical across the whole set.
It does not replace mandate.conformance. A conformance receipt answers whether one transaction fit a per transaction constraint. The aggregate answers whether a set of them fit a cumulative constraint. That is why the conformance boundary says a series of individually conforming transactions may still exceed a spending intent it cannot see. The aggregate is what sees it. It also does not replace the delegated authority receipt itself, and it inherits that receipt's revocation limitation through its members.
Status
production_deployed.