Beersy
BRC-29

Simple Authenticated BSV P2PKH Payment Protocol

Sending an ordinary Bitcoin payment leaves the recipient unsure whether it is real without checking the whole chain. This defines a straightforward payment between two parties that the recipient can verify independently, and that any compliant wallet can take part in.

About Payment handshakes, the back and forth that completes a payment.

AlsoKey mathsSPV

Ty Everettchanged 20 Oct 202610 min read

Reference for an AI

Everything an assistant needs to answer questions about BRC-29 accurately, including what it depends on.

Summary

Why
Simple bitcoin payments need a way to generate a fresh, unlinkable key per payment while still letting the recipient's wallet recognize and claim the resulting output.
What
BRC-29 is a protocol for sending and receiving bitcoin payments using per-payment derived keys and wallet-verifiable remittance metadata.
How
A sender derives a one-time recipient public key with BRC-42 using a payment-wide prefix and a per-output suffix, builds a P2PKH output with it through a BRC-100 wallet's , and sends the resulting transaction plus the prefix, suffix, output index and sender to the recipient, who calls…

What this lets you do

  • Generate one-time, unlinkable keys per payment output using BRC-42 derivation
  • Build P2PKH payment outputs through a BRC-100 wallet's createAction call
  • Send transaction data alongside derivation metadata so a recipient can verify and claim it
  • Receive and validate incoming payments via internalizeAction with paymentRemittance fields
  • Identify which output in a multi-output transaction belongs to a given recipient

Written by claude-sonnet-5 from the specification text. Where the two differ, the original is correct.

senderrecipientidentitykeyone-time key

The specification

Abstract

This BRC specifies a protocol for exchanging simple payments between a sender and a recipient in a way that is SPV-compliant and cross-compatible. The protocol makes use of BRC-42 key derivation to derive public and private keys between users and BRC-62 / BRC-95 data to relay transaction validation information. Current wallet implementations use BRC-100 createAction and internalizeAction to construct and receive these payments.

Motivation

The motivation for this BRC is to establish a simple, secure, and cross-compatible payment protocol that facilitates P2PKH payments across the BSV . The protocol utilizes BRC-42 key derivation to provide a privacy-enhanced approach to P2PKH transactions. The incorporation of BRC-9 checking ensures secure validation of transactions while maintaining efficient processing times. This standard aims to simplify the process of P2PKH payments for wallets and applications, providing a straightforward implementation path for developers.

Status Note

The original JSON payment message in this document used extended BRC-8 . That framing is historical for new wallet integrations. Current bsv-blockchain/ts-sdk and wallet-toolbox integrations use BRC-100 transaction creation, Atomic BEEF transport, and internalizeAction remittance metadata.

Implementers SHOULD treat the legacy transactions array of BRC-8 envelopes as deprecated unless explicitly maintaining compatibility with older systems.

Specification

We specify a protocol for exchanging simple P2PKH payments between a sender and a recipient. The protocol employs BRC-42 key derivation to derive related public and private keys with , BEEF transaction data to relay SPV-related information, and recipient-side wallet validation to internalize the payment.

Key Derivation Scheme

As defined by BRC-42, the sender and the recipient each have a and a . The invoice number is used to derive related keys, which can be used to facilitate payments. A payment sender can derive a public key for the recipient, and with the same invoice number, the recipient can derive the corresponding private key.

We start with the need for a unique identifier for the payment, used for key derivation. To provide for the possibility that multiple outputs can be exchanged as part of the same payment, we also need a UTXO-specific number. We specify these two values as follows:

  • : A unique value generated by the sender of a payment to distinguish keys used within this payment from keys used in other payments.
  • : Each suffix is a unique value generated by the sender, so that each in the same payment has a different key, and so that the keys are not linkable by third parties.

The BRC-197 transparent listing profile intentionally uses derivationPrefix="brc197", derivationSuffix="authority" and counterparty=anyone for all payout outputs belonging to one identity. This is a narrow, explicit exception to the suffix-uniqueness and unlinkability properties of ordinary BRC-29 payments. Its activation verifies the public derivation once on chain, and its recipients must opt into fixed-child remittance and protected signing before funds are locked. Remittance must identify those exact fields and the recipient identity; the receiving wallet verifies the resulting child P2PKH hash. Other BRC-29 payments retain the unique-prefix and unique-suffix rules above; a receiver must not silently treat BRC-197 outputs as ordinary private payment outputs.

The keys that protect the funds exchanged under this protocol are derived with BRC-42 key derivation by the sender from the identity key of the recipient. The invoice number is specified as follows:

2-3241645161d8-<derivationPrefix> <derivationSuffix>

Where:

  • 2 is a protocol denoting the access restrictions applied under this protocol (see BRC-43 Security Levels)
  • 3241645161d8 is a magic number that denotes compliance with this BRC
  • <derivationPrefix> is the payment-specific prefix used to arrive at a common key universe for all outputs in this payment
  • <derivationSuffix> is the UTXO-specific suffix used to arrive at a unique key for a specific P2PKH UTXO

Application key access and spending boundary

The payment [2, "3241645161d8"] and <derivationPrefix> <derivationSuffix> MUST remain unchanged. Applications may request public derivation and signature verification under ordinary permissions; BRC-44 reserves private-key operations to the wallet. Payment construction, receipt and authorized signing through BRC-100 createAction, internalizeAction and signAction remain available.

The anyone remains valid; remittance uses its compressed private-key-1 public key, not the literal string anyone. Fixed prefixes alone are not grounds for rejection; normal uniqueness, privacy and receipt validation requirements still apply. BRC-207 separately defines 1Color token custody and authorization without changing BRC-29 payment keys.

Current BRC-100 Payment Construction

The sender creates one or more P2PKH outputs spendable by the recipient-derived key:

  1. Obtain the recipient identity key.
  2. Generate a payment-wide derivationPrefix.
  3. Generate a unique derivationSuffix for each payment output.
  4. Derive the recipient public key with BRC-42 using:
    • [2, "3241645161d8"]
    • key ID <derivationPrefix> <derivationSuffix>
    • counterparty equal to the recipient identity key
  5. Convert the derived public key into a P2PKH as defined by BRC-16.
  6. Call BRC-100 createAction with outputs paying those locking scripts.

For each BRC-100 output, customInstructions SHOULD carry enough remittance data for the recipient or service layer to identify the payment, commonly:

{
  "derivationPrefix": "<payment prefix>",
  "derivationSuffix": "<output suffix>",
  "payee": "<recipient identity key>"
}

When a protocol requires a known payment output index, the sender SHOULD set options.randomizeOutputs to false.

Current Payment Message Construction

Current integrations transport the resulting transaction as Atomic BEEF. BRC-29 defines payment key derivation and remittance semantics; it does not require one universal transport envelope. The PeerPay-specific requirements below apply when selecting the described JSON byte-array format. The transaction bytes, their representation at the BRC-100 , and their encoding in a higher-level message are distinct:

  • A completed transaction returned as BRC-100 createAction.tx is represented by transaction bytes, and internalizeAction.tx consumes transaction bytes. A base64 string is not itself a BRC-100 byte array.
  • For a JSON message using the deployed PeerPay byte-array format, transaction MUST be a non-empty JSON array of integers in the inclusive range 0–255, in the original byte order. Senders MUST serialize typed byte arrays as numeric arrays, rather than as objects with numeric property names.
  • A higher-level protocol MAY specify a different explicit byte encoding. For example, BRC-105 specifies base64 in its x-bsv-payment JSON header. The receiver MUST decode that encoding to bytes before calling the wallet. BRC-105's base64 header encoding does not imply that a PeerPay recipient accepts a base64 transaction string.

The following illustrates transaction byte representation in a JSON envelope with top-level derivation metadata. The sample bytes are an encoding example only, not a valid Atomic BEEF payment:

{
  "derivationPrefix": "<payment prefix>",
  "derivationSuffix": "<output suffix>",
  "transaction": [0, 1, 127, 128, 255]
}

The outer envelope and location of derivation metadata are defined by the higher-level protocol carrying the payment. In particular, the current PeerPay payment_inbox body nests the derivation values in customInstructions and includes the payment amount:

{
  "customInstructions": {
    "derivationPrefix": "<payment prefix>",
    "derivationSuffix": "<output suffix>"
  },
  "transaction": [0, 1, 127, 128, 255],
  "amount": 1000
}

Again, these bytes illustrate encoding only. In this PeerPay body, amount is the amount in , and an omitted outputIndex denotes output 0. A sender MUST ensure that the index used by the recipient identifies the intended payment output. If multiple outputs or transactions are used, the higher-level message MUST identify the transaction, derivation suffix and output index for every output intended for the recipient; the single-output example does not define a multi-output envelope.

Encoding and decoding the transaction MUST preserve its bytes exactly. The derivationPrefix and derivationSuffix are the strings used in the key ID, not instructions to decode or re-encode those strings. Their exact text MUST be preserved during remittance, even when their generation uses base64-encoded random data.

Legacy JSON Envelope

The legacy payment message was a JSON object with:

  • "protocol" equal to 3241645161d8
  • "senderIdentityKey" as the sender identity key
  • "derivationPrefix" as the payment-wide prefix
  • "transactions" as an array of extended BRC-8 transaction envelopes

Each legacy envelope included an outputs object mapping output indices to suffix values. This format is deprecated for new BRC-100 integrations.

Sending Payments

The steps for a sender to send a payment under this protocol are as follows:

  1. Learn the identity key of the recipient, determine the total amount of the payment and generate a derivation prefix.
  2. Decide on the number of outputs (across one or multiple transactions) that will comprise the payment.
  3. For each output, generate a derivation suffix for the output and decide on the number of satoshis in the output.
  4. For each output, use BRC-42 key derivation to derive a public key for the recipient for the output, and use the public key to construct a P2PKH Bitcoin output script as per BRC-16.
  5. Use a BRC-100 wallet to construct and sign transactions that contain the output scripts derived for the recipient from the previous step.
  6. With the Atomic BEEF transaction data, derivation prefix, derivation suffixes, output indices, and sender identity key in hand, construct a payment message for the recipient that contains this information.

Recipient Validation

When the recipient processes an incoming payment, it checks that the public key hashes in the output scripts are properly derived from the sender and recipient identities, the derivation prefix, and the output suffixes. The recipient should also validate the supplied BEEF data according to its wallet policy.

Current BRC-100 wallets receive the payment by calling internalizeAction with output metadata such as the following. The tx value shown is a placeholder for the Atomic BEEF byte array:

{
  "tx": [1, 1, 1, 1],
  "outputs": [
    {
      "outputIndex": 0,
      "protocol": "wallet payment",
      "paymentRemittance": {
        "derivationPrefix": "<payment prefix>",
        "derivationSuffix": "<output suffix>",
        "senderIdentityKey": "<sender identity key>"
      }
    }
  ],
  "description": "Incoming BRC-29 payment"
}

After the wallet accepts the payment, the application may acknowledge receipt and fulfill the corresponding goods or services according to its higher-level protocol.

Implementations

Implementations of this protocol should adhere to the key derivation scheme and current BRC-100 remittance behavior specified in this BRC. The transaction submission system within any wallet can implement this protocol and validate that incoming transactions submitted under this protocol contain UTXOs that are properly derivable by the recipient. Interoperability also requires agreement on the higher-level envelope and its byte encoding, as described above.

Encoding Compatibility and Migration

Earlier wording showed "transaction": "<base64 AtomicBEEF>" without identifying a transport. That example was accurate for BRC-105's explicitly encoded header, but did not describe the deployed PeerPay body. This clarification preserves PeerPay's numeric-array contract and BRC-105's base64 contract; it does not change BRC-29 key derivation or transaction bytes.

The reference byte normalizer also accepts a contiguous numeric-key object at a known byte-field boundary to recover historical typed-array JSON serialization. Such recovery is an implementation compatibility feature, not the preferred form for new senders. It does not make arbitrary application objects or strings into transaction bytes.

A PeerPay sender MUST NOT assume base64 support solely because the recipient implements BRC-29. Receivers MAY add an explicitly defined base64 decoding adapter for compatibility with applications built from the earlier example. Sender migration to that representation requires established receiver support; this clarification does not require or claim such support in the pinned implementation. Malformed byte representations MUST be rejected before submitting the payment to the wallet. Successful byte decoding alone does not establish valid BEEF, correct derivation, sufficient payment, or wallet acceptance.

Transport body limits and delivery preflight remain higher-level concerns. This encoding clarification does not define a relay-size discovery protocol or resolve the separate delivery concerns in the linked issue.

Encoding Conformance Examples

For the synthetic byte sequence 00 01 7f 80 ff:

  • JSON numeric-array representation: [0,1,127,128,255].
  • Base64 representation, only where explicitly specified by the transport: AAF/gP8=. Decoding it MUST recover the same five bytes before wallet submission.
  • A JSON string "AAF/gP8=" MUST NOT be treated as a byte array without an explicit base64 decoder. It is not accepted by the pinned PeerPay byte normalizer.
  • Arrays containing a non-integer, a negative integer, an integer greater than 255, or a string element are invalid byte arrays.

These examples test representation only and MUST NOT be submitted as payments.

Revision History

  • 2026-10-08: Clarified application key-access restrictions while preserving payment derivation and receipt. Added the BRC-207 1Color module cross-reference.

  • 2026-09-30: Clarified that the deployed PeerPay JSON body carries numeric byte arrays, whereas BRC-105 explicitly carries base64 in its payment header. Added byte-preservation and compatibility guidance, an implementation-pinned envelope example, and synthetic encoding vectors. This resolves the previously unqualified base64 example while preserving existing transport contracts during the standards' early stabilization; key derivation is unchanged.

References

The following public implementation references are pinned to TS Stack commit 3e41d6a220783b268b6240ae654f27628c4af557:

Was this helpful?

Search Beersy

Search standards by number, title, author or topic