Corteksa
GuidesAutomation

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"
  }
}
FieldNotes
urlTarget 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.
methodPOST, PUT, or PATCH
headersExtra headers, merged over the defaults
payload_modefull_record (auto body) or custom (your template)
custom_payloadRequired 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 with error: "HTTP <status>", and action_result.detail records { 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

On this page