A receipt is a signed record of how one protected action ended. K-Block Cloud packs it into a portable evidence bundle (a .kbundle file) together with every signed step it covers and the identity documents of every signer. Anyone holding the file can check it offline, without an account and without trusting the Cloud API.
A valid receipt is strong evidence about signatures and decisions: who asked for exactly which call, who approved it, under which delegation and policy, and what the Gateway recorded as the result (for a decision-only call, that K-Block authorized it: there is no result). It is not, on its own, evidence that something happened in the outside world. This page explains where that line is, so that you rely on receipts for what they prove and nothing more.
To check a receipt, see Verify a receipt. For the bundle's fields, see Receipt fields.
When a receipt is issued
K-Block issues a receipt when an action reaches an end that someone signed. An action that ends without a signed final step gets no receipt.
| How the action ended | Receipt | Last signed step (head) |
|---|---|---|
| succeeded | yes | RESULT |
| failed (the upstream call or the Gateway failed) | yes | RESULT |
| failed (the execution was interrupted) | yes, when K-Block can sign the recovery with the registered gateway identity and the action's signed steps still verify | RESULT with error INTERRUPTED |
| rejected | yes | REJECTION |
| cancelled | yes | CANCELLATION |
| authorized (decision only) | yes: an authorization receipt | PROPOSAL (outcome pending), or APPROVAL (outcome granted) when a person approved |
| denied | no: nothing is signed for a denied call | — |
| expired (approval expired, task expired, or superseded: closed because something the decision relied on changed) | no | — |
Rejection and cancellation receipts carry the outcome final, because that is the only workflow state of those steps. The Receipts list, the receipt page's header and the action's page show them under the action's status (Rejected, Cancelled) instead; the Receipt card on the receipt page shows the signed outcome, Final, with the action's status beside it. See Action statuses for every status.
Who signs what
Every step of a protected action is a signed object (a K-Object). In K-Block Cloud the signers are:
| Step | Signed by |
|---|---|
| TASK (the request, with the policy decision) | the gateway identity, on behalf of your organization's principal |
| PROPOSAL (the exact call: tool, arguments, amount, upstream) | the gateway identity |
| APPROVAL or REJECTION | the approver's personal identity, in their browser |
| CANCELLATION | your organization's principal, in an owner's or admin's browser |
| EXECUTION and RESULT | the gateway identity |
| RECEIPT | the gateway identity (the issuer) |
The gateway identity is the K-Block identity (a KID) of the K-Block Gateway your agents connect to. The organization principal is your organization's own K-Block identity, set by the owner; it delegates authority to the gateway identity through a signed delegation. See Identities and KIDs for how these identities are created.
What a valid receipt proves
A verifier checks the bundle in seven steps: Bundle format, Identity chains, Signature chain, Receipt coverage, Graph integrity, Workflow & authorization and Receipt summary. The report is valid only if every check passes and there are no errors. A valid report establishes:
- Every covered step was signed by the identity it names, with a key that the signer's identity documents list as valid.
- Nothing was changed after signing. Object IDs are content hashes, so editing one byte of any step breaks it.
- The steps form the committed chain, from the TASK to the head, with nothing unrelated attached, and each step was allowed by the approval workflow (right parent, right role, right order).
- Who approved exactly which call. The APPROVAL points at the PROPOSAL by its content hash, so the approver signed these exact terms: the tool, the arguments, the executing server, the action, the amount and currency, and the upstream URL.
- The RESULT's terms equal the approved terms, and the result payload has the digest stated in the receipt.
- Under which delegation and policy the call was made: the TASK carries the delegation, the principal, the policy ID, version, digest and decision, the organization, the agent, the API key and the environment.
The summary in the report (who requested, approved and executed) is re-derived by the verifier from the signed steps. It is never copied from the issuer.
What a receipt does not prove
A valid receipt does not establish:
| Not proven | Why |
|---|---|
| That the upstream really did what the result says | The RESULT is signed by the gateway, not by the upstream, unless the upstream attested it. |
| When things happened | Every timestamp, including the receipt's, is asserted by its signer. Only the order of the steps is checked. |
| That nothing else happened in the thread | Only the path from the TASK to the head is covered. A cancellation receipt covers TASK → CANCELLATION; an earlier PROPOSAL or APPROVAL is not part of it. |
| That a decision-only call was executed, or that a refused one was not | An authorization receipt ends at the PROPOSAL or APPROVAL: K-Block performed nothing, and the system your code called signed nothing. A refused call has no receipt, and nothing binds what your code did after a refusal. |
| That K-Block Cloud still hosts it | A receipt is hosted for the organization's retention period. A bundle you downloaded stays verifiable after that; the hosted copy does not. |
| That no key was compromised or revoked later | The bundle contains what the issuer included. A key-compromise report published elsewhere is seen only if you supply current identity documents; the report says when it could not check this. |
| That the tool binding was unchanged | The Gateway also pins the tool's credential version, input schema and amount mapping to the decision, but that pin lives in K-Block's own records, not in the signed evidence. |
| That the Cloud API and the Gateway are separate parties | Both sign with the same gateway identity and both issue receipts (the Cloud API issues rejection, cancellation and recovery receipts). |
| What happened after an interruption | An interrupted execution is signed as failed with error INTERRUPTED, although the upstream may have acted. Check the upstream before you repeat the call. |
| Why a gateway-side failure happened, from the action record alone | Every failure recorded with a RESULT, except an interruption (INTERRUPTED), is stored with the action error code UPSTREAM_FAILED, also when the Gateway and not the upstream failed. For a failure the Gateway detected, the precise code (for example ATTESTATION_MISSING) starts the error detail. |
The trust model: pin the gateway identity
Anyone can create a bundle that verifies: a valid report proves the bundle is internally consistent and correctly signed by the identities it contains. Whether the Gateway your agents connect to issued it is a separate question, answered by comparing the issuer with the gateway identity you trust.
That is why you pin the gateway identity: you decide in advance which Gateway KID you trust, and compare every issuer with it. The dashboard shows the Gateway KID right after you create a gateway API key; if it does not show it, contact K-Block support. The dashboard itself normally knows which Gateway identity to trust, and uses this pin to judge every receipt:
| Verdict | Meaning |
|---|---|
| VALID | Every check passed, the pinned gateway issued the receipt and signed its TASK, PROPOSAL, and (for an executed call) EXECUTION and RESULT, and it is the receipt, thread, organization and action the page shows. |
| CONSISTENT | Every check passed, but the dashboard could not establish which Gateway identity to trust, so it cannot tell who issued the receipt. Compare the issuer KID with a Gateway KID you already trust (one K-Block gave you, or one you noted earlier when the dashboard showed it after you created a gateway API key). If the dashboard keeps showing this verdict, contact K-Block support. |
| NOT THIS GATEWAY | The bundle is consistent, but another identity issued it or signed its steps. Do not rely on it as a receipt of the Gateway your agents connect to. |
| MISMATCH | The bundle verifies, but it is a different receipt than the page shows. |
| INVALID | The receipt did not verify, or its SHA-256 differs from the hash recorded at issuance. |
Outside the dashboard, do the same comparison yourself: check that the report's issuer equals the Gateway KID you trust. Verify a receipt shows how.
Attestations
An attestation is a signed claim by a third party about a step. In K-Block Cloud, attestations come from K-Block-aware upstream servers: MCP servers registered with their own server identity (a server KID, see Tools and MCP servers).
For such a server, the Gateway sends the signed EXECUTION and its evidence along with the tool call. The server must answer with an attestation that claims executed about that execution, binding the input and the output. The Gateway verifies it before recording the result:
- A successful answer without an attestation: the execution is recorded as failed with
ATTESTATION_MISSING. (An error answer without one is recorded as a failure with the upstream's own error.) - An attestation that does not verify: recorded as failed with
ATTESTATION_INVALID. - A valid attestation: bound into the RESULT, and carried in the bundle.
In both failure cases the upstream may already have acted. Check its effect before you repeat the call.
An attestation counts only for a verifier that chooses to trust its attester. In the dashboard you pick attesters under Trust attestations from; with the SDK you pass trustedAttesters; with the Rust CLI you pass --trust <KID>. The Verification by the Cloud check trusts every K-Block-aware server currently registered in your organization. Ordinary MCP servers produce no attestations, and this release does not include a public package for building a K-Block-aware server.
Limits
- A bundle may hold at most 1,024 objects, 1,024 identity documents and 1,024 disclosures; the verifier refuses larger ones.
- The dashboard verifies uploaded files of up to 16 MiB in the browser.
- A Cloud bundle carries the call's arguments, the upstream URL and the tool's output in plain text, so anyone who holds the file can read them. Share bundles as you would share the action's details.