Webhook retry is everyone's problem. AXME eliminates it with 5 delivery bindings - SSE stream, poll, HTTP push, inbox, internal - all with at-least-once delivery.
Stop building webhook retry logic. Exponential backoff? Jitter? Dead letter queues? Thundering herd? AXME gives you 5 delivery options with at-least-once guarantees. The receiver chooses how to get messages. No webhook endpoint needed.
Alpha - Built with AXME (AXP Intent Protocol). cloud.axme.ai - hello@axme.ai
You need to deliver a message from service A to service B reliably. Your options today:
Option 1: Webhooks
- Build an HTTP endpoint on the receiver
- Implement HMAC signature verification
- Handle duplicate deliveries (idempotency)
- Build retry with exponential backoff + jitter
- Dead letter queue for permanent failures
- Thundering herd when retries all fire at once
- Log, monitor, alert on delivery failures
Option 2: Message queue (RabbitMQ, SQS, Kafka)
- Deploy and operate the queue infrastructure
- Build producers and consumers
- Handle poison messages, DLQ, offset management
- Monitor queue depth, consumer lag, partition rebalancing
Both options: 200+ lines of infrastructure code before any business logic.
Sender: client.send_intent(payload)
Receiver: picks delivery mode that fits
stream - SSE (real-time, agent keeps connection open)
poll - GET polling (serverless, cron-based consumers)
http - Webhook POST (traditional, but AXME handles retry)
inbox - Human inbox (for human-in-the-loop)
internal - Platform-internal (reminders, escalations)
The sender doesn't care how the receiver gets the message. AXME delivers with at-least-once guarantees on all modes.
pip install axme
export AXME_API_KEY="your-key" # Get one: axme loginfrom axme import AxmeClient, AxmeClientConfig
import os
client = AxmeClient(AxmeClientConfig(api_key=os.environ["AXME_API_KEY"]))
# Send an order - AXME delivers to the processor
intent_id = client.send_intent({
"intent_type": "intent.order.process.v1",
"to_agent": "agent://myorg/production/order-processor",
"payload": {
"order_id": "ORD-2026-00142",
"customer": "acme-corp",
"total": 4999.50,
},
})
print(f"Submitted: {intent_id}")
# Wait for result - no polling on your side
result = client.wait_for(intent_id)
print(f"Done: {result['status']}")npm install @axme/axmeimport { AxmeClient } from "@axme/axme";
const client = new AxmeClient({ apiKey: process.env.AXME_API_KEY! });
const intentId = await client.sendIntent({
intentType: "intent.order.process.v1",
toAgent: "agent://myorg/production/order-processor",
payload: {
orderId: "ORD-2026-00142",
customer: "acme-corp",
total: 4999.5,
},
});
console.log(`Submitted: ${intentId}`);
const result = await client.waitFor(intentId);
console.log(`Done: ${result.status}`);| Language | Directory | Install |
|---|---|---|
| Python | python/ |
pip install axme |
| TypeScript | typescript/ |
npm install @axme/axme |
| Go | go/ |
go get github.com/AxmeAI/axme-sdk-go |
# Webhook endpoint (receiver must build this)
@app.post("/webhooks/orders")
async def receive_order(req):
# Verify HMAC signature
signature = req.headers.get("x-webhook-signature")
if not verify_hmac(signature, req.body, WEBHOOK_SECRET):
return {"error": "invalid signature"}, 401
# Check idempotency (handle duplicate deliveries)
idempotency_key = req.headers.get("x-idempotency-key")
if db.exists("processed_webhooks", idempotency_key):
return {"status": "already processed"}, 200
# Process the order
process_order(req.json())
db.insert("processed_webhooks", idempotency_key)
return {"status": "ok"}, 200
# Sender must build retry logic
async def send_with_retry(url, payload, max_retries=5):
for attempt in range(max_retries):
try:
resp = requests.post(url, json=payload, headers=sign(payload))
if resp.status_code == 200:
return resp
if resp.status_code >= 500:
raise RetryableError()
except (ConnectionError, Timeout, RetryableError):
delay = min(2 ** attempt + random.uniform(0, 1), 300) # backoff + jitter
await asyncio.sleep(delay)
# Dead letter queue
dlq.send(payload)
alert("Webhook delivery failed after 5 retries")
# Plus: DLQ consumer, monitoring, alerting, cleanup...intent_id = client.send_intent({
"intent_type": "intent.order.process.v1",
"to_agent": "agent://myorg/production/order-processor",
"payload": {"order_id": "ORD-2026-00142", "customer": "acme-corp", "total": 4999.50},
})
result = client.wait_for(intent_id)No webhook endpoint. No HMAC verification. No idempotency table. No retry logic. No backoff. No jitter. No DLQ. No monitoring. AXME handles all of it.
| Binding | Transport | Best For | Receiver Builds |
|---|---|---|---|
stream |
SSE (server-sent events) | Real-time agents, services | SSE client (3 lines) |
poll |
GET polling | Serverless, cron jobs | GET request (1 line) |
http |
Webhook POST | Services with HTTP endpoint | Nothing (AXME handles retry) |
inbox |
Human inbox | Approvals, reviews | Nothing (CLI/email/form) |
internal |
Platform-internal | Reminders, escalations | Nothing (automatic) |
The receiver chooses the binding. The sender just calls send_intent().
+-----------+ send_intent() +----------------+ deliver +-----------+
| | ---------------> | | ---------> | |
| Sender | | AXME Cloud | (stream, | Receiver |
| | <- wait_for() -- | (platform) | poll, | (agent) |
| | resumes when | | http, | |
| | receiver done | at-least-once | inbox) | processes |
| | | delivery on | | and |
| | | ALL bindings | <- resume | resumes |
+-----------+ +----------------+ +-----------+
- Sender submits an intent with payload and target
- AXME delivers via the receiver's configured binding
- If delivery fails, AXME retries (up to
max_delivery_attempts) - Receiver processes and resumes with result
- Sender gets the result via SSE stream (real-time, no polling)
# Install CLI (one-time)
curl -fsSL https://raw.githubusercontent.com/AxmeAI/axme-cli/main/install.sh | sh
# Open a new terminal, or run the "source" command shown by the installer
# Log in
axme login
# Install Python SDK
pip install axmeaxme scenarios apply scenario.json
# Note the intent_id in the outputGet the agent key after scenario apply:
# macOS
cat ~/Library/Application\ Support/axme/scenario-agents.json | grep -A2 order-processor-demo
# Linux
cat ~/.config/axme/scenario-agents.json | grep -A2 order-processor-demoRun in your language of choice:
# Python
AXME_API_KEY=<agent-key> python agent.py
# TypeScript (requires Node 20+)
cd typescript && npm install
AXME_API_KEY=<agent-key> npx tsx agent.ts
# Go
cd go && go run ./cmd/agent/axme intents get <intent_id>
# lifecycle_status: COMPLETED- AXME - project overview
- AXP Spec - open Intent Protocol specification
- AXME Examples - 20+ runnable examples across 5 languages
- AXME CLI - manage intents, agents, scenarios from the terminal
- Replacing Webhooks with AXME - webhook replacement example
Built with AXME (AXP Intent Protocol).