bChat Open Feed Protocol v2

Version 2, 6 October 2026. Contact: support@bwalletx.com

1. Why an open BSV feed

Posts on Bitcoin SV are already public: anyone can read them from the chain. What keeps social apps apart is their indexers and interfaces, not the data. This spec describes one shared format for posts, replies, likes, follows and payments, so that every app can show everyone's posts, label where each came from, and compete on its own experience.

bChat writes this format, reads it, and runs a free public indexer for it. Any app can join.

2. Envelope

Each action is one OP_FALSE OP_RETURN output, using Bitcom pipes (|) between protocols:

OP_FALSE OP_RETURN
  [B <content> <mime> <encoding> [filename]]          (posts, replies, quotes; repeatable)
| MAP SET app <your app> type <type> v 2 [keys...]
| AIP BITCOIN_ECDSA <signing address> <compact sig>   (or SIGMA, see §5)

Protocol prefixes:

ProtocolPrefix
B19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut
MAP1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5
AIP15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva

Rules:

  • app is the name of the app that wrote the action (bChat writes bChat).
  • v=2 marks this version. Readers treat a missing v as v1 (the same layout, minus the v2 additions below).
  • Readers ignore keys they do not know.
  • Txids are lowercase hex.
  • Post text goes in B as text/markdown, UTF-8, at most 2000 characters. Media goes in further B parts as binary with a mime type and filename.

3. Message types

typeExtra MAP keysB?Payment outputs
postoptional media_<n>yesnone
reply (post)context tx tx <parent txid> or context url url <link>yesoptional tip (§6)
quote (post)quote <txid> (no context, so not a reply)yesnone
like / unlikecontext tx tx <txid>nonone
paid likeas like, plus amount <sats> paid 1noone to the author (§6)
repostcontext tx tx <txid>nonone
follow / unfollowbapID <id> (or idKey / address without a BAP identity)nonone
tipcontext tx tx <txid> amount <sats> [currency BSV]noone to the author (§6)
lockcontext tx tx <txid>noa locked output
hide / unhidecontext tx tx <txid> (an author's own post, §7.1)nonone

v1 likes omitted context and wrote only tx <txid>. Readers accept both.

Optional source hint for posts that originated in another app: source <app>, plus that app's own post id where its API is not keyed by txid (for example twetch_post_id <n>).

4. Cross-app referencing

  1. If you have the on-chain txid, use context tx tx <txid>. This is Bitcoin Schema, and it is what most BSV social indexers read.
  2. Replying into a Treechat thread: also write treechat_thread_id <uuid>, and point tx at the thread's root post.
  3. If you only have a URL (no txid), use context url url <link>. Other indexers will not be able to attach it to the original.
  4. Never write another app's app= value and never reuse its private or server-only keys. That is impersonation.

5. Signing

  • Default: AIP BITCOIN_ECDSA, signed by the user's posting key. The signature covers OP_RETURN, every push before the AIP prefix, and a trailing |, hashed as a Bitcoin Signed Message. The signature is the 65-byte compact form.
  • Optional: SIGMA (SIGMA BSM <address> <sig> <vin>). SIGMA binds the signature to a transaction input, so the OP_RETURN cannot be replayed into another transaction. That matters for paid likes, where the claim is "I paid". Readers accept either.
  • The user's own wallet signs. A server never signs on a user's behalf.

6. Payments: tips and paid likes

Status: specified; shipping in bChat soon. Not live yet.

The action and its payment are in the same transaction, so they are atomic and an indexer can match them:

out 0: OP_RETURN (MAP type like|tip ... amount <A> [paid 1] [fee <F> feeTo <app address>]
                  [home <H> homeTo <home app address>] | AIP)
out 1: P2PKH -> author address    A sats
out 2: P2PKH -> app address       F sats   (only with an optional client fee, §6.1)
out 3: P2PKH -> home app address  H sats   (only with a home app share, §6.2; out 2 when no fee)
out n: change

(out 0 stands for the action output wherever it sits; the payment is always the output right after it, a fee output the one after that, and a home share output the one after the fee, or right after the payment when there is no fee.)

  • The author is paid directly. Nothing passes through bChat or any relay. bChat's own client fee is currently 0.
  • Author address, in this order: (a) for Bitcoin Schema posts, the post's AIP signing address; (b) for apps that relay posts through a shared signer, the author's own paymail or published payment address, never the relay's address. If no author address can be resolved, do not offer a paid like or tip; fall back to a free like.
  • amount must equal output 1's value. Indexers must check that the output exists and pays the resolved author; otherwise the tip counts as 0.
  • Defaults in bChat: paid like 1,000 sats; tip chosen by the user, minimum 546 sats.
  • Network fee at the wallet's standard rate. A like transaction is about 300 bytes.
  • Unlike does not refund. A paid like followed by an unlike keeps the payment and removes the like.

6.1 Optional client fee

The app where the reader taps tip or paid like MAY add a fee to itself, under these rules:

  • Separate and visible. The fee is its own P2PKH output, immediately after the author's output, and is declared in MAP as fee <F> and feeTo <address>. The wallet's approval prompt must show it as a separate line ("App fee").
  • Never from the author's share. The author's output is still exactly amount. The fee is paid on top.
  • Capped. F is a whole number of sats, at least 1, at most 5% of amount, and at most 10,000 sats. feeTo must not be the author's address.
  • Readers check the author output exactly as before; a fee output never invalidates a tip. A fee is valid only when the next output pays feeTo exactly F within the caps; readers ignore (and may flag) an invalid fee, and never count any fee towards the author's total.
  • A transaction with no fee key has no fee. bChat currently sets none.

6.2 Home app share

When a reader tips or paid-likes a post that was written in another app (its home app, e.g. Treechat, Twetch, Peck, Fwetch), the app where the reader taps MAY add a share for the home app, on top, in the same transaction. bChat does: 5% of amount.

  • Separate and visible. Its own P2PKH output, right after the fee output (or right after the author's output when there is no fee), declared in MAP as home <H> and homeTo <address> (after fee/feeTo when both are present). The wallet's approval prompt shows it as its own line ("Home app"), and the tip sheet says so ("Treechat gets $0.01 on top").
  • Never from the author's share. The author's output is still exactly amount.
  • Capped. H is a whole number of sats, at least 1, at most 5% of amount, and at most 10,000 sats. homeTo must not be the author's address or feeTo.
  • Only to an address the home app published for itself (see "Publishing a home payment address" below). Never inferred from the app's posts: a relay or shared posting address is not a payment address unless the app itself says it is. If no address is known, the share is skipped silently; the tip goes ahead without it.
  • Optional per client. A client that does not pay home shares writes no home keys. Posts written in the paying app itself get no home share.
  • Readers check the author output exactly as before; a home output never invalidates a tip. A home share is valid only when its output pays homeTo exactly H within the caps; readers ignore (and may flag) an invalid one and never count it towards the author's total.
  • A transaction with no home key has no home share.

Publishing a home payment address. For now, the simplest thing: the Open Feed keeps a registry of home payment addresses in bChat's source (homePayTo per app in src/lib/feed/sources.ts of bit-sign), and an app gets listed by asking us at support@bwalletx.com from an address we can tie to the app. The registry is empty today: bChat will start paying each app's share as soon as that app confirms an address. A signed on-chain declaration (MAP SET app <app> type payto homeTo <address>, AIP-signed by a key the app publishes on its own domain) may replace the registry in a later version.

7. Open Feed member rules

Authors first

Posts on BSV are public, and they belong to the people who wrote them, not to the app they were written in. So the Open Feed is built around authors:

  • Every author's post can be shown by any app, with credit and a link home (rules 1–2).
  • Authors get paid wherever their post is read (rule 3).
  • An author's own request to hide a post is honoured by every member app.
  • App-level visibility flags (for example a post marked "local" or "this app only" by the app that wrote it, rather than chosen by its author) are noted, but they are not binding on other readers. An app that wants its content off the open feed can keep it off-chain or encrypt it.
  • A post its home app has taken down for moderation reasons is treated as hidden.

7.1 Author hide requests

An author hides their own post by writing:

OP_FALSE OP_RETURN
  MAP SET app <your app> type hide v 2 context tx tx <txid>
| AIP BITCOIN_ECDSA <address> <compact sig>   (or SIGMA)

and reverses it with type unhide (same keys).

  • Only the author's own key counts. A hide is valid only when its signature verifies and the signing address is the address that signed the original post (for Bitcoin Schema posts, the post's AIP address; for apps that sign with their own identity keys, that key's address). A hide signed by anyone else, including the app that relayed the post, is ignored.
  • Latest wins. For each post, readers take the latest valid hide or unhide from its author (block order, then first-seen time). If it is hide, the post is hidden.
  • Any app can write it. app is the writing app; a hide is honoured whichever app wrote it.
  • Readers hide, they do not delete. The post stays on chain. Member apps drop it from feeds, threads, profiles and embeds, and may show "hidden by its author" in its place.
  • Posts relayed through a shared signing key (where the author's key is unknown, e.g. Treechat) cannot be hidden this way; ask the home app instead.
  • The public indexer (§9) verifies hides and serves them at /social/hides.

An app that joins the Open Feed agrees to five things:

  1. Attribution. Show a source label on every post from another app ("from bChat", "from <app>"). Never present another app's post as your own.
  2. Link home. Every syndicated post links back to the original on its home app.
  3. Pay the author. Tips and paid likes go to the author's own address or paymail (§6), never to the app that relayed the post. A home app share (§6.2) goes to the home app on top of that, never out of the author's amount. Each app publishes a stable payment destination per author.
  4. Own moderation. Each app applies its own filters, mutes and takedown list, and is never obliged to show anything. Hiding happens when reading; on-chain data is untouched. Authors' own hide requests are honoured across apps.
  5. Write as yourself. Your actions carry your own app= value and the user's own signature (§5).

8. Reader rules

  • Count likes per post per signer (BAP id, or address). The last of like/unlike wins.
  • When merging counts from another app's API, show them separately ("N on <app> + M on bChat"). Never claim your likes appear in another app.
  • Check payment outputs (§6) before showing tip totals. Never count a client fee (§6.1) or a home app share (§6.2) as a tip.
  • Hide a post when the latest valid hide/unhide from its own author is a hide (§7.1).
  • Filtering is each reader's choice and changes only what that reader sees. Content filters (language, sensitive media, mutes) are display-only: never treat a filtered post as deleted, and never stop serving, counting or linking to it because some reader filters it. Author hides (§7.1) and an app's own takedowns (§7, rule 4) are separate from filtering.
  • Ignore unknown keys and unknown types rather than failing.

9. Free public indexer

bChat runs a public indexer of this format at https://push.bwalletx.com/feed. No key, open CORS, rate-limited per IP, cached. Responses are JSON.

MethodPathReturns
GET/healthIndexer status: last indexed block, chain tip, post count
GET/social/feed?page=&limit=Latest posts, newest first
GET/social/post/<txid>One post
GET/social/post/<txid>/reply?page=&limit=Replies to a post
GET/social/post/<txid>/like?limit=Likes on a post
GET/social/post/address/<address>?page=&limit=Posts by one signing address
GET/social/hides?tx=<txid>,<txid>…Author hides (§7.1) for up to 100 posts: {hidden:[{tx, address, by, ts}]}, latest action per signer, hides only. Check address is the post's author key
POST/ingest with {"rawTx": "<hex>"}Indexes a just-broadcast transaction immediately, so it shows before the block indexer sees it

Lists from this indexer already leave out posts hidden by their own author.

Example:

curl https://push.bwalletx.com/feed/social/feed?limit=20

10. How an app joins

  1. Read. Pull posts from the public indexer (or run your own indexer of this format) and show them with a source label and a link home.
  2. Expose payment destinations. Publish a stable per-author paymail or address, so tips from any member app reach the right person. This matters most if your app relays posts through a shared signer. Optionally, publish your app's own payment address to receive the home app share (§6.2) when readers in other apps tip your posts.
  3. Optionally, count others' actions. Index likes, replies and reposts written by other member apps against your posts' txids, at least those that carry a verified payment to the author (a paid like is spam-resistant).
  4. Confirm. Exchange a test txid each way with us to check that posts and replies display.

Your data stays yours, your users stay yours, and you can leave at any time. In return your posts reach every member app's users, those users can pay your authors, and every syndicated post links back to you.

Write to support@bwalletx.com to join or to propose changes.

11. Join the Open Feed: embed it in minutes

Show the Open Feed on your site or in your app with one tag:

<script src="https://www.bitcoinchat.online/embed/feed.js" data-source="bchat" data-limit="20"></script>

It renders a small feed right after the tag: each post with its author, a "from <app>" source badge linking to the original, and a link to the post on bChat.

AttributeValuesDefault
data-sourceall, bchat, treechat, twetch, peck, fwetchall
data-limit1 to 5020
data-themeauto (follows the reader's light/dark setting), light, darkauto
data-targetid of an element to render intoright after the tag

Or use an iframe:

<iframe src="https://www.bitcoinchat.online/embed/feed?source=bchat&limit=20&theme=auto"
        width="100%" height="600" style="border:0" loading="lazy" title="bChat Open Feed"></iframe>

Or read the JSON yourself (public, CORS open, no key):

GET https://www.bitcoinchat.online/api/feed/open?source=bchat&limit=20
→ { "feed", "home", "spec", "source",
    "posts": [{ "txid", "url", "text", "mediaCount", "author": {"name","handle"},
                "source", "sourceLabel", "sourceUrl", "at", "replyTo", "likes", "replies" }] }
  • Moderated. Posts hidden by their authors (§7.1), bChat's takedown list, and posts our filters flag as adult are left out. Replies are left out; the feed shows top-level posts.
  • No tracking. No cookies, no storage, no analytics. The widget makes one request, to bitcoinchat.online, with no credentials and no referrer. It shows text only, so it loads nothing from third parties; media is a link away.
  • Attributed. Keep the source badge and the link to each post. That is what rules 1 and 2 (§7) ask of every member app.
  • Rate-limited per IP and cached for about a minute.

12. Test vectors

These were produced by bChat's own script builder and signer. The test key is the private key 0x01 (a well-known public test key; never use it for funds), address 1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH. AIP signatures are deterministic (RFC 6979), so you should reproduce them byte for byte. They show the layout bChat writes today, which has no v key (readers treat it as v1).

Referenced txid: b6006fca35b647f5a186f60987811871fbfda6eeffeee52be4fde287d8852cae

Post "gm from bChat", signed (locking script hex):

006a2231394878696756345179427633744870515663554551797131707a5a56646f4175740d676d2066726f6d2062436861740d746578742f6d61726b646f776e055554462d38017c223150755161374b36324d694b43747373534c4b79316b683536575755374d745552350353455403617070056243686174047479706504706f7374017c22313550636948473232534e4c514a584d6f53556157566937575371633768436676610d424954434f494e5f454344534122314267475a3974634e34726d394b427a446e374b7072517a3837535a323653414d4841209c8e195d58f5e0d3182971a6c65f8034592e21fe221b0fe1d4466219fb74b88f21006b7a6bae1e65547939c4b2a58f7a8031743c56dd1df00bbdcc1ea37d1f96

Reply "agreed" to the referenced txid, unsigned:

006a2231394878696756345179427633744870515663554551797131707a5a56646f417574066167726565640d746578742f6d61726b646f776e055554462d38017c223150755161374b36324d694b43747373534c4b79316b683536575755374d745552350353455403617070056243686174047479706504706f737407636f6e746578740274780274784062363030366663613335623634376635613138366636303938373831313837316662666461366565666665656535326265346664653238376438383532636165

Its AIP signature (compact, hex): 1fda2347e7afe4b887e1c5612abc9bb400fc5c7f850cf7e3146fb53de4b6d1b07d273e81e346eda0121d12d2d455e23a0aa9f2bf3a36eda741f2033b70b7f8be5e

Like on the referenced txid (v1 layout, no context), signed:

006a223150755161374b36324d694b43747373534c4b79316b683536575755374d7455523503534554036170700562436861740474797065046c696b650274784062363030366663613335623634376635613138366636303938373831313837316662666461366565666665656535326265346664653238376438383532636165017c22313550636948473232534e4c514a584d6f53556157566937575371633768436676610d424954434f494e5f454344534122314267475a3974634e34726d394b427a446e374b7072517a3837535a323653414d484120c16616413e890c25e26cb7f2cb09b58c03d61af62dbc695b17ce32680c62bafc5a168d97b3362ac25e4fcf6e4f5b1b7baca4d6c1bcef518647986ce3dafa13d5

Author hide of the referenced txid (§7.1), signed:

006a223150755161374b36324d694b43747373534c4b79316b683536575755374d745552350353455403617070056243686174047479706504686964650176013207636f6e746578740274780274784062363030366663613335623634376635613138366636303938373831313837316662666461366565666665656535326265346664653238376438383532636165017c22313550636948473232534e4c514a584d6f53556157566937575371633768436676610d424954434f494e5f454344534122314267475a3974634e34726d394b427a446e374b7072517a3837535a323653414d48411f5c5320a70b066b16bb5b82e84ba7cd8a45c0e66cb37f7f436bd8a4148035afbe6f6ac33daf9fbb99714e238a7fb44b73aba63f152b174e927c816ccfcd1b0602

Tip of 10,000 sats with a 500-sat client fee (§6.1), signed. The fee goes to the test address here only to keep the vector self-contained; a real fee never goes to the payer or the author.

006a223150755161374b36324d694b43747373534c4b79316b683536575755374d7455523503534554036170700562436861740474797065037469700176013207636f6e74657874027478027478406236303036666361333562363437663561313836663630393837383131383731666266646136656566666565653532626534666465323837643838353263616506616d6f756e74053130303030036665650335303005666565546f22314267475a3974634e34726d394b427a446e374b7072517a3837535a323653414d48017c22313550636948473232534e4c514a584d6f53556157566937575371633768436676610d424954434f494e5f454344534122314267475a3974634e34726d394b427a446e374b7072517a3837535a323653414d48411f1523bd266b772b62d15a834f978168e3992a50f391834eb7ce63aeb8278e73f426758beb519b29278bfc0f046fe6257fad32eebad6523f7d4a904f7f96ec4b01

Tip of 10,000 sats with a 500-sat home app share (§6.2), signed. As above, the share goes to the test address only to keep the vector self-contained. The transaction carries the author's output (10,000 sats) and then the home output (500 sats to homeTo).

006a223150755161374b36324d694b43747373534c4b79316b683536575755374d7455523503534554036170700562436861740474797065037469700176013207636f6e74657874027478027478406236303036666361333562363437663561313836663630393837383131383731666266646136656566666565653532626534666465323837643838353263616506616d6f756e7405313030303004686f6d650335303006686f6d65546f22314267475a3974634e34726d394b427a446e374b7072517a3837535a323653414d48017c22313550636948473232534e4c514a584d6f53556157566937575371633768436676610d424954434f494e5f454344534122314267475a3974634e34726d394b427a446e374b7072517a3837535a323653414d48412049264c2ec5dd5abe1376096c1b022b8b949cf61f8da666034d2b9583dcacc4e73332a18448cd64b392f64241f51e80609833fbe72ff3deba6c3d29b4e5be94c9

13. Versioning

Questions, corrections and join requests: support@bwalletx.com