graph.cash is a GraphQL indexer for the Memo network.
It exposes posts, profiles, transactions, blocks, and SLP token data through queries and live subscriptions.
The endpoint accepts POST for queries and mutations, and a WebSocket upgrade for subscriptions.
https://graph.cash/graphql
wss://graph.cash/graphql
Subscriptions follow the graphql-transport-ws protocol. A live playground with introspection is available for development.
Top-level types and the operations that return them.
type Query {
tx(hash: Hash!): Tx
txs(hashes: [Hash!]): [Tx]
address(address: Address!): Lock
addresses(addresses: [Address!]): [Lock]
block(hash: Hash!): Block
block_by_height(height: Int!): Block
block_newest: Block
blocks(newest: Boolean, start: Uint32): [Block!]
profiles(addresses: [Address!]): [Profile]
posts(txHashes: [Hash!]): [Post]
posts_newest(start: Date, tx: Hash, limit: Uint32): [Post]
room(name: String!): Room!
}
type Subscription {
tx(hash: Hash!): Tx
address(address: Address!): Tx
addresses(addresses: [Address!]): Tx
blocks: Block
posts(hashes: [Hash!]): Post
profiles(addresses: [Address!]): Profile
rooms(names: [String!]): Post
room_follows(addresses: [Address!]): RoomFollow
}
type Mutation {
broadcast(raw: String!): Boolean!
}
Selected object types most relevant for building feeds and profile views:
type Post {
tx_hash: Hash!
address: Address!
text: String!
tx: Tx!
lock: Lock!
likes: [Like!]
parent: Post
replies: [Post!]
room: Room
}
type Profile {
address: Address!
lock: Lock!
name: SetName
profile: SetProfile
pic: SetPic
following(start: Date): [Follow]
followers(start: Date): [Follow]
posts(start: Date, newest: Boolean): [Post]
rooms(start: Date): [RoomFollow!]
}
type Lock {
address: Address
profile: Profile
txs(start: Date, tx: Hash, limit: Uint32): [Tx!]
}
type Tx {
hash: Hash!
raw: Bytes!
inputs: [TxInput!]!
outputs: [TxOutput!]!
blocks: [TxBlock]
seen: Date
version: Int32!
locktime: Uint32!
}
type Room {
name: String!
posts(start: Int): [Post!]
followers(start: Int): [RoomFollow!]
}
Page through recent posts. Pass tx with the oldest post's hash from the previous page to paginate.
query Newest($limit: Uint32) {
posts_newest(limit: $limit) {
tx_hash
text
address
tx { seen }
lock { profile { name { name } } }
room { name }
}
}
query Post($hash: Hash!) {
posts(txHashes: [$hash]) {
tx_hash
text
address
likes { address tip }
replies {
tx_hash
text
address
}
}
}
query Profile($address: Address!) {
profiles(addresses: [$address]) {
address
name { name }
profile { text }
pic { pic }
posts(newest: true) {
tx_hash
text
tx { seen }
}
}
}
query AddressTxs($address: Address!) {
address(address: $address) {
txs(limit: 25) {
hash
seen
outputs { amount lock { address } }
}
}
}
async function graphql(query, variables) {
const res = await fetch("https://graph.cash/graphql", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({query, variables})
});
const json = await res.json();
if (json.errors) {
console.error(json.errors);
}
return json.data;
}
Subscriptions stream new events as they are indexed. Pass an empty list to posts(hashes: [])
to receive every new post on the network; pass specific hashes to receive replies and likes for those posts.
subscription {
posts(hashes: []) {
tx_hash
text
address
tx { seen }
lock { profile { name { name } } }
room { name }
}
}
subscription Watch($hashes: [Hash!]) {
posts(hashes: $hashes) {
tx_hash
text
parent { tx_hash }
likes { address tip }
}
}
subscription Activity($address: Address!) {
address(address: $address) {
hash
seen
}
}
subscription {
blocks {
hash
height
timestamp
}
}
Subscriptions use the graphql-transport-ws sub-protocol over a WebSocket.
The minimum handshake is connection_init → connection_ack, then
subscribe for each subscription, and next messages stream back.
const ws = new WebSocket("wss://graph.cash/graphql", "graphql-transport-ws");
ws.onopen = () => {
ws.send(JSON.stringify({type: "connection_init"}));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === "connection_ack") {
ws.send(JSON.stringify({
id: "1",
type: "subscribe",
payload: {
query: "subscription { posts(hashes: []) { tx_hash text address } }"
}
}));
} else if (msg.type === "next") {
console.log("new post", msg.payload.data.posts);
} else if (msg.type === "ping") {
ws.send(JSON.stringify({type: "pong"}));
}
};
The graph supports broadcasting raw transactions. Sign the transaction client-side (for example with JMemo) and submit the hex-encoded raw transaction:
mutation Broadcast($raw: String!) {
broadcast(raw: $raw)
}
Hash — 32-byte transaction or block hash, hex-encoded.Address — Bitcoin Cash address (legacy 1... form).Bytes — arbitrary byte sequence, hex-encoded.Date — RFC 3339 timestamp.Int32, Int64, Uint8, Uint32, Uint64 — sized integers.HashIndex — transaction hash + output index pair.
See the posts feed example for a self-contained page that
renders the live posts subscription and paginates with posts_newest.