Webhooks
Receive events from Twentybaan in real time.
Events
- contact_message.created
- listing.published
- listing.updated
Note: webhook.test exists internally and cannot be subscribed to through the public subscribe endpoints.
Signing and delivery
Webhook deliveries are HTTP POST requests with JSON bodies and these headers: X-TB-Event, X-TB-Delivery, X-TB-Timestamp, X-TB-Signature.
Signing secret
When you create a webhook endpoint in Settings → Integrations, you get a signing secret. Use it to verify the signature.
Verify signature
# Verify against the raw request body (before JSON parsing).
secret="$TWENTYBAAN_WEBHOOK_SECRET"
timestamp="$X_TB_TIMESTAMP"
provided="${X_TB_SIGNATURE#sha256=}"
raw="$(cat webhook-body.json)"
expected="$(printf '%s.%s' "$timestamp" "$raw" | openssl dgst -sha256 -hmac "$secret" | awk '{print $2}')"
[ "$expected" = "$provided" ] || echo "Invalid signature"Failed deliveries are retried with backoff, starting at 1 minute and increasing up to 24 hours. Timeouts are short, so respond quickly and do heavy work asynchronously.
Payload examples
Webhooks use a stable envelope: event, delivery_id, timestamp, and data.
The inner data depends on the event.
contact_message.created
{
"event": "contact_message.created",
"delivery_id": "b5b55f1f8c0b4d45a1b28b0b6ab77d2c",
"timestamp": "2026-01-12T07:00:00Z",
"data": {
"id": 456,
"topic": "Schedule a viewing",
"request_kind": "viewing",
"request_status": "new",
"request_timezone": "Asia/Bangkok",
"spot_name": "Modern condo near BTS",
"spot_slug": "modern-condo-near-bts",
"from_url": "https://twentybaan.com/listings/?id=123",
"listing_id": 123,
"thread_id": 789,
"name": "Jane Doe",
"email": "jane@example.com",
"phone": "+66 800 000 000",
"move_in": "2026-02-01",
"budget": "฿35,000 / month",
"lease_length": "12",
"occupants": 2,
"has_pets": false,
"notes": "Can we tour this weekend?",
"preferred_slots": [
{"day": "Saturday", "window": "10:00-12:00"},
{"day": "Sunday", "window": "14:00-16:00"}
],
"rep_name": "Your Agent",
"rep_brand": "Twentybaan",
"rep_user_id": 123,
"created_at": "2026-01-12T07:00:00Z"
}
}listing.published
{
"event": "listing.published",
"delivery_id": "f0a1e9d2c9c24a91b5a6f0a8d8c2e3aa",
"timestamp": "2026-01-12T07:00:00Z",
"data": {
"listing": {
"id": 123,
"status": "published",
"slug": "modern-condo-sukhumvit",
"title": "Modern condo near BTS",
"city": "Bangkok",
"area": "Sukhumvit",
"property_type": "condo",
"offer_type": "rent",
"rent_price_amount": 35000,
"rent_price_period": "month",
"sale_price_amount": null,
"price_text": "฿35,000 / month",
"beds_text": "2",
"area_sqm": 62,
"image_url": "https://...",
"published_at": "2026-01-12T06:59:00Z",
"created_at": "2025-12-15T09:12:00Z",
"updated_at": "2026-01-12T06:59:00Z"
}
}
}