Smart WebhooksEvent Filtering

Event Filtering

Smart Webhooks can filter incoming events so that only specific event types trigger AI processing. Use the source_events array to define which events your webhook cares about. Unmatched events are silently skipped.

How Filtering Works

When a webhook payload arrives, the execution engine extracts the event type from the payload by checking these fields in order:

  1. payload.type
  2. payload.event.type
  3. payload.event_type
  4. payload.action

The extracted event type is compared against the source_events array. If it matches any entry, the webhook is processed. If not, it is skipped.

Incoming payload -> Extract event type -> Match against source_events?
                                               |
                                    Yes -------+-------- No
                                               |           |
                                          Process      Return { ok: true, skipped: true }

Setting Source Events

On Creation

curl -X POST https://api.aerostack.dev/api/smart-webhooks \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "github-pr-reviewer",
    "workspace_id": "ws_abc123",
    "instructions": "When a PR is opened or updated, review the changes...",
    "source_type": "github",
    "source_events": ["opened", "synchronize"]
  }'

On Update

curl -X PATCH https://api.aerostack.dev/api/smart-webhooks/swh_your_id \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source_events": ["opened", "synchronize", "reopened"]
  }'

Accept All Events

Use ["*"] as a wildcard to accept all event types:

curl -X POST https://api.aerostack.dev/api/smart-webhooks \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "catch-all",
    "workspace_id": "ws_abc123",
    "instructions": "Log all incoming events and categorize them...",
    "source_events": ["*"]
  }'

When source_events contains "*", all events are processed regardless of type.

No Filter (Accept All)

If source_events is not set or is an empty array, all events are accepted:

# No source_events field -- accepts everything
curl -X POST https://api.aerostack.dev/api/smart-webhooks \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "process-everything",
    "workspace_id": "ws_abc123",
    "instructions": "Handle all incoming webhooks..."
  }'

Omitting source_events and setting source_events: ["*"] have the same effect — all events are processed. Use ["*"] if you want to be explicit about the intent.

Skipped Event Response

When an event does not match the filter, the response includes a skipped flag:

{
  "ok": true,
  "skipped": true
}

Skipped events are not logged in the run history and do not consume AI tokens.

Provider-Specific Event Types

GitHub

GitHub sends the event type in the action field of the payload. Common events to filter on:

EventDescription
openedIssue or PR opened
closedIssue or PR closed
synchronizeNew commits pushed to a PR
reopenedIssue or PR reopened
labeledLabel added to issue/PR
assignedIssue/PR assigned
createdComment created
submittedReview submitted

Example — PR review bot:

{
  "source_events": ["opened", "synchronize", "reopened"]
}

Example — Issue triager:

{
  "source_events": ["opened"]
}

Stripe

Stripe sends the event type in the type field at the top level. Common events:

EventDescription
payment_intent.succeededPayment completed
payment_intent.payment_failedPayment failed
customer.subscription.createdNew subscription
customer.subscription.updatedSubscription changed
customer.subscription.deletedSubscription cancelled
invoice.payment_succeededInvoice paid
invoice.payment_failedInvoice payment failed

Example — Payment handler:

{
  "source_events": [
    "payment_intent.succeeded",
    "payment_intent.payment_failed",
    "customer.subscription.deleted"
  ]
}

Shopify

Shopify uses the X-Shopify-Topic header and includes the event in the payload. Common topics:

EventDescription
orders/createNew order placed
orders/fulfilledOrder fulfilled
orders/cancelledOrder cancelled
products/updateProduct updated
customers/createNew customer

Example — Order processor:

{
  "source_events": ["orders/create", "orders/fulfilled"]
}

Custom Services

For your own services, include the event type in the payload using any of the supported fields:

// Using "type" field
{
  "type": "user.created",
  "data": { "id": "usr_123", "email": "[email protected]" }
}
// Using "event_type" field
{
  "event_type": "order.shipped",
  "order_id": "ord_456"
}
// Using "action" field
{
  "action": "deployment.completed",
  "environment": "production"
}

Limits

ConstraintValue
Maximum events in source_events array50
Maximum event string length100 characters

Combining with HMAC Verification

Event filtering runs after HMAC signature verification. The processing order is:

  1. Signature verification (if signing_secret is set)
  2. Event type extraction from payload
  3. Event filter check against source_events
  4. AI execution (if event matches)

A request that passes signature verification but fails the event filter is not processed and returns { ok: true, skipped: true }. It is not logged in the run history.

Best Practices

Be specific with filters. Only process the events you need. This reduces AI token consumption and avoids unnecessary tool calls:

// Good -- specific events
{ "source_events": ["opened", "reopened"] }
 
// Avoid -- processes everything, wastes tokens on irrelevant events
{ "source_events": ["*"] }

Match your instructions to your filters. If your source_events includes multiple event types, write instructions that handle each case:

Instructions:
- If the event is "opened": Classify and label the issue
- If the event is "reopened": Check if the original fix was reverted and comment with context
- If the event is "closed": Thank the contributor if it was fixed via PR

Use dedicated webhooks for different workflows. Instead of one webhook that handles all GitHub events, create separate webhooks for issues, PRs, and deployments. This keeps instructions focused and reduces the chance of the AI misinterpreting the payload.