Skip to content

Verify method 📢 Webhooks

Verifies the authenticity of incoming webhook requests by validating their signatures using the provided options.

All webhooks are signed by default. There are three HTTP headers to consider during the signature verification process:

  • Content-Digest: hash of the message body
  • Signature-Input: describes what parts of the message are signed, along with other data about the signing method
  • Signature: the cryptographic signature

Usage

ts
import { Webhooks } from 'mailchannels-sdk'

const { data, error } = await Webhooks.verify({
  payload: rawBody,
  headers: {
    'content-digest': req.headers['content-digest'],
    'signature': req.headers['signature'],
    'signature-input': req.headers['signature-input']
  },
  publicKey: 'MCowBQYD...'
})
ts
import { MailChannelsClient, Webhooks } from 'mailchannels-sdk'

const mailchannels = new MailChannelsClient('your-api-key')
const webhooks = new Webhooks(mailchannels)

const { data, error } = await webhooks.verify({
  payload: rawBody,
  headers: {
    'content-digest': req.headers['content-digest'],
    'signature': req.headers['signature'],
    'signature-input': req.headers['signature-input']
  },
  publicKey: 'MCowBQYD...'
})
ts
import { MailChannels } from 'mailchannels-sdk'

const mailchannels = new MailChannels('your-api-key')

const { data, error } = await mailchannels.webhooks.verify({
  payload: rawBody,
  headers: {
    'content-digest': req.headers['content-digest'],
    'signature': req.headers['signature'],
    'signature-input': req.headers['signature-input']
  },
  publicKey: 'MCowBQYD...'
})

NOTE

The Webhooks class provides both a static and an instance verify method. The static method is useful for quickly verifying webhook requests without needing to create an instance of the MailChannels class using your API Key. However, you can also use the instance method if you prefer, as both will yield the same result.

Params

  • options WebhooksVerifyOptions required: The options for verifying the webhook.
    • payload string required: The raw body of the incoming webhook request as a string. This should be the exact payload received from the webhook, without any modifications or parsing, to ensure accurate signature verification.
    • headers Record<string, string> required: The headers of the incoming webhook request as a record of key-value pairs. These headers should include content-digest, signature, and signature-input required for validating the authenticity of the webhook request.
    • publicKey string optional: The public key used to verify the webhook signature. If not provided, the SDK will attempt to retrieve the appropriate public key based on the keyid specified in the signature-input header.

      NOTE

      The key ID included in the signature-input header of each incoming webhook is used to identify the key used to sign the request.

      TIP

      The intended pattern is to fetch the public key once, cache it, and then reuse it for all subsequent requests. You'd only need to call the getSigningKey method again if you see a key ID you haven't encountered before (e.g. if MailChannels rotate the key), which is a rare event.

      The public key can be provided in PEM format or as a raw base64 string. The SDK will handle both formats correctly.

    • cache boolean optional: Whether to cache signing keys fetched from the API by their keyId. Defaults to true.

Response

  • data WebhookEvent[] | null nullable
    • event WebhookEventType guaranteed: The type of event that occurred.
    • customerHandle string guaranteed: The MailChannels account ID that generated the webhook. If the message was sent by a sub-account, this field contains the sub-account handle.
    • timestamp number guaranteed: The Unix timestamp (in seconds) when the event occurred; the timezone is always UTC.
    • email string optional: The sender's email address.
    • smtpId string optional: The Message-Id of the message that generated the event.
    • requestId string optional: A unique identifier generated to track the original HTTP request.
    • campaignId string optional: The campaign identifier for the message that generated the event.
    • recipients string[] optional: The recipients of the message.
    • userAgent string optional: The User-Agent header given when the recipient opened the message. This field is only present for open and click events.
    • ip string optional: The IP address of the host that made the HTTP request. This field is only present for open and click events.
    • url string optional: The URL that was clicked by the recipient. This field is only present for click events.
    • status string optional: The SMTP status code that caused the bounce. This field is only present for hard-bounced, soft-bounced, and dropped events.
    • reason string optional: A human-readable explanation of why the message bounced or was dropped. This field is only present for hard-bounced, soft-bounced, and dropped events.
  • error ErrorResponse | null nullable: Error information if the operation failed.
    • message string guaranteed: A human-readable description of the error.
    • statusCode number | null nullable: The HTTP status code from the API, or null if the error is not related to an HTTP request. This field is intended for diagnostic use only and should not be relied upon.
    • type string guaranteed: A string identifier for the type of error. This field is intended for diagnostic use only and should not be relied upon.

TIP

This method returns data as an array of events if the webhook request is authentic and valid. If the verification fails, data will be null, indicating the signature verification failed and the request may not be from MailChannels or could have been tampered with.

Type declarations

Signature

ts
async function verify (options: WebhooksVerifyOptions): Promise<WebhooksVerifyResponse>

Response type declarations

ts
interface ErrorResponse {
  message: string;
  statusCode: number | null;
  type: ErrorType;
}
ts
type DataResponse<T> = {
  data: T;
  error: null;
} | {
  data: null;
  error: ErrorResponse;
};

Event type declarations

ts
type WebhookEventType =
  | "processed"
  | "delivered"
  | "open"
  | "click"
  | "hard-bounced"
  | "soft-bounced"
  | "dropped"
  | "complained"
  | "unsubscribed"
  | "test";
ts
interface WebhookEventProcessed extends WebhookEventBase<"processed"> {}
ts
interface WebhookEventDelivered extends WebhookEventBase<"delivered"> {}
ts
interface WebhookEventOpen extends WebhookEventBase<"open">, WebhookEventWithTracking {}
ts
interface WebhookEventClick extends WebhookEventBase<"click">, WebhookEventWithTracking {
  url?: string;
}
ts
interface WebhookEventHardBounced extends WebhookEventBase<"hard-bounced">, WebhookEventWithStatus {}
ts
interface WebhookEventSoftBounced extends WebhookEventBase<"soft-bounced">, WebhookEventWithStatus {}
ts
interface WebhookEventDropped extends WebhookEventBase<"dropped">, WebhookEventWithStatus {}
ts
interface WebhookEventComplained extends WebhookEventBase<"complained"> {}
ts
interface WebhookEventUnsubscribed extends WebhookEventBase<"unsubscribed"> {}
ts
interface WebhookEventTest extends Omit<WebhookEventBase<"test">, "recipients" | "campaignId"> {}
ts
type WebhookEvent =
  | WebhookEventProcessed
  | WebhookEventDelivered
  | WebhookEventOpen
  | WebhookEventClick
  | WebhookEventHardBounced
  | WebhookEventSoftBounced
  | WebhookEventDropped
  | WebhookEventComplained
  | WebhookEventUnsubscribed
  | WebhookEventTest;

Verify type declarations

ts
interface WebhooksVerifyOptions {
  payload: string;
  headers: Record<string, string> | {
    "content-digest": string;
    "signature": string;
    "signature-input": string;
  };
  publicKey?: string;
  cache?: boolean;
}
ts
type WebhooksVerifyResponse = DataResponse<WebhookEvent[]>;

Source

SourcePlaygroundDocsTests

Released under the MIT License.