Beersy
BRC-246Draft (proposed number, not a BSVA assignment)

Session Upgrade: BRC-33 Messages over WebRTPay

Two wallets that are both online right now still end up sending chat messages, item deliveries and coordination notices through a slow relay server meant for offline delivery, which adds delay for no reason. At the same time, two installs of the same account (like a phone and a laptop) have no good way to tell each other apart or talk directly. This fixes both by letting online wallets message each other straight over an existing direct connection instead.

About Messaging, sending a message to someone who may be offline.

AlsoTransportFrames

Brandon Cryderman / HandCashchanged 29 Oct 20267 min read

Reference for an AI

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

Summary

Why
Routing every message through a store-and-forward relay is slow and unnecessary when both wallets are already online and reachable.
What
BRC-246 defines how to carry traffic, such as chat and item deliveries, over a direct WebRTC data channel instead of the relay, reusing the WebRTPay connection built for payments.
How
A wallet signals over the existing messagebox using a new "messages" purpose and a separate box so payment-only wallets ignore it, dials the peer following WebRTPay's knock/ring/offer/answer flow, then exchanges small `msg` and `ack` session objects over the resulting channel, falling back to the messagebox if the…

What this lets you do

  • Send BRC-33 message bodies directly between two online wallets
  • Address a specific install when one has multiple devices
  • Fall back automatically to the messagebox when a direct dial fails or times out
  • Acknowledge message delivery with a dedicated ack object
  • Coordinate between installs of one account for session handoff (BRC-249)

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

webrtpay/1 conmessages purpomsg/ack sessio

The specification

Abstract

This BRC lets two online wallets, or two installs of one account, send BRC-33 traffic over a direct WebRTC data channel. It uses the connection that webrtpay/1 (WebRTPay protocol reference) defines for direct payments, unchanged: the same signalling , presence check, channel framing and identity handshake. It adds only what messages need: a messages purpose, device addressing for installs that share an , and two session messages, msg and ack.

The messagebox stays the meeting point and the offline inbox. The channel carries the same message bodies the box would. It never carries custody.

Motivation

A messagebox exists because the other wallet is often offline, firewalled, or unable to keep a listener. When both wallets are online, sending every chat line, remittance card and coordination message through a store-and-forward only adds delay.

webrtpay/1, shipped as @bsv/webrtpay in the BSV TypeScript stack, already the hard parts for payments: NAT traversal, a presence check that answers in about two seconds, end-to-end encrypted signalling, a channel bound to both identity keys through BRC-100 signatures, an optional relay and TURN. A second protocol for the same connection would split wallets into two groups that cannot reach each other. This BRC reuses that connection and defines only the messaging layer.

Relationship to other documents

ConcernDocument
Connection: signalling envelopes and their encryption, knock and ring, ICE, channel framing, identity handshake, relaywebrtpay/1 (reference) §3 to §5, §7 to §9
Messages carriedBRC-33, each body sealed per BRC-78
Keys and signaturesBRC-100
Coordination between installs of one accountDraft BRC-249 (#311)

Section numbers such as webrtpay/1 §7.4 refer to the reference at the commit linked below.

Specification

The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" are to be interpreted as described in RFC 2119.

1. Scope

This BRC covers messages that already travel over : chat, remittance cards, token deliveries and similar notices, and coordination between installs of one account such as BRC-249 release requests. It does not cover coin selection, signing or broadcast. An on-chain output remains the only proof of payment or item custody. A payment by itself uses webrtpay/1's payment purpose, not this one.

2. Endpoints

An endpoint is one install: an identity key and a device, a random identifier of 1 to 128 characters from [A-Za-z0-9._-] that the install keeps for its lifetime. Two endpoints may share an identity key, as installs of one account do; they MUST then differ in device. The device SHOULD NOT be derived from any key or hardware identifier.

3. Signalling

Signals are webrtpay/1 signalling envelopes (§7.1 to §7.3), encrypted with BRC-100 encrypt under protocol [2, "webrtpay signaling"] exactly as there, with these differences:

  • Purpose. The plaintext's purpose is "messages".
  • Devices. The plaintext carries fromDevice, the sender's device, and toDevice, the recipient's device. In a knock or offer to another identity, toDevice MAY be empty, meaning whichever install answers. It MUST be set when to equals from, and in every ring, answer and reject, where it is the dial's fromDevice.
  • Box. On a messagebox carrier, signals go in box webrtpay_messages, never in webrtpay_signals. A wallet that implements only payments never lists that box, so it never decrypts a signal it would refuse. A relay carrier (webrtpay/1 §8) carries them unchanged.

A receiver opens a signal as webrtpay/1 §7.4 does, accepting purpose "messages" in step 2 and checking the device fields before anything else:

  1. It ignores a signal whose from is its own identity and whose fromDevice is its own device.
  2. It ignores a signal whose toDevice names another device, and MUST NOT acknowledge it on the messagebox, so the addressed install still finds it.
  3. It acknowledges every other signal once it has processed it.

Installs that share an identity share its box. An install applies these rules even when it cannot open a data channel, so it never consumes a signal meant for another install.

4. Dialing and admission

Dialing follows webrtpay/1 §7.5: knock, ring, offer, answer, with its presence and dial timeouts and its network binding. A dial that ends peer_unreachable, timeout or rejected sends its messages through the messagebox.

When the messagebox is polled rather than pushed (BRC-33 listMessages), a reply comes only after the peer's next read. A dialer on such a carrier adds the peer's poll interval to both the presence and the dial timeout. A polling wallet reads its signalling box at least every 2.5 s while it receives and every second while it dials.

A wallet SHOULD ring and answer only identities the user has exchanged messages with, and its own installs, and otherwise answer a knock with reject not_receiving or not at all. Intake limits follow webrtpay/1 §7.6.

An endpoint has at most one messages session with another endpoint. If installs of one account dial each other at the same time, the one whose identityKey + "\n" + device sorts lower keeps its dial and the other answers it.

5. Session messages

After the identity handshake (webrtpay/1 §5), the session carries webrtpay/1 frames (§4) whose objects are:

{ "t": "msg", "id": "<1–64 characters>", "body": "<the body the messagebox would have carried>" }
{ "t": "ack", "id": "<the msg id>" }

and webrtpay/1's error and bye (§6.4). Any other t is a protocol error, as in webrtpay/1 §6.

  • The receiver MUST pass body to the same ingest path as a messagebox message from the identity the handshake proved, and send ack after ingest accepts it.
  • A msg MUST NOT exceed 256 KiB; a larger body goes through the messagebox.
  • If the sender receives no ack within one second, it MUST close the session and send that message through the messagebox. A body can therefore arrive twice, once per path, so ingest MUST treat a repeat as it treats a repeated messagebox delivery.
  • An ack acknowledges delivery of a message, never a payment.

6. Lifetime

A session ends when its channel closes, ICE fails, or either side sends bye. Messages then go through the messagebox until a new dial completes. A wallet SHOULD close a session that has been idle for ten minutes, and MUST close its sessions when it locks or switches account.

7. What this is not

  • Not a replacement for BRC-33. First contact, offline peers and failed dials use the messagebox.
  • Not a custody channel.
  • Not history sync. Installs of one account may hold a session to carry coordination messages, not to merge state continuously.
  • Not a listener requirement. Neither side opens a port.

Security considerations

  • Authentication and encryption are webrtpay/1's: each side signs a transcript of both DTLS fingerprints, both and both identity keys with a BRC-100 key, so a messagebox host, STUN server or TURN relay cannot read or redirect the channel. Each body also keeps its own BRC-78 envelope, as on the box.
  • Address exposure. An offer or answer reveals the sender's public address, and possibly local ones, to its recipient only, since signals are encrypted to it. webrtpay/1 gathers no ICE before a ring, so a knock discloses nothing. STUN servers learn a wallet's public address; a TURN relay learns both endpoints' addresses and sees only encrypted traffic. For this reason §4 limits who is answered.
  • Abuse. Anyone can post signals to a wallet's webrtpay_messages box. Answering only known identities, and webrtpay/1's intake limits, bound the .

Rationale

  • Why build on webrtpay/1. It is the WebRTC connection the BSV stack ships, with a byte-level reference and test vectors. Reusing it gives one connection for payments and messages, one handshake to audit, and wallets that work together.
  • Why a separate purpose and box. webrtpay/1 receivers refuse any purpose but payment and close on unknown session messages. A separate purpose and box leave payment-only wallets untouched. A wallet that implements both can route each signal without trial decryption.
  • Why devices. Two installs of one account have the same identity key. The device tells them apart in addressing, in simultaneous dials and in acknowledgement. That is what lets BRC-249 coordinate a move over a direct session.

Implementation

@bsv/webrtpay (bsv-blockchain/ts-stack) implements the connection. HandCash Desktop and Mobile implement an earlier revision of this BRC, which signed session descriptions directly, and are moving to this one.

References

  • webrtpay/1: WebRTPay protocol reference, @bsv/webrtpay
  • BRC-33: PeerServ Message Relay Interface
  • BRC-78: Serialization Format for Portable Encrypted Messages
  • BRC-100:
  • Draft BRC-249 (#311): Vault Account Holding Across Devices
  • RFC 8445: Interactive Connectivity Establishment (ICE)
  • RFC 8831: WebRTC Data Channels
Was this helpful?

Search Beersy

Search standards by number, title, author or topic