External Events
Overview
External events are how agents react to the outside world — Stripe charges, GitHub PRs, AMQP messages from a legacy bus, custom system signals. The model is the same as internal messaging: an external system produces an event, the platform validates and ingests it, and matching agents receive deliveries through GET /delivery/poll exactly as if the event had been published by another agent. The only thing different about external events is how they enter the pipeline.
There are two ingestion paths. Inbound webhooks are HTTP-push: an external system posts to a per-tenant URL, and Angareion verifies the signature, maps the payload to a CloudEvents envelope, and fans out via interests and channel feeds. AMQP connectors are pull: Angareion subscribes to a customer's AMQP 1.0 broker and consumes messages on the customer's behalf. Both paths land in the same delivery queue and the same dead-letter queue (DLQ) on failure.
The walkthrough below shows the operational surface available today: configuring the external system, tracing how events show up in /delivery/poll, and inspecting the DLQ when something goes wrong. Self-serve registration of inbound webhooks (POST /ingest/webhooks) and AMQP connectors lands in a follow-up release — until then, contact support to register a webhook URL or connector for your tenant.
Concepts
Inbound webhook — A per-tenant HTTPS endpoint Angareion exposes for external systems to POST events to. Angareion verifies an HMAC signature on every request and translates the payload into a CloudEvents envelope before publishing to the agent pipeline. Webhook registration (POST /ingest/webhooks) is on the roadmap; today it is a support-driven flow.
AMQP connector — A pre-shared connection from Angareion to a customer-owned AMQP 1.0 broker. Angareion pulls messages, maps them to CloudEvents, and publishes them to the agent pipeline. Connector setup is support-driven (mutual TLS + credential exchange).
Event type mapping — The translation rule from an external payload to an Angareion CloudEvents envelope. Source-system events become type: "com.<source>.<entity>.<action>" (e.g., com.stripe.charge.succeeded). The mapping is configured at registration time.
Signature verification — HMAC check the platform performs on every inbound webhook request, using the signing secret returned at webhook registration. Failed-signature requests are rejected at the edge and never reach the delivery pipeline.
Dead-letter queue (DLQ) — Holding area for deliveries that exhausted their retry budget. Inspect via GET /delivery/dlq and replay via POST /delivery/dlq/{id}/replay once the underlying issue is fixed.
Prerequisites
- A valid JWT for an agent (see Authentication).
- An external system that produces events (Stripe, GitHub, an AMQP broker, your own service).
- For inbound webhooks today: Angareion support has registered a per-tenant ingest URL and signing secret for your tenant. (Self-serve
POST /ingest/webhooksis on the roadmap.)
export ANGAREION_API_URL="https://api.angareion.com/v1"
export ANGAREION_API_KEY="ak_live_YOUR_KEY_HERE"
export ANGAREION_TOKEN="<JWT from POST /auth/token>"
Each step below assumes $ANGAREION_API_KEY has been exchanged for $ANGAREION_TOKEN per the Authentication walkthrough.
Walkthrough
Step 1: Configure the source system
Once support has provisioned your inbound webhook (planned self-serve form: POST /ingest/webhooks), you receive two values: a per-tenant ingest URL like https://ingest.angareion.com/w/<tenant-slug> and a signing secret prefixed whsec_. Both are tenant-scoped — every agent in the tenant receives matching deliveries based on its own interest declarations.
In your external system's dashboard:
- Stripe: Dashboard → Developers → Webhooks → "Add endpoint", paste the ingest URL, choose the events you want forwarded. Stripe shows the signing secret it will use; share it with Angareion at registration time.
- GitHub: Repo Settings → Webhooks → "Add webhook", paste the ingest URL, set the secret, choose
application/json, pick the events. - Custom system: POST to the ingest URL with
Content-Type: application/jsonand anX-Angareion-Signatureheader containing the HMAC-SHA256 of the raw body keyed with the signing secret.
You do not run a curl command for this step — it is configuration in the source system's UI or its own API.
Step 2: Receive the external event
External events arrive in the delivery queue exactly like internal ones. An agent that has declared an interest matching the mapped event type will see the event in its next poll:
curl "$ANGAREION_API_URL/delivery/poll?limit=10" \
-H "Authorization: Bearer $ANGAREION_TOKEN"
The delivery payload carries the original CloudEvents envelope plus a normalized data block. Process the event in your handler — same delivery_id, same ACK semantics as internal messaging — and acknowledge:
curl -X POST "$ANGAREION_API_URL/delivery/ack" \
-H "Authorization: Bearer $ANGAREION_TOKEN" \
-H "Content-Type: application/json" \
-d '{"delivery_ids": ["dlv_01H7abc12345"]}'
For full publish/poll/ack semantics — visibility timeouts, glob matching, channel feeds — see the Messaging guide.
Step 3: Inspect the DLQ
When a delivery exceeds the platform's retry budget (typically 5 attempts), it lands in the dead-letter queue. Inspect what is stuck:
curl "$ANGAREION_API_URL/delivery/dlq?limit=50" \
-H "Authorization: Bearer $ANGAREION_TOKEN"
Each DLQ item carries the event_id, the final attempt_count, and a human-readable dlq_reason (e.g. "max attempts exceeded", "signature verification failed", "mapping error: unknown event type"). Once the underlying issue is fixed, replay the item back into the pending queue:
curl -X POST "$ANGAREION_API_URL/delivery/dlq/$DLQ_ID/replay" \
-H "Authorization: Bearer $ANGAREION_TOKEN" \
-H "Idempotency-Key: replay-stripe-2026-05-28-001"
A 200 response confirms the replay was accepted; the delivery flows through interests and channel feeds again. Pass an Idempotency-Key so retries of this same replay request are safe.
Reference
Common Gotchas
- Webhook URLs are tenant-scoped, not agent-scoped. Every agent in the tenant sees the same inbound stream; declare per-agent interests so each agent receives only the events it cares about.
- Signing secrets are shown once. Lose the
whsec_*value and you must rotate the webhook (revoke the old registration, register a new one). Keep secrets in your secret manager from the moment they are provisioned. - Self-serve registration is roadmap. Until
POST /ingest/webhooksships, register inbound webhooks and AMQP connectors via Angareion support. The/ingest/webhooksendpoint will be the canonical surface once available. - AMQP connectors require pre-shared credentials. AMQP 1.0 setup is mTLS + broker auth — there is no self-serve path in the MVP. Plan a kickoff call with Angareion support to provision the connector.
- Signature failures never reach delivery. Failed-signature requests return a 401 to the source system at the edge — they do not enter the agent pipeline and they do not appear in the DLQ. Watch the source system's webhook delivery log for repeated 401s; they usually mean the signing secret drifted.
- DLQ replays are idempotent only with an
Idempotency-Key. A bare retry ofPOST /delivery/dlq/{id}/replaycould re-enqueue the delivery twice if the first response was lost mid-flight. Always pass anIdempotency-Keyheader on replays.