SpoolisDocs

Spoolis docs

Outcome Receipt specification

The Outcome Receipt is Spoolis's signed answer to: what happened, what passed, and what was earned? It is not payment authority, and Spoolis does not hold or move funds.

Field reference

Most integrators care about these five fields

  • agreement: Which accepted Spool and agreement version this receipt covers.
  • condition_results: What each agreed condition required and how it resolved.
  • result: The overall pass, partial, fail, or uncertain outcome.
  • units: How many units were submitted, accepted, and rejected.
  • amounts.earned: The amount produced by the agreed economic rule.

The full field reference follows for completeness.

FieldMeaning
schemaThe versioned identifier. Version 1 is spoolis/outcome-receipt@1.
environmentproduction or demo. The account-free sandbox issues receipts in the demo environment. A verifier must require the environment it expects.
idA content-derived identifier. It is ocr_ plus the first 24 hex characters of the canonical unsigned body digest.
agreementThe Spool ID, accepted agreement version, and SHA-256 agreement hash bound into the receipt.
verificationPlan, compiler, evidence-policy, run, digest, and aggregation-policy identifiers used for this outcome.
evidence_rootA SHA-256 digest binding the evidence set used by the run.
condition_resultsOne row per condition. Each row records requirement, result, execution method, verifier, evidence references, optional provenance, optional confirmer, and optional reason.
resultThe aggregate pass, partial, fail, or uncertain result.
unitsOptional unitized outcome: total, accepted, rejected, earning rule, rejection summary, and unit-results digest.
amountsDecimal-string earned amount, optional committed amount, asset, and decimal precision. Earned is what the economic rule produced. Committed is the agreed maximum when present.
actorsPayer and provider subject references, kinds, and optional alternate identifiers.
issued_at and execute_byIssue time and an optional deadline for acting on the receipt. Passing execute_by does not invalidate the signature.
nonce, series, and supersedesUniqueness, optional recurring-series context, and optional correction or appeal-reversal linkage.
signing_key_id, signature, and algorithmThe SHA-256 ID of the Ed25519 public key, the base64 signature, and the fixed algorithm value Ed25519.

See the machine-readable JSON Schema for required properties, formats, and enum values.

Condition results

requirement is mandatory or optional. result is pass, partial, fail, uncertain, not_evaluated, or not_applicable. Evidence provenance, when present, records source and capture facts. It is not a trust score. Missing provenance means unknown origin. Schema support for a method does not mean its executor is live. Use the single method-status table when choosing a request value.

MethodStatusMeaning
Live today
deterministicLiveFixed code and inputs produce a fixed evaluation. Durable evidence may support later reproduction; time-bound network observations may not.
human_confirmedLiveAn authorized person supplied the confirmation. Spoolis recorded it and applied the agreed rule.
Reserved / planned
external_toolReserved, not liveReserved for a named external system. No planner or executor emits it today.
ai_assistedPlanned, not livePlanned for grounded model evaluation. The current executor returns uncertain instead of emitting this method.

Earned and committed amounts

The schema stores decimal strings in amounts.earned and optional amounts.committed. API views may also expose earned_amount_cents and committed_amount_cents. Those cent fields are projections, not Outcome Receipt v1 field names. Earned cannot exceed committed when committed is present.

Ed25519 signature model

Spoolis canonicalizes the unsigned receipt, derives the content-based receipt ID, and signs the canonical payload with Ed25519. The key ID is the SHA-256 digest of the DER-encoded public key. A valid signature proves that the receipt came from a trusted key and was not altered. It does not prove the evidence was true, make every check reproducible, authorize payment, or establish settlement. Pin keys from the published trust set. An environment with no configured signing key is omitted rather than given a substitute key.

Trust boundary

A valid signature proves the receipt is authentic and unaltered. It does not prove the underlying evidence was true or authorize payment.

Receipt status

Offline signature verification is live and does not depend on Spoolis uptime. The optional public endpoint GET /api/receipts/{id}/status adds online status after that offline check. It returns only receipt_id, status, advisories, and checked_at. No account or API key is required.

active, corrected, and revoked are live online states. An authorized operator manages corrected and revoked overrides and supplies the advisory reason. Either override makes verifier policy return invalid, but it does not change the receipt's offline signature authenticity. The response does not identify a replacement receipt. No payment is automatically reversed; reconciliation remains the consumer's policy.

Worked 100-record example

A buyer pays for 100 enrichment records at $1.00 per accepted record. Spoolis verifies the delivery. Ninety-eight records are accepted and two are rejected with reasons, so the signed Outcome Receipt records $98.00 earned from $100.00 committed. Spoolis determines earned value and signs the Outcome Receipt. A wallet, marketplace, payment system, or configured integration may verify and consume it, then act under its own authorization and settlement policy. The placeholders below identify run-specific values.

100 submitted · 98 accepted · 2 rejected · $98.00 earned

outcome-receipt.json
{
  "schema": "spoolis/outcome-receipt@1",
  "environment": "demo",
  "id": "ocr_<content-derived digest>",
  "agreement": { "spool_id": "spl_<demo id>", "agreement_version": 1, "agreement_hash": "<64 hex>" },
  "verification": {
    "plan_version": "vp_1", "plan_hash": "<64 hex>", "compiler_version": "compiler@1",
    "evidence_policy_version": "ep_1", "run_id": "vr_<run id>", "run_digest": "<64 hex>",
    "aggregation_policy": { "policy_id": "all_mandatory_pass", "policy_version": "1" }
  },
  "evidence_root": "<64 hex>",
  "condition_results": [
    { "condition_id": "cond_<count>", "requirement": "mandatory", "result": "pass", "method": "deterministic", "verifier_id": "rows.count", "verifier_version": "1", "evidence_refs": ["evd_<count>"] },
    { "condition_id": "cond_<fields>", "requirement": "mandatory", "result": "partial", "method": "deterministic", "verifier_id": "nulls.absent", "verifier_version": "1", "evidence_refs": ["evd_<fields>"], "reason": "98 of 100 records passed." }
  ],
  "result": "partial",
  "units": { "total": 100, "accepted": 98, "rejected": 2, "earning_rule": { "type": "per_unit", "unit_amount": "1.00" }, "rejection_summary": [{ "reason": "nulls.absent", "count": 2 }], "unit_results_digest": "<64 hex>" },
  "amounts": { "earned": "98.00", "committed": "100.00", "asset": "USD", "decimals": 2 },
  "actors": { "payer": { "subject": "spoolis:<payer>", "kind": "human" }, "provider": { "subject": "spoolis:<provider>", "kind": "human" } },
  "issued_at": "<ISO 8601 time>", "nonce": "<unique nonce>",
  "signing_key_id": "<64 hex>", "signature": "<base64 Ed25519 signature>", "algorithm": "Ed25519"
}

Verify against the published key

Install @spoolis/receipt-verifier, then run this with a production receipt. For production, review and pin the accepted trust entry instead of fetching it during every verification. Sandbox consumers must change the expected environment to demo.

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

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

const check = await verifyOutcomeReceipt(receipt, {
  trustSet,
  environment: expectedEnvironment,
})
if (!check.valid) throw new Error(check.reasons.join(', '))
console.log({ authentic: true, earned: receipt.amounts.earned })

Read offline verification and status checks for corrections, revocations, and advisories.

Run the 30-second sandbox walk →

Outcome Receipt specification · Spoolis