Webhooks

Register HTTP endpoints to receive workflow events when intake is submitted. This is the primary integration path for CRM sync, database writes, email triggers, and internal queues.

Use the same shell variables as the first onboarding tutorial: BASE=https://willowriverautomation.com/relay, API_KEY, and FLOW_ID.

Register a webhook

curl -X POST "$BASE/v1/flows/$FLOW_ID/webhooks" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/intake",
    "events": ["intake.submitted"]
  }'

The response includes a secret for signature verification. Store it securely.

Payload

{
  "event": "intake.submitted",
  "flow_id": "550e8400-e29b-41d4-a716-446655440000",
  "flow_version": 1,
  "intake_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
  "data": {
    "email": "dev@acme.com",
    "company": "Acme",
    "plan": "pro"
  },
  "metadata": {
    "ip": "203.0.113.1",
    "user_agent": "Mozilla/5.0 ..."
  },
  "created_at": "2026-05-21T12:00:00Z"
}

Signature verification

Each delivery includes:

Header Value
X-Intake-Signature HMAC-SHA256 hex digest of raw body
X-Intake-Event Event name
X-Intake-Delivery-Id Delivery UUID for idempotent processing
import hmac, hashlib

def verify(secret: str, body: bytes, signature: str) -> bool:
    expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)

Retries

Failed deliveries (non-2xx or timeout) are retried with exponential backoff. Available on all plans (Free, Starter, Growth, Scale).

Attempt Delay
1 immediate
2 30s
3 2m
4 10m
5 1h

After 5 attempts, status is failed. Inspect via:

curl "$BASE/v1/flows/$FLOW_ID/webhooks/deliveries?submission_id=$INTAKE_ID" \
  -H "Authorization: Bearer $API_KEY"

Idempotent webhook handling

Use intake_id + X-Intake-Delivery-Id to deduplicate. Your handler should return 2xx only after successfully processing.

SaaS onboarding pattern

User completes intake embed
        ↓
intake.submitted webhook
        ↓
Your handler:
  1. Create CRM contact
  2. Provision tenant
  3. Send welcome email
  4. Update user record

This replaces custom webhook form system code in your backend.