Multipart Body Transport for BRC-105 Payments
A payment large enough to need several transactions will not fit in a web request header, where the payment scheme puts it. This moves the payment into the request body when it grows too big.
Summary
- Why
- Payment data attached to a web request can outgrow the size limits that servers and proxies impose on HTTP headers, breaking payments that would otherwise be valid.
- What
- BRC-118 defines a way to send BRC-105 payment data in the body of a request, using multipart/form-data, when it is too large to fit in an HTTP header.
- How
- A server lists which transports it supports in a 402 response header, and a client that has an oversized payment sends a multipart body with one part for the payment JSON and one part for the original request payload, while the server detects the content type and routes both parts into the same verification logic…
What this lets you do
- Send oversized payment data in the request body instead of a header
- Advertise supported transports from the server via a 402 response header
- Switch between header and multipart transport based on payload size
- Keep the original request payload and its content type intact alongside the payment
- Reuse BRC-105 verification unchanged regardless of transport
Written by claude-sonnet-5 from the specification text. Where the two differ, the original is correct.
Reference for an AI
Everything an assistant needs to answer questions about BRC-118 accurately, including what it depends on.
The specification
1. Abstract
This document specifies an alternative transport mechanism for the x-bsv-payment data defined in BRC-105. When a payment transaction encoded in BEEF or Atomic BEEF format exceeds practical HTTP header size limits, the client transmits the payment as a named part within a multipart/form-data request body instead of an HTTP header value.
The existing header-based transport defined in BRC-105 is preserved unchanged and remains the default for small payments. This specification adds a negotiated, backward-compatible body transport for large payments.
2. Motivation
BRC-105 specifies that the client sends payment data in the x-bsv-payment HTTP header. This works well for small transactions, but HTTP headers are subject to practical size limits that vary by infrastructure:
- Cloudflare Workers enforce approximately 128 KB total header size
- Most reverse proxies and CDNs enforce 8–16 KB per header value
- Node.js defaults to 16 KB maximum header size (configurable)
BEEF transactions grow with unconfirmed ancestor chain depth. Since BEEF must include the full raw transaction for every unconfirmed ancestor back to the last confirmed input (only confirmed ancestors can be represented compactly as BUMPs), the BEEF size is cumulative: the BEEF for transaction N in a chain includes the full transaction data of transactions 1 through N-1. Each chained payment adds its raw transaction (~200–700 bytes) to the cumulative BEEF of its ancestors.
Applications that perform rapid sequential payments — such as autonomous agents making dozens of paid API calls per task, or wallets consolidating fragmented UTXOs — routinely chain transactions faster than blocks confirm. Since block confirmations average 10 minutes by consensus, any application making multiple payments per minute will accumulate unconfirmed chains.
Empirical measurements from a production wallet database (7,416 transactions) demonstrate the growth:
| Chain Depth | Elapsed Time | BEEF Size (single tx) |
|---|---|---|
| Baseline avg | — | 4.9 KB |
| ~60 links | ~1 min | 15.6 KB |
| ~120 links | ~2 min | 42 KB |
| ~180 links | ~3 min | 75 KB |
| ~300 links | ~5 min | 155.7 KB |
Each row represents the BEEF payload for a single transaction — one micropayment. The 155.7 KB entry exceeds the Cloudflare Workers 128 KB header limit. These measurements were taken with BEEF compaction active (upgrading confirmed ancestors to BUMPs every 15 minutes); without compaction or during sustained activity between block confirmations, sizes grow further. Historical observations in the same database include individual BEEFs exceeding 400 KB.
These payloads cannot be transmitted as HTTP header values.
multipart/form-data (RFC 7578) is the natural choice for body transport: it is a well-established standard with universal library support, separates the payment data from the original request payload without ambiguity, and request body size limits on modern platforms are orders of magnitude larger than header limits.
3. Relationship to BRC-105
BRC-105 defines the complete HTTP micropayment protocol: the 402 Payment Required response, derivation prefix/suffix exchange, payment JSON structure, and server verification flow. This specification does not modify any of those semantics.
BRC-118 adds a single concern: an alternative transport for the x-bsv-payment JSON when it exceeds header size limits. The payment JSON structure, derivation logic, nonce replay protection, transaction verification, and internalizeAction() processing defined in BRC-105 are all unchanged. The only difference is where the payment bytes reside in the HTTP request.
4. Specification
4.1 Transport Negotiation
The server advertises supported transport mechanisms in the 402 Payment Required response via a new optional header:
x-bsv-payment-transports: header,multipart
- The value is a comma-separated list of transport names.
- Defined transport names are
header(BRC-105 default) andmultipart(this specification). - If the header is absent, the client MUST assume only
headertransport is supported. - Servers implementing this specification SHOULD include this header in all
402responses.
4.2 Client Transport Selection
The client selects the transport mechanism based on the size of the serialized x-bsv-payment JSON and the server's advertised transports:
- If the payment JSON fits within HTTP header size limits and the server supports
headertransport, the client SHOULD use header transport as defined in BRC-105. - If the payment JSON exceeds header size limits and the server advertises
multiparttransport, the client MUST use multipart body transport as defined in Section 4.3. - If the payment JSON exceeds header size limits and the server does not advertise
multiparttransport, the client SHOULD attempt header transport and handle any resulting errors.
A recommended threshold for switching to multipart transport is 8 KB (8,192 bytes), which provides a safe margin under the most restrictive common header limits.
4.3 Multipart Body Transport Format
When using multipart body transport, the client sends the payment and original request payload as a multipart/form-data request body containing two parts:
| Part Name | Content-Type | Required | Description |
|---|---|---|---|
x-bsv-payment | application/json | Yes | The payment JSON object (identical format to the header value) |
body | Varies | No | The original request payload with its native Content-Type |
The x-bsv-payment part carries the same JSON structure as the header transport:
{
"derivationPrefix": "<prefix from server 402 response>",
"derivationSuffix": "<client-generated suffix>",
"transaction": "<base64-encoded AtomicBEEF>"
}
The body part carries the original request payload. Its Content-Type matches what the client would have sent as the request Content-Type without multipart wrapping. If the original request has no body (e.g., a GET-equivalent POST), the body part MAY be omitted.
All other BRC-105 and BRC-103/BRC-104 headers remain as HTTP headers and are not affected by this transport.
4.4 Request Examples
4.4.1 JSON API Request with Multipart Payment
POST /generate HTTP/1.1
Content-Type: multipart/form-data; boundary=----BsvPayment7a3f9e1b0c4d2e8f
x-bsv-auth-version: 0.1
x-bsv-auth-identity-key: 02...
------BsvPayment7a3f9e1b0c4d2e8f
Content-Disposition: form-data; name="x-bsv-payment"
Content-Type: application/json
{"derivationPrefix":"AAAAA...","derivationSuffix":"BBBBB...","transaction":"AQEBAQ..."}
------BsvPayment7a3f9e1b0c4d2e8f
Content-Disposition: form-data; name="body"
Content-Type: application/json
{"prompt": "a banana on mars", "resolution": "1024x1024"}
------BsvPayment7a3f9e1b0c4d2e8f--
4.4.2 Binary Payload with Multipart Payment
POST /transcribe HTTP/1.1
Content-Type: multipart/form-data; boundary=----BsvPayment3c8a1f5d9e2b7064
x-bsv-auth-version: 0.1
x-bsv-auth-identity-key: 02...
------BsvPayment3c8a1f5d9e2b7064
Content-Disposition: form-data; name="x-bsv-payment"
Content-Type: application/json
{"derivationPrefix":"CCCCC...","derivationSuffix":"DDDDD...","transaction":"AQEBAQ..."}
------BsvPayment3c8a1f5d9e2b7064
Content-Disposition: form-data; name="body"
Content-Type: audio/wav
<binary audio data>
------BsvPayment3c8a1f5d9e2b7064--
4.5 Server Transport Detection
The server determines which transport is in use by examining the request Content-Type header:
- If
Content-Typestarts withmultipart/form-data— extract the payment JSON from thex-bsv-paymentpart and the request payload from thebodypart. - Otherwise — read the payment JSON from the
x-bsv-paymentHTTP header and treat the request body as the payload directly.
Both paths feed into the identical payment verification pipeline defined in BRC-105 Section 6.4. The transport mechanism has no effect on payment semantics or verification logic.
When using multipart transport, the server MUST reconstruct the request for downstream handling such that the handler receives only the body part content with its associated Content-Type. The handler MUST NOT be exposed to the multipart wrapper or the payment part.
4.6 Boundary Format
The multipart boundary string SHOULD include sufficient randomness to avoid collisions with request payload content. A recommended format is:
----BsvPayment{16 random hexadecimal characters}
For example: ----BsvPayment7a3f9e1b0c4d2e8f
5. Backward Compatibility
This specification is fully backward compatible with BRC-105:
- Existing clients that send
x-bsv-paymentas a header continue to work without modification. Header transport is not deprecated. - Existing servers that do not implement multipart extraction continue to work with header-transport clients. The
x-bsv-payment-transportsheader is optional; its absence signals header-only support. - Payment semantics are unchanged. The JSON structure, derivation logic, amount verification, and internalization flow are identical regardless of transport.
- No migration timeline. Header transport can be used indefinitely for transactions that fit within header limits.
6. Security Considerations
-
Authentication Compatibility
- BRC-103/BRC-104 mutual authentication signs the raw HTTP request as transmitted. When using multipart transport, the client signs the request with the
multipart/form-dataContent-Type and the full multipart body. The server verifies the signature against the same raw request. The authentication guarantee is preserved because the signed content matches the transmitted content exactly. - Authentication verification MUST occur before multipart extraction. The server verifies the BRC-103 signature on the complete request (including the multipart body), then extracts the payment and payload parts for processing.
- BRC-103/BRC-104 mutual authentication signs the raw HTTP request as transmitted. When using multipart transport, the client signs the request with the
-
No New Attack Surface
- The multipart transport does not introduce new trust assumptions. The same mutually authenticated channel carries the same payment data in a different encoding. Multipart boundary parsing uses well-established RFC 7578 implementations.
-
Replay Protection
- The nonce-based replay protection defined in BRC-105 Section 8 applies identically. The
derivationPrefixuniqueness guarantee is independent of transport mechanism.
- The nonce-based replay protection defined in BRC-105 Section 8 applies identically. The
-
Header Size and Denial of Service
- HTTP header size limits exist as a defense against denial-of-service attacks. Servers must allocate memory to buffer and parse all headers before the request can be authenticated or processed. Requiring servers to raise header limits to accommodate large BEEF payloads weakens this protection and increases exposure to resource exhaustion attacks. Body transport avoids this concern entirely: request bodies support streaming and chunked parsing with well-established memory management, and servers can enforce body size limits independently of header limits.
7. Implementations
- Server (Cloudflare Workers):
bsv-auth-cloudflaremiddleware —prepare_multipart_payment()extracts payment from multipart body, deployed across 9 x402 service agents. - Client (Rust):
rust-bsv-worm—build_multipart_body()inx402/payment.rs, auto-switches at 8 KB threshold when server advertises multipart support. - Client (Python):
codex-x402—build_multipart_body()inlib/payment.py, identical threshold and format.
8. References
- BRC-105: HTTP Service Monetization Framework
- BRC-103: Peer-to-Peer Mutual Authentication and Certificate Exchange Protocol
- BRC-104: HTTP Transport for BRC-103
- BRC-62: Background Evaluation Extended Format (BEEF) Transactions
- BRC-95: Atomic BEEF Transactions
- BRC-74: BSV Unified ,[object Object] (BUMP) Format
- BRC-29: Simple Authenticated BSV P2PKH Payment Protocol
- RFC 7578: Returning Values from Forms: multipart/form-data