Receive. Deliver.
Stay in control.
Create your Webhooks account with your email address, or sign in if you already have one. No existing AGNT account or app subscription is required. Agent keys are scoped to read, emit and manage; they cannot purchase credit or create more keys.
Open your account →Headless signup (agents)
No email, no browser. The secret is your identity.
POST https://webhooks.agnt.gg/hooks/v1/agents
Content-Type: application/json
{"name":"my-agent"}
→ 201 { "agentId": "agt_…", "secret": "hook_…", "balance": 0,
"fund": { "claimUrl": "https://webhooks.agnt.gg/claim/agt_…", "x402": "POST /hooks/v1/funding/x402" } }Share the funding link with the person paying for the agent, or pay over x402 (next section). After hosting is active, GET /hooks/v1/agents/AGENT_ID/claim returns hostingActive: true; a funded balance alone does not create an endpoint. Machine-readable: llms.txt · openapi.json.
Agents pay for themselves with x402
An agent can fund its own account without a browser, a card, or a human: request a funding order, pay the returned x402 requirements in USDC on Base, and the credit lands on the same balance cards use. Settlement runs through the Coinbase x402 facilitator and is recorded as a Stripe payment. This is the same flow AGNT Mail runs live today.
The 20-line client (JavaScript)
// pay.mjs — an agent funding its own AGNT Webhooks account
// npm i @x402/fetch @x402/evm @x402/core viem
import { privateKeyToAccount } from 'viem/accounts';
import { x402Client } from '@x402/core/client';
import { registerExactEvmScheme } from '@x402/evm/exact/client';
import { wrapFetchWithPayment } from '@x402/fetch';
const auth = { Authorization: 'Bearer ' + process.env.HOOK_SECRET, 'Content-Type': 'application/json' };
const wallet = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY); // holds USDC on Base; no ETH needed
// 1. Create a funding order → HTTP 402 with x402 requirements
const created = await fetch('https://webhooks.agnt.gg/hooks/v1/funding/x402', { method: 'POST', headers: auth, body: JSON.stringify({ amountCents: 1000 }) });
const order = await created.json(); // { orderId, state: 'awaiting_payment', requirements }
// 2. Let the x402 client sign and pay. The default spend cap is $1 — raise it or every order is refused.
const client = new x402Client().setSpendControls({ maxAmountPerPayment: '$50' });
registerExactEvmScheme(client, { signer: wallet, networks: ['eip155:8453'] });
const paidFetch = wrapFetchWithPayment(fetch, client);
const paid = await paidFetch('https://webhooks.agnt.gg/hooks/v1/funding/x402/' + order.orderId, { method: 'POST', headers: auth, body: '{}' });
const result = await paid.json(); // { state: 'credited', transactionId: '0x…', paymentIntent: 'pi_…' }
// 3. Spend the credit: buy a plan, make an endpoint, start receiving
await fetch('https://webhooks.agnt.gg/hooks/v1/hosting/purchase', { method: 'POST', headers: { ...auth, 'Idempotency-Key': order.orderId }, body: JSON.stringify({ plan: 'starter' }) });
await fetch('https://webhooks.agnt.gg/hooks/v1/endpoints', { method: 'POST', headers: auth, body: JSON.stringify({ name: 'orders' }) });
Two things that will bite you
- Spend cap.
@x402/fetchrefuses any payment over $1 by default. Every order is $10 or more, so callsetSpendControls({ maxAmountPerPayment: '$50' })or the payment silently fails with a confusing error. - Your wallet needs USDC on Base and nothing else. The facilitator pays the gas, so you do not need ETH. Easiest way to fund it: Coinbase app → Send → USDC → network Base.
Amounts: 1000, 2500 or 5000 cents. Orders expire after 10 minutes; a settled transaction can never be replayed onto another order, and a wrong amount, destination or expired authorization returns 400 without charging. Network eip155:8453 (Base), asset USDC, protocol x402 v2. GET /hooks/v1/capabilities reports autonomousFunding: true when x402 is enabled for this product. Card and wallet Checkout remain available for humans.
Create your Webhooks account
- Enter your email on the account page and request a verification code. A new Webhooks account is created when you verify it.
- Add prepaid credit through Stripe ($10 minimum top-up).
- Activate one month of hosting for $5 from your balance, then create your endpoint. Use View events to watch what arrives, or create a scoped key for your agent.
- Use that key in the Authorization header. Keep it secret.
Card and supported stablecoin payments are available through Stripe Checkout, and agents can fund headlessly with USDC on Base over x402. Existing prepaid credit can activate standalone hosting; eligible paid AGNT accounts include hosting.
Endpoints and receiving
POST /hooks/v1/endpoints {"name":"orders"} → 201 { id, slug, url, state }
GET /hooks/v1/endpoints → { endpoints: [ … ] }
POST /hooks/v1/endpoints/ID/pause · /resume → pause or resume the public URL
DELETE /hooks/v1/endpoints/ID → retire; the slug is never reusedAn endpoint's public URL is https://webhooks.agnt.gg/in/SLUG. Anything can POST to it—no authentication, the slug is the address. Rotate by retiring and creating a new one.
POST https://webhooks.agnt.gg/in/SLUG
Content-Type: application/json (also application/x-www-form-urlencoded, text/plain)
Idempotency-Key: order-42 (optional; otherwise the body hash deduplicates)
→ 202 { "eventId": "…", "state": "stored" }
→ 200 { "eventId": "…", "state": "stored" } same key or body seen before; no new charge
→ 404 endpoint_not_found · 413 payload_too_large (>256 KB) · 415 unsupported_media_type
→ 402 overage_not_enabled / hosting_required (owner's plan) · 429 rate_limited · 503 ingress_unavailableThe body is written to disk and one unit is reserved and settled before the 202 is returned. We never execute, fetch or follow anything in a body. Per-endpoint rate limits: 60, 600 or 6,000 events per minute by plan.
Read, replay and export
GET /hooks/v1/endpoints/ID/events?after=RECEIVED_AT → { events: [ { id, source, bytes, content_type, received_at, expires_at } ] }
GET /hooks/v1/events/EVENT_ID → { id, endpointId, source, contentType, bytes, receivedAt, expiresAt, body }
POST /hooks/v1/events/EVENT_ID/replay → re-queue to every active receiver (Pro and Business)
GET /hooks/v1/endpoints/ID/export?since=0 → NDJSON, one event with body per line (owner)Events are returned oldest first, 100 per page; pass the last received_at as after to continue. Bodies are returned as the raw string that was posted. Events are purged after your plan's retention window (7, 30 or 90 days); export before then if you need to keep them.
Receivers and signed delivery
Register a public HTTPS receiver and every stored event is pushed to it. Register from the account page or with an agent key that has hook:manage.
POST /hooks/v1/webhooks {"url":"https://your-agent.example/inbound"} → 201 { id, secret }
GET /hooks/v1/webhooks
POST /hooks/v1/webhooks/ID/resume
DELETE /hooks/v1/webhooks/ID
GET /hooks/v1/webhook-deliveries attempts, status and last HTTP code per event
GET /hooks/v1/notifications?after=0 the event log behind deliveriesEach delivery carries X-AGNT-Event-ID, X-AGNT-Timestamp and X-AGNT-Signature: v1=hex, where the signature is HMAC-SHA256 over the timestamp, a period, and the exact raw JSON body. Verify with the secret from registration, reject stale timestamps and deduplicate on event ID. The body is { id, type: "event.received" | "event.emitted" | "receiver.paused", eventId, endpointId, body } where body is the event as posted (parsed JSON when possible).
Delivery is at least once. Retries back off from 60 seconds to one hour, up to 3 attempts on Starter and 12 on Pro and Business. A receiver that exhausts 5 events in a row is paused and a receiver.paused event is recorded; resuming re-queues the exhausted deliveries. Public HTTPS on port 443 only; redirects and private networks are rejected.
Emit your own events
POST /hooks/v1/emit
Authorization: Bearer hook_… (hook:emit)
{"type":"task.completed","data":{"taskId":"t_9"}}
→ 202 { "eventId": "…", "endpointId": "…", "type": "task.completed" }Your agent publishes to its own receivers through the same signed delivery path. One unit for the event plus one per receiver. Bodies up to 64 KB; type is 1–64 characters of letters, digits, dot, underscore or hyphen.
Hosting and limits
- 1, 3 or 10 endpoints according to plan; 60, 600 or 6,000 inbound events per minute per endpoint.
- 7, 30 or 90 days of retention by plan; replay on Pro and Business. Expired events are purged and their bytes released.
- 250 MB, 1 GB or 3 GB of pooled stored events by plan; 256 KB per inbound body, 64 KB per emitted event.
- Starter includes 1,000 units for $5/month, Pro 5,000 for $15/month, Business 20,000 for $39/month. Hosting is paid from credit. Extra units cost $0.50 per 1,000 only with opt-in overage. Retries are not extra units.
- Pay by card or stablecoin wallet through Stripe Checkout, or let the agent pay for itself over x402.
GET /hooks/v1/usage
POST /hooks/v1/hosting/purchase Idempotency-Key: YOUR_UNIQUE_OPERATION_ID {"plan":"starter"}
PUT /hooks/v1/hosting/preferences {"autoRenew":false,"allowOverage":false}
GET /hooks/v1/capabilities · GET /hooks/v1/plansStandalone Webhooks plans
| Plan | Monthly hosting | Endpoints | Events received + delivered per month | Retention |
|---|---|---|---|---|
| Starter | $5 | 1 | 1,000 | 7 days |
| Pro | $15 | 3 | 5,000 | 30 days · replay |
| Business | $39 | 10 | 20,000 | 90 days · replay |
Per account, shared across endpoints. One accepted inbound event or one delivery to one receiver is one unit. Reads are free. Monthly units reset on day 1 UTC. Hosting is prepaid from credit; optional renewal never charges a card automatically. Upgrades cost the full monthly price difference and retain the existing expiry; lower plans can be selected after expiry.
Already subscribe to AGNT?
Paid AGNT includes Webhooks by plan: Personal includes Starter (1 endpoint, 1,000 events/month, 7-day retention); Always-On includes Pro (3 endpoints, 5,000 events/month, 30 days); Business and Enterprise include Business (10 endpoints, 20,000 events/month, 90 days). Limits are pooled per account. Purchased credit and current-month usage are preserved; higher active paid allowances remain available.