programSubscribe
Subscribes to a program by id and streams a notification whenever any account owned by that program changes, with optional size and byte-match filters.
programSubscribe is the streaming counterpart of getProgramAccounts: you
name a program id, and the server pushes a programNotification every time
the lamports or data of any account owned by that program change. Each
notification identifies the changed account by pubkey and carries its full
new state in account — the same shape getAccountInfo returns — so you can
maintain a live mirror of a program's account set without rescanning it.
Because popular programs own millions of accounts, the config object's
filters array is what makes this method practical. Two filter kinds can be
combined (an account must match all of them): dataSize keeps only
accounts whose data is exactly N bytes (e.g. 165 for SPL token accounts),
and memcmp keeps accounts whose bytes at a given offset equal a base-58
bytes needle — the standard trick for matching a specific field, such as a
token account's owner at offset 32 or a mint at offset 0. commitment and
encoding behave as in accountSubscribe; jsonParsed is worth requesting
for well-known programs so notifications arrive pre-decoded.
Real-world uses: tracking every token account of a wallet (token program +
memcmp on the owner field), watching a DEX program's pool accounts for
reserve changes, following an on-chain order book, or monitoring a lending
protocol's obligation accounts for liquidation thresholds. It also fires when
new accounts are created under the program, which makes it a natural
new-market or new-mint detector.
Gotchas: an unfiltered subscription on a busy program can flood a connection —
always start from the tightest dataSize/memcmp combination you can.
Filters are fixed at subscribe time; to change them, open a new subscription
and drop the old one with programUnsubscribe.
And the stream is session-scoped: a reconnect requires resubscribing, with a
getProgramAccounts snapshot to re-sync state you may have missed.
Parameters
Positional params array: [programId, config?].
programIdstring (base-58)requiredconfigobjectoptionalcommitmentstringoptionalprocessed, confirmed (default), or finalized.encodingstringoptionalbase58, base64, base64+zstd, or jsonParsed.filtersarrayoptionalfilters entriesobjectResponse
Subscribe ack:
Each matching account change is pushed as a programNotification:
{
"jsonrpc": "2.0",
"method": "programNotification",
"params": {
"subscription": 60214,
"result": {
"context": { "slot": 348392077 },
"value": {
"pubkey": "H4vnBqifaSACnKa7acsxstsY1iV1bvJNxsCY7enrd1hq",
"account": {
"lamports": 2039280,
"owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"data": ["dGVzdCBkYXRh", "base64"],
"executable": false,
"rentEpoch": 361,
"space": 165
}
}
}
}
}result (on ack)integerprogramUnsubscribe.params.result.context.slotintegerparams.result.value.pubkeystringparams.result.value.accountobjectgetAccountInfo's value.Errors
| Code | Meaning | When it happens |
|---|---|---|
-32602 | Invalid params | programId not valid base-58, or a malformed filters entry. |
4003 | forbidden | Your tier is below basic (tier_insufficient). |
4029 | rate_limited | Subscribe rate exceeded for your tier. |
Notes
- Filter aggressively: unfiltered subscriptions on high-traffic programs
produce enormous volume;
dataSize+memcmpis the standard combination. - Creations count as changes: brand-new accounts under the program emit a notification, which makes this a new-account detector.
- Filters are immutable per subscription — subscribe anew to change them, then unsubscribe the old id.
- Related methods:
programUnsubscribe,accountSubscribe(a single known account),getProgramAccounts(snapshot to pair with the stream).