Create a webhook

Register an HTTPS endpoint for event delivery.

Register an HTTPS endpoint and choose which event types it receives. At least one event type is required — list every type you want (see the Webhooks page for all eleven).

POST /v3/webhooks

Body parameters

ParameterTypeRequiredDescription
urlstringRequiredDestination URL. Must be https — a scheme-less value gets https:// prepended, and an explicit http:// URL is rejected. Private and internal addresses are also rejected.
eventsarray of stringsRequiredOne or more event types to deliver: queued, sent, delivered, opened, clicked, bounced, complained, unsubscribed, delayed, rejected, failed. Unknown values are rejected.
enabledbooleanOptionalCreate the endpoint paused by passing false. Default true.
secretstringOptionalSigning secret, 32–512 chars (a shorter secret is rejected). Omit to have one generated (whsec_…) — it is revealed only in the create response, so store it immediately.
domain_iduuidOptionalScope the endpoint to a single sending domain you own. Omit (or pass null) to receive events for all domains.
authobjectOptionalReceiver-side authentication — credentials wemail presents to your server on every delivery. Defaults to { "type": "none" }. See the fields below.

The auth object

If your receiver sits behind an auth layer, tell wemail how to authenticate. Pick a type and supply its fields — fixed credentials (bearer, basic, custom_headers) are sent as-is on every delivery; oauth2 makes wemail fetch a client-credentials token from your identity provider and attach it as a Bearer header, cached per endpoint until expiry, refreshed automatically, and retried once with a fresh token on a 401/403. A delivery never goes out with a missing or invalid token — a failed token fetch fails the attempt into the normal retry schedule.

ParameterTypeRequiredDescription
auth.typestringOptionalOne of none, hmac, bearer, basic, custom_headers, oauth2, mtls. Default none. Pick a type to reveal its fields.
auth.secretstringOptionalhmac only, optional. Omit to have wemail generate a whsec_ signing secret — the plaintext is returned once on the create response, then stored encrypted and never shown again. Reads echo secret_set and a secret_hint (…{last4}).
auth.header_namestringOptionalhmac only, optional. Signature header name (default X-Wemail-Signature). Each delivery also carries X-Wemail-Timestamp and X-Wemail-Key-Id. Signature format: t={unix_ts},v1={hex hmac-sha256 of "{t}.{raw_body}"} — reject timestamps older than 5 minutes.
auth.tokenstringOptionalbearer only (required). Delivered as Authorization: Bearer <token>. Write-only — never echoed back.
auth.usernamestringOptionalbasic only (required). Delivered as Authorization: Basic <base64(username:password)>.
auth.passwordstringOptionalbasic only (required). Write-only — never echoed back.
auth.headersobjectOptionalcustom_headers only (required). Up to 5 name→value pairs merged into every delivery. Names: RFC 7230 tokens, max 64 chars; values: max 1024 chars, no CR/LF. Content-Type and wemail signature headers cannot be overridden. Values are write-only.
auth.token_urlstring (URL)Optionaloauth2 only (required). Your identity provider's client-credentials token endpoint — must be a public HTTPS URL (private/internal targets are rejected).
auth.client_idstringOptionaloauth2 only (required). Sent form-urlencoded with grant_type=client_credentials.
auth.client_secretstringOptionaloauth2 only (required). Write-only — never echoed back.
auth.scopestringOptionaloauth2 only, optional. Included in the token request when set.
auth.audiencestringOptionaloauth2 only, optional. Included in the token request when set.
auth.client_certstring (PEM)Optionalmtls only (required). PEM client certificate, max 16 KB. Validated and checked to match the key at save time; reads echo cert_fingerprint_sha256, cert_subject and cert_expires_at.
auth.client_keystring (PEM)Optionalmtls only (required). PEM private key, max 16 KB. Write-only — presented during the TLS handshake with your server; reads echo key_set.

Responses

StatusDescription
201Created. The webhook endpoint. For HMAC auth the generated signing secret is returned once, here, and never again.
400Validation error — e.g. a non-HTTPS url, a signing secret shorter than 32 characters, an unknown domain, or a URL that fails SSRF checks.
401Missing or invalid API key.
403Your plan's webhook-endpoint allowance is used up — upgrade for unlimited endpoints.

Code examples

cURL
curl -X POST https://api.wemail.io/v3/webhooks \
  -H "Authorization: Bearer afn_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/webhooks/wemail",
    "events": ["delivered", "bounced", "complained"],
    "auth": {
      "type": "oauth2",
      "token_url": "https://auth.yourapp.com/oauth/token",
      "client_id": "wemail-events",
      "client_secret": "s3cr3t-value",
      "scope": "webhooks:write"
    }
  }'
Node.js
// Your endpoint sits behind OAuth? Give wemail client credentials —
// it fetches, caches and refreshes the token itself.
const webhook = await wemail.webhooks.create({
  url: "https://yourapp.com/webhooks/wemail",
  events: ["delivered", "bounced", "complained"],
  auth: {
    type: "oauth2",
    token_url: "https://auth.yourapp.com/oauth/token",
    client_id: "wemail-events",
    client_secret: process.env.WEBHOOK_OAUTH_SECRET,
    scope: "webhooks:write",
  },
});
Python
webhook = wemail.webhooks.create(
    url="https://yourapp.com/webhooks/wemail",
    events=["delivered", "bounced", "complained"],
    auth={
        "type": "oauth2",
        "token_url": "https://auth.yourapp.com/oauth/token",
        "client_id": "wemail-events",
        "client_secret": os.environ["WEBHOOK_OAUTH_SECRET"],
        "scope": "webhooks:write",
    },
)
PHP
$webhook = $wemail->webhooks->create([
    'url'    => 'https://yourapp.com/webhooks/wemail',
    'events' => ['delivered', 'bounced', 'complained'],
    'auth'   => [
        'type'          => 'oauth2',
        'token_url'     => 'https://auth.yourapp.com/oauth/token',
        'client_id'     => 'wemail-events',
        'client_secret' => getenv('WEBHOOK_OAUTH_SECRET'),
        'scope'         => 'webhooks:write',
    ],
]);
Ruby
webhook = wemail.webhooks.create(
  url:    "https://yourapp.com/webhooks/wemail",
  events: ["delivered", "bounced", "complained"],
  auth: {
    type:          "oauth2",
    token_url:     "https://auth.yourapp.com/oauth/token",
    client_id:     "wemail-events",
    client_secret: ENV["WEBHOOK_OAUTH_SECRET"],
    scope:         "webhooks:write"
  }
)
Go
webhook, _ := client.Webhooks.Create(ctx, &wemail.WebhookParams{
    URL:    "https://yourapp.com/webhooks/wemail",
    Events: []string{"delivered", "bounced", "complained"},
    Auth: map[string]interface{}{
        "type":          "oauth2",
        "token_url":     "https://auth.yourapp.com/oauth/token",
        "client_id":     "wemail-events",
        "client_secret": os.Getenv("WEBHOOK_OAUTH_SECRET"),
        "scope":         "webhooks:write",
    },
})
Java
JSONObject webhook = wemail.webhooks().create(
  WebhookParams.builder()
    .url("https://yourapp.com/webhooks/wemail")
    .events(List.of("delivered", "bounced", "complained"))
    .auth(Map.of(
      "type", "oauth2",
      "token_url", "https://auth.yourapp.com/oauth/token",
      "client_id", "wemail-events",
      "client_secret", System.getenv("WEBHOOK_OAUTH_SECRET"),
      "scope", "webhooks:write"))
    .build());
.NET
var webhook = await wemail.Webhooks.CreateAsync(new WebhookParams {
  Url = "https://yourapp.com/webhooks/wemail",
  Events = new[] { "delivered", "bounced", "complained" },
  Auth = new {
    type = "oauth2",
    token_url = "https://auth.yourapp.com/oauth/token",
    client_id = "wemail-events",
    client_secret = Environment.GetEnvironmentVariable("WEBHOOK_OAUTH_SECRET"),
    scope = "webhooks:write",
  },
});
ResponseExample response
{
  "id": "9b2f6c1e-4a8d-4f3b-9c7e-2d1a5b8e0f4c",
  "url": "https://yourapp.com/webhooks/wemail",
  "events": ["delivered", "bounced", "complained"],
  "enabled": true,
  "domain_id": null,
  "secret": "whsec_1f8a…d92c",
  "auth": {
    "type": "oauth2",
    "token_url": "https://auth.yourapp.com/oauth/token",
    "client_id": "wemail-events",
    "scope": "webhooks:write",
    "client_secret_set": true
  },
  "created_at": "2026-05-10T09:42:18Z"
}