EXENDE

Exende Docs

Callback API

Docs

Callback API

Temporary public webhook endpoints for AI agents, scripts and automated workflows.

Create Callback

Create a callback, give the public callback URL to an external service, then read or wait for the resulting events. No account, API key or subscription is required. Callback creation is paid per request using x402.

Endpoint

POST https://api.exende.dev/v1/callbacks

Without a valid x402 payment, the server responds with HTTP 402 Payment Required. This is the only operation that requires payment; receiving webhooks, reading events, waiting, and deleting the callback do not trigger another x402 payment.

bash

Create callback

curl -i -X POST \
  https://api.exende.dev/v1/callbacks \
  -H "Content-Type: application/json" \
  -d '{}'

Payment-required advertises

x402 version2
NetworkBase Mainnet
CAIP-2eip155:8453
AssetUSDC
Price$0.01

json

HTTP 201 response

{
  "id": "cb_3t2cC09baD4yOvoeVMDK2vGQ",
  "callback_url": "https://cb.exende.dev/hooks/cb_3t2cC09baD4yOvoeVMDK2vGQ",
  "events_url": "https://api.exende.dev/v1/callbacks/cb_3t2cC09baD4yOvoeVMDK2vGQ/events",
  "wait_url": "https://api.exende.dev/v1/callbacks/cb_3t2cC09baD4yOvoeVMDK2vGQ/wait",
  "read_token": "ex_cb_sk_...",
  "expires_at": "2026-08-22T14:30:00.000Z",
  "limits": {
    "events": 10,
    "payload_bytes": 262144
  }
}
FieldMeaning
idPublic identifier matching ^cb_[A-Za-z0-9]{24}$ exactly.
callback_urlPublic send-only webhook URL. Give this URL to the external service.
events_urlAuthenticated endpoint used to retrieve received events.
wait_urlAuthenticated long-polling endpoint used to wait for the next event.
read_tokenPrivate bearer token used to read, wait for, or delete the callback.
expires_atUTC expiration timestamp.
limits.eventsMaximum number of events accepted by the callback.
limits.payload_bytesMaximum payload size for each webhook event.

Security note

The read_token is secret. Never give it to the service sending the webhook. Only callback_url is public.

Send a Webhook

The external service sends an event using POST, PUT, or PATCH on the callback host: https://cb.exende.dev/hooks/{callback_id}.

bash

Webhook event

curl -X POST \
  https://cb.exende.dev/hooks/cb_3t2cC09baD4yOvoeVMDK2vGQ \
  -H "Content-Type: application/json" \
  -d '{"status":"completed","result":"https://example.com/output"}'

json

Successful response

{
  "received": true,
  "event_id": "evt_6ec6e7b4a917d63861a07d9238d4cf6d"
}
Supported payload typesapplication/json, text/*, application/x-www-form-urlencoded
Missing Content-TypeAccepted and stored as text
Event cap10 events per callback
Event ID format^evt_[a-f0-9]{32}$
Rate limit30 requests per 60 seconds per callback

JSON bodies are validated before storage. Binary and file uploads are not supported. Only content-type, user-agent, stripe-signature, svix-id, svix-timestamp, svix-signature, x-hub-signature, x-hub-signature-256, webhook-id, webhook-timestamp, webhook-signature, x-signature, and x-webhook-signature headers are retained.

Callback ID validation and per-callback rate limiting run before callback lookup and body parsing. POST, PUT, and PATCH use the same handler and return the same response and error shapes.

StatusWebhook error
400INVALID_CALLBACK_ID
400INVALID_JSON
404CALLBACK_NOT_FOUND
410CALLBACK_EXPIRED
410CALLBACK_EVENT_LIMIT_REACHED
413PAYLOAD_TOO_LARGE
415UNSUPPORTED_MEDIA_TYPE
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

Wait for an Event

GET https://api.exende.dev/v1/callbacks/{id}/wait

Authentication: Authorization: Bearer ex_cb_sk_...

bash

Long poll

curl \
  "https://api.exende.dev/v1/callbacks/cb_3t2cC09baD4yOvoeVMDK2vGQ/wait?timeout=30" \
  -H "Authorization: Bearer ex_cb_sk_..."
timeoutCoerced with JavaScript Number. Missing or non-finite values default to 30. Finite values are floored, then clamped to 1–30 seconds. Examples: 1.9 → 1, 0 → 1, 31 → 30, invalid → 30.
afterOptional event ID; wait only for the next event after it

json

Event received

{
  "received": true,
  "timeout": false,
  "event": {
    "id": "evt_6ec6e7b4a917d63861a07d9238d4cf6d",
    "received_at": "2026-08-22T14:05:17.000Z",
    "method": "POST",
    "content_type": "application/json",
    "headers": {
      "content-type": "application/json"
    },
    "body": {
      "status": "completed",
      "result": "https://example.com/output"
    },
    "size_bytes": 60
  },
  "next_wait_url": "/v1/callbacks/cb_3t2cC09baD4yOvoeVMDK2vGQ/wait?after=evt_6ec6e7b4a917d63861a07d9238d4cf6d&timeout=30"
}

json

Timed out

{
  "received": false,
  "timeout": true,
  "after": null
}

When an event is received, the response includes received: true, timeout: false, the full event object, and a relative next_wait_url. A timeout returns received: false, timeout: true, and after as the supplied event ID or null. An unknown after event returns HTTP 404 EVENT_NOT_FOUND.

StatusWait error
400INVALID_CALLBACK_ID
401MISSING_AUTHORIZATION
401INVALID_AUTHORIZATION
401INVALID_TOKEN
404CALLBACK_NOT_FOUND
404EVENT_NOT_FOUND
410CALLBACK_EXPIRED
500INTERNAL_ERROR

Read All Events

GET https://api.exende.dev/v1/callbacks/{id}/events

Authentication: Authorization: Bearer ex_cb_sk_...

bash

Read events

curl \
  https://api.exende.dev/v1/callbacks/cb_3t2cC09baD4yOvoeVMDK2vGQ/events \
  -H "Authorization: Bearer ex_cb_sk_..."

json

Events response

{
  "callback_id": "cb_3t2cC09baD4yOvoeVMDK2vGQ",
  "status": "active",
  "expires_at": "2026-08-22T14:30:00.000Z",
  "event_count": 1,
  "events": [
    {
      "id": "evt_6ec6e7b4a917d63861a07d9238d4cf6d",
      "received_at": "2026-08-22T14:05:17.000Z",
      "method": "POST",
      "content_type": "application/json",
      "headers": {
        "content-type": "application/json"
      },
      "body": {
        "status": "completed",
        "result": "https://example.com/output"
      },
      "size_bytes": 60
    }
  ]
}

Returns callback_id, status, expires_at, event_count, and all stored events ordered by received_at ascending. Each event includes id, received_at, method, content_type, filtered headers, body, and size_bytes. JSON bodies are returned as parsed JSON; text and form bodies remain strings. Events with the same second-level received_at timestamp preserve deterministic receipt order. Events are read-only.

StatusEvents error
400INVALID_CALLBACK_ID
401MISSING_AUTHORIZATION
401INVALID_AUTHORIZATION
401INVALID_TOKEN
404CALLBACK_NOT_FOUND
410CALLBACK_EXPIRED
500INTERNAL_ERROR

Delete Callback

DELETE https://api.exende.dev/v1/callbacks/{id}

Authentication: Authorization: Bearer ex_cb_sk_...

bash

Delete callback

curl -X DELETE \
  https://api.exende.dev/v1/callbacks/cb_3t2cC09baD4yOvoeVMDK2vGQ \
  -H "Authorization: Bearer ex_cb_sk_..."

json

Delete response

{
  "deleted": true,
  "callback_id": "cb_3t2cC09baD4yOvoeVMDK2vGQ"
}

Deletes the callback and its stored events before automatic expiration.

StatusDelete error
400INVALID_CALLBACK_ID
401MISSING_AUTHORIZATION
401INVALID_AUTHORIZATION
401INVALID_TOKEN
404CALLBACK_NOT_FOUND
410CALLBACK_EXPIRED
500INTERNAL_ERROR

Expiration

Callbacks live for 10 minutes. Expired callbacks are automatically cleaned up.

Limits

API version1.0.0
Lifetime10 minutes
Maximum events10
Maximum payload262144 bytes (256 KB) per event
Webhook methodsPOST, PUT, PATCH
Wait timeout1–30 seconds (default 30)
Price$0.01 USDC
NetworkBase Mainnet
CAIP-2 networkeip155:8453
Payment protocolx402 v2

Errors

These are the standard error codes used across the Callback API. Each endpoint section above lists the subset it can return.

Authenticated routes validate the callback ID first, then the Authorization header and Bearer scheme, callback existence, read token, and expiration in that order.

A missing Authorization header returns MISSING_AUTHORIZATION. A non-Bearer header returns INVALID_AUTHORIZATION. An empty or incorrect Bearer token returns INVALID_TOKEN.

StatusCode
400INVALID_CALLBACK_ID
400INVALID_JSON
401MISSING_AUTHORIZATION
401INVALID_AUTHORIZATION
401INVALID_TOKEN
404CALLBACK_NOT_FOUND
404EVENT_NOT_FOUND
410CALLBACK_EXPIRED
410CALLBACK_EVENT_LIMIT_REACHED
413PAYLOAD_TOO_LARGE
415UNSUPPORTED_MEDIA_TYPE
429RATE_LIMIT_EXCEEDED
500INTERNAL_ERROR

json

Error response shape

{
  "error": {
    "code": "INVALID_TOKEN",
    "message": "The read token is invalid.",
    "request_id": "req_81731247-7585-44a8-8716-d9dda3e0ff61"
  }
}

Error responses include request_id.

Typical AI Agent Workflow

AI Agent → create Exende callback
x402 payment
receives callback_url + read_token
gives callback_url to external service
external job runs asynchronously
service POSTs result to Exende
agent calls /wait
result received
workflow continues

An AI agent starts an asynchronous video generation job. The video service requires a webhook URL for completion. The agent creates an Exende callback for $0.01, passes callback_url to the video service, and waits using wait_url. When rendering finishes, the service sends the result to Exende and the agent continues automatically.

  • asynchronous image/video generation
  • long-running scraping jobs
  • background processing
  • payment notifications
  • third-party webhook integrations
  • agent workflows without a public server