Socket API
The Socket API provides real-time cryptocurrency data through Server-Sent Events (SSE). It streams live transactions, blocks, and RBF replacements from multiple networks. Events use the same { time, type, crypto, data } envelope as the Query API, so the same data structures and query patterns work across both.
Endpoint
Connection
Connect by opening an EventSource to the endpoint. The server sends a heartbeat every 5 seconds to keep the connection alive. Events arrive as JSON in the data field of each SSE message.
const query = btoa(JSON.stringify({
find: { crypto: "btc", type: "tx" }
}));
const source = new EventSource(`https://sock.freedom.st/sse?q=${query}`);
source.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log(data);
};
An empty query {} streams all events across all networks.
Query Language
The socket uses the same query language as the Query API. Your query is a JSON object, base64-encoded and passed as the q parameter.
{
"find": { ... },
"project": [ ... ]
}
find contains filter conditions. Each field must match for an event to be streamed.
project is optional. When provided, only the specified fields are included in streamed events.
Operators
| Operator | Meaning | Example |
|---|---|---|
| (direct value) | Equals | { "crypto": "btc" } |
| (array value) | Any of | { "crypto": ["btc", "ltc"] } |
eq |
Equal to | { "data.fee": { "eq": 0.001 } } |
ne |
Not equal to | { "crypto": { "ne": "btc" } } |
gt |
Greater than | { "data.fee": { "gt": 0.001 } } |
lt |
Less than | { "data.size": { "lt": 500 } } |
ge |
Greater/equal | { "data.size": { "ge": 5000 } } |
le |
Less/equal | { "data.to.amount": { "le": 0.01 } } |
sw |
Starts with | { "data.to.address": { "sw": "bc1q" } } |
ew |
Ends with | { "data.to.address": { "ew": "abc" } } |
co |
Contains | { "data.mining.miner_message": { "co": "pool" } } |
Multiple operators can be combined on the same field: { "data.fee": { "gt": 0.001, "lt": 0.1 } }
All string matching is case-insensitive. Every operator accepts both a single value and an array of values. With an array, the condition matches if any element satisfies it (except ne, which requires none to match).
Dot-path notation
Use dot-separated paths to query nested fields. For example, data.fee accesses the fee field inside data.
When a path passes through an array (like data.to), the condition matches if any element in the array satisfies it. This means "data.to.amount": { "gt": 1 } matches a transaction if at least one output has an amount greater than 1.
Queryable Fields
| Path | Type | Description |
|---|---|---|
type |
string | "tx", "block", or "rbf" |
crypto |
string | Network: btc, bch, ltc, doge, dash, xec |
data.seen |
number | When first indexed (Unix seconds) |
data.hash |
string | Transaction or block hash |
data.block |
string/null | Block hash (null if unconfirmed) |
data.fee |
number | Transaction fee |
data.fee_usd |
number | Fee in USD |
data.size |
number | Transaction or block size in bytes |
data.from.address |
string | Input address |
data.from.amount |
number | Input amount |
data.to.address |
string | Output address |
data.to.amount |
number | Output amount |
data.to.script_type |
string | Output script type |
data.height |
number | Block height |
data.mining.miner |
string | Mining pool name |
Networks
| Code | Network |
|---|---|
btc |
Bitcoin |
bch |
Bitcoin Cash |
ltc |
Litecoin |
doge |
Dogecoin |
dash |
Dash |
xec |
eCash |
Event Types
| Type | Description |
|---|---|
tx |
New transaction |
block |
New block |
rbf |
Replace-By-Fee replacement |
Query Examples
Stream everything
{}
Only blocks
{
"find": { "type": "block" }
}
BTC and LTC transactions
{
"find": {
"crypto": ["btc", "ltc"],
"type": "tx"
}
}
Everything except BTC
{
"find": { "crypto": { "ne": "btc" } }
}
Transactions with an output over 10 BTC
{
"find": {
"crypto": "btc",
"type": "tx",
"data.to.amount": { "gt": 10 }
}
}
Transactions over 5KB
{
"find": {
"type": "tx",
"data.size": { "ge": 5000 }
}
}
Monitor an address for incoming payments
{
"find": {
"data.to.address": "bc1qryhgpmfv03qjhhp2dj8nw8g4ewg08jzmgy3cyx"
}
}
RBF replacements
{
"find": { "type": "rbf" }
}
OP_RETURN and multisig outputs
{
"find": {
"type": "tx",
"data.to.script_type": ["nulldata", "multisig"]
}
}
Only stream hash and fee (projection)
{
"find": { "type": "tx", "crypto": "btc" },
"project": ["data.hash", "data.fee", "data.fee_usd"]
}
Address prefix matching for k-anonymity
By querying a prefix instead of a full address, the server cannot determine which specific address you are monitoring. The shorter the prefix, the more addresses match, providing stronger privacy. Filter for your exact address client-side.
{
"find": {
"type": "tx",
"data.to.address": { "sw": "bc1q0awq9" }
}
}
Since every operator accepts arrays, you can monitor multiple address prefixes in a single connection:
{
"find": {
"type": "tx",
"data.to.address": { "sw": ["bc1q0awq9", "1Df43", "36hNC"] }
}
}
Event Data
All events share the same envelope: type, crypto, and data. The data.seen field is a unix timestamp (seconds) indicating when the event was first indexed. This format is identical to how events are returned by the Query API, so the same data structures work across both SSE and HTTP.
Transaction
{
"type": "tx",
"crypto": "btc",
"data": {
"hash": "287a1af93ffa2e0f86071670344ab867c50256b3ed5b2ff8e1ac6bf2a6673c9a",
"version": 2,
"locktime": 943587,
"seen": 1775278749,
"mined": null,
"block": null,
"size": 222,
"fee": 0.00000141,
"fee_usd": 0.09,
"from": [
{
"hash": "bd78d64b339a01fa740af6b7f15a51f78e61c6a3f4bc4162c1ae131bf6f11570",
"index": 1,
"sequence": 4294967293,
"address": "bc1qnj93mcjyf7a6pxr7x4uzd3dn82tqsszgu4erp5",
"script_type": "witness_v0_keyhash",
"amount": 0.02605691,
"amount_usd": 1742.12
}
],
"to": [
{
"index": 0,
"address": "bc1q3kxmhgz7jr4mngxeeluegqz24gknfmwdzkx3nz",
"script_type": "witness_v0_keyhash",
"script": "00148d8dbba05e90ebb9a0d9cff994004aaa2d34edcd",
"amount": 0.0024,
"amount_usd": 160.46
},
{
"index": 1,
"address": "bc1q2th7r9ms67c3w0r3qx2he9vdaa4chz5ljj7ent",
"script_type": "witness_v0_keyhash",
"script": "001452efe19770d7b1173c7101957c958def6b8b8a9f",
"amount": 0.0236555,
"amount_usd": 1581.56
}
],
"vsize": 141,
"weight": 561
}
}
Block
{
"type": "block",
"crypto": "btc",
"data": {
"hash": "000000000000000000010391f292467e02d166a172684750f23222f6d75c5e05",
"height": 943587,
"version": "2c2da000",
"seen": 1775278334,
"mined": 1775278318,
"previous_block": "000000000000000000018abc2b20bc00fae79ba53770106122e47420c93ef23c",
"next_block": null,
"merkle_root": "a853b0b15fbab2897b21cd78d97b2dc9748b67bb049079df2c1b65cd3a5d8aa3",
"size": 1550516,
"weight": 3993707,
"mining": {
"nonce": 868323383,
"bits": "17020684",
"difficulty": "138966872071213",
"chainwork": "00000000000000000000000000000000000000011cc048b774f70b6bf763eb60",
"miner": "Foundry USA",
"miner_message": "/Foundry USA Pool #dropgold/..."
},
"reward": {
"hash": "b475a4ff15a75b8c077c627eed7f6dd70f4ccde24f5099ab9adcc662981caee6",
"subsidy": 3.125,
"subsidy_usd": 208892.28,
"fees": 0.0273978,
"fees_usd": 1831.42
},
"transactions": [
"b475a4ff15a75b8c077c627eed7f6dd70f4ccde24f5099ab9adcc662981caee6",
"..."
]
}
}
RBF Replacement
{
"type": "rbf",
"crypto": "btc",
"data": {
"seen": 1775278749,
"replaced": true,
"opt_in": true,
"outputs_changed": true,
"old_hash": "048b6041694f0ee1567a55d015661bfcbf3d6771d60cbc28040f2d59c1b0937d",
"old_fee": 0.00000203,
"old_fee_usd": 0.14,
"new_hash": "5856d22c50e42be84cedee272031190a0954cabe91392348f7aad35f184de807",
"new_fee": 0.00000468,
"new_fee_usd": 0.31
}
}
outputs_changed-falsemeans a pure fee bump.truemeans the replacement sends to different addresses.opt_in- whether the replaced transaction opted in to RBF per BIP-125 (nSequence < 0xfffffffe).