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:
| Protocol | Prefix |
|---|---|
| B | 19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut |
| MAP | 1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5 |
| AIP | 15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva |
Rules:
appis the name of the app that wrote the action (bChat writesbChat).v=2marks this version. Readers treat a missingvas 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 asbinarywith a mime type and filename.
3. Message types
| type | Extra MAP keys | B? | Payment outputs |
|---|---|---|---|
post | optional media_<n> | yes | none |
reply (post) | context tx tx <parent txid> or context url url <link> | yes | optional tip (§6) |
quote (post) | quote <txid> (no context, so not a reply) | yes | none |
like / unlike | context tx tx <txid> | no | none |
paid like | as like, plus amount <sats> paid 1 | no | one to the author (§6) |
repost | context tx tx <txid> | no | none |
follow / unfollow | bapID <id> (or idKey / address without a BAP identity) | no | none |
tip | context tx tx <txid> amount <sats> [currency BSV] | no | one to the author (§6) |
lock | context tx tx <txid> | no | a locked output |
hide / unhide | context tx tx <txid> (an author's own post, §7.1) | no | none |
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
- 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. - Replying into a Treechat thread: also write
treechat_thread_id <uuid>, and pointtxat the thread's root post. - 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. - 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 coversOP_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.
amountmust 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>andfeeTo <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.
Fis a whole number of sats, at least 1, at most 5% ofamount, and at most 10,000 sats.feeTomust 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
feeToexactlyFwithin the caps; readers ignore (and may flag) an invalid fee, and never count any fee towards the author's total. - A transaction with no
feekey 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>andhomeTo <address>(afterfee/feeTowhen 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.
His a whole number of sats, at least 1, at most 5% ofamount, and at most 10,000 sats.homeTomust not be the author's address orfeeTo. - 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
homekeys. 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
homeToexactlyHwithin the caps; readers ignore (and may flag) an invalid one and never count it towards the author's total. - A transaction with no
homekey 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
hideorunhidefrom its author (block order, then first-seen time). If it ishide, the post is hidden. - Any app can write it.
appis 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:
- Attribution. Show a source label on every post from another app ("from bChat", "from <app>"). Never present another app's post as your own.
- Link home. Every syndicated post links back to the original on its home app.
- 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.
- 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.
- 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.
| Method | Path | Returns |
|---|---|---|
| GET | /health | Indexer 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
- 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.
- 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.
- 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).
- 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.
| Attribute | Values | Default |
|---|---|---|
data-source | all, bchat, treechat, twetch, peck, fwetch | all |
data-limit | 1 to 50 | 20 |
data-theme | auto (follows the reader's light/dark setting), light, dark | auto |
data-target | id of an element to render into | right 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
- The
vkey in MAP names the version. Missingvmeans v1. - New keys and types may be added within a version; readers ignore what they do not know.
- A change that would make existing readers misread data gets a new
v. - This document is published at https://www.bitcoinchat.online/docs/feed-protocol, with the raw text at https://www.bitcoinchat.online/docs/feed-protocol.md.
Questions, corrections and join requests: support@bwalletx.com