Email Status Event Webhook Configuration

This section explains how users can configure webhooks in the application and verify signatures using the provided signature verification secret for enhanced security.

Adding a Webhook URL

Users can specify a webhook URL in the application where events will be sent. The webhook URL should be a publicly accessible endpoint capable of handling HTTP POST requests.

Steps to Add a Webhook:
  • Go to Settings -> API Settings -> Email -> Status Update. Easify Email Webhook Settings
Webhook Event Structure:

When an event is triggered, the application will send a POST request to the configured webhook URL with the following headers and body:

Headers
  • X-Easify-Signature: A Base64-encoded signature of the payload, generated using the verification secret.
  • X-Easify-Timestamp: The UNIX timestamp of the request.
Payload

The POST body contains the event data. Example:

[
  {
    "additional_data" : "{'name':'John','id':'232'}",
    "email": "example@test.com",
    "email_id": "675",
    "timestamp": 1734081***,
    "smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
    "event": "processed",
    "category": ["cat facts"],
    "sg_event_id": "4mA9l_cHKMlUEEkEuZc3****",
    "sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****"
  },
  {
    "additional_data" : "{'name':'John','id':'232'}",
    "email": "example@test.com",
    "email_id": "675",
    "timestamp": 1734081***,
    "smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
    "event": "deferred",
    "category": ["cat facts"],
    "sg_event_id": "eKRNAYmTi2jlSdymGKZs****",
    "sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****",
    "response": "400 try again later",
    "attempt": "5"
  },
  {
    "additional_data" : "{'name':'John','id':'232'}",
    "email": "example@test.com",
    "email_id": "675",
    "timestamp": 1734081***,
    "smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
    "event": "delivered",
    "category": ["cat facts"],
    "sg_event_id": "GuGhSahRjAq7Ci2m_FF****",
    "sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****",
    "response": "250 OK"
  },
  {
    "additional_data" : "{'name':'John','id':'232'}",
    "email": "example@test.com",
    "email_id": "675",
    "timestamp": 1734081***,
    "smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
    "event": "open",
    "category": ["cat facts"],
    "sg_event_id": "ABygEH8H1JfhmJQnDEtz****",
    "sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****",
    "useragent": "Mozilla/4.0 (compatible; MSIE 6.1; Windows XP; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
    "ip": "255.255.255.***"
  },
  {
    "additional_data" : "{'name':'John','id':'232'}",
    "email": "example@test.com",
    "email_id": "675",
    "timestamp": 1734081***,
    "smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
    "event": "click",
    "category": ["cat facts"],
    "sg_event_id": "RlVuHd4e6J1KX1c3UXtu****",
    "sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****",
    "useragent": "Mozilla/4.0 (compatible; MSIE 6.1; Windows XP; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
    "ip": "255.255.255.***",
    "url": "http://www.sendgrid.com/"
  },
  {
    "additional_data" : "{'name':'John','id':'232'}",
    "email": "example@test.com",
    "email_id": "675",
    "timestamp": 1734081***,
    "smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
    "event": "bounce",
    "category": ["cat facts"],
    "sg_event_id": "SMrxoGPPPugXFS_tLM0b****",
    "sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****",
    "reason": "500 unknown recipient",
    "status": "5.0.*"
  },
  {
    "additional_data" : "{'name':'John','id':'232'}",
    "email": "example@test.com",
    "email_id": "675",
    "timestamp": 1734081***,
    "smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
    "event": "dropped",
    "category": ["cat facts"],
    "sg_event_id": "00udEyCl5KqOB8aviHUI****",
    "sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****",
    "reason": "Bounced Address",
    "status": "5.0.*"
  },
  {
    "additional_data" : "{'name':'John','id':'232'}",
    "email": "example@test.com",
    "email_id": "675",
    "timestamp": 1734081***,
    "smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
    "event": "spamreport",
    "category": ["cat facts"],
    "sg_event_id": "cxwA33aN6INAhHxR4eEl****",
    "sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****"
  },
  {
    "additional_data" : "{'name':'John','id':'232'}",
    "email": "example@test.com",
    "email_id": "675",
    "timestamp": 1734081***,
    "smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
    "event": "unsubscribe",
    "category": ["cat facts"],
    "sg_event_id": "6KQ3MWWC3jY5Fm9PgYxE****",
    "sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****"
  },
  {
    "additional_data" : "{'name':'John','id':'232'}",
    "email": "example@test.com",
    "email_id": "675",
    "timestamp": 1734081***,
    "smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
    "event": "group_unsubscribe",
    "category": ["cat facts"],
    "sg_event_id": "E9VM-8dxczn2XE1nstn4****",
    "sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****",
    "useragent": "Mozilla/4.0 (compatible; MSIE 6.1; Windows XP; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
    "ip": "255.255.255.***",
    "url": "http://www.sendgrid.com/",
    "asm_group_id": 1*
  },
  {
    "additional_data" : "{'name':'John','id':'232'}",
    "email": "example@test.com",
    "email_id": "675",
    "timestamp": 1734081***,
    "smtp-id": "<14c5d75ce93.dfd.64b469@ismtpd-***>",
    "event": "group_resubscribe",
    "category": ["cat facts"],
    "sg_event_id": "Q3zFzf5hk2ec_Ck5330R****",
    "sg_message_id": "14c5d75ce93.dfd.64b469.filter0001.16648.5515E0B8****",
    "useragent": "Mozilla/4.0 (compatible; MSIE 6.1; Windows XP; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
    "ip": "255.255.255.***",
    "url": "http://www.sendgrid.com/",
    "asm_group_id": 1*
  }
]

* You can use the status in the response by checking both the email and email_id values

Steps for Validating the Signature

  1. Extract Header and Payload Information

X-Easify-Timestamp from the request headers.

X-Easify-Signature from the request headers.

Raw JSON payload from the request body.

  1. Recreate the Signature

To validate the signature, recreate it using the following process:

Use the raw JSON payload as the input:

$payloadString = json_encode($payload);

Generate an HMAC signature using the shared webhook_secret:

$computedSignature = hash_hmac('sha256', $payloadString,  $webhook_secret);

Encode the generated signature in Base64

$computedSignatureBase64 = base64_encode($computedSignature);
  1. Compare the Signatures

Compare the computed signature with the one received in the X-Easify-Signature header:

if (hash_equals($computedSignatureBase64, $receivedSignature)) {

// Signature is valid

} else {

// Signature is invalid

}
  1. Validate the Timestamp

To prevent replay attacks, ensure that the timestamp in X-Easify-Timestamp is within an acceptable range (e.g., ±5 minutes):

$currentTime = time();

if (abs($currentTime - $receivedTimestamp) > 300) {

// 5 minutes

// Reject the request as expired

}

pixel for linkedin