Accept your first event
Create a workspace and a source, then send an event to its ingest URL.
Start on Axel Cloud to use the managed service. These guides cover sources, routing, delivery, recovery, and reports.
Open Reports in the dashboard and pick a Drip or Chargebee source. A generic webhook source works too once it has received Drip broadcast or Chargebee events. Axel reads that source's events directly, so you don't need a destination or a warehouse. New events reach the report as they arrive, and Axel loads the source's last 30 days when the first report starts.
Create a workspace and a source, then send an event to its ingest URL.
Sources accept events. Routes filter and transform them. Destinations receive the result. Retries keep the same event ID so receivers can deduplicate them.
Inspect failures, fix route errors, and replay retained events.
Event metadata, retry defaults, storage, and response codes.
Create an Axel Cloud workspace and a workspace API key with write access. Set AXEL_API_KEY in your shell before running the example.
curl -X POST https://app.axelapp.ai/api/v1/sources \
-H "Authorization: Bearer $AXEL_API_KEY" \
-H "content-type: application/json" \
-d '{ "name": "my-webhook" }'The response includes the source ID, ingest URL, and secret_token. Axel shows the token only once. Set AXEL_INGEST_URL to the returned ingest URL and AXEL_SOURCE_TOKEN to the token before the next command.
curl -X POST "$AXEL_INGEST_URL" \
-H "x-axel-token: $AXEL_SOURCE_TOKEN" \
-H "content-type: application/json" \
-d '{ "type": "order.created", "id": "ord_123" }' Axel returns 202 after storing the payload and queueing it for routing. This confirms acceptance, not destination delivery.
Open app.axelapp.ai. Check Overview for accepted events and Usage for traffic by source. To deliver events onward, create a destination and an active route from this source, then send another event and check Deliveries.
Axel Cloud keeps searchable event history for 30 days. Raw payloads expire after 30 days by default, or sooner if you configure shorter retention.
Welcome back. Here's what's happening across Northwind.
evt_01HZQ8R7XKHTTP 503 from warehouse-webhook · retry 2/12evt_01HZQ7N4WTTLS handshake timeout · destination pausedevt_01HZQ6M2VRReplay batch resolved · 11 deliveriesevt_01HZQ5L1UQSchema guard rejected · depth > 24Create a source in the dashboard, then point your webhook producer at the ingest URL it shows. With the Axel CLI, run axel auth login and axel listen --source <source_id> --forward-to <url> to forward new events to a local handler.
Use the generic source for producers that can POST JSON, form data, or bytes.
Create a source with curl or the dashboard, then POST to https://ingest.axelapp.ai/in/{source_id} with the x-axel-token header you received. No signature required.
curl -X POST https://ingest.axelapp.ai/in/src_01H... \
-H "x-axel-token: $AXEL_SOURCE_TOKEN" \
-H "content-type: application/json" \
-d '{ "type": "order.created", "id": "ord_123" }'You can also bring a custom HMAC secret and Axel will verify an X-Axel-Signature: t=<unix>,v1=<hex> header with a five-minute timestamp tolerance. Senders that can't set custom headers can use a separately generated URL credential, enabled per source.
Each source has its own authentication, rate limit, body size limit, and nesting depth limit.
{
"event_id": "evt_01HZQ8R7XK",
"source": "stripe.webhooks",
"event": "invoice.paid",
"customer": "cus_PqJ8XKr",
"amount": 14250,
"currency": "usd",
"routes": ["payments.live"]
}Routes choose destinations and define which fields each destination receives.
JSONB column.stripe.webhooksmongo://ordersgithub.webhookss3://raw-ledgershopify.webhookspostgres://billingpartner.webhookhttps://hooks.exampleDeliver with retries to the systems you already run.
{date}, {event_id}). Cloudflare R2: write JSON objects under a configurable key prefix.Axel provides at-least-once delivery to external destinations. Delivery attempts use a stable key of the form workspace:event:route:destination, and retries reuse that key. A signed HTTP receiver should deduplicate on X-Axel-Event-Id because a process can fail after the destination accepts a request but before Axel records the acknowledgement. Replays use a new event ID and are intentionally delivered again.
Replay an accepted event while its original payload is retained.
Use the dashboard to replay through your routes. Use the CLI to send stored bytes directly to a local handler:
# Dashboard: click any event → Replay
# CLI (exact bytes to your laptop)
axel replay evt_01HZQ8R7XK --forward-to http://localhost:3000/webhook --keep-signature preserves only headers still present in the retrieved metadata; it cannot restore headers removed at ingestion or make an expired signature valid.Terminal failures appear in the Inbox after retries are exhausted or the destination returns a non-retryable error. Open the failure to inspect its history, retry after a fix, or mute it.
The event detail page shows the receipt, the stored payload, and a delivery history of every HTTP attempt with its status, latency, and the failure reason (TLS error, 503, timeout, etc.).
If a declarative filter excludes an event it is dropped; if a transform or filter errors at runtime the event is dead-lettered and shows up in the Inbox. Oversized or too-deep payloads are rejected at ingest with a 413 before they are ever stored or routed.
Every stored event carries Axel metadata and a pointer to the raw body in R2 (the body is referenced by r2_key rather than inlined). Example shape:
{
"event_id": "evt_01HZQ8R7XK",
"workspace_id": "ws_...",
"source_id": "src_...",
"received_at": "2026-06-16T14:22:09.123Z",
"r2_key": "...",
"size_bytes": 1024,
"headers": { "x-my-signature": "..." },
"query": {}
}Up to 12 delivery attempts with exponential backoff. Retries are included in the inbound event price. The retry policy is fixed and not per-source configurable.
ClickHouse stores receipt, routing, and delivery metadata for 30 days. The dashboard and CLI use it for event search and delivery history. Raw payloads stay in R2.
Email support with setup, usage, account, or billing questions.