Webhooks
Automation — Webhooks
The send_webhook action makes an outbound HTTP call from a workflow to an
external URL — "when this happens in the CRM, POST to my endpoint". This is the
one webhook surface Automation owns; it is separate from provider → Corteksa
inbound webhooks (see Messaging Webhooks).
Config
{
"action_type": "send_webhook",
"action_config": {
"url": "https://hooks.example.com/crm",
"method": "POST",
"headers": { "X-Team": "sales" },
"payload_mode": "full_record"
}
}| Field | Notes |
|---|---|
url | Target URL. Private/local addresses are blocked (localhost, 127.*, 10.*, 172.16–31.*, 192.168.*, 0.*, ::1, fc00:, fe80:) — the action fails with a "Blocked host" error. |
method | POST, PUT, or PATCH |
headers | Extra headers, merged over the defaults |
payload_mode | full_record (auto body) or custom (your template) |
custom_payload | Required for custom — a JSON string with {{variables}}; interpolated, then parsed (falls back to { "raw": "..." } if it isn't valid JSON) |
Request the receiver sees
Default headers: Content-Type: application/json,
User-Agent: Corteksa-Synapse/1.0, plus your headers, plus a signature:
X-Workflow-Signature: sha256=<hex HMAC of the raw body>The HMAC uses the server's WORKFLOW_WEBHOOK_SECRET. Verify it on your side
before trusting the body — recompute the HMAC-SHA256 of the raw request body with
the shared secret and compare.
Auto payload for a data-triggered workflow (payload_mode: full_record):
{
"event": "workflow.action",
"object_slug": "deals",
"record_slug": "deal-247",
"record_id": 247,
"data": { "name": "...", "status": "won", "...": "..." },
"timestamp": "2026-07-14T12:00:00.000Z"
}For a message-triggered workflow the auto payload is instead
{ event: "workflow.message.<direction>", direction, session_slug, chat_slug, body, sender_name, sender_phone, timestamp }.
Delivery semantics
- Timeout: 10 seconds.
- Success: any
2xx. A non-2xx does not throw — the execution is marked failed witherror: "HTTP <status>", andaction_result.detailrecords{ url, method, statusCode, responseBody }(response body truncated to 500 chars). - Retries: the Bull job retries up to 3× with exponential backoff on an error (network/timeout). A clean non-2xx response is logged as a failed run, not retried — make your endpoint idempotent regardless.
Next
- Real-time run status → Events
- Failure fixes → Troubleshooting