STEAK with POTATOES
Paying for a digital item on a private overlay used to leave a gap: the network could confirm your transaction went through, but nothing told you whether you were actually entitled to receive the thing you paid for, like a song's decryption key, or gave you a safe way to get it if the first delivery attempt failed. Buyers had no durable, signed promise of the terms before they paid, and sellers had no standard way to prove a release was properly authorized rather than just handed over informally.
Reference for an AI
Everything an assistant needs to answer questions about BRC-196 accurately, including what it depends on.
Summary
- Why
- Buyers need proof they are entitled to a purchased digital result, and sellers need a standard, verifiable way to release that result only once payment is properly admitted and the agreed release conditions are met.
- What
- BRC-196 is an overlay purchase profile that pairs the existing transaction-admission receipt (STEAK) with a new signed private-result packet (POTATOES) released only after agreed conditions are verified.
- How
- A client calls /overlay/v1/purchases/prepare to lock in signed terms, submits the funded transaction to /overlay/v1/purchases/submit, and receives a PurchaseEnvelope that carries STEAK once the transaction is admitted and POTATOES (a signed secret) once delivery succeeds, with recovery available until recoveryUntil.
What this lets you do
- Get a signed, frozen set of purchase terms before paying
- Submit a purchase transaction and poll for admission plus delivery status
- Receive a secret (like a decryption key) only after the purchase is confirmed
- Recover a delivery if the first attempt failed, using a recovery deadline
- Verify release evidence (local, processor-signed or mined) against the agreed policy
Written by claude-sonnet-5 from the specification text. Where the two differ, the original is correct.
The specification
Abstract and status
An overlay submit already returns STEAK, the Submitted Transaction Execution AcKnowledgment. A private overlay can additionally release a result whose authorization follows from that admitted transaction. For a music purchase, the result is the decryption capability needed to play the purchased song.
POTATOES means Private Overlay Topical Admittance-linked Transactional Outward Evidentiary Secret. The analogy is deliberate: you get potatoes back with your steak on private-overlay submits. The useful distinction is that STEAK describes topical processing, while POTATOES is a separately authorized private result. Neither is a mining-finality certificate.
This proposed profile is negotiated through BRC-194. It uses BRC-192 encodings, BRC-195 private stores/trusted contexts, and BRC-193 errors. It does not add fields to the legacy STEAK object, whose validators and callers must continue to work unchanged.
1. Preparation before spending
A client first uses free catalogue lookup to select a seller and listing. Before constructing a purchase, it obtains a durable promise of the applicable release/recovery terms from that seller. POST /overlay/v1/purchases/prepare, selected with #steak-potatoes-v1, accepts:
type Prepare = {
version: 1; requestId: string; topic: string;
listing: Outpoint; assetId: Hex32; termsDigest: Hex32;
recipient: Identity; request: Bytes
}
type PurchaseTerms = {
version: 1; acquisitionId: Hex32; requestDigest: Hex32;
seller: Identity; recipient: Identity; topic: string;
listing: Outpoint; assetId: Hex32; termsDigest: Hex32;
domainProfile: string; domainEvidence: { schema:string; bytes:Bytes };
releasePolicy: ReleasePolicy;
purchaseUntil: U64; recoveryUntil: U64
}
type SignedPurchaseTerms = { body:PurchaseTerms; signature:Bytes }
type ReleasePolicy =
| { kind: 'local-admission' }
| { kind: 'processor-accepted'; identity: Identity; policy: string }
| { kind: 'mined'; confirmations: U32 }
The caller equals recipient. Request IDs use BRC-193's constraints. The acquisition ID is digest("purchase", {chain,seller,recipient,topic,requestId}), and request digest is digest("purchase-request", Prepare). The result is a signed packet of type purchase-terms, signed by seller. It freezes private readiness and request semantics before funding; identical retries return the original complete signed terms, while changed bodies conflict. domainProfile names an installed purchase validator. The purchase-domain identifier for BRC-197 is https://bsv.brc.dev/tokens/0197#listing-purchase-v1; it uses the concrete executable https://bsv.brc.dev/tokens/0197#revenue-listing-v1 family defined there. Selecting the domain requires exact family-byte, Script and lineage verification, not only a named predicate. A mined policy requires a positive confirmation count. Processor acceptance needs attributable evidence for the exact transaction under the named policy; a broadcast acknowledgement alone is insufficient.
recoveryUntil >= purchaseUntil + 86400. The buyer MUST NOT begin a new purchase at or after purchaseUntil. The seller retains the original obligation through recoveryUntil. As in BRC-195, valid first delivery during recovery is accepted without pretending raw transaction bytes contain a reliable creation time. Preparation does not reserve an on-chain UTXO against competing buyers and does not charge an HTTP fee.
2. Submission and response envelope
POST /overlay/v1/purchases/submit accepts:
type PurchaseSubmit = {
version: 1; acquisitionId: Hex32; txid: Hex32; beef: Bytes
}
type PurchaseResult = {
version: 1; acquisitionId: Hex32; txid?: Hex32;
purchaseCommitment?: Hex32;
status: 'prepared' | 'admission-pending' | 'admission-rejected'
| 'admitted-delivery-pending' | 'delivery-failed' | 'delivered' | 'expired';
steak?: STEAK; potatoes?: SignedPotatoes; recoveryUntil: U64;
decision?: { reason:string; policy:ReleasePolicy; evidence:Bytes;
decidedAt:U64; globalOutcome:'unknown' };
}
type PotatoesBody = {
version: 1; acquisitionId: Hex32; requestDigest: Hex32;
seller: Identity; recipient: Identity; topic: string;
txid: Hex32; purchaseCommitment?: Hex32;
assetId: Hex32; termsDigest: Hex32;
releasePolicy: ReleasePolicy;
evidenceDigest: Hex32; schema: string; secret: Bytes;
issuedAt: U64; recoveryUntil: U64
}
type SignedPotatoes = { body: PotatoesBody; signature: Bytes }
type ReleaseEvidence = {
chain: Chain; txid: Hex32; policy: ReleasePolicy; acceptedAt: U64;
processorEvidence?: Bytes;
blockEvidence?: {
blockHash: Hex32; height: U64; tipHash: Hex32; tipHeight: U64; beef: Bytes;
contextId:string; chainPolicyDigest:Hex32
}
}
type PurchaseEnvelope = {
result: PurchaseResult; releaseEvidence?: ReleaseEvidence;
currentAlias?: { txid: Hex32; beef: Bytes }
}
STEAK is the existing unmodified BRC-22 object. A response has no STEAK until durable topical processing succeeds; admitted/delivered responses MUST include it. Only delivered includes POTATOES. evidenceDigest commits to ReleaseEvidence using digest("release-evidence", body). processorEvidence contains the policy-defined signed evidence bytes; fields inconsistent with the selected policy are forbidden. Submit and recovery return PurchaseEnvelope. Missing required evidence leaves delivery pending. Delivered MUST include the exact release evidence committed by POTATOES; its policy and txid match the result's historical release transaction. Local admission records acceptedAt and has neither optional field. Mined evidence must verify inclusion and ancestry to the stated tip, with tipHeight - height + 1 at least the selected confirmations; arithmetic, chain identity and block hashes are checked rather than trusting displayed heights.
For BRC-197, purchaseCommitment is the full 32-byte SHA256d of the exact authenticated SIGHASH_ALL|FORKID (0x41) preimage for the listing input at index zero, before reduction modulo the curve order. This preimage commits to transaction version, every ordered input outpoint and sequence, the listing outpoint/amount/scriptCode, every output, locktime and hash type. It does not commit to unlocking Scripts. Derive it from the independently verified complete transaction; never trust a supplied digest or the reduced Script scalar z as the identity. It is mandatory in every post-reservation PurchaseResult and POTATOES for this domain. The txid remains the identifier of the exact raw transaction selected for admission and signed release evidence.
POTATOES uses packet signature type potatoes, signed by seller. The secret bytes follow the named installed schema, which MUST define recipient binding, content/key commitment and any licensing evidence. Raw secret schemas require BRC-103/104 over HTTPS; a schema may instead use BRC-78 encryption to recipient. A signature is evidence of what a seller returned, not proof that the key decrypts the intended content. The client verifies that relationship before calling the acquisition usable.
The topic verifies exact purchase conditions and the acquisition/request/recipient binding in the transaction, using the frozen preparation terms. Merely admitting some output in the topic is insufficient. A valid public txid or a copied purchase transaction is not a bearer coupon: only the recorded recipient can recover the result. This profile does not permit a second BRC-105 song charge at submit or recovery.
3. Atomicity and recovery
Before external admission work, persist a unique association of acquisition ID, recipient, frozen terms and the domain-defined immutable candidate identity, plus the exact submitted txid. For BRC-197 that identity is the purchase commitment below; another installed domain must define its own independently verifiable equivalence rule or pin the exact txid. One acquisition has one authorized economic spend and at most one private release. The public admission, protected release intent, saved STEAK and replay fence MUST either commit atomically or have a staged durable coordinator that can establish those facts without re-admitting or double-counting the purchase. A transient in-memory callback or a plugin error logged after STEAK is not sufficient.
Only after durable admission and the chosen release policy are satisfied may the result be marked delivered. Failures after public admission yield admitted-delivery-pending, preserving saved STEAK and a recoverable private intent. Repeated submissions merge valid proof variants for the same transaction. For BRC-197, a different txid with the same purchase commitment is an equivalent spend variant only after its complete raw transaction, every input, outputs, receipt and domain lineage independently verify; a claim that it is mined additionally needs selected-chain evidence. Such a variant joins the same acquisition without a second release or charge. Two variants cannot both be mined on one chain because they consume the same ordered prevouts. Public GASP replay and ordinary reindexing MUST NOT invoke private release. Private-byte absence on a replica is delivery-pending/unavailable, not an excuse to charge again.
If the exact prepared purchase was already publicly admitted through another path, an authorized recipient submission MAY establish the private association from the retained verified admission and preparation records, without admitting or accounting for it twice. The same binding and release checks still apply. An empty newly-admitted list in a duplicate STEAK is not proof that the earlier purchase failed. Conversely, discovering a public transaction in history cannot create a preparation or authorize its caller retroactively.
POST /overlay/v1/purchases/recover accepts {version:1, acquisitionId:Hex32} and returns the same wrapper to the authenticated recipient without payment. If admission has not begun, return prepared (or expired at the unpinned recovery deadline), with no claim that a submitted transaction failed. Wrong recipients receive the same not-found behavior. The provider retains the result or sufficient protected material to reproduce it through recoveryUntil. Equivalent regenerated encrypted envelopes are allowed, but asset, rights, recipient, domain-defined candidate identity, historical signed release evidence and secret capability cannot change. For BRC-197 the candidate identity is the purchase commitment. For BRC-197, currentAlias may report a different fully verified transaction from the provider's selected chain view; its BEEF must target its exact txid and independently prove the same purchase commitment, receipt, outputs and lineage. The client checks its own chain view before treating it as current. This field is never signed release evidence and does not rewrite an already signed release, settlement or License. Its absence does not invalidate historical recovery; the recipient may submit a newly discovered valid alias through /purchases/submit.
When two listeners spend the same listing, at most one chain spend can survive. A client MUST resolve its first authorized candidate identity and every known txid alias before authorizing another purchase/payment. A rejection containing only “input spent” does not identify the winner. Check exact txid, evidence and the provider's recovery state; uncertainty remains pending. A retained local rejection permits discussing a replacement; it does not prove that the first signed transaction cannot later settle. Any replacement uses a new request ID and renewed explicit buyer authorization acknowledging unresolved or later-settlement risk. An unconstructed prepared request can be abandoned after its private-fulfillment reservation expires; this is never an exclusive reservation of the UTXO.
An unconfirmed admission or processor acceptance can later conflict or be reorganized. A key already delivered cannot be recalled. The seller chooses and discloses this risk through releasePolicy; a client must not display local admission as mined settlement. Reassess chain evidence and public projections without deleting the acquisition history. The covenant constrains payment; it cannot force an off-chain seller to deliver a key, so this is not an atomic fair-exchange claim.
4. Adapters, compatibility and conformance
Use an optional admission-result companion around the existing engine and an explicit selected-host client API. Do not append potatoes to an ordinary STEAK, silently change /submit response parsing, or drop per-host private results inside an aggregate broadcaster. Legacy clients remain on legacy routes. Private publication and recovery obligations from BRC-195 remain necessary even when payment moves from HTTP lookup to a covenant.
Required tests cover preparation replay; body conflict; no-key readiness rejection; exact recipient/acquisition binding; rejection before admission; crash before and after admission commit; already-public admission with an empty duplicate STEAK; release-policy delay; lost response; repeated evidence variants; a distinct valid txid with the same purchase commitment; rejection of a different commitment under a pinned acquisition; a mined variant discovered after local release; unauthorized recovery; GASP replay with no secret release; selected-host routing; races with an uncertain earlier purchase; wrong decryption capability; and a later chain conflict. A real reference implementation must demonstrate both immediate local release and a delayed release policy without fabricating confirmation evidence.
5. Reservation, release and recovery details
Preparation validates selected seller/topic/profile/chain, recipient=caller, exact listing outpoint, asset/terms/request schema, domainEvidence and private result capacity before committing a promise. For BRC-197, it additionally checks an activated listing, the public child links and current chain height below the descriptor's expiryHeight; the standing Offer discloses the same height. Its complete Prepare digest, original signed PurchaseTerms and all deadlines are immutable on retry. The domainEvidence schema is an installed immutable IRI; for BRC-197 it is https://bsv.brc.dev/tokens/0197#lineage-package-v1 and bytes are UTF-8 JCS LineagePackage. It is returned during preparation, not inferred from a listing ID. RecoverySeconds and an applicable Offer's longer promise have exactly BRC-195's deadline/late-first-delivery precedence. Retain sufficient protected material to deliver after catalogue turnover; preparation never locks a Bitcoin output against other buyers. Later expiry does not revoke a timely prepared purchase's delivery/recovery obligation.
A submit is processed in this order: authenticate current recipient; resolve original capability/terms; verify complete bounded target BEEF/raw txid and every input; check configured chain, exact listing consumption, installed family/domain, asset, terms, receipt acquisition ID, request digest and recipient; derive the BRC-197 full purchase commitment (or another domain's specified immutable candidate identity); then atomically reserve (acquisitionId,candidateIdentity) and durable admission work before any external admission. A malformed or conclusively domain-invalid first candidate returns invalid without reserving a candidate identity. Incomplete verification is pending bounded candidate work and cannot invoke admission. After an external effect, a different candidate identity requires a new explicit authorization and cannot reuse this acquisition. For BRC-197, verified txid variants under the same commitment are recorded with evidence and admission status per txid; a duplicate alias cannot create another private release. Unconfirmed alias storage and verification work are bounded, but a verified selected-chain alias cannot be refused solely because an unconfirmed alias cache is full: evict unconfirmed entries while retaining the historical release txid, any pending external operation and the current mined alias. The authenticated recipient may submit a newly observed alias, and recovery must recheck the selected chain where available. One acquisition/candidate identity may recover already committed topic processing; neither a duplicate STEAK nor a public reindex job creates a new private release.
An otherwise fully verified BRC-197 candidate that is currently Bitcoin-non-final is pending finality, not conclusively domain-invalid. Retain it as bounded pending candidate work before external-effect reservation; it cannot invoke topical admission or private release until finality and the other applicable checks succeed. Reassess it under the current selected-chain context, or its containing block's applicable context for verified inclusion. A nonzero locktime or nonfinal sequence alone is not grounds to reject a final purchase or its lineage.
The state transition table is:
| From | Trigger and durable effect | To |
|---|---|---|
| absent | validated preparation and protected capacity committed | prepared |
| prepared | validated candidate and unique admission intent committed | admission-pending |
| prepared | recovery deadline, no pinned candidate/effect | expired |
| admission-pending | retained definitive local rejection | admission-rejected |
| admission-pending | topic processing/STEAK linked exactly once | admitted-delivery-pending |
| admission-rejected | authorized recovery with newly verified eligible evidence for the same candidate identity; durable admission/reconciliation intent committed | admission-pending |
| admission-rejected | authorized recovery verifies the eligible transaction's existing durable topical admission under the same candidate identity and links its exact-txid STEAK once | admitted-delivery-pending |
| admitted-delivery-pending | selected release evidence and private envelope committed | delivered |
| admitted-delivery-pending | retained irrecoverable delivery failure | delivery-failed |
| delivered | authorized recovery/reissue of same right | delivered |
Uncertainty after an external call stays pending and is reconciled by its saved operation/txid. Definitive local rejection stores decision reason, selected policy, bounded canonical evidence, time and globalOutcome=unknown. For BRC-197, all post-reservation statuses carry a purchase commitment and historical selected txid; prepared/expired do not. Other domains carry their defined identity when present and always carry the historical selected txid. STEAK is required only in admitted-delivery-pending/delivery-failed/delivered. Potatoes and releaseEvidence are required exactly in delivered; decision is required exactly in admission-rejected/delivery-failed and forbidden otherwise. No negative service response establishes that a transaction is globally unable to mine. A failed candidate that was pinned before deadline remains recoverable to its retained decision unless newly verified eligible evidence enables the recovery transitions above; an admitted purchase awaiting delivery survives deadline as an outstanding obligation under BRC-195's rules.
While recovery is promised, an authenticated recipient may submit new evidence through /purchases/submit, or invoke /purchases/recover to reconcile retained evidence, after admission-rejected. For BRC-197, this includes an independently verified mined alias with the same full purchase commitment. The provider MUST re-evaluate that evidence against the original terms, recipient, candidate identity and selected policy. If admission remains necessary and is now eligible, persist a durable per-txid admission/reconciliation operation before the external call and return to admission-pending; resolve any earlier uncertain operation rather than repeat it. If the eligible transaction was already durably admitted, link its retained STEAK and move directly to admitted-delivery-pending without admitting or accounting for it twice. Mining alone does not establish topical admission. If the new evidence is incomplete or still fails the selected policy, retain the rejection and bounded pending work as appropriate; unchanged retries do not restart rejected external work.
These transitions retain the original acquisition, purchase commitment, frozen terms and deadlines. Preserve every earlier per-txid operation and rejection in the audit history; the old decision is not a field of the newly pending or admitted response. Before first release the selected txid may change to an independently verified eligible alias, while after release the historical signed txid is immutable. Recovery never authorizes a new payment, different commitment or second logical private release. Outstanding admitted-delivery obligations continue under the existing deadline rules; these transitions do not silently extend an unadmitted acquisition's recovery promise. Public replay and reindexing still cannot initiate private release.
A local-admission ReleaseEvidence has neither processorEvidence nor blockEvidence. Its acceptedAt is the provider's durable topical acceptance time and relies on that provider's signed response. A processor-accepted policy requires processorEvidence and forbids blockEvidence. This BRC registers policy https://bsv.brc.dev/overlays/0196#processor-attestation-v1: processorEvidence is UTF-8 JCS of a BRC-192 signed packet of type processor-acceptance, body {version:1,chain:Chain,txid:Hex32,policy:string,acceptedAt:U64}. The signature signer equals ReleasePolicy.identity, policy equals this IRI, and chain/txid/acceptedAt equal ReleaseEvidence. The processor asserts it accepted that exact transaction under its published policy; it does not assert mining or universal availability. A client must have explicitly trusted that identity for this weaker acceptance mode. Future processor formats use different IRIs.
A mined policy requires blockEvidence and forbids processorEvidence. Its BEEF proves the target's inclusion in blockHash. Heights and tipHash are not sufficient evidence of a best chain. The verifier must resolve both against its configured genesis and a locally selected immutable chain-tracker context identified by contextId/chainPolicyDigest. The tracker supplies authenticated headers/ancestry, difficulty/work validation under the configured chain policy, and inclusion on its selected best chain; the caller bounds bytes, header count, work and deadline before retrieval. Unknown headers, budget limits or a changed view are unresolved/limited/context-changed, never invented confirmation depth. Release requires a positive selected confirmation count, contiguous verified ancestry, checked tipHeight-height+1, and a final same-context check at commit. acceptedAt is when this assessment first satisfied release policy; it is not claimed block time. A reorganization invalidates current assessments but not the historical delivery event. Claiming this release mode requires real inclusion and reorganization qualification; a mock tip string is insufficient.
The buyer separately tracks received, validating, usable, and unusable(reason). Delivered is the seller's durable issuance statement, not an assertion that decryption or licensing succeeded. Wrong key, missing/invalid license, overbroad key grant, unavailable ciphertext or invalid settlement remains unusable/pending as appropriate; uncharged recovery can repair transport/encryption/signature packaging, not buy again implicitly. Reissue may change signature randomness, encryption nonce, wrapper issuedAt and an equivalent License's non-rights issuance fields. It MUST retain acquisition/request, asset/version, exact recipient, purchase commitment, accepted rights/key periods/key commitments, original releaseEvidence and its digest, original deadlines (or an explicit extension), and settlement identity. A changed accepted right is not equivalent recovery. Clients keep both the historical release evidence and today's separately assessed currentness. Once released, recovery does not re-gate the old grant on today's confirmation depth. No rule here reverses a disclosed key or promises refunds/fair exchange.
BRC-192 spend reconciliation determines the client's currently observed compatible history, not this seller's release authorization. A first-seen selection or non-final replacement is not ReleaseEvidence. Reorg/conflict updates may change present currentness and projections; they neither create a second acquisition nor erase the original delivery/recovery obligation. Before first release, select an independently verified, topically admitted alias satisfying the chosen release policy and make its exact txid the signed release/settlement target; mined policy additionally requires the actually mined alias. A pending result's selected txid may change to that verified alias while earlier external-operation records remain durable, including recovery from a prior local rejection as specified above. After release under a weaker policy, the selected historical txid is immutable. A different mined alias with the same commitment changes currentness only: preserve historical signed evidence and entitlement, verify the mined raw transaction independently, and expose the alias as separate currentAlias evidence. A different commitment is a conflicting spend even if outputs appear similar. BRC-197 purchases and their ancestry use ordinary Bitcoin finality and the frozen Script/domain checks, without an additional zero-locktime/all-final-sequence restriction. Currently non-final candidates remain pending; becoming final permits reassessment but never bypasses the selected admission and release policy.