Webhooks
Last updated: June 16, 2026
A webhook is an HTTP request that WWPager sends to your URL whenever a new message arrives. This lets you process incoming mail in your own services in real time. The URL and signing secret are configured per address in the app (Email Clients section).
When it fires
WWPager sends a webhook for the following events:
- email.received — a new message arrived at the address.
Delivery
The request is sent via POST to your URL. The body is UTF-8 JSON (Content-Type: application/json). The following headers are included:
X-WWPager-Event— event type, e.g.email.received.X-WWPager-Delivery— unique delivery ID (matches theidfield in the body).X-WWPager-Signature— body signature (see the Signature section).User-Agent—WWPager-Webhook/1.0.
Payload format
The request body has the following structure:
{
"id": "evt_8Kf2mQ1pZ0xW",
"type": "email.received",
"timestamp": "2026-06-16T12:34:56.789012Z",
"data": {
"message_id": "msg_123456",
"email": "you@wwpnext.com",
"from": "sender@example.com",
"subject": "Привет!",
"html": "<p>Текст письма в HTML</p>",
"text": "Текст письма (plain)",
"attachments": [
{
"filename": "invoice.pdf",
"content_type": "application/pdf",
"size": 102400
}
],
"headers": {
"Message-ID": "<abc@example.com>",
"Reply-To": "noreply@example.com",
"In-Reply-To": "<prev@example.com>",
"References": "<prev@example.com>"
},
"is_spam": false,
"received_at": "2026-06-16T12:34:56Z"
}
}
id— event identifier (matchesX-WWPager-Delivery).type— event type.timestamp— event dispatch time (UTC, ISO 8601).data.email— your address that received the message.data.from— sender address.data.html/data.text— message body; either field may be empty.data.attachments— list of attachments (name, MIME type, size in bytes).data.is_spam— whether the message was classified as spam.
Signature (HMAC-SHA256)
To let you verify that the request came from WWPager and was not tampered with, every body is signed with a secret key. The secret is shown in the app next to the webhook setting. The signature is sent in the X-WWPager-Signature header and is computed as follows:
- Take the exact raw request body bytes as received.
- Compute HMAC-SHA256 using your signing secret as the key.
- Hex-encode the result (lowercase) and prepend the prefix
sha256=.
X-WWPager-Signature: sha256=3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b
Verifying the signature
On your side, compute the HMAC of the received body with the same secret and compare it to the header using a constant-time comparison.
Python
import hmac, hashlib
def verify(raw_body: bytes, secret: str, signature_header: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode(), raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature_header)
Node.js
const crypto = require('crypto');
function verify(rawBody, secret, signatureHeader) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(signatureHeader || '');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Important: the signature is computed over the raw request body bytes. Do not re-serialize the JSON before verifying — re-serialization changes the bytes (whitespace, key order) and the signature will not match.
Response and retries
Your server must respond with a 2xx status code to acknowledge receipt. Any other code or a timeout counts as a delivery failure. Process webhooks idempotently: use the id field to guard against processing the same event twice.
Questions
If you have questions about integration, contact us:
- Email: support@wwpager.com
- Telegram: @wwpagersupportbot