Webbu Docs

Step 3: Send a Webhook

Send your first webhook payloads to Webbu for buffering.

Point your webhook sender at the buffer's ingest URL:

POST https://webbu.dev/api/v1/ingest/{projectId}/{bufferId}

The body must be JSON, sent with Content-Type: application/json.

Send a test webhook

curl -X POST https://webbu.dev/api/v1/ingest/p_shop/b_orders \
  -H "Content-Type: application/json" \
  -d '{
    "event": "order.created",
    "customerId": "cus_001",
    "orderId": "ord_100",
    "amount": 49.99
  }'
const res = await fetch('https://webbu.dev/api/v1/ingest/p_shop/b_orders', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    event: 'order.created',
    customerId: 'cus_001',
    orderId: 'ord_100',
    amount: 49.99,
  }),
});
console.log(res.status, await res.json()); // 202 { status: 'accepted', ... }
resp = requests.post(
    "https://webbu.dev/api/v1/ingest/p_shop/b_orders",
    json={
        "event": "order.created",
        "customerId": "cus_001",
        "orderId": "ord_100",
        "amount": 49.99,
    },
)
print(resp.status_code, resp.json())  # 202 {'status': 'accepted', ...}
Try it in the API reference

Response (202 Accepted):

{
  "status": "accepted",
  "messageId": "5b0c6f0e-5f7e-4a51-9d0b-0d6c2a9f1e11",
  "itemId": "0e6d1c2b-3a4f-4b5c-8d7e-9f0a1b2c3d4e"
}

202 means the payload is stored and will be delivered when a flush condition is met. Each accepted webhook uses 1 credit per started KB of payload (see Credits & Billing).

The ingest endpoint doesn't require an API key, so treat the ingest URL as a secret. You can send X-API-Key (it must then be valid for this buffer's project), and you can turn on source verification so only signed requests are accepted.

Send more webhooks

Send a few more with the same customerId to see batching:

curl -X POST https://webbu.dev/api/v1/ingest/p_shop/b_orders \
  -H "Content-Type: application/json" \
  -d '{"event": "order.paid", "customerId": "cus_001", "orderId": "ord_100"}'

curl -X POST https://webbu.dev/api/v1/ingest/p_shop/b_orders \
  -H "Content-Type: application/json" \
  -d '{"event": "order.shipped", "customerId": "cus_001", "trackingId": "TRK123"}'
for payload in [
    {"event": "order.paid", "customerId": "cus_001", "orderId": "ord_100"},
    {"event": "order.shipped", "customerId": "cus_001", "trackingId": "TRK123"},
]:
    requests.post("https://webbu.dev/api/v1/ingest/p_shop/b_orders", json=payload)

All three share customerId: "cus_001", so they land in the same group and are delivered together.

Deduplication

Give each event a stable message ID so a resend isn't stored twice. Webbu uses, in order:

  1. a top-level messageId field in the JSON body
  2. the X-Idempotency-Key request header
  3. otherwise a random UUID (no deduplication)
curl -X POST https://webbu.dev/api/v1/ingest/p_shop/b_orders \
  -H "Content-Type: application/json" \
  -H "X-Idempotency-Key: evt_unique_123" \
  -d '{"event": "order.created", "customerId": "cus_001"}'

A duplicate gets 202 with "duplicate": true and uses no credits. Duplicates are detected while the original is still buffered in the same group; after the batch has been delivered, the same ID is accepted again.

Common errors

StatusBody errorFix
400Could not extract group key from requestThe body has no value at groupKey.path and the fallback header is missing
400Buffer is disabledRe-enable the buffer (it may have been auto-paused)
400Buffer does not belong to this projectUse the buffer's own projectId in the URL
400(HTML "Bad Request")The body isn't valid JSON
401Missing signature header / Invalid signatureSource verification is on; sign the request correctly
401UnauthorizedYou sent an X-API-Key that is invalid or revoked
403API key does not have access to this bufferThe key belongs to another account or isn't scoped to this project
404Buffer not foundCheck the bufferId in the URL
429Insufficient creditsBuy credits or wait for your monthly reset; see Credits & Billing

On this page