Outbound HTTP Webhooks
Connect Moul collections to external systems with synchronous before-hooks, async after-hooks, and HMAC-SHA256 signatures.
Moul supports outbound HTTP webhooks configured per collection, enabling deep integrations with payment gateways, external automation tools, and microservices.
Hook Execution Lifecycles
1. Synchronous Before-Hooks (*:before)
- Triggers:
create:before,update:before,delete:before - Behavior: Executed synchronously before physical database operations are committed.
- Validation Guard: If the target webhook URL returns a non-2xx HTTP response or times out (5-second limit), the database operation is aborted and an error is returned to the client.
2. Asynchronous After-Hooks (*:after)
- Triggers:
create:after,update:after,delete:after - Behavior: Executed asynchronously in the background after successful database commits. Adds zero latency to client response times.
Webhook Payload & Headers
When dispatching webhooks, Moul sends an HTTP POST request with the following headers:
Content-Type: application/jsonX-Moul-Event: Event name (e.g.create:after,update:before)X-Moul-Webhook-ID: Unique ID of the triggered webhook ruleX-Moul-Timestamp: RFC3339 timestamp of the eventX-Moul-Signature: HMAC-SHA256 hex digest of the raw JSON body computed using the configured webhook secret.
Payload Schema
{
"event": "update:after",
"moul": "orders",
"record": {
"id": "ord_9901",
"status": "paid",
"amount": 149.50,
"user_id": "usr_4412"
},
"old_record": {
"id": "ord_9901",
"status": "pending",
"amount": 149.50,
"user_id": "usr_4412"
},
"timestamp": "2026-08-01T15:30:00Z"
}Verifying Webhook Signatures
import crypto from 'node:crypto';
export function verifyMoulSignature(payloadRawBody: string, signature: string, secret: string): boolean {
const hmac = crypto.createHmac('sha256', secret);
const digest = hmac.update(payloadRawBody).digest('hex');
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(digest));
}package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
)
func VerifySignature(payload []byte, signature, secret string) bool {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(payload)
expectedMAC := hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(signature), []byte(expectedMAC))
}import hmac
import hashlib
def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(signature, expected)Webhook Management Endpoints
GET /api/moul/:name/webhooks— List all registered webhooks for a collection.POST /api/moul/:name/webhooks— Register a new webhook.GET /api/moul/:name/webhooks/:id— Get webhook details.PATCH /api/moul/:name/webhooks/:id— Update webhook URL, events, or secret.DELETE /api/moul/:name/webhooks/:id— Remove a webhook.POST /api/moul/:name/webhooks/:id/test— Sends a testpingevent payload to verify receiver connectivity.