Asynchronous delivery
Signed booking webhooks
Webhook delivery is driven by the transactional booking outbox. A booking remains confirmed even if notification delivery fails; delivery state is never booking truth.
- Manage scope
- aune.webhooks.manage
- Signature
- HMAC-SHA256 over id.timestamp.raw-body
- Timeout
- 8 seconds
- Redirects
- Rejected
- Secret
- Shown once
Register an endpoint
POST `/v1/webhook-endpoints` with an OAuth token carrying `aune.webhooks.manage`. Destinations must use public HTTPS on port 443; Aune resolves DNS and rejects private, loopback, link-local, multicast, local, and internal targets.
Endpoint registration
curl -X POST "https://aune-homepage-chat.vercel.app/v1/webhook-endpoints" \
-H "Authorization: Bearer $AUNE_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
--data '{"url":"https://agent.example/aune/webhooks","event_types":["booking.confirmed","booking.rescheduled","booking.cancelled"]}'Verify before parsing
Read the exact raw bytes. Reject stale timestamps, compare signatures in constant time, and deduplicate `Webhook-Id`. Only then parse JSON or trigger side effects.
Node.js verification core
import { createHmac, timingSafeEqual } from "node:crypto";
const signed = `${webhookId}.${webhookTimestamp}.${rawBody}`;
const expected = `v1,${createHmac("sha256", secret)
.update(signed)
.digest("base64url")}`;
const valid = Math.abs(Date.now() / 1000 - Number(webhookTimestamp)) <= 300 &&
timingSafeEqual(Buffer.from(signature), Buffer.from(expected));Event contract
- `booking.confirmed`: durable booking committed.
- `booking.rescheduled`: same booking moved to a newly revalidated option.
- `booking.cancelled`: booking lifecycle status changed to cancelled.
- `booking.provider_action_required`: provider-side follow-up is required.
- Replay through `POST /v1/webhook-events/{outbox_id}/replay`; ownership is bound to the OAuth client.