# Multipart Body Transport for BRC-105 Payments

John Calhoun (<dev@calhounjohn.com>)

## 1. Abstract

This document specifies an alternative transport mechanism for the `x-bsv-payment` data defined in [BRC-105](https://bsv.brc.dev/payments/0105). When a payment transaction encoded in [BEEF](https://bsv.brc.dev/transactions/0062) or [Atomic BEEF](https://bsv.brc.dev/transactions/0095) 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](https://bsv.brc.dev/transactions/0074)), 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](https://datatracker.ietf.org/doc/html/rfc7578)) 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](https://bsv.brc.dev/payments/0105) 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) and `multipart` (this specification).
* If the header is absent, the client **MUST** assume only `header` transport is supported.
* Servers implementing this specification **SHOULD** include this header in all `402` responses.

### 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:

1. If the payment JSON fits within HTTP header size limits and the server supports `header` transport, the client **SHOULD** use header transport as defined in BRC-105.
2. If the payment JSON exceeds header size limits **and** the server advertises `multipart` transport, the client **MUST** use multipart body transport as defined in Section 4.3.
3. If the payment JSON exceeds header size limits and the server does **not** advertise `multipart` transport, 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:

```json
{
  "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

```http
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

```http
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:

1. If `Content-Type` starts with `multipart/form-data` — extract the payment JSON from the `x-bsv-payment` part and the request payload from the `body` part.
2. Otherwise — read the payment JSON from the `x-bsv-payment` HTTP 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](https://bsv.brc.dev/payments/0105). 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:

1. **Existing clients** that send `x-bsv-payment` as a header continue to work without modification. Header transport is not deprecated.
2. **Existing servers** that do not implement multipart extraction continue to work with header-transport clients. The `x-bsv-payment-transports` header is optional; its absence signals header-only support.
3. **Payment semantics are unchanged.** The JSON structure, derivation logic, amount verification, and internalization flow are identical regardless of transport.
4. **No migration timeline.** Header transport can be used indefinitely for transactions that fit within header limits.

## 6. Security Considerations

1. **Authentication Compatibility**
   * [BRC-103](https://bsv.brc.dev/peer-to-peer/0103)/[BRC-104](https://bsv.brc.dev/peer-to-peer/0104) mutual authentication signs the raw HTTP request as transmitted. When using multipart transport, the client signs the request with the `multipart/form-data` Content-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.
2. **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](https://datatracker.ietf.org/doc/html/rfc7578) implementations.
3. **Replay Protection**
   * The nonce-based replay protection defined in BRC-105 Section 8 applies identically. The `derivationPrefix` uniqueness guarantee is independent of transport mechanism.
4. **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

1. **Server (Cloudflare Workers)**: `bsv-auth-cloudflare` middleware — `prepare_multipart_payment()` extracts payment from multipart body, deployed across 9 x402 service agents.
2. **Client (Rust)**: `rust-bsv-worm` — `build_multipart_body()` in `x402/payment.rs`, auto-switches at 8 KB threshold when server advertises multipart support.
3. **Client (Python)**: `codex-x402` — `build_multipart_body()` in `lib/payment.py`, identical threshold and format.

## 8. References

* [BRC-105](https://bsv.brc.dev/payments/0105): HTTP Service Monetization Framework
* [BRC-103](https://bsv.brc.dev/peer-to-peer/0103): Peer-to-Peer Mutual Authentication and Certificate Exchange Protocol
* [BRC-104](https://bsv.brc.dev/peer-to-peer/0104): HTTP Transport for BRC-103
* [BRC-62](https://bsv.brc.dev/transactions/0062): Background Evaluation Extended Format (BEEF) Transactions
* [BRC-95](https://bsv.brc.dev/transactions/0095): Atomic BEEF Transactions
* [BRC-74](https://bsv.brc.dev/transactions/0074): BSV Unified Merkle Path (BUMP) Format
* [BRC-29](https://bsv.brc.dev/payments/0029): Simple Authenticated BSV P2PKH Payment Protocol
* [RFC 7578](https://datatracker.ietf.org/doc/html/rfc7578): Returning Values from Forms: multipart/form-data


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bsv.brc.dev/payments/0118.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
