SpoolisDocs

Spoolis docs

Verify a receipt

The Outcome Receipt is the public, portable economic artifact. Verify its authenticity with no Spoolis account or API call, and pin the trust set when verification must work offline.

Verification example

In the canonical recipe, Spoolis verifies 100 enrichment records at $1.00 per accepted record, accepts 98, rejects 2 with reasons, and signs an Outcome Receipt for $98.00 earned. Verify that receipt before the payment stack acts on the earned amount.

verify.mjs
import { verifyOutcomeReceipt } from '@spoolis/receipt-verifier'

const keys = await fetch('https://spoolis.com/.well-known/spoolis-keys.json').then(r => r.json())
const expectedEnvironment = 'production'
const trustSet = keys.receipts[expectedEnvironment]
if (!trustSet) throw new Error('No receipt key is published for this environment')

const result = await verifyOutcomeReceipt(receipt, { trustSet, environment: expectedEnvironment })
console.log(result.valid)
console.log(receipt.amounts.earned)

Sandbox and demo receipts use expectedEnvironment = 'demo'. Install with npm install @spoolis/receipt-verifier. The package has zero runtime dependencies and uses WebCrypto.

Pin trust material for offline use

Outcome Receipts use schema spoolis/outcome-receipt@1. Receipt keys are published at https://spoolis.com/.well-known/spoolis-keys.json. Save and review the receipt entries your application trusts, then pass that array as trustSet. The JSON Schema is published at https://spoolis.com/schema/outcome-receipt-v1.schema.json.

Offline signatures and optional online status

Signature validity is offline and permanent when the receipt and pinned trust set are available. It does not depend on Spoolis uptime. A valid Ed25519 signature proves the receipt is genuine and unaltered. It does not prove every underlying check is reproducible or that the evidence reflects real-world truth.

strict-status.mjs
import { fetchReceiptStatus, verifyOutcomeReceipt } from '@spoolis/receipt-verifier'

const keys = await fetch('https://spoolis.com/.well-known/spoolis-keys.json').then(r => r.json())
const expectedEnvironment = 'production'
const trustSet = keys.receipts[expectedEnvironment]
if (!trustSet) throw new Error('No receipt key is published for this environment')

const offline = await verifyOutcomeReceipt(receipt, { trustSet, environment: expectedEnvironment })
if (!offline.valid) throw new Error(offline.reasons.join(', '))

const statusSource = await fetchReceiptStatus('https://spoolis.com', receipt.id)
const result = await verifyOutcomeReceipt(receipt, { trustSet, environment: expectedEnvironment, statusSource })

The status call is optional and adds operator-managed correction, revocation, and advisory state after offline authentication. Offline signature verification remains sufficient, so an unreachable status endpoint never makes a genuine receipt read as invalid. GET /api/receipts/{id}/status returns {receipt_id, status, advisories, checked_at} where status is active, corrected, or revoked. An authorized operator supplies the advisory reason for corrected or revoked. Either state makes verifier policy return invalid without changing offline signature authenticity. The response does not identify a replacement receipt, and no payment is automatically reversed. In the command-line tool, spoolis verify receipt.json --strict adds this online check and fails only on a corrected or revoked status, never when the endpoint cannot be reached.

No account required

No Spoolis account is required for offline verification or the public status endpoint. A valid result does not claim that payment was authorized, captured, or settled.

Authenticity is not pay-once enforcement

A Spoolis Outcome Receipt proves the agreed outcome happened and that the receipt is authentic. It does not by itself prove the receipt has not already been used to release payment.

Any system that releases money on a receipt must enforce pay-once itself. It must record each receipt id it has acted on and refuse to act on the same id twice.

Spoolis offers an optional online consumed-status check and an optional hard execute_by rejection for consumers that want them. Offline signature verification remains sufficient for authenticity. Spoolis does not prevent double-spend on the payer's behalf.

Verify a receipt · Spoolis