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.