---
title: programSubscribe
description: Subscribe to notifications for accounts owned by a given program.
url: /docs/rpc/websocket/programsubscribe
type: reference
hideTableOfContents: true
---

Subscribe to notifications for accounts owned by a given program.

<Callout type="info" title="Source">
  [`program_subscribe`](https://github.com/anza-xyz/agave/blob/v3.1.8/rpc/src/rpc_pubsub.rs#L449)
</Callout>

<APIMethod>

```jsonc !!request curl
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "programSubscribe",
  "params": [
    // !hover 0
    "11111111111111111111111111111111",
    // !hover(1:4) 1
    {
      // !hover encoding
      "encoding": "base64",
      // !hover filters
      "filters": [{ "dataSize": 80 }]
    }
  ]
}
```

```ts !!request title="Kit"
import { address, createSolanaRpcSubscriptions } from "@solana/kit";

const rpc = createSolanaRpcSubscriptions("wss://api.devnet.solana.com");

const subscription = await rpc
  .programNotifications(address("11111111111111111111111111111111"), {
    encoding: "base64",
    filters: [{ dataSize: 80n }]
  })
  .subscribe({ abortSignal: AbortSignal.timeout(5_000) });

for await (const notification of subscription) {
  console.log(notification);
}
```

```ts !!request title="web3.js"
import { Connection, PublicKey, clusterApiUrl } from "@solana/web3.js";

const connection = new Connection(clusterApiUrl("devnet"), "confirmed");

const programId = new PublicKey("11111111111111111111111111111111");

const subscriptionId = connection.onProgramAccountChange(
  programId,
  (keyedAccountInfo, context) => {
    console.log("Account changed:", keyedAccountInfo);
    console.log("Context:", context);
  },
  "finalized",
  [{ dataSize: 80 }]
);
```

```rs !!request title="Rust"
use anyhow::Result;
use futures::StreamExt;
use solana_account_decoder::UiAccountEncoding;
use solana_client::{
    nonblocking::pubsub_client::PubsubClient, rpc_config::RpcProgramAccountsConfig,
    rpc_filter::RpcFilterType,
};
use solana_commitment_config::CommitmentConfig;
use solana_sdk::pubkey::Pubkey;
use std::str::FromStr;

#[tokio::main]
async fn main() -> Result<()> {
    let pubsub_client = PubsubClient::new("wss://api.devnet.solana.com/").await?;

    let program_id = Pubkey::from_str("11111111111111111111111111111111")?;

    let config = RpcProgramAccountsConfig {
        filters: Some(vec![RpcFilterType::DataSize(80)]),
        account_config: solana_client::rpc_config::RpcAccountInfoConfig {
            encoding: Some(UiAccountEncoding::Base64),
            commitment: Some(CommitmentConfig::finalized()),
            data_slice: None,
            min_context_slot: None,
        },
        with_context: None,
        sort_results: None,
    };

    let (mut notifications, unsubscribe) = pubsub_client
        .program_subscribe(&program_id, Some(config))
        .await?;

    while let Some(notification) = notifications.next().await {
        println!("{:?}", notification);
    }

    unsubscribe().await;

    Ok(())
}
```

### !params

#### !! 0

!type string !required

Pubkey of the `program_id`, as base-58 encoded string

#### !! 1

!type object

Optional configuration object.

##### !! commitment

!type string !values processed confirmed finalized !default finalized

The commitment describes how finalized a block is at that point in time. See
[Configuring State Commitment](/docs/rpc#configuring-state-commitment).

##### !! filters

!type array

Filter results using up to 4 filter objects. See
[Filtering](/docs/rpc#filter-criteria). All filters must match for a given
account to be included.

<Callout type="info">
  The node validates and optimizes the supplied filters before the subscription
  is created.
</Callout>

##### !! encoding

!type string !values base58 base64 base64+zstd binary jsonParsed !default binary

Encoding format for account data.

- `base58` is slow.
- `jsonParsed` encoding attempts to use program-specific state parsers to return
  more human-readable and explicit account state data.
- If `jsonParsed` is requested but no parser is available, the RPC node falls
  back to `[data, "base64"]`.
- `binary` is a deprecated legacy alias for base58 data returned as a plain
  string.

##### !! dataSlice

!type object

Request a slice of each returned account's data.

| Field    | Type    | Description                                           |
| -------- | ------- | ----------------------------------------------------- |
| `offset` | `usize` | Byte offset from which to start reading account data. |
| `length` | `usize` | Number of bytes to return.                            |

<Callout type="info">
  Data slicing is only available for `base58`, `base64`, `base64+zstd`, and
  `binary` encodings.
</Callout>

<Callout type="info">
  `base58` and `binary` use base-58 encoding and fail if the selected payload is
  more than 128 bytes after slicing. Use `base64` for larger accounts.
</Callout>

##### !! withContext

!type bool !values true false !default false

Accepted for compatibility.

<Callout type="info">
  Unlike [getProgramAccounts](/docs/rpc/http/getprogramaccounts),
  `programNotification` messages already include `context`. `withContext`,
  `minContextSlot`, and `sortResults` are accepted for compatibility, but PubSub
  subscriptions do not currently change behavior based on those fields.
</Callout>

### !!result

```jsonc !response
{
  "jsonrpc": "2.0",
  // !hover result
  "result": 24040,
  "id": 1
}
```

!type integer

Subscription id. Pass this to
[programUnsubscribe](/docs/rpc/websocket/programunsubscribe).

</APIMethod>

### Notification format

Notifications are delivered as `programNotification`.

<CodeReference>

```jsonc !!
{
  // !hover jsonrpc
  "jsonrpc": "2.0",
  // !hover method
  "method": "programNotification",
  // !hover(1:19) params
  "params": {
    // !hover(1:16) params.result
    "result": {
      // !hover(1:3) params.result.context
      "context": {
        // !hover params.result.context.slot
        "slot": 583
      },
      // !hover(1:11) params.result.value
      "value": {
        // !hover params.result.value.pubkey
        "pubkey": "BpdYYo2Vw1NVbzE2DqJxCX2xEfr42xvMYFU2dKd1CW57",
        // !hover(1:8) params.result.value.account
        "account": {
          "lamports": 499997095000,
          "data": ["", "base64"],
          "owner": "11111111111111111111111111111111",
          "executable": false,
          "rentEpoch": 18446744073709551615,
          "space": 0
        }
      }
    },
    // !hover params.subscription
    "subscription": 11
  }
}
```

## !reference

### !! jsonrpc

!type string

Always `"2.0"`.

### !! method

!type string

Always `"programNotification"`.

### !! params

!type object

Notification wrapper with a single matching account and the subscription id.

#### !! result

!type object

Notification result object with `context` and `value`. For PubSub notifications,
`context` includes `slot` and omits `apiVersion`.

##### !! context

!type object

Context for the bank slot that produced the notification.

###### !! slot

!type u64

Slot associated with the notification.

##### !! value

!type object

Single matching account returned for the subscription.

###### !! pubkey

!type string

Address of the matching account, as a base-58 encoded string.

###### !! account

!type object

Account data using the same structure documented in
[Account Data](/docs/rpc/json-structures#account-data).

#### !! subscription

!type integer

Subscription id that produced this notification.

</CodeReference>
