Vulpine is a social network, a wallet and a game whose records live on the Bitcoin SV chain. Everything is public: anyone can read it, and anyone can write their own reader. This page takes you from nothing to reading and writing in a few minutes. Every example here is copied from working code.
The API is https://api.vulpinenetwork.com/api. Every Vulpine reader serves the same API, so https://fwetch.lol/api answers the same way. It is open to every website (CORS), it answers JSON, and an error comes back as {"error": "what went wrong"} with an HTTP status.
curl "https://api.vulpinenetwork.com/api/feed?limit=5"
| You want | Ask for |
|---|---|
| The newest posts | GET /api/feed |
| One post | GET /api/post/:txid |
| Someone's posts | GET /api/posts-by/:address |
| Every board | GET /api/boards |
| One board | GET /api/boards/:slug |
A chat room (the troll box is global) | GET /api/chat/global/messages |
| Only messages newer than one you have | GET /api/chat/global/messages?after=:id |
| A .fox name | GET /api/name/:name |
| A user number | GET /api/handle/:number |
| Records of any kind, by type or author | GET /api/assertions?type=:type&author=:address |
| One record and its history | GET /api/assertion/:txid |
| Tartary's land, a window of districts | GET /api/tartary/map?from=0&count=100 |
| A Tartary deed, ready for a game | GET /api/tartary/deed/:parcel |
| Is the reader up? | GET /api/health |
Every route, in full: the API reference.
Everything you write is a small JSON record signed with your identity key. The reader checks the signature before it keeps anything, and the house pays the network fee, so writing costs you nothing.
Sign, in JavaScript (npm install @bsv/sdk):
import { PrivateKey, ProtoWallet, Utils } from '@bsv/sdk'
// Your identity key. Keep it: it is who you are.
const key = PrivateKey.fromRandom()
// The rule for every record: everything but pub and sig, keys sorted, as
// JSON, signed with BRC-42 and the counterparty "anyone", so anyone can check it.
async function sign(record) {
const clean = {}
for (const k of Object.keys(record).sort()) clean[k] = record[k]
const { signature } = await new ProtoWallet(key).createSignature({
data: Utils.toArray(JSON.stringify(clean), 'utf8'),
protocolID: [0, 'fwetch identity'], keyID: '1', counterparty: 'anyone',
})
return { ...record, pub: key.toPublicKey().toString(), sig: Utils.toHex(signature) }
}
Say something in the troll box:
const t = Math.floor(Date.now() / 1000), body = 'gm'
const s = await sign({ p: 'fwetch-chat', room: 'global', body, enc: '', anon: '', t })
await fetch('https://api.vulpinenetwork.com/api/chat/global', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ pub: s.pub, sig: s.sig, t, body }),
})
To post as Anonymous, sign with anon: '1' and send anon: true. A message must be sent within five minutes of its t.
Put a record of your own on the chain. An assertion is the general record: any type you choose (lowercase letters, digits, - and _) and any JSON payload. The house pays to write it.
const record = await sign({
p: 'fwetch-assert', type: 'my-game-score', payload: { score: 1200 },
t: Math.floor(Date.now() / 1000), app: 'my-game',
})
const r = await fetch('https://api.vulpinenetwork.com/api/sponsor/opreturn', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ kind: 'post', payload: record }),
})
const { txid } = await r.json() // your record, on the chain
Read it back with GET /api/assertion/:txid, or every one of yours with GET /api/assertions?type=my-game-score&author=:address. To replace a record, write a new one with parent: '<the old txid>'; the old one is marked as superseded. The reader limits how often one key can write, and how big a record can be. The maze's saves on the chain are records like this one.
One line, where you want it:
<script src="https://fwetch.lol/embed/trollbox.js" async></script>
It is the network's one open room, the same one the wallet, Fwetch and Gekker show, in a small window. data-width and data-height size it (360 by 440 unless you say). Or frame it yourself:
<iframe src="https://fwetch.lol/embed/trollbox" width="360" height="440" style="border:0"></iframe>
Visitors read it with nothing installed. The first time someone sends a message, the box makes a throwaway key in their browser, keeps it there, and posts as Anonymous, signed like everything else.
Every district, parcel and deed is open, in a shape game engines and NFT tools already read. See Tartary deeds, for any game or world.