# Webhook Event Types

Every event a Linked API webhook can deliver – workflow, account, inbox and network events, signal events soon – and how to choose the ones your webhook receives.

> The API Reference is also the SDK and CLI reference. Consecutive code fences marked `tab=HTTP`, `tab=Node`, `tab=Python` and `tab=CLI` are the same call on each surface (a fence marked `tab=HTTP,CLI` is the same text for both), and a block between `:::surface <names>` and `:::` applies only to the surfaces it names. Identifiers in the text are written as in Node and in HTTP JSON (camelCase); the Python SDK spells methods, parameters and result attributes in snake_case (`sendMessage` → `send_message`, `reconnectionLink` → `reconnection_link`), while names inside HTTP JSON stay camelCase.

Every event arrives in the same [envelope](/docs/webhooks#event-envelope). This page lists the event types by area and explains how to choose which of them your webhook receives.

:::surface node,python
In the SDKs, the [parse helper](/docs/webhooks#receiving-events) returns one type per area on this page. In Node the union is discriminated on `type`, so checking `type` narrows `data`; in Python, branch on the event class with `isinstance`, since every event's `type` is an open string:

| Events | Node | Python |
| --- | --- | --- |
| `workflow.*` | `TWorkflowWebhookEvent` | `WorkflowWebhookEvent` |
| `account.*` | `TAccountWebhookEvent` | `AccountWebhookEvent` |
| `inbox.*` | `TInboxMessageWebhookEvent` | `MessageWebhookEvent` |
| `network.*` | `TNetworkWebhookEvent` | `NetworkWebhookEvent` |
| `webhook.test` | `TWebhookTestEvent` | `WebhookTestEvent` |

Their union is `TWebhookEvent` in Node and `WebhookEvent` in Python; in Python it also includes `UnknownWebhookEvent`, returned for an event type the installed version doesn't know yet. Signal events are not part of the union yet. In Python, `data` fields are snake_case, such as `workflow_id` and `person_hashed_url`, and a field that is absent is `None`.
:::

:::surface cli
In the CLI, `linkedin admin webhook event-types` lists every event type you can choose, and `linkedin admin webhook set-events <id> <events>` chooses which of them the webhook receives – a comma-separated list such as `"workflow.completed,inbox.*"`, or `--all`. See [Managing webhooks](/docs/admin-webhooks?surface=cli#webhook-setevents).
:::

## Workflow events

`data` carries `workflowId`, `accountId`, and `status`. All events for one run share the same `workflowId`, so you can correlate them.

- `workflow.created` – your request was accepted and queued. `status` is `pending`.
- `workflow.started` – the workflow actually started running. `status` is `running`.
- `workflow.completed` – the workflow reached a terminal state. `status` is `completed` or `failed`.

`data.result` is included only on `workflow.completed`, and only in `fat` payload mode. Cancelled workflows do not emit a webhook.

## Account events

`data` carries `accountId` and `status`, emitted when a connected LinkedIn account changes status.

- `account.reconnectionRequired` – the account needs the user to reconnect. `status` is `reconnection_required`.
- `account.active` – the account (re)connected and is operational. `status` is `active`.
- `account.frozen` – the account was frozen, for example due to an unpaid subscription. `status` is `frozen`.
- `account.deleted` – the account was deleted. `status` is `deleted`.

## Inbox events

The `inbox.*` namespace covers messages observed in a connected account's inbox, as opposed to the state of your own Linked API entities. These events fire for accounts that have [inbox monitoring](/docs/monitoring-inbox) enabled via `st.syncInbox` / `nv.syncInbox`, one event per inbox message. History loaded with [`st.syncConversation`](/docs/action-st-sync-conversation) / [`nv.syncConversation`](/docs/action-nv-sync-conversation) does not produce events.

- `inbox.messageReceived` – an incoming message was observed in the inbox.
- `inbox.messageSent` – an outgoing message from the account was observed. This covers messages sent through the LinkedIn UI **and** messages sent through the Linked API, so an API-sent message emits `inbox.messageSent` in addition to its `workflow.completed`.

`data` carries the message with the following fields:

- `accountId` – the connected LinkedIn account the message belongs to.
- `type` – inbox type the message belongs to (`st` or `nv`).
- `threadId` – identifier of the conversation thread. Pass it to [`st.sendMessage`](/docs/action-st-send-message) / [`nv.sendMessage`](/docs/action-nv-send-message) to reply.
- `personUrn` – [URN](/docs/data-conventions#linkedin-urns) of the other participant, or `null` if LinkedIn does not expose it.
- `personHashedUrl` – [hashed](/faq/what-are-hashed-url-and-public-url) LinkedIn URL of the other participant. This is the form the inbox exposes; every action that takes a person URL accepts it.
- `personPublicUrl` – [public](/faq/what-are-hashed-url-and-public-url) LinkedIn URL of the other participant, or `null` if it has not been resolved. It can be `null` on **any** message, including the first one in a thread, so never treat it as guaranteed. See [inbox polling](/docs/monitoring-inbox) for how it is resolved.
- `personUrl` – **deprecated**, replaced by `personHashedUrl`, which carries the same value. Still sent so existing subscribers keep working; do not use it in new code.
- `messageId` – unique identifier of the message, matching the `id` returned by [inbox polling](/docs/monitoring-inbox).
- `sender` – `us` for `inbox.messageSent`, `them` for `inbox.messageReceived`.
- `text` – message text.
- `time` – ISO 8601 timestamp of the message.

> Because `inbox.messageSent` also fires for outbound messages your own automations send, filter by `data.sender` and `data.type` rather than assuming every event is a fresh inbound reply.

## Network events

The `network.*` namespace covers changes to a connected account's connection graph. These events fire for accounts that have [network monitoring](/docs/monitoring-network) enabled via `st.syncNetwork`, one event per connection change.

- `network.connectionRequestReceived` – someone sent the account a connection request. A new incoming pending invitation was observed.
- `network.connectionAccepted` – a new connection that matches a request the account sent. The other person accepted an outgoing invitation.
- `network.connectionAdded` – a new connection that is not attributable to a request the account sent, for example an incoming request the account accepted, or a connection formed outside the API.

`data` carries the connection event with the following fields:

- `accountId` – the connected LinkedIn account the event belongs to.
- `personUrn` – [URN](/docs/data-conventions#linkedin-urns) of the other person, or `null` if LinkedIn did not expose an identifier on the row that produced the event.
- `personUrl` – LinkedIn URL of the other person.
- `detectedAt` – ISO 8601 timestamp of when Linked API observed the event, matching the `detectedAt` returned by [network polling](/docs/monitoring-network).

## Signal events

> 🚧 **Coming soon.** Signals are not available yet. These events will be delivered once they launch.

The `signal.*` namespace covers what your [signals](/docs/signals-overview) detect, one event per new item. `data` carries the event exactly as [`/signals/poll`](/docs/signal-events#polling) returns it, plus `accountId`.

- `signal.postPublished` – a watched person or company published a post. See [Posts by person or company](/docs/signal-posts).
- `signal.postFound` – a new post matched a keyword signal. See [Posts by keyword](/docs/signal-keyword-posts).
- `signal.commentAdded` – a new comment under a watched post. See [Comments and reactions](/docs/signal-post-engagement).
- `signal.reactionAdded` – a new reaction on a watched post. See [Comments and reactions](/docs/signal-post-engagement).
- `signal.profileViewed` – a new identified viewer of the account's profile. See [Profile viewers](/docs/signal-profile-viewers).

The [`network`](/docs/signal-network) signal keeps the `network.*` events above.

## Event selection

By default a webhook receives every event on this page. You can narrow it to the events you handle. The choice is optional and per webhook, and a webhook that never makes one keeps receiving every event, so existing webhooks are unchanged.

In the [dashboard](https://app.linkedapi.io/webhook), open **Advanced → Events** on your endpoint, or in the dialog that creates it, and switch off **All events** to choose. The endpoint's **Events** row shows the current selection. Programmatically, pass `events` to [`webhook.set`](/docs/admin-webhooks#webhook-set), change it later with [`webhook.setEvents`](/docs/admin-webhooks#webhook-setevents), and list the types you can choose with [`webhook.eventTypes`](/docs/admin-webhooks#webhook-eventtypes).

A selection is either `null`, meaning every event, or a list whose entries are each:

- an exact event type, such as `workflow.completed`;
- a namespace wildcard `<namespace>.*`, such as `inbox.*`. The namespace is the part before the first `.`: `workflow`, `account`, `inbox`, `network` or, once signals launch, `signal`.

**A wildcard follows the family; an exact type pins it.** `inbox.*` matches every inbox event, including event types added later. `inbox.messageReceived` matches only itself and never widens. In the dashboard, choosing a whole group stores its wildcard, while ticking each of its types one by one stores those exact types.

A selection is checked when you save it. An unknown type or namespace, `webhook.test`, `webhook.*`, a bare `*`, any other pattern, or an empty list is rejected with `invalidRequestPayload` naming the entry, so a typo never becomes a webhook that silently receives nothing. A selection holds up to 50 entries of up to 64 characters each. It is stored de-duplicated and sorted, and reading the webhook returns it as `events`.

Delivered whatever you select:

- `webhook.test`, so [`webhook.sendTest`](/docs/admin-webhooks#webhook-sendtest) works on any webhook;
- a [replayed delivery](/docs/admin-webhooks#webhook-replaydelivery), even of a type you have deselected since.

**An event you do not select is never recorded.** Filtering happens when the event is produced, so a deselected event creates no delivery at all. It does not appear in [recent deliveries](/docs/admin-webhooks#webhook-deliveries), cannot be replayed, and does not come back if you select its type later.

**A change applies from the moment you save it.** Events produced after that follow the new selection. Deliveries that were already queued, pending or being retried, are still delivered.
