Skip to main content

Events

Packet exposes live event helpers for UI refreshes and agents that are already running.

These APIs are live subscriptions, not historical indexers. They do not replay missed messages. Use thread/inbox/activity loading APIs when you need past messages.


Message events​

client.messageEvents listens to MessageSent Anchor emit_cpi! events through client.cpiEvents.

const sub = client.messageEvents.listenIncoming({
onMessage: async (message, event) => {
console.log("new message", event.threadId, event.msgSeq);

// The event gives you a MessageClient handle.
// Load the account if you need raw message data.
await message.loadRetrying(5, 500);
},
onError: console.error,
});

await sub.stop();

This listener subscribes to program logs, fetches the transaction, decodes CPI-emitted Anchor events, and then applies SDK-level filters.

Methods​

MethodDescription
client.messageEvents.listen(params)Listen to all live message events with optional filters.
client.messageEvents.listenIncoming(params)Shorthand for messages where receiver is client.walletPublicKey.
client.messageEvents.listenOutgoing(params)Shorthand for messages where sender is client.walletPublicKey.
client.messageEvents.listenThread(threadId, params)Listen to live events in one thread.

ListenMessagesParams​

FieldTypeDescription
onMessage(message: MessageClient, event: PacketMessageSentEvent) => void | Promise<void>Called for each matching live event.
onError(error: unknown) => voidCalled when decoding/loading/callback processing throws.
threadIdnumberFilter to a specific thread.
senderPublicKeyFilter by sender.
receiverPublicKeyFilter by receiver.
incomingForPublicKeyReceiver must equal this key.
outgoingFromPublicKeySender must equal this key.
eventName"messageSent" | stringEvent name compatibility override.
commitmentFinalityWebSocket/getTransaction commitment.
maxRetriesnumberRetry count while waiting for the transaction to become fetchable.

PacketMessageSentEvent​

type PacketMessageSentEvent = {
threadId: number;
msgSeq: number;
sender: PublicKey;
receiver: PublicKey;
slot: number;
signature?: string;
};

Inbox account events​

InboxClient.listenEvents listens to live account changes for one inbox. It is cheaper than listening to every message event when you only need to know that one inbox changed.

const inbox = await client.inbox(0);

const sub = inbox.listenEvents({
clearPages: true,
onChange: async (inboxClient, event) => {
console.log("inbox changed at slot", event.slot);
console.log("new len", inboxClient.Inbox.len.toString());
},
onError: console.error,
});

await sub.stop();

ListenInboxEventsParams​

FieldTypeDescription
commitmentFinalityAccount-change subscription commitment. Defaults to confirmed.
clearPagesbooleanClear cached inbox body/archive pages when the inbox account changes.
filter(event: InboxChangedEvent) => boolean | Promise<boolean>Suppress changes by returning false.
onChange(client: InboxClient, event: InboxChangedEvent) => void | Promise<void>Called for each matching account change.
onError(error: unknown) => voidCalled if decoding/filter/callback processing throws.

InboxChangedEvent​

type InboxChangedEvent = {
address: PublicKey;
previous: Inbox;
inbox: Inbox;
slot: number;
accountInfo: AccountInfo<Buffer>;
};

Low-level CPI event client​

client.cpiEvents is available for advanced callers who need to decode other Anchor CPI events.

const sub = client.cpiEvents.listen({
eventName: ["messageSent", "MessageSent"],
parse: (raw, ctx) => ({ raw, signature: ctx.signature }),
filter: (event) => Boolean(event.raw),
onEvent: async (event) => {
console.log(event.signature);
},
});

Most apps should use client.messageEvents or inbox.listenEvents instead.


Subscription lifecycle​

All event methods return:

type PacketEventSubscription = {
id: number;
stop: () => Promise<void>;
};

Call stop() when a component unmounts, an agent loop exits, or a CLI process is shutting down.