Verify a receipt
Confirm a governance outcome was real,
not fabricated by an LLM.
Every BlackLake decision returns an HMAC-signed receipt binding the evaluation id, the outcome, and the cost. When an AI Actor transcript claims “BlackLake denied that call”, or that a particular run cost a specific amount, you can verify the receipt independently — and reject the claim if the signature doesn’t check. AI can hallucinate compliance, and it can hallucinate cost. Receipts prove both.
See it work
Authentic vs hallucinated — the difference is one check
Toggle between a real receipt and a fabricated one to see what verification returns. The HMAC check is the boundary between a provable governance outcome and a claimed one.
Real token
bldt_v1:GjNk9zT…
Result
valid: true
Decision confirmed
A real receipt was signed by the BlackLake server at decision time. The HMAC check confirms the outcome, cost, and policy snapshot are intact.
Why this exists
AI can hallucinate compliance
An autonomous AI Actor can claim “I asked for permission and the request was denied” without ever calling the governance API. From the transcript alone, a hallucinated denial is indistinguishable from a real one. That breaks every audit chain that takes the AI Actor’s word for what happened.
BlackLake fixes this with cryptography rather than trust. Every real govern() call returns a token of the form bldt_v1:<hmac> bound to the evaluation id and the decision. Anyone with that token can ask the BlackLake server “was this you?” — and the server verifies the HMAC without trusting the caller. A fabricated token fails the check; a tampered decision fails the check; a real one validates cleanly.
Try it
See what verification returns
Two sample receipts below — one authentic, one tampered. Click either to see the response BlackLake returns. The real /v1/decisions/verify endpoint runs the same check against your workspace’s ledger.
Request
POST /v1/decisions/verify
Content-Type: application/json
{
"evaluation_id": "eval_01jvqr5x8a3f7p9c2nykvq6mtb",
"decision_token": "bldt_v1:GjNk9zT0p4cJ7QrYqXmL6aBnE3ZdWv8KuXQpHfNyTcM"
}Response
valid · this denial really happened{
"valid": true,
"evaluation": {
"id": "eval_01jvqr5x8a3f7p9c2nykvq6mtb",
"agent_id": "agent_01jv...",
"tool_id": "tool_01jv...",
"outcome": "deny",
"policy_id": "pol_01jv...",
"evaluated_at": "2026-04-30T17:42:11.094Z"
}
}Run the same call against your workspace: get a receipt from any bl.govern(...) response and POST it to /v1/decisions/verify. The console exposes the same flow at /decisions/verify if you prefer the UI.
The protocol
What the API actually does
Verification is one request. Send the evaluation id and the decision token; the server looks up the recorded outcome, recomputes the HMAC against its signing key, and returns a constant-time compare result. A 200 response with valid: true confirms the receipt is authentic.
Request
POST /v1/decisions/verify
POST /v1/decisions/verify HTTP/1.1Host: api.blacklake.systemsContent-Type: application/json{ "evaluation_id": "eval_01jvqr5x8a3f7p9c2nykvq6mtb", "decision_token": "bldt_v1:GjNk9zT0p4cJ7QrYqXmL6aBnE3ZdWv8…"}Response — authentic
200 OK
{ "valid": true, "token_version": "v2", "evaluation_id": "eval_01jvqr5x8a3f7p9c2nykvq6mtb", "decision": "approval_required", "evaluated_at": "2026-04-30T17:42:11.094Z", "receipt_version": 2, "cost_summary": { "total_usd": 0.0382, "input_tokens": 1820, "output_tokens": 412, "cache_read_tokens": 0, "cache_write_tokens": 0, "thinking_tokens": 0, "pricing_version": "2026-05", "record_count": 1 }, "cost_signed": "Cost is cryptographically bound to this decision via the v2 token.", "redacted": true, "note": "Anonymous verification — only the fields signed by the decision token are returned. Authenticate with an x-api-key for the owning workspace to see the full view."}Response — tampered
200 OK
{ "valid": false, "reason": "signature_mismatch" }Cryptographic detail
- HMAC-SHA256 over the concatenation of evaluation id and decision string. The signing key is HKDF-derived from a server KEK with a fixed context label so a leaked decision-signing key cannot decrypt webhook secrets and vice versa.
- Constant-time compare via
crypto.timingSafeEqualso the verifier doesn’t leak signature length to a probing client. - Bound to outcome — the token signs the specific decision (allow / deny / approval_required / default_deny). Re-using a deny token to claim an allow fails the check.
- Bound to org — verification requires the evaluation id to belong to your workspace. A token leaked from a different org doesn’t resolve to a record you can see.
Compare
Why most audit trails can’t answer this question
Existing logs assume the source telling you what happened is honest. AI Actors break that assumption.
Generic audit logs (e.g. structured app logs, OpenTelemetry traces)
Capture what the application reports, not what the model claims. If the AI Actor never invoked the governed call but the transcript says it did, there’s no log entry to contradict it.
Cloud audit logs (GCP Cloud Audit, AWS CloudTrail)
Authoritative for production effects, but they record what reached the cloud — not what was governed before it. A denial decision that prevented a side effect produces no cloud-audit entry.
BlackLake decision tokens
Bind the decision itself to a server-signed receipt. Verification works with no other infrastructure. A hallucinated denial fails the check; a real one validates against the recorded evaluation.
Sign your audit trail. Verify it later.
BlackLake is free while in beta. Every governed call ships with a receipt you can verify cryptographically.