> For the complete documentation index, see [llms.txt](/llms.txt).
> A full single-fetch corpus is available at [llms-full.txt](/llms-full.txt).
---
title: Build a webhook triage agent
description: Receive events, deduplicate delivery attempts, run async triage, and expose a trace per webhook.
tags: ["Webhooks", "Dedupe", "Async"]
date: 2026-05-13
last_verified: 2026-05-13
audience: both
---

Webhook delivery is noisy: providers retry, events arrive late, and downstream
systems fail. This cookbook builds a triage agent that deduplicates events and
runs async work under a trace.

## Scenario

A product receives incident webhooks. The workflow deduplicates events, asks an
agent to classify urgency, opens a ticket when needed, and records the result.

## What you build

- A webhook entry point.
- Event deduplication.
- Async triage with an agent.
- Idempotent ticket creation.
- A trace link returned to the webhook caller or dashboard.

## Workflow shape

```python
@workflow
async def triage_webhook(ctx: WorkflowContext, event: WebhookEvent) -> WebhookOutcome:
    deduped = await ctx.step(record_event_once, event.provider_event_id, event)
    if deduped.already_seen:
        return WebhookOutcome(status="duplicate", original_run_id=deduped.run_id)

    classification = await ctx.step(classify_incident_event, event)
    if classification.priority == "ignore":
        return WebhookOutcome(status="ignored")

    ticket = await ctx.step(create_incident_ticket_once, event.provider_event_id, classification)
    return WebhookOutcome(status="ticket_created", ticket_id=ticket.id)
```

The provider event ID is the key. It protects both dedupe and ticket creation.

## Webhook response

Return quickly with a run ID when the provider requires a fast response.

```json
{
  "accepted": true,
  "run_id": "run_01JWEBHOOK",
  "trace_url": "https://app.agnt5.com/runs/run_01JWEBHOOK"
}
```

The trace becomes the operational record for the asynchronous work.

## Production checks

- Duplicate provider deliveries return the original run or receipt.
- Ticket creation uses the provider event ID as an idempotency key.
- The trace includes raw event payload, classification, and side-effect receipt.
- Late events are processed according to explicit business rules.
- Failed events can be replayed locally.

## Next steps

- [Retry AI workflow steps without duplicate side effects](/cookbooks/retry-without-duplicate-side-effects.md)
- [Debug and replay a failed AI workflow](/cookbooks/debug-production-run.md)
- [Debug AI workflows with traces, not scattered logs](/cookbooks/workflow-native-observability.md)
