Skip to content
BLACKLAKE

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…

POST /v1/decisions/verify
HMAC check

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.timingSafeEqual so 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.