New:Microsoft Teams Notifications Are Now Available in Socket.Learn more →
Get Started

@spoolis/receipt-verifier

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@spoolis/receipt-verifier

Verify signed Spoolis Outcome Receipts offline. Spoolis is Outcome infrastructure for machine commerce.

Source
npmnpm
Version
0.1.3
Version published
Weekly downloads
16
-55.56%
Maintainers
1
Weekly downloads
 
Created
Source

Verify a Spoolis outcome receipt

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

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

Install

npm install @spoolis/receipt-verifier

No Spoolis account is required to verify a receipt. The package has no runtime dependencies and uses WebCrypto in Node 20 or later, browsers, workers, and agent sandboxes.

Require an outcome

requireOutcome verifies the full receipt before applying the consumer's policy. This example acts only on a valid Outcome with a passing result, at least 100 accepted units, and fully satisfied evidence requirements:

import { requireOutcome } from '@spoolis/receipt-verifier'

const required = await requireOutcome(receipt, {
  minimum_status: 'pass',
  min_accepted_units: 100,
  evidence_requirements: 'satisfied',
}, { trustSet })

if (!required.ok) throw new Error(required.reasons.join(', '))

The optional third argument accepts the same verification options as verifyOutcomeReceipt, including trustSet, environment, statusSource, and now. The issuer policy matches the verified receipt.signing_key_id. Spoolis supplies the signed fact; the consumer decides the rule and whether to act. Forward supersession cannot be determined from an offline receipt, so consumers that need current correction or revocation state should provide the hosted status response through statusSource.

Trust material

Spoolis publishes receipt trust material at https://spoolis.com/.well-known/spoolis-keys.json. Pin the receipt entries you accept and pass that array as trustSet for offline verification. fetchTrustSet(url, environment) is an online convenience that returns only the selected environment's receipt trust entries. The environment defaults to production; pass demo explicitly for sandbox receipts. Fetching at verification time is not required or preferred for a pinned deployment.

Offline verification and online status

Signature validity is offline and permanent when a verifier has the receipt and a pinned trust set. It does not depend on Spoolis uptime. Online status is optional:

import { fetchReceiptStatus, verifyOutcomeReceipt } from '@spoolis/receipt-verifier'

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

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

GET /api/receipts/{id}/status currently returns active for a stored receipt. The response reserves corrected, revoked, advisory entries, and superseding_receipt_id for future workflows. Without a status source, verification stays offline-only and includes the status_source_unavailable advisory. A receipt can remain cryptographically valid even if a future online status marks it superseded.

A later resolution never mutates the original receipt. It produces a new signed Outcome that supersedes it. The supersedes block identifies the original receipt and may use dispute_resolution when agreed dispute handling produced the successor.

Reasons

ReasonMeaning
unknown_schemaThe receipt schema version is not supported.
environment_mismatchThe receipt environment does not match the requested environment.
invalid_evidence_rootThe evidence root is not a lowercase SHA-256 digest.
invalid_run_digestThe verification run digest is malformed.
invalid_agreement_hashThe agreement hash is malformed.
receipt_id_mismatchThe content-derived receipt ID does not match the payload.
earned_amount_mismatchPer-unit arithmetic does not equal the earned amount.
aggregation_inconsistentA recognized aggregation policy does not produce the stated result.
correctedThe online status source marks this receipt corrected.
revokedThe online status source marks this receipt revoked.
untrusted_signing_keyNo recognized, non-revoked trust entry matches the signing key.
signing_key_id_mismatchThe trust entry public key does not hash to the signing key ID.
invalid_signatureThe Ed25519 signature does not verify.
malformed_receiptA required structure or value is malformed.

Advisories

AdvisoryMeaning
unknown_aggregation_policyThe verifier does not know how to recompute this policy.
past_execute_byThe optional execution deadline has passed. This does not expire the receipt.
status_source_unavailableNo corrected or revoked status source was supplied.
key_retiringThe receipt uses a trusted key marked as retiring or retired.

Security model

A valid result proves that the receipt payload was signed by a key in the supplied trust set. It proves that the content-derived ID matches the signed content. It checks digest formats, recognized aggregation rules, and unit arithmetic. It also enforces the selected production or demo environment. Verification does not prove that referenced evidence is true or available. It does not resolve actor identities. It does not grant payment authority. It does not prove authorization, capture, settlement, or finality on any payment rail. Consumers must enforce their own authorization and consume-once rules before taking economic action. Pin trust material through a trusted channel and review key rotation policy. Use an online status source when corrected or revoked state matters.

Golden vectors

The conformance corpus is maintained at tests/fixtures/receipt-vectors/ in the Spoolis repository. The package test runs every declared vector against the standalone implementation.

Keywords

outcome receipt

FAQs

Package last updated on 31 Aug 2026

Related posts