- Ty Everett (ty@projectbabbage.com)
- Brayden Langley (brayden@projectbabbage.com)
- Imran Munir (imran.munir@bsvassociation.org)
This document specifies an HTTP-based micropayment framework that extends BRC-103 (mutual authentication and certificate exchange) and BRC-104 (HTTP transport for BRC-103). It defines how a server can advertise payment requirements for a given HTTP request and how a client can respond with a BSV transaction fulfilling these requirements. By leveraging:
- HTTP 402 Payment Required responses
- Nonce-based derivation prefixes (BRC-29)
- BRC-103 Identity keys
this specification enables an authenticated, verifiable mechanism to monetize any web service with micropayments. The server could even cryptographically bind each payment to the mutual-authenticated session, ensuring that the payment correlates uniquely to the requested action.
This document defines the primary BSV-native HTTP monetization framework in this repository.
BRC-118 extends this specification with multipart body transport for large payment payloads without deprecating the original header transport. BRC-120 documents conformance to the frozen external x402 specification, and BRC-121 defines a smaller BSV-specific 402 profile. Those documents do not replace the semantics defined here unless they are being adopted explicitly for a given integration.
Current HTTP-based APIs often rely on subscription models or external billing/invoicing solutions. This approach can be cumbersome for fine-grained (micropayment-level) usage-based billing. By contrast, BSV Blockchain capabilities allow on-chain micropayments. However, bridging these seamlessly into existing HTTP flows requires:
- Standardized BSV wallet functionality (BRC-100)
- A standard approach to advertise payment requirements (HTTP 402)
- A mechanism to tie a user’s payment to their session identity (via BRC-103 identity keys)
- Nonce-based replay protection (ensuring the same payment is not reused maliciously)
BRC-105 addresses these needs by specifying how a BRC-103–authenticated server can request and verify a BSV payment from the client within a standard HTTP request–response cycle. Clients can use specialized 402-handling agents (e.g. AuthFetch or custom code) to automatically respond to 402 Payment Required, building and broadcasting a transaction on the user’s behalf.
- Payer (or Client): The party sending the HTTP request, who must pay the server if required. They are already mutually authenticated to the server via BRC-103/104.
- Payee (or Server): The HTTP endpoint receiving the request, which may respond with
402 Payment Required, specifying the needed payment details. - Derivation Prefix: A random nonce string used to derive or reference a unique public key / payment output. Defined in BRC-29.
- Derivation Suffix: An additional, output/script-level field included by the client with the payment transaction that is used by the payee's wallet for verification. Also defined in BRC-29.
x-bsv-paymentheader: A custom header carrying JSON data, including the transaction references and derivation prefixes/suffixes.internalizeAction(): A function defined by the payee’s wallet or server that finalizes the transaction acceptance logic (e.g., verifying the correct output script, ensuring the derivation prefix is valid, confirming the transaction is not a duplicate, etc.).
BRC-103 defines mutual authentication and certificate exchange but does not define how to handle micropayments. BRC-104 applies BRC-103 to HTTP, detailing how to wrap BRC-103 handshake data in HTTP messages.
BRC-105 sits on top of BRC-104, specifying a payment layer for monetizing HTTP endpoints. It reuses:
identityKey: The user’s 33-byte compressed public key from the BRC-103 session.- Nonce generation: The server can generate derivation prefixes that are cryptographically bound to its identity key, used by the parties to derive an ephemeral key pair for the payment.
- HTTP 402 status code**: A reserved status code in current HTTP semantics, used here by ecosystem convention for BSV micropayments.
-
Client Authenticates
- The client (payer) establishes a BRC-103 session with the server (payee) using BRC-104. This ensures both parties have authenticated and exchanged any necessary certificates to establish identity.
-
Server Determines Price
- The server calculates how many satoshis this request requires (if any). This can be a static fee, dynamic, or zero.
-
402 Payment Required (if fee > 0 and no valid payment provided)
- If the client has not included a valid
x-bsv-paymentheader, the server responds with HTTP status 402 and sets:x-bsv-payment-version: Protocol version, currently1.0.x-bsv-payment-satoshis-required: Number of satoshis required.x-bsv-auth-identity-key: The server identity key to which the payment derivation is bound.x-bsv-payment-derivation-prefix: A random nonce (BRC-29) for the transaction.
- If the client has not included a valid
-
Client Submits Payment
- The client’s wallet or user agent sees the 402 response.
- It constructs a BSV transaction paying the requested amount to the server’s derivation.
- The client re-sends the request with a header
x-bsv-paymentcontaining JSON:{ "derivationPrefix": "AAAAA...", "derivationSuffix": "...", "transaction": "SGVsbG8s" // a BSV transaction in AtomicBEEF format encoded as base64 }
-
Server Verifies Payment
- The server checks the prefix (
derivationPrefix) and suffix (derivationSuffix), ensures it matches what was advertised, and that the transaction properly pays the required amount. - If successful, the server considers the request to be funded.
- The server checks the prefix (
-
Server Continues
- Assuming the payment is valid, the server proceeds with the requested operation and returns a normal success response (e.g., 200).
x-bsv-payment-version- The current supported version is 1.0.
- If a client does not explicitly support the server's indicated version, the client MUST NOT submit a payment.
x-bsv-payment-satoshis-required- Integer number of satoshis needed for this request.
- Sent from server → client in
402 Payment Required.
x-bsv-payment-derivation-prefix- Payment-level nonce for deriving the payment output script.
- Sent from server → client in
402 Payment Required.
x-bsv-auth-identity-key- The server/payee identity key used as the BRC-29 payment counterparty.
- Sent from server → client in
402 Payment Required. - A client MUST NOT construct the payment if this value is absent or invalid.
x-bsv-payment- JSON structure containing the actual transaction data.
- Sent from client → server in a subsequent request or retry after 402.
x-bsv-payment-known-txids(optional)- Comma-separated transaction IDs the payee already holds and has validated, and which the payer MAY therefore omit from the payment's ancestry.
- Sent from server → client in
402 Payment Required. - Optional in both directions: a payee need not send it, and a payer that ignores it remains correct. See Section 5.3.
The x-bsv-payment transaction is encoded in BEEF or Atomic BEEF, which carries the payment transaction and its unconfirmed ancestry. An unconfirmed ancestor has no merkle proof to collapse to, so the whole ancestor travels. A payer spending its own unconfirmed change — which any payer does once it pays faster than blocks confirm — therefore resends an ancestry that grows with each payment, even though the payee already received, validated and retained every transaction in it.
BRC-96 supplies the mechanism to avoid this: a BEEF V2 entry may carry only the 32-byte txid of a transaction the parties have already agreed is valid. What BRC-96 does not define is how the parties reach that agreement. This section defines it for BRC-105 payments, in the only direction that is safe — the payee, which is the party that knows what the payee holds.
A payee MAY include the following header on a 402 Payment Required response:
x-bsv-payment-known-txids: <txid>[,<txid>...]
- Each entry is a 64-character hexadecimal transaction ID.
- The payee MUST declare only transactions it already holds and has itself validated.
- The list MUST be scoped to the payer identity authenticated for the current BRC-103 session. One payer's transactions never appear in another payer's ancestry, so an unscoped list saves nothing and discloses one customer's payment history to another.
- The payee MUST NOT declare a transaction it will be unable to resolve when verifying the payment. See Section 8, item 6.
- The payee SHOULD keep the list short. A txid-only entry terminates its whole branch of the BEEF, so declaring a payer's most recent payment collapses that payer's entire self-chained run by itself. The cost of a long list falls on the payee's own response header budget, which is subject to the same infrastructure limits described in BRC-118 Section 2.
- A payer that does not implement this section MUST ignore the header and construct the payment exactly as it otherwise would. This is always correct; it forgoes an optimisation and nothing else.
- A payer that does implement it MUST parse the header leniently. Entries are trimmed and matched case-insensitively, duplicates are removed, and a malformed entry is discarded rather than treated as an error. An absent header, an empty value, or a value with no well-formed entry MUST leave payment construction unchanged. A hint is an optimisation, and a bad hint must never cost a payment.
- A payer SHOULD bound how many IDs it accepts, so that a hostile or faulty payee cannot inflate the wallet call. The
@bsv/sdkimplementation accepts 256. - The payer passes the resulting list to its wallet as the BRC-100
createActionknownTxidsoption; the wallet emits each matching ancestor as a BRC-96 txid-only entry. - A payer MUST NOT infer this list. An ancestor omitted on the payer's own initiative makes the payment unverifiable to the payee. In particular, a payer MUST NOT derive it from its own record of previous payments to this payee: what the payer sent and what the payee retained are different facts.
BRC-118 addresses the same pressure by a different route: it moves an oversized x-bsv-payment out of the header and into a multipart/form-data body. The two are complementary and independent — this section makes the payload smaller, BRC-118 makes a large payload transmissible — and both are negotiated the same way, through an optional response header on the 402 that is absent by default. An implementation MAY adopt either, both, or neither.
A mutually authenticated request arrives (client has previously performed BRC-103 handshake). The request may or may not contain x-bsv-payment data:
- If no payment is needed (the server’s
calculateRequestPricereturns0), proceed normally. - If the request has a non-zero price and the client did not supply
x-bsv-payment, or the payment is invalid, the server responds with402 Payment Required.
When the server determines a payment is needed but not yet provided or invalid:
- HTTP Status:
402 Payment Required. - Headers:
x-bsv-payment-version:1.0x-bsv-payment-satoshis-required:<price in satoshis>x-bsv-auth-identity-key:<server identity key>x-bsv-payment-derivation-prefix:<nonce>(often base64 or hex)x-bsv-payment-known-txids:<txid>[,<txid>...]— optional; see Section 5.3
- Body: Optional JSON describing the error or instructions for convenience:
{ "status": "error", "code": "ERR_PAYMENT_REQUIRED", "satoshisRequired": 200, "description": "A BSV payment is required..." }
After receiving this, the client is expected to construct and broadcast a payment transaction referencing this prefix.
Subsequent request includes the header x-bsv-payment, JSON:
{
"derivationPrefix": "<prefix from server>",
"derivationSuffix": "<optional suffix>",
"transaction": "SGVsbG8s"
}derivationPrefix: Must match what the server gave in the402response.transaction: A fully signed transaction paying an output script derived from the prefix, acceptable on the BSV network.
Current ts-sdk AuthFetch behavior constructs this transaction with BRC-29 derivation using protocol ID [2, "3241645161d8"], key ID <derivationPrefix> <derivationSuffix>, and counterparty equal to x-bsv-auth-identity-key. It sets randomizeOutputs to false when creating the payment action so the payment output can be identified deterministically by the verifier.
Upon receiving x-bsv-payment, the server:
- Ensures the prefix is the same as previously advertised (and not used before).
- Validates the transaction using
wallet.internalizeAction()or similar. Steps might include:- Ensuring the output script pays to the correct derivation from
derivationPrefix. - Checking if the amount is at least the required
satoshisRequired. - Preventing double-spend or replay.
- Ensuring the output script pays to the correct derivation from
If validated, the server MUST proceed to handle the request logic, and is obliged to provide the requested service, according to what the client has paid for.
If payment is successful, the server responds with a normal (e.g., 200 OK) plus any business logic response body. The server may add:
x-bsv-payment-satoshis-paid: <value>- Possibly additional data about the transaction or usage.
-
Auth Check (BRC-103/104)
- If not authenticated, respond
401 Unauthorized.
- If not authenticated, respond
-
Calculate Price
- E.g.,
price = 200satoshis.
- E.g.,
-
If
x-bsv-paymentProvided- Parse and verify. If valid, continue. If invalid, return
400 Bad Request.
- Parse and verify. If valid, continue. If invalid, return
-
If Not Paid
- Return
402+x-bsv-payment-version+x-bsv-payment-derivation-prefix+x-bsv-payment-satoshis-required+x-bsv-auth-identity-key.
- Return
-
If Paid
- Proceed to business logic.
-
Send Request
- If server returns
402, parsex-bsv-payment-version+x-bsv-payment-satoshis-required+x-bsv-payment-derivation-prefix+x-bsv-auth-identity-key.
- If server returns
-
Construct Payment
- Create transaction paying the server’s derivation.
- Store it in
x-bsv-paymentJSON.
-
Re-Send
- Re-send the request with
x-bsv-paymentheader. - If accepted, receives normal
200 OK. - If server fraudulently absconds with client funds:
- Clients should request more robust identity certificates using BRC-103 in the future.
- Do not use the service again.
- Make reports to the issuers of the server's certificates to have them revoked.
- Do not trust certifiers who are willing to issue certificates to fraudulent entities.
- Contact your local police department.
- File an IC3 complaint.
- Re-send the request with
-
Replay Attacks
- The server and its wallet must ensure each
derivationPrefixcan only be used once. Typically, this prefix is stored in a wallet database or in-memory structure. Once a valid transaction is processed, subsequent attempts to reuse the prefix or submit the same transaction for multiple requests must fail.
- The server and its wallet must ensure each
-
Man-in-the-Middle
- Because all requests are already mutually authenticated via BRC-103, a MITM cannot hijack the payment flow. Tampering with the transaction or the prefix invalidates the request and leads to cryptographic failure.
-
Underpayment
- The server should reject transactions that pay less than required. Or, if partial payments are allowed, the server must define how to handle partial coverage. Servers should set clear refund policies, and policies for services not used or partially paid. Generally, partial payment is prohibited.
-
Double Spends
- The server’s
wallet.internalizeAction()logic must handle double-spend scenarios, ensuring the transaction is fully-signed, final and valid on the network.
- The server’s
-
Data Confidentiality
- BRC-105 does not itself encrypt data. Transport-level encryption (e.g., TLS) is recommended to protect transaction details and requests from eavesdroppers.
-
Declared Ancestors the Payee Cannot Resolve
- Declaring a txid under Section 5.3 creates an obligation to supply it. The payer acts on the declaration before signing and broadcasting, so a payee that cannot resolve the omitted ancestor at verification time refuses a payment for which a real input has already been spent and a mining fee already paid. Money moves, no service is given, and every retry repeats it — an outcome strictly worse than never having declared.
- A payee MUST therefore declare only what it can resolve from its own records at verification time, and MUST NOT let its declared set outlive the records that resolve it. A set that can outlive its resolvable counterpart — an in-process cache that survives a restart its storage does not, for example — produces exactly this failure.
- A payee that verifies ancestry MUST NOT declare an ancestor it would then demand. A payee that verifies only the subject transaction against its own derivation, and never walks the ancestry, may declare freely.
- A payer's handling of the header is not observable in advance: no field distinguishes a payer that honours the declaration correctly from one that mishandles it, and the difference only becomes visible once a payment has been broadcast. A payee SHOULD therefore be able to stop declaring, globally and per payer, without redeployment, and SHOULD stop declaring to a payer whose payment is refused for a missing declared ancestor.
- The declaration does not affect the amount, the payee, the derivation, signing, or retry authorization, and an unknown txid does not inject a transaction into the payer's BEEF. Its failure mode is availability of the payment, not misdirection of funds.
- Advanced Pricing: BRC-105 does not define how to calculate price. Implementation can adopt static or dynamic logic.
- Refund Handling: Out of scope for this version. The server might store overpayments or offer on-chain refunds via additional flows.
- Multi-Output Payments: Some use cases might require paying multiple outputs. The basic 402 flow still applies but must be extended with more sophisticated transaction logic.
- BRC-103: Peer-to-Peer Mutual Authentication and Certificate Exchange Protocol
- BRC-104: HTTP Transport for BRC-103
- BRC-29: Derivation-based Payment Protocol
- BRC-62: Background Evaluation Extended Format (BEEF) Transactions
- BRC-96: BEEF V2, Txid Only Extension
- BRC-118: Multipart Body Transport for BRC-105 Payments
- RFC 9110 Section 15.5.3: 402 Payment Required
- 402 Payment Required
BRC-105 introduces a standard approach to HTTP-based micropayment flows, leveraging the authentication and transport models defined in BRC-103 and BRC-104. By responding with 402 Payment Required and specifying a nonce-based derivation, the server ensures each payment is uniquely bound to the mutual-authenticated session and request. This framework enables straightforward pay-per-use APIs and extends the BSV ecosystem with a robust, standardized mechanism for monetizing web services at scale.