Every consequential action on an AgenticBoxes account writes an audit event, and every audit event is hash-chained to the one before it. A reconciliation job re-walks each account's chain on a schedule, confirms nothing was edited, deleted, or reordered, and writes the result below. The score is published as raw, machine-readable JSON, written by the reconciliation job itself — so the number here is the job's own output on a schedule, not a figure we hand-edit. (What it does and doesn't prove is spelled out below.)
Loading the live score…
Each row is one reconciliation pass. Newest first.
| When (UTC) | Check | Chains intact | Broken | Events |
|---|---|---|---|---|
| Loading run history… | ||||
Each audit event carries a _chain object: its sequence
number, the hash of the event before it, and its own hash —
sha256 over the event's canonical contents plus that
previous hash. Change any historical event's content, drop one, or
swap two, and every hash downstream stops matching. The reconciliation
job re-walks the whole chain from a known anchor every run; a single
altered byte turns Chains intact red and
Tampering detected non-zero. The job can't quietly skip itself
either — missed runs show up as gaps.
Be precise about the guarantee: the chain makes any change to a
recorded event detectable after the fact. It does not,
by itself, prove we recorded every event in the first place — no
self-published score can, and we won't pretend otherwise. For independent
proof of a specific message, that's what the evidence envelope (below) is
for: a signed per-message record you can corroborate against the
recipient's own copy via its Message-ID, without trusting us.
The score is the platform's tamper-evident self-check; the envelope is
your independent receipt.
The number isn't a figure we hand-edit — it's emitted by the reconciliation job as the JSON this page reads, every run. Read it yourself:
curl https://docs.agenticboxes.email/audit.json
The score above is the platform grading itself. You can also request a cryptographically-signed audit of your account's traffic — the evidence trail for a specific message. We're running this as an open beta: during the beta, message audits are free, and we currently honor requests for any message sent or received in the last 7 days (a 7-day-in-arrears window while we tune retention).
Call the endpoint with your account's API key (admin scope). It returns the signed bundle as JSON:
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.agenticboxes.email/api/v1/account/audit/message/<message_id>
The bundle includes message (your message's identity + the
SES message id), evidence (storage timestamp + SES acceptance),
signing (the key, algorithm, canonicalization), and a base64
signature.
Verification is two steps: get the public key, then verify the signature over a deterministic canonical form of the bundle. There are two ways to get the key, and they're not equivalent on trust:
signing.key_arn; the key's resource policy grants
kms:GetPublicKey to all principals, so any verifier with
AWS credentials can fetch the PEM from KMS:
aws kms get-public-key --key-id <signing.key_arn>
This roots the trust in AWS — not in a key file we host on our own
domain. We can't substitute a different key without losing access to
our own, and any key state change is recorded in CloudTrail.
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.agenticboxes.email/api/v1/account/audit/public-key
This endpoint dogfoods kms:GetPublicKey on every call, so
the PEM is always in sync with what KMS would return for the ARN — but
the trust root is us, not AWS. For high-stakes verification, the AWS
path is the one to use.
Once you have the PEM, strip the signature field from the
bundle, recompute the canonical JSON over what's left (recursive
sort-keys, compact JSON.stringify, UTF-8), then verify the
base64-decoded signature against those bytes with ECDSA_SHA_256 + the
public key. Canonicalization is deterministic, so any verifier
reproduces the exact bytes we signed.
For direction=received the bundle additionally carries
DKIM evidence under message.dkim. That gives you an
independent, key-independent cryptographic chain — the sender's MTA
signed the email at send time with a key in DNS we don't control
once published, so verifying DKIM proves the headers (and body)
really came from the sender, without trusting our attestation at
all. There are two halves to verify, header signature and body
hash, and they're independent:
message.dkim.signatures[] pairs the raw
DKIM-Signature header value with the published public
key as we resolved it at bundle-issue time
(public_key_txt) — so verification doesn't depend on
the sender still publishing that selector when you verify. Per
the signature's h= tag, canonicalize the named
headers from signed_headers using the
c='s header canonicalization (relaxed or simple),
then RSA-verify the signature's b= bytes against
that hash with the public key in public_key_txt.
bh=). The bundle does
NOT carry the message body — we keep it out so the bundle stays
forwardable without privacy loss. As the bundle owner, fetch the
original RFC 5322 bytes:
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.agenticboxes.email/api/v1/messages/<message_id>/raw
Strip everything up to (and including) the first blank line —
that's the body. Apply the body canonicalization in the
signature's c= tag (relaxed or simple), SHA-256 the
result, base64-encode. Compare to the signature's
bh= value. Match means the body in our store is
byte-equivalent to what the sender signed — i.e. we haven't
tampered with it post-receipt.
Both halves verifying without our public key in the chain is the
"independent witness" upgrade — your confidence in the message no
longer rests on our attestation. For direction=sent,
message.dkim is currently {not_applicable:true};
SES adds its DKIM after our send call returns and we don't retain
those bytes today. (Sent-side passthrough is on the roadmap.)
We try to keep the framing honest. A signed bundle is real evidence, but it is not the same thing as independent third-party proof. Read the bundle for what it is:
SendEmail / receive event;
that's the upgrade path for harder claims.
direction=received, we now attach the original
DKIM-Signature header(s) and signed-header values under
message.dkim — that is a chronologically-separate,
key-independent witness (the sender's MTA signed at send time with
a key in DNS we don't control once published), so a verifier can
corroborate independently of our attestation. For
direction=sent the same passthrough isn't available yet
(SES adds DKIM after our send call); the strongest corroboration is
the recipient's DKIM-bearing copy of the email sitting alongside
our bundle.
Short version: credible vendor-attested receipt, tamper-evident, useful internally and for cooperative counterparties. For court-grade evidence today, pair it with the recipient's copy of the email. The deeper-audit tier (AWS-signed CloudTrail bundle + DKIM passthrough) closes most of this gap; it's on the roadmap.
Add this one line wherever you want the badge to appear — it renders a live
integrity pill (reading the same audit.json) right there:
<script src="https://docs.agenticboxes.email/badge.js" async></script>
That script is all you need. To place the badge somewhere other than where the script sits — a global header or footer, say — keep the script and also drop this empty span at the spot you want; the badge fills it in:
<span id="agenticboxes-audit-badge"></span>
Live render: