Webhooks API
Subscribe to real-time events from your Rentalot account. When events occur (new inquiry, message sent, showing booked, etc.), Rentalot sends a POST request to your URL with the event payload.
Event Types
| Event | Description |
|---|---|
inquiry.created | A new contact reached out for the first time |
message.received | An inbound message was received from a contact |
message.sent | An outbound message was sent to a contact |
showing.booked | A showing was scheduled |
showing.cancelled | A showing was cancelled |
contact.updated | A contact’s details were updated |
property.updated | A property listing was updated |
workflow.created | A new workflow template was created |
workflow.updated | A workflow template was updated |
workflow.deleted | A workflow template was deleted |
workflow.completed | A workflow run finished |
List Webhooks
GET /api/v1/webhooksResponse:
{
"data": [
{
"id": "wh_abc123",
"url": "https://example.com/webhooks/rentalot",
"events": ["inquiry.created", "showing.booked"],
"active": true,
"description": "CRM sync",
"lastDeliveredAt": "2026-02-11T14:30:00Z",
"createdAt": "2026-02-01T10:00:00Z"
}
],
"pagination": { "page": 1, "limit": 20, "total": 2 }
}Create Webhook
POST /api/v1/webhooksRequest Body:
{
"url": "https://example.com/webhooks/rentalot",
"events": ["inquiry.created", "message.received", "showing.booked"],
"description": "CRM sync webhook"
}| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | HTTPS URL to receive events |
events | string[] | Yes | At least one event type from the list above |
description | string | No | Human-readable label (max 500 chars) |
Response 201 Created:
{
"data": {
"id": "wh_abc123",
"url": "https://example.com/webhooks/rentalot",
"events": ["inquiry.created", "message.received", "showing.booked"],
"active": true,
"description": "CRM sync webhook",
"secret": "whsec_a1b2c3d4e5f6..."
}
}The secret is only returned once on creation. Save it — you’ll need it to verify webhook signatures.
Get Webhook
GET /api/v1/webhooks/:idUpdate Webhook
PATCH /api/v1/webhooks/:id{
"events": ["inquiry.created", "showing.booked"],
"active": false
}| Field | Type | Description |
|---|---|---|
url | string | New HTTPS endpoint |
events | string[] | Replace subscribed events |
active | boolean | Enable or disable delivery |
description | string | Update label |
Delete Webhook
DELETE /api/v1/webhooks/:idReturns 204 No Content.
Test Webhook
POST /api/v1/webhooks/:id/testSends a test ping event to the webhook URL. Use this to verify your endpoint is reachable and correctly handling payloads.
Response 200 OK:
{
"data": {
"success": true,
"statusCode": 200,
"deliveredAt": "2026-02-11T15:00:00Z"
}
}Payload Format
Every webhook delivery is a POST request with a JSON body:
{
"event": "showing.booked",
"data": {
"id": "showing_abc123"
},
"timestamp": "2026-02-11T14:30:00Z",
"webhookId": "wh_abc123"
}Verifying Signatures
Every delivery includes these headers:
| Header | Description |
|---|---|
X-Webhook-Signature | sha256={HMAC-SHA256 hex digest} |
X-Webhook-Id | Unique delivery ID |
X-Webhook-Timestamp | ISO 8601 delivery timestamp |
To verify, compute the HMAC-SHA256 of the raw request body using your webhook secret and compare with the signature header.
import crypto from "crypto";
function verifyWebhook(body, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(body)
.digest("hex");
return signature === `sha256=${expected}`;
}Retry Policy
Failed deliveries (non-2xx response or timeout) are retried up to 3 times with exponential backoff: 1 minute, 5 minutes, 30 minutes.
After 10 consecutive failures, the webhook is automatically deactivated. Re-enable it via PATCH with active: true after fixing your endpoint.
Idempotency
POST /api/v1/webhooks supports the Idempotency-Key header.