# WebhookSignalProvider

**Added in:** `@mastra/core@1.39.0`

Concrete signal provider for push-based event delivery. Routes incoming webhook payloads to subscribed agent threads by matching the payload against a configurable resource ID extractor.

Extends [`SignalProvider`](https://mastra.ai/reference/signals/signal-provider) with public subscription management and a built-in `handleWebhook()` implementation.

## Usage example

Route GitHub webhook events to subscribed threads:

```typescript
import { WebhookSignalProvider } from '@mastra/core/signals'

const webhookProvider = new WebhookSignalProvider({
  extractResourceId: payload => `${payload.repository?.full_name}`,
  buildNotification: (payload, subscription) => ({
    source: 'github-webhook',
    kind: payload.action ?? 'event',
    summary: `${payload.action} on ${subscription.externalResourceId}`,
    payload,
  }),
})
```

Register with an agent and subscribe a thread:

```typescript
import { Agent } from '@mastra/core/agent'

const agent = new Agent({
  signals: [webhookProvider],
})

// subscribe a thread to a specific repo
webhookProvider.subscribeThread({ threadId: 'thread-1', resourceId: 'user-1' }, 'mastra-ai/mastra')

// handle an incoming webhook
const result = await webhookProvider.handleWebhook({
  body: { repository: { full_name: 'mastra-ai/mastra' }, action: 'push' },
  headers: {},
})
// result.matched === 1
```

## Constructor parameters

**id** (`string`): Unique identifier for the provider instance. (Default: `'webhook-signals'`)

**name** (`string`): Human-readable name. (Default: `'Webhook Signals'`)

**extractResourceId** (`(payload: unknown) => string | string[] | undefined`): Extract the external resource ID from a webhook payload. Return \`undefined\` to skip the event. Can return an array to match multiple resources. (Default: ``Returns `payload.resource` or `payload.externalResourceId` if present``)

**buildNotification** (`(payload: unknown, subscription: SignalSubscription) => SendNotificationSignalInput`): Build the notification object from a webhook payload and the matched subscription. (Default: `` Returns `{ source: id, kind: 'webhook-event', summary, payload }` ``)

## Methods

### Subscription management

#### `subscribeThread(target, externalResourceId, metadata?)`

Subscribe a thread to receive webhook events for a specific external resource.

```typescript
webhookProvider.subscribeThread(
  { threadId: 'thread-1', resourceId: 'user-1' },
  'mastra-ai/mastra',
  { watchType: 'push' },
)
```

Returns: `SignalSubscription`

**target** (`SignalProviderTarget`): The thread to subscribe. Must include \`threadId\` and \`resourceId\`.

**externalResourceId** (`string`): The external resource to monitor (for example, a repository full name).

**metadata** (`Record<string, unknown>`): Additional data to store with the subscription.

#### `unsubscribeThread(target, externalResourceId)`

Unsubscribe a thread from a specific external resource.

```typescript
const removed = webhookProvider.unsubscribeThread(
  { threadId: 'thread-1', resourceId: 'user-1' },
  'mastra-ai/mastra',
)
```

Returns: `boolean`

### Webhook handling

#### `handleWebhook(request)`

Process an incoming webhook request. Extracts the resource ID from the payload, finds matching subscriptions, builds a notification for each, and calls `notify()`.

```typescript
const result = await webhookProvider.handleWebhook({
  body: { repository: { full_name: 'mastra-ai/mastra' }, action: 'push' },
  headers: { 'x-github-event': 'push' },
})
```

Returns: `Promise<{ status: number; body: { matched: number } }>`

Returns `{ status: 200, body: { matched: N } }` where `N` is the number of subscriptions that received notifications. Returns `matched: 0` when no resource ID could be extracted or no subscriptions match.

**request** (`object`): The incoming webhook request.

**request.body** (`unknown`): The parsed webhook payload.

**request.headers** (`Record<string, string>`): HTTP headers from the webhook request.

### Static signal factories

#### `WebhookSignalProvider.signals.subscribe(externalResourceId)`

Create a reactive signal input that subscribes the current thread to an external resource.

```typescript
const signal = WebhookSignalProvider.signals.subscribe('mastra-ai/mastra')
```

Returns: `{ type: 'reactive'; tagName: string; contents: string; attributes: { resource: string } }`

#### `WebhookSignalProvider.signals.unsubscribe(externalResourceId)`

Create a reactive signal input that unsubscribes the current thread from an external resource.

```typescript
const signal = WebhookSignalProvider.signals.unsubscribe('mastra-ai/mastra')
```

Returns: `{ type: 'reactive'; tagName: string; contents: string; attributes: { resource: string } }`