Critsend's Event API
Overview
The Event API allows the users to setup web services that receive event notifications about their emails and their recipients from CritSend.
Details
User may enable the Event API by specifying a target URL in the 'Event API' section under the 'Mail Settings' tab. In the same section, the user can choose in which event categories they are interested in (see the categories below).
An HTTP POST will be issued to the user's specified URL at a fixed interval (e.g. 5 minutes) with all the events we received in the meantime. The POST request payload describes the collection of events using the Webhooks model, and consists of a UTF8-encoded JSON array of JSON objects (events) in the following format:
[
{
"category": "hard_bounce",
"date": "2011-09-02T14:39:53",
"recipient": "recipient1@example.org",
"mx": "example.com",
"tags": ["default", "tag1"],
"user-object": {"id": 42, "another_field": "Another value"}
},
{
"category": "blocked",
"date": "2011-09-02T14:55:53",
"recipient": "recipient2@example.org",
"mx": "example.com",
"tags": ["default", "tag2"],
"user-object": {"id": 42, "another_field": "Another value"}
},
...
]
While we will make a best effort to promptly deliver all the Webhooks events, messages may not arrive in order of commit. If we fail to reach the specified URL, we will retry several times over a 7-days period. This allows your services to be down for short maintenance windows and still receive all messages.
Web services should respond to the POST request with a 2XX response code to indicate successful delivery. Redirects (3XX response codes) are not followed, and no further delivery attempts will be made. Server errors (5xx response codes) are treated as failures and will be retried. All other response codes are ignored.
Event Format
The payload's event JSON object contains the following items:
| Field | Type | Description |
|---|---|---|
| category | String | The name of the event category. See the full list below. |
| date | String | The datetime the event happenned in ISO 8601 format (YYYY-MM-DDTHH:MM:SS). |
| recipient | String | The recipient's email address. |
| mx | String | The domain responsible for accepting the recipient's emails. |
| tags | Array | An array containing the tags that the email is related with. Each tag's type is String. |
| url | String | The clicked url if Critsend's tracking is enabled. It's included only when the event category is 'click'. |
The list of event categories is:
- open
- click
- unsubscribed
- hard_bounce
- soft_bounce
- blocked
- spam_report
- filtered
- error
Note: The event's JSON representation fields should not be considered as fixed. Later on, new JSON fields may be added.
Authentication
The Critsend Webhook's API uses HMAC-SHA256 to authenticate requests. Every user has a unique Webhooks 'secret key', in the 'Event API' section under the 'Mail Settings' tab. This key is used to seed the HMAC-SHA256 algorithm. Each POST request contains header called X-Critsend-Webhooks-Signature used to authenticate the payload. This header's value is a 64-character hexadecimal string. To verify the Webhook request is originating from CritSend you encode the payload with the HMAC-SHA256 algorithm (using your Webhooks 'secret key' as a key and SHA256 digest mode) and compare the resulting hexdigest to the X-Critsend-Webhooks-Signature header's value (signature).
Authentication example in Python:
import hmac, hashlib
def is_authenticated(your_webhooks_key, your_request_json_payload,
x_critsend_webhooks_signature):
my_signature = hmac.new(key=your_webhooks_key,
msg=your_request_json_payload,
digestmod=hashlib.sha256).hexdigest()
return x_critsend_webhooks_signature == my_signature
Authentication example in PHP:
function is_authenticated($your_webhooks_key, $your_request_json_payload,
$x_critsend_webhooks_signature)
{
$my_signature = hash_hmac("sha256", $your_request_json_payload, $your_webhooks_key);
return $x_critsend_webhooks_signature == $my_signature;
}
Example in PHP:
$our_webhooks_key = "xxxxxxxxxxxxxxx";
$critsend_signature = $_SERVER["HTTP_X_CRITSEND_WEBHOOKS_SIGNATURE"];
$json_payload = file_get_contents('php://input');
# Check if payload is valid
if($critsend_signature != hash_hmac("sha256", $json_payload, $our_webhooks_key))
throw exception("Invalid payload according to our webhooks key");
$events = json_decode($json_payload);
foreach($events as $event)
{
switch($event["category"])
{
case "open": event_open($event); break;
case "click": event_click($event); break;
case "unsubscribed": event_unsubscribe($event); break;
case "hard_bounce": event_hard_bounce($event); break;
case "soft_bounce": event_soft_bounce($event); break;
case "blocked": event_blocked($event); break;
case "spam_report": event_spam_report($event); break;
case "filtered": event_filtered($event); break;
case "error": event_error($event); break;
default: throw exception("Invalid category");
}
}