On this page
Guides / Events

Events

Listen to your workspace's events live over SSE, or read them from the 30-day event log.

Updated View .md

met.events is the feed of what happens in your workspace: runs that finish, messages arriving through a channel, contacts being created. There are two ways to read it, and they serve different purposes:

Both require the events:read scope.

Listen live with stream()

met.events.stream() opens an ephemeral SSE subscription that emits each event as soon as it happens. It is the same source met listen uses in the CLI: ideal for the dev loop and for real time without standing up an endpoint.

const met = new Met(key, { workspaceId });

for await (const ev of met.events.stream()) {
  console.log(ev.type, ev.data);
}

Each ev is an { id, type, created, livemode, data } — the same types as the outbound webhooks catalog.

Filter by type

Pass types to receive only what you care about:

for await (const ev of met.events.stream({ types: ['run.completed', 'contact.message.received'] })) {
  if (ev.type === 'run.completed') console.log('run done:', ev.data);
}

Stop the stream

Break out of the for await (with break), or pass an AbortSignal to close it from the outside:

const ac = new AbortController();
setTimeout(() => ac.abort(), 30_000);   // cuts off after 30s

for await (const ev of met.events.stream({ signal: ac.signal })) {
  console.log(ev.type);
}

Some useful types from the catalog: run.completed, run.failed, contact.message.received, contact.created, task.completed, conversation.handoff.

Of that list, a met_test_ key only ever receives run.completed and run.failed. The rest are always emitted live — see *What you see and what you don't*, further down.

stream() vs. outbound webhooks. met.events.stream is ephemeral: it does not retry, and events only reach you while your process is connected. It is meant for development and real time. For guaranteed cross-instance delivery — the event arrives even if your service is down, and gets retried — set up a persistent webhook. See Webhooks.

The event log

stream() only reaches you while you are connected. The log keeps every event in the workspace for 30 days, whether or not it was delivered to a webhook, and you can query it whenever you want.

It answers the uncomfortable question: *what if my server was down on Saturday?*

const page = await met.events.list({ limit: 50 });

for (const ev of page.data) {
  console.log(ev.id, ev.type, ev.created);
}

Each item is the same envelope that stream() emits and that gets signed in an outbound delivery, with the same id. If you received a webhook and want to read it again, ask for it by that id:

const event = await met.events.retrieve('evt_01M1065RWR7BXJAEE10Y605SMV');

Paginate

The list returns the newest first and paginates by cursor, like every other list in the API:

let cursor: string | undefined;
do {
  const page = await met.events.list({ limit: 100, starting_after: cursor });
  for (const ev of page.data) process(ev);
  cursor = page.has_more ? page.data[page.data.length - 1].id : undefined;
} while (cursor);

has_more tells you whether older events remain; starting_after takes the id of the last one you saw.

Filter by type

const runs = await met.events.list({ types: ['run.completed', 'run.failed'] });

What you see and what you don't

Workspace change history

A different thing, which is why it has a different name: which entity was touched, by whom, and what it looked like before and after. These are not the catalog events.

const changes  = await met.events.changes();            // workspace changes
const activity = await met.events.activity();           // workspace activity
const forItem  = await met.events.itemActivity(1234);   // activity for one item