Webhooks
Webhooks allow external services to trigger actions in Open Genie. Each webhook has a shared secret for validation and maps to a specific action.
How It Works
External Service
↓
POST /api/webhooks/{id}
Headers: X-Webhook-Secret: <secret>
Body: { custom payload }
↓
Validate secret against DB record
↓
Merge incoming payload with stored actionPayload
↓
actionRegistry.execute(actionType, mergedPayload)
↓
Return ActionResult
Webhook Record
{
id: "uuid",
name: "Home Assistant Motion",
secret: "random-secret-string",
actionType: "send_notification",
actionPayload: {
title: "Motion Alert",
target: "phones",
level: "warning"
},
enabled: true,
lastTriggeredAt: "2024-01-15T10:30:00Z"
}
Payload Merging
The webhook's stored actionPayload is merged with the incoming request body. Incoming fields override stored defaults:
Stored: { title: "Motion Alert", target: "phones" }
Incoming: { body: "Kitchen sensor triggered", target: "all" }
Merged: { title: "Motion Alert", body: "Kitchen sensor triggered", target: "all" }
REST API
| Method | Path | Description |
|---|---|---|
GET | /api/webhooks | List all webhooks |
POST | /api/webhooks | Create a webhook |
PATCH | /api/webhooks/[id]/manage | Update webhook |
DELETE | /api/webhooks/[id]/manage | Delete webhook |
POST | /api/webhooks/[id] | Trigger the webhook |
Create a Webhook
curl -X POST http://localhost:3000/api/webhooks \
-H "Content-Type: application/json" \
-d '{
"name": "Doorbell Alert",
"actionType": "send_notification",
"actionPayload": {
"title": "Doorbell",
"body": "Someone is at the door",
"target": "all",
"level": "info"
}
}'
Response includes the generated id and secret.
Trigger a Webhook
curl -X POST http://localhost:3000/api/webhooks/{id} \
-H "X-Webhook-Secret: <secret>" \
-H "Content-Type: application/json" \
-d '{"body": "Override message"}'
Integration Examples
Home Assistant
# configuration.yaml
rest_command:
notify_genie:
url: "http://genie-server:3000/api/webhooks/YOUR_WEBHOOK_ID"
method: POST
headers:
X-Webhook-Secret: "YOUR_SECRET"
Content-Type: "application/json"
payload: '{"body": "{{ trigger.to_state.attributes.friendly_name }} triggered"}'
IFTTT / Zapier / n8n
Point a webhook action at:
POST http://your-server:3000/api/webhooks/{id}
Header: X-Webhook-Secret: <secret>
Key Files
| File | Purpose |
|---|---|
lib/webhooks.ts | Secret validation and action execution |
server/routes/webhooks.ts | List, create, trigger, update/delete endpoints |