Authority family

Cumulative Mandate Receipt: settling what a delegated spender actually spent across a window

The Cumulative Mandate Receipt is a signed statement about a set of mandate conformance receipts. It attests that every member receipt in the set names the same delegated authority, that every linked transaction time falls inside a stated window, that every member uses one currency, that no member appears twice, and that the cumulative total and count were recomputed by the verifying service in integer minor units and compared against a stated cumulative constraint. The parties who need it are the account holder who granted a spending mandate, the platform whose agent spent under it, and whoever later has to settle an argument about the total.

The property that separates this from a spend log is recomputation. A log records a total that some system asserted. This receipt refuses to accept an asserted total. The service adds the member amounts itself, counts the members itself, derives the within or exceeds finding itself, and signs only what it derived. A forged total fails a gate rather than appearing in a report. The receipt also states plainly that it cannot know whether the supplied set is complete, so the finding is scoped to the receipts presented and not to everything the mandate holder spent.

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.

FieldMeaning
receipt_typeFixed to mandate.aggregate. Pins the instrument type inside the signed bytes.
schemaFixed to r1.0.0. The receipt schema revision the body conforms to.
aggregate_idCaller chosen identifier for this aggregation, one to 256 characters.
tenant_idThe tenant the aggregation belongs to, one to 256 characters.
mandate_refReference to the one delegated authority receipt all members must share, carrying receipt_id, payload_sha256 and delegation_id.
windowThe accounting window, with opens_at and closes_at as UTC instants.
cumulative_constraintThe ceiling being tested, with max_total_minor, a three letter currency code, and max_count.
membersOne to 1000 member entries. Each carries the member receipt_id, its payload_sha256, its amount_minor, its currency and its authorized_at.
totalsThe claimed aggregate, with total_minor, count and currency.
outcomeOne of within_cumulative, exceeds_cumulative or indeterminate.
evaluated_atThe UTC instant the aggregation was evaluated.
boundaryThe 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.

  1. SCHEMA. Validates the whole envelope against the mandate aggregate v1 schema, including additionalProperties: false at every level and the boundary constant. A failure means the receipt is not a well formed instrument of this type.
  2. ISSUER_KEY_MATCH. Resolves envelope.key_id in the trusted keyring. A failure means the key does not resolve, or that no trusted keyring resolver was supplied to the verifier at all.
  3. PAYLOAD_DIGEST, RECEIPT_ID, SIGNATURE and SIGNER_IDENTITY. The shared envelope layer. The canonical digest over signed_body is recomputed against payload_sha256, receipt_id has to parse into the r_<type>_<unix_seconds>_<12 hex> form with a type segment equal to signed_body.receipt_type, and the Ed25519 signature has to verify against the trusted key for key_id or, 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.
  4. MEMBER_LINKS. For every member, requires that a conformance envelope was supplied and that member.payload_sha256 equals 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.
  5. MEMBER_INTEGRITY. Runs the full mandate.conformance verification 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.
  6. MEMBER_MANDATE_MATCH. Requires each member's own mandate_ref to equal the aggregate mandate_ref on all three of receipt_id, payload_sha256 and delegation_id. A failure means the set mixes spending under different delegated authorities.
  7. 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.
  8. MEMBERS_IN_WINDOW. Parses the window, requires it to be valid and non decreasing, and requires every member's linked transaction.authorized_at to fall at or inside opens_at and closes_at. A failure names the member and the offending instant.
  9. 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.
  10. TOTALS_RECOMPUTE. Requires each member's amount_minor, currency and authorized_at to equal the linked receipt's transaction values, then recomputes the integer minor unit sum, the count and the currency and compares them to totals. A failure means the stated totals are not the totals the members produce.
  11. OUTCOME_RECOMPUTE. Derives the outcome as exceeds_cumulative when total_minor exceeds max_total_minor or count exceeds max_count, and within_cumulative otherwise, then compares it to the stated outcome. 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:

MeasureValue
Mint p506.928 ms
Mint p9510.33 ms
Verify p506.261 ms
Verify p956.795 ms
Artifact size2043 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 requires Authorization: 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.

References for this instrument
Canon entry
Cumulative Mandate Receipt in the Hive canon
JSON Schema
https://thehiveryiq.com/.well-known/schemas/mandate-aggregate-v1.json
Verify route
POST /verify/mandate-aggregate
Canonical type
mandate.aggregate
Private by design. Hive does not store your prompts. Every request is already receipted by a one-way SHA-256 fingerprint, not the words. Proof, not surveillance.