Webhook Payload Reference

When an email arrives, Conduit parses the message and delivers it to your target URL as an HTTP POST with a JSON body and a set of request headers.


Request headers

Every delivery includes these HTTP request headers:

Header Description
Content-Type application/json
X-Conduit-Signature HMAC-SHA256 signature of the raw request body (see Verifying signatures)

Any custom_headers configured on the webhook are also included in every delivery request.


JSON body

The request body is a JSON object with the following fields:

Field Type Always present Description
message_id string Yes SMTP Message-ID, or a generated value if the sender did not supply one
from string Yes SMTP envelope sender address (MAIL FROM)
to array of strings Yes SMTP envelope recipient addresses (RCPT TO)
subject string No Subject header, omitted when absent
date string No Date header parsed to RFC 3339 UTC, omitted when absent or unparseable
text string No Plain-text body, omitted when the message has no plain-text part
html string No HTML body, omitted when the message has no HTML part
headers object No Non-standard headers as { "Header-Name": ["value", ...] }, omitted when none are present

The headers object contains only headers that are not already surfaced as top-level fields. The following headers are always excluded from headers: Message-Id, From, To, Subject, Date, Content-Type, Mime-Version.

Example payload

{
  "message_id": "<abc123@mail.example.com>",
  "from": "alerts@monitoring.example.com",
  "to": ["webhook-01HX...@incoming.conduit.email"],
  "subject": "Disk usage above 90% on web-01",
  "date": "2024-01-15T10:00:00Z",
  "text": "Disk usage on web-01 is at 91%. Please investigate.",
  "html": "<p>Disk usage on web-01 is at <strong>91%</strong>. Please investigate.</p>",
  "headers": {
    "X-Priority": ["1"],
    "X-Mailer": ["AlertManager 2.4"]
  }
}

Verifying the signature

Every delivery includes an X-Conduit-Signature header:

X-Conduit-Signature: sha256=<hex-encoded-digest>

The signature is an HMAC-SHA256 of the raw request body bytes, keyed with the webhook secret. Verify it before processing the payload:

import hmac
import hashlib

def verify_signature(body: bytes, secret: str, header: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, header)

Reject requests where the signature does not match. The signature is computed over the exact bytes received, so read the raw body before parsing JSON.


Payload templates

By default, Conduit sends the full JSON structure shown above. If you need a different shape — for example, to post directly to a Slack incoming webhook — set a payload_template on the webhook.

A payload template is a Go text/template string rendered against the parsed email. The rendered output replaces the default JSON body entirely; it must be valid for whatever your target URL expects.

Template variables

Variable Type Description
{{.MessageID}} string SMTP Message-ID
{{.From}} string Envelope sender address
{{.To}} []string Envelope recipient addresses
{{.Subject}} string Subject line (empty string if absent)
{{.Date}} string Date in RFC 3339 UTC (empty string if absent)
{{.Text}} string Plain-text body (empty string if absent)
{{.HTML}} string HTML body (empty string if absent)
{{.Headers}} map[string][]string Non-standard headers

Example — Slack incoming webhook

{"text": "*{{.Subject}}*\nFrom: {{.From}}\n\n{{.Text}}"}

Example — extract a single non-standard header

{"priority": "{{index (index .Headers "X-Priority") 0}}", "subject": "{{.Subject}}"}

Templates are validated when the webhook is created or updated. An invalid template is rejected with a 422 response and error code payload_template_invalid.


Custom headers

The custom_headers field on a webhook adds static key/value headers to every delivery request. This is useful for passing an API key or a shared secret to your endpoint alongside the Conduit signature:

{
  "custom_headers": {
    "Authorization": "Bearer my-api-key",
    "X-My-App-Source": "conduit"
  }
}

Header names must be valid HTTP token characters (RFC 7230). The reserved header X-Conduit-Signature cannot be overridden and is rejected with error code custom_headers_invalid.

custom_headers is currently only configurable through the API — there is no UI form for it.