Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.truthlocks.com/llms.txt

Use this file to discover all available pages before exploring further.

What Are Receipts?

Receipts are signed, immutable records of discrete events — payments, security incidents, compliance checks, deliveries, and more. Unlike logs or audit trails, every receipt is:
  • Cryptographically signed with your issuer key (Ed25519 or ES256)
  • Anchored in the transparency log with a Merkle inclusion proof
  • Offline-verifiable via proof bundle export
  • Idempotent — the same event always produces the same receipt

Receipt types

Platform-defined receipt types are available to all tenants. Each type has a JSON Schema that the payload field is validated against before signing.
TypeUse Case
payment_receiptPayments, invoices, refunds
security_event_receiptAuth events, key rotations, anomalies
delivery_receiptDocument delivery, notifications
compliance_receiptKYC/AML checks, regulatory evidence
custom_receiptAny other event with open schema

Discovering available types

Call GET /v1/receipt-types to list every type your tenant can use, or GET /v1/receipt-types/{name} to fetch a single type and inspect its JSON Schema.
const types = await client.receipts.listTypes();

// Inspect a specific type's schema
const paymentType = await client.receipts.getType("payment_receipt");
console.log(paymentType.schema.required); // ["amount", "currency", "provider", ...]

Minting a receipt

1

Choose a receipt type

Call GET /v1/receipt-types to list available types and inspect the schema for required fields.
2

Build your payload

Construct the payload object matching the required fields for your receipt type. For payment_receipt, you need amount, currency, provider, provider_reference, and subject.
3

Mint via API

curl -X POST https://api.truthlocks.com/v1/receipts \
  -H "X-API-Key: tl_live_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "issuer_id": "<your-issuer-id>",
    "kid": "ed-key-2026",
    "alg": "Ed25519",
    "receipt_type": "payment_receipt",
    "subject": "customer@example.com",
    "payload": {
      "amount": 5000,
      "currency": "USD",
      "provider": "stripe",
      "provider_reference": "ch_3Px..."
    }
  }'
4

Store the receipt_id

The response includes the receipt_id and log.leaf_index. Store both for future verification.

SDK Examples

const receipt = await client.receipts.mint({
  issuer_id: 'your-issuer-id',
  kid: 'ed-key-2026',
  alg: 'Ed25519',
  receipt_type: 'payment_receipt',
  subject: 'customer@example.com',
  payload: {
    amount: 5000,
    currency: 'USD',
    provider: 'stripe',
    provider_reference: 'ch_3Px...'
  }
});

console.log(receipt.receipt_id, receipt.log.leaf_index);

Listing receipts

const receipts = await client.receipts.list({
  receipt_type: "payment_receipt",
  status: "active",
  limit: 20,
});

Retrieving a receipt

const receipt = await client.receipts.get("receipt-uuid");

Webhook events

Subscribe to receipt events by configuring a webhook endpoint in the console:
EventTriggered When
receipt.createdA receipt is successfully minted
receipt.revokedA receipt is revoked

Revoking a receipt

Revocation is permanent and recorded in the transparency log. Receipts with status revoked remain queryable and their revocation timestamp is included in proof bundles. You can include an optional reason to record why the receipt was revoked.
curl -X POST https://api.truthlocks.com/v1/receipts/{id}/revoke \
  -H "X-API-Key: tl_live_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Duplicate charge refunded"}'
await client.receipts.revoke("receipt-uuid", {
  reason: "Duplicate charge refunded",
});

Verifying a receipt

Use the verify endpoint to check a receipt’s cryptographic validity and current status. The API checks the signature, key status, and revocation state, then returns a verdict.
curl -X POST https://api.truthlocks.com/v1/receipts/verify \
  -H "X-API-Key: tl_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "receipt_id": "receipt-uuid" }'
const result = await client.receipts.verify("receipt-uuid");

if (result.verdict === "VALID") {
  console.log("Receipt is valid");
}

Verdicts

VerdictMeaning
VALIDSignature is valid, key is active, receipt is not revoked
REVOKEDReceipt has been explicitly revoked
INVALID_SIGNATURECryptographic signature verification failed
KEY_COMPROMISEDSigning key was marked compromised at or before issuance
KEY_INACTIVESigning key is no longer active
NOT_FOUNDReceipt not found for this tenant

Proof bundles

A proof bundle is a self-contained package for offline verification. It includes the signed receipt envelope, Merkle inclusion proof from the transparency log, and the issuer key snapshot at issuance time. After downloading a proof bundle, you can verify the receipt without making any further API calls.
const bundle = await client.receipts.getProofBundle("receipt-uuid");

console.log(bundle.bundle_version);          // "receipt-v1"
console.log(bundle.transparency_log);        // Merkle inclusion proof
See the proof bundle API reference for the full bundle structure.
You can download proof bundles directly from the console. Open a receipt’s detail page and click Download Proof Bundle. See downloading in the console.

Searching receipts

Search across your receipts using full-text search and faceted filters. The search index supports queries against payload content, and you can narrow results by type, status, date range, or indexed payload fields.
curl -X POST https://api.truthlocks.com/v1/receipts/search \
  -H "X-API-Key: tl_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "q": "stripe",
    "receipt_type": "payment_receipt",
    "from_date": "2026-01-01T00:00:00Z",
    "limit": 20
  }'
const results = await client.receipts.search({
  q: "stripe",
  receipt_type: "payment_receipt",
  from_date: "2026-01-01T00:00:00Z",
  limit: 20,
});

for (const r of results.items) {
  console.log(r.receipt_id, r.receipt_type);
}

Search filters

FieldTypeDescription
qstringFull-text search across payload content
receipt_typestringFilter by type name
statusstringactive, revoked, superseded, or redacted
issuer_idUUIDFilter by issuer
from_dateRFC 3339Start of date range
to_dateRFC 3339End of date range
index_keystringIndexed payload field name
index_valuestringValue to match for index_key
limitintegerMax results (1–100, default 20)
offsetintegerPagination offset
You can also search receipts from the console without writing code. Open Receipts in the sidebar and use the search bar and filter controls. See searching in the console.

Exporting receipts

Queue an asynchronous bulk export of receipts as JSON or CSV. The API returns immediately with a job ID. Poll the export status endpoint until status is complete, then download from the pre-signed URL.
// Start an export
const job = await client.receipts.export({
  format: "json",
  filters: {
    receipt_type: "payment_receipt",
    status: "active",
  },
});

console.log(job.id, job.status); // "pending"

// Poll for completion
const completed = await client.receipts.getExport(job.id);
if (completed.status === "complete") {
  console.log("Download:", completed.download_url);
}

// List all export jobs
const exports = await client.receipts.listExports();

Export status values

StatusMeaning
pendingQueued, not yet started
runningProcessing records
completeDone — download_url is available
failedError — see error_message
You can queue exports and track their progress from the console. Open Receipts, click Export, and choose CSV or JSON. A status banner tracks the job until the download is ready. See exporting in the console.

Redacting receipts

Redaction permanently removes PII from a receipt’s payload while preserving the cryptographic proof. The receipt’s signature, transparency log entry, and Merkle inclusion proof remain intact — only the payload_json is replaced with a redaction marker. Use this for GDPR right-to-erasure requests on receipts containing personal data.
await client.receipts.redact("receipt-uuid");
Redaction is permanent. The original payload cannot be restored. The cryptographic proof remains valid for audit purposes.
After redaction:
  • status changes to redacted
  • payload_json is replaced with {"redacted": true, "redacted_by": "tenant_request"}
  • A RECEIPT_REDACT event is anchored in the transparency log
  • All other fields (signature, log proof, receipt type) are preserved

Managing receipts in the console

You can manage the full receipts lifecycle from the console without writing any code. Open Receipts in the console sidebar to access the following features.

Searching receipts

The receipts list page includes a search bar and filters. Type a keyword to search across receipt payloads, or use the filter controls to narrow results by receipt type, status, issuer, or date range. Results update in real time as you refine your query.

Exporting receipts

Click Export from the receipts list to queue a bulk export as CSV or JSON. A status banner appears at the top of the page tracking the job through pending, running, and complete states. Once the export finishes, click the banner to download the file. You can also monitor export jobs from the API using GET /v1/receipt-exports/{id} — see export receipts.

Downloading a proof bundle

Open any receipt’s detail page and click Download Proof Bundle to save a self-contained verification package. The bundle includes the signed receipt envelope, Merkle inclusion proof, and issuer key snapshot — everything needed for offline verification.

Redacting a receipt

From any active receipt’s detail page, click Redact to permanently remove personally identifiable information from the payload. A confirmation dialog explains that redaction is irreversible before you proceed. Redaction is only available for receipts with active status. After redaction, the cryptographic proof and transparency log entry are preserved — only the payload content is removed. See redacting receipts for details on what changes.

Retention policy

Receipts are automatically cleaned up based on the retention policy set at mint time. A background worker sweeps expired receipts on a regular schedule. Set retention_policy when minting:
PolicyDurationDescription
standard2 yearsDefault. Suitable for most transactional receipts.
extended7 yearsFor compliance use cases requiring longer retention.
permanentNeverNever automatically deleted.
Receipts approaching their retention deadline can be redacted instead of deleted if you need to preserve the cryptographic proof while removing payload data.

Next steps

Proof bundle specification

Full structure and offline verification steps for proof bundles.

Receipts API reference

Complete API reference for minting, searching, exporting, and redacting receipts.

Webhooks

Subscribe to receipt events and process them in real time.

Issuance policies

Enforce approval workflows and constraints on receipt minting.