H-Seal: proof of what was asked and done
Anchor tamper-evident receipts of agent work on chain, and verify them later. How to notarize and anchor from the showroom, and how an agent anchors and verifies against the backend.
H-Seal is the proof product of the H-Series. It gives agents and services tamper-evident records of what was asked and what was done, anchored on Hedera Consensus Service. Any MCP server, REST API, or agent-to-agent interaction can anchor a receipt and later prove it against the chain. HCS is the source of truth; the local index is a derivable cache. Anchoring a receipt is a $0.05 x402 micropayment; anchoring a request envelope (the notary surface) is free.
What it does
- Receipts (paid). A signed envelope over a task: the service endpoint, request and response hashes, result status, timing, and the caller and provider identities. It goes on chain and the caller gets back a consensus timestamp to prove against.
- Request envelopes (free). The inbound counterpart, “what was asked”, anchored so it can be paired with a receipt’s “what was done” by a correlation id.
- Stateless verification.
POST /verifyre-checks a receipt’s signature against its on-chain anchor and stores nothing; a downloadable bundle verifies offline. - Selective disclosure. Prove a single field of a receipt against its commitment without revealing the rest, content-blind and pure crypto.
- Compliance export. Assemble an audit export (EU AI Act Art. 12 / 19) from the on-chain records, per caller or per receipt.
- Privacy for enterprise identity. OIDC-bridge callers are anchored as salted commitments, so the raw identity never touches the immutable ledger.
Using it from the showroom
The showroom is at h-series.xr-utilities.com/seal. It is for a person anchoring or checking a proof by hand.
- Sign in. Connect a wallet. Your signature is the identity binding on everything you anchor.
- Notarize a request (free). On the notarize page, record what an agent was asked to do; the request envelope is anchored on chain independent of any response.
- Anchor a receipt (paid). On the anchor page, fill in the receipt details (endpoint, request and response hashes, status, timing), sign the payload, pay the $0.05 fee in USDC, and the receipt is permanently anchored.
- Verify. On the verify page, look up a receipt by id and re-check its signature against the on-chain anchor, without trusting the operator.
- Review history. Browse anchored receipts and request envelopes, and follow a chain-of-custody trail that pairs the two.
Using it from an agent (the backend)
The backend is at h-seal.xr-utilities.ai. An agent anchors a receipt after doing work, and any party can verify it later. Reads are free and unauthenticated; anchoring needs a TIP-712 signature and an x402 payment. The receipt fields, the caller signature, and the xPayment settlement envelope are all fields of the JSON body (not HTTP headers):
POST https://h-seal.xr-utilities.ai/anchor
Content-Type: application/json
{
"taskId": "abc-123",
"serviceEndpoint": "https://example.com/tool",
"requestHash": "<hex>",
"responseHash": "<hex>",
"resultStatus": "success",
"startedAt": 1717000000000,
"completedAt": 1717000001000,
"latencyMs": 1000,
"callerIdentity": "hedera:mainnet:0.0.12345",
"providerIdentity": "hedera:mainnet:0.0.67890",
"receiptTopicId": "0.0.10500472",
"issuedAt": 1717000001000,
"signature": "<TIP-712 signature over the payload>",
"xPayment": "<x402 settlement envelope for $0.05>"
}
-> 200 { "id": "0.0.10500472/42", "consensusTimestamp": "1717000001.123456789" }
An anchor with no xPayment returns 402 Payment Required with the accepted rails; select one, settle the transfer, and resubmit with the xPayment field populated. Callers with no wallet can authorize with an OIDC token in the callerOidc field instead of signature when the identity bridge is enabled (it is live on the mainnet service). The free notary surface is POST /anchor-request. Reads include GET /receipts (filter by caller, provider, or task), GET /receipts/:id (with a read-only narrative overlay), GET /receipts/:id/bundle (a self-contained verification bundle), and the chain-of-custody trail at GET /receipts/trail/:correlationId. Verification is POST /verify; selective disclosure is under POST /disclose/*. Agents can reach the same capability through the H-Series MCP server.
For the full request schema, disclosure recipe, and payment rails, see the H-Seal reference.
Paying for a receipt
Anchoring a receipt is $0.05, settled per anchor over x402; there is no account balance and nothing to withdraw. Five stablecoin rails are live and paid-verified on mainnet, one per chain:
| Chain | Token | Network id |
|---|---|---|
| Hedera | USDC | hedera-mainnet |
| Base | USDC | eip155:8453 |
| XRPL | RLUSD | xrpl:0 |
| Solana | USDC | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp |
| Stellar | USDC | stellar:pubnet |
Payment is stablecoin-only by default; the native-coin rails (HBAR, ETH, XRP, SOL, XLM) are disabled. The exact per-chain amount and the treasury address are advertised in the 402 Payment Required challenge and in GET /config. The facilitator is never trusted: every settlement is re-verified on chain, bound to the caller, and locked single-use against replay. An allowlisted provider can anchor free by co-signing (sponsored anchoring, off by default).
Using the provider SDK
A service whose callers anchor receipts against it can co-sign a provider attestation with the @xr-utilities/h-seal-provider SDK instead of calling the API by hand, so a receipt is genuinely two-party (caller and provider) rather than one key self-attesting both sides. It is published on GitHub Packages, so add the scoped registry to .npmrc and authenticate with a GitHub token that has read:packages:
# .npmrc
@xr-utilities:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}
npm install @xr-utilities/h-seal-provider
Then attest inside your tool handler:
import { HSealProvider, ed25519Signer } from "@xr-utilities/h-seal-provider";
const provider = new HSealProvider({
identity: "hedera:mainnet:0.0.7777", // your provider account
signer: ed25519Signer(process.env.PROVIDER_KEY_RAW!), // 32-byte ed25519 seed
network: "mainnet",
});
// after you have the request and the response:
const attestation = await provider.attest({ request, response });
// hand `attestation` back to the caller, who attaches it to their receipt
attest hashes request and response with sha256 over canonical JSON; pass requestHash / responseHash yourself if you hash them elsewhere. For an EVM or Hedera-ECDSA provider, swap ed25519Signer for evmSigner.
How the identity binding works
A wallet caller signs the receipt payload (TIP-712 on Hedera and EVM, canonical JSON for Ed25519, XRPL, Solana, and Stellar) and is anchored as its public CAIP-10 identity. A caller authorized through the OIDC identity bridge is anchored as a salted commitment of its oidc:<issuer>:<subject> badge; the raw identity and the per-receipt salt stay off chain, so the ledger never carries the IdP domain or subject, and the holder can disclose the pair later to recompute the commitment.
Request envelopes and chain of custody
Besides receipts (“what was done”), H-Seal anchors request envelopes (“what was asked”) for free through a notarize step (POST /anchor-request). A receipt is paired to its request by a correlation id, so the two sides of one interaction can be read back together. GET /receipts/trail/:correlationId returns the full request-to-receipt trail. The showroom exposes free request anchoring on the /notarize page.
Listing and reading request envelopes
Anchored request envelopes are readable on their own, not only through a receipt’s trail. GET /requests lists them (public, no auth): pass ?caller=<CAIP-10> or ?recipient=<CAIP-10> to scope to one identity, or neither to get the recent feed, with ?limit= (1-100, default 50) and cursor pagination via ?cursor=. The response is { requests, nextCursor }; carry nextCursor back as cursor for the next page. To read a single envelope by its id, call GET /requests/:id where :id is the topic/sequence id (URL-encode the slash); it returns the stored record, or 404 if there is none.
GET https://h-seal.xr-utilities.ai/requests?caller=hedera:mainnet:0.0.12345&limit=50
-> 200 { "requests": [ ... ], "nextCursor": "1717000001.123456789" }
GET https://h-seal.xr-utilities.ai/requests/0.0.10500473%2F17
-> 200 { ...the request envelope record... }
Receipts for a specific request
When you have a request envelope and want the receipts that fulfil it (the “what was done” for one “what was asked”), call GET /receipts/by-request/:requestId. It is the join between the two independently anchored halves. :requestId is the request’s id (URL-encode the slash); the response is { requestId, request, receipts }, pairing the envelope with every receipt that references it, and 404 when neither exists. Use GET /receipts/trail/:correlationId instead when you want the whole multi-hop chain of custody rather than a single request’s receipts.
GET https://h-seal.xr-utilities.ai/receipts/by-request/0.0.10500473%2F17
-> 200 { "requestId": "0.0.10500473/17", "request": { ... }, "receipts": [ ... ] }
Your receipt history report
GET /report is a filterable, indexed view of one caller’s anchored receipts: the full history rather than a bounded on-chain replay. It is public with the same visibility as GET /receipts?caller= (a caller’s receipts are already public), so no signature is needed. Pass the required ?caller=<CAIP-10>, then narrow with ?result= (success | error | timeout | partial), a ?from=/?to= millisecond time window, ?limit= (1-1000, default 200), and ?before= for cursor pagination. The response is { caller, events, nextCursor }; carry nextCursor back as before to page.
GET https://h-seal.xr-utilities.ai/report?caller=hedera:mainnet:0.0.12345&result=error&limit=200
-> 200 { "caller": "hedera:mainnet:0.0.12345", "events": [ ... ], "nextCursor": "1717000001.123456789" }
Discovering config and rails
GET /config is a public read that advertises everything a caller needs to anchor without guessing: the schema_version, the endpoint map, the Hedera network and receiptTopicId, whether request-envelope anchoring is enabled, the current pricing.anchoringUsdCents, and the accepts block (the per-chain amount and treasury address for each accepted stablecoin rail, the same content the 402 challenge carries). It also publishes the tip712 domain and typed-data definitions you sign against (EIP-712 for EVM and Hedera-ECDSA, sha256 over canonical JSON for Hedera-Ed25519, XRPL, and Solana, with a 300-second freshness window), and whether the OIDC identity bridge is enabled with its expected audience.
GET https://h-seal.xr-utilities.ai/config
-> 200 {
"schema_version": "0.1.0",
"endpoints": { "anchor": "/anchor", "receipts": "/receipts", ... },
"network": "mainnet",
"receiptTopicId": "0.0.10500472",
"pricing": { "anchoringUsdCents": 5, "testMode": false },
"accepts": [ ...per-rail amount + treasury... ],
"tip712": { "domain": { ... }, "types": { ... }, "freshnessSeconds": 300 },
"identityBridge": { "enabled": true, "audience": "..." }
}
Selective disclosure
Reveal a single field of a receipt against its commitment without exposing the rest. A receipt commits to its fields as a sha256 Merkle tree (per-field salts, canonical JSON leaves, sorted-pair / commutative hashing so positions are not needed), and a disclosure hands a verifier one field plus a Merkle proof to the committed root. The verify is content-blind and pure crypto (POST /disclose/verify, POST /disclose/verify-field), and GET /disclose/recipe documents the exact commitment and Merkle formulas so a third party can recompute and verify offline.
Compliance export
GET /compliance assembles an audit export aligned to EU AI Act Article 12 / 19 record-keeping, built from the anchored receipts (GET /compliance/receipt/:id for a single receipt). It is a read over on-chain records, so an auditor can reconstruct it independently.
Verification bundle
GET /receipts/:id/bundle returns a self-contained bundle (the receipt, the on-chain proof, and the Hedera mirror reference) so an auditor can verify a receipt offline against any Hedera mirror, without trusting or reaching the H-Seal service.
XRPL users can sign and pay through Xaman: the POST /xaman/sign, POST /xaman/pay, and GET /xaman/result/:uuid endpoints drive a Xaman wallet binding and payment (config-gated).
Where to go next
- Anchor your first receipt from the Console, where every paid run anchors an H-Seal receipt automatically.
- See how proof closes the lifecycle in Start here.
- Related: H-Index (a listing advertises H-Seal anchoring via
slaReceiptRef), H-Grant (a gated release can anchor a receipt), and H-Relay (a delivery anchors a request envelope through H-Seal).
Frequently asked
What is the difference between a receipt and a request envelope? +
A request envelope is what was asked (the inbound side); a receipt is what was done (the outbound side). Anchoring a request envelope is free (the notary surface); anchoring a receipt is a $0.05 paid action. Pairing them by correlation id gives a two-sided, tamper-evident record of an interaction.
Is the request or response content written on chain? +
No. H-Seal anchors hashes (requestHash, responseHash) and metadata, never the raw payloads. You keep the content; the chain holds a commitment you can prove against later.
Can I verify a receipt without trusting H-Seal? +
Yes. POST /verify is a stateless re-check of the signature against the on-chain anchor; it stores nothing. You can also download a self-contained verification bundle and check it offline against any Hedera mirror.
Do I have to reveal who the agent was? +
A wallet caller is anchored as its public CAIP-10 identity. A caller authorized through the OIDC identity bridge is anchored as a salted commitment of its identity, never the raw issuer and subject, so an enterprise identity stays off chain and GDPR erasure remains possible. The holder can later disclose the pair to recompute the commitment.
What can I prove with a receipt in a dispute? +
That a specific caller and provider recorded a task with a given request hash, response hash, result status, and timing, at a consensus timestamp no party can backdate. It is evidence for an SLA, a billing dispute, or a compliance audit (EU AI Act Art. 12 / 19 export included).
Which chains and tokens can I pay with? +
Five stablecoin rails, one per chain: USDC on Hedera, USDC on Base (eip155:8453), RLUSD on XRPL (xrpl:0), USDC on Solana, and USDC on Stellar (stellar:pubnet). Payment is stablecoin-only by default; the native-coin rails (HBAR, ETH, XRP, SOL, XLM) are disabled. The exact amount and treasury for each rail is advertised in the 402 challenge and in GET /config.
Do I keep a balance or need to withdraw funds from H-Seal? +
No. H-Seal holds no custody and keeps no per-user balance. Each receipt is a one-off $0.05 x402 payment settled directly to the treasury on the chain you pay from; there is nothing to top up and nothing to withdraw. Request-envelope anchoring is free. (A balance you fund and later withdraw is an H-Agent concept, not H-Seal.)
Can a provider anchor a receipt for free? +
Yes, if the operator has allowlisted that provider's identity for sponsored anchoring. An allowlisted provider's valid co-signature stands in for the x402 payment, verified on chain and locked single-use. The allowlist is empty by default, so out of the box every receipt pays.