Payload Format
This page shows detailed payload examples and explains how to verify webhook signatures for security.
Signature Verification
Every webhook request includes a signature in the X-Otesse-Signature header. Always verify this signature to ensure the request came from Otesse and was not tampered with.
How to Verify
The signature is an HMAC-SHA256 hash of the request body using your webhook secret:
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your webhook handler:
app.post('/webhooks/otesse', (req, res) => {
const signature = req.headers['x-otesse-signature'];
const isValid = verifyWebhookSignature(
JSON.stringify(req.body),
signature,
process.env.OTESSE_WEBHOOK_SECRET
);
if (!isValid) {
return res.status(401).send('Invalid signature');
}
// Process the event...
res.status(200).send('OK');
});
Python Example
import hmac
import hashlib
def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode('utf-8'),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
Payload Examples
booking.created
{
"id": "evt_01HQ3K5M7N8P9R",
"type": "booking.created",
"created_at": "2026-02-26T14:00:00Z",
"data": {
"id": "bk_01HQ3K5M7N8P9R",
"status": "confirmed",
"customer_id": "cust_01HQ3K5M7N",
"industry": "cleaning",
"scheduled_at": "2026-03-01T10:00:00Z",
"address": {
"street": "123 Main St",
"city": "Eugene",
"state": "OR",
"zip": "97401"
},
"pricing": {
"subtotal": 15000,
"tax": 1275,
"total": 16275
}
},
"previous_data": null
}
payment.succeeded
{
"id": "evt_02JR4L6N8O9Q0S",
"type": "payment.succeeded",
"created_at": "2026-02-26T18:05:00Z",
"data": {
"id": "pay_01HQ3K5M7N",
"invoice_id": "inv_01HQ3K5M7N",
"customer_id": "cust_01HQ3K5M7N",
"amount": 16275,
"currency": "usd",
"payment_method": {
"type": "card",
"brand": "visa",
"last4": "4242"
},
"stripe_charge_id": "ch_3abc123..."
},
"previous_data": null
}
Headers
Every webhook request includes these headers:
| Header | Description |
|---|---|
Content-Type | application/json |
X-Otesse-Signature | HMAC-SHA256 signature |
X-Otesse-Event | Event type (e.g., booking.created) |
X-Otesse-Delivery | Unique delivery ID for idempotency |
X-Otesse-Timestamp | Unix timestamp of when the event was sent |
User-Agent | Otesse-Webhooks/1.0 |
Idempotency
Use the X-Otesse-Delivery header to detect duplicate deliveries. Store processed delivery IDs and skip any that you have already handled. This prevents duplicate processing if Otesse retries a delivery.
On this page