Webhooks
Missive allows applications to be notified of certain actions (incoming emails, outgoing emails, label changes, etc.) in the form of an HTTP POST
payload sent to an URL.
How to setup
To subscribe to a webhook you need to create a rule with a webhook action. Open your Missive settings, go to the Rule tab, create a new rule and select Webhook as the action.
When saving the rule your endpoint should already be configured to receive a POST
request successfully. A validation request will be sent to make sure your endpoint is working.
Request format
Each webhook request contains a JSON object. The JSON object follows this general structure:
{
"rule": {
"id": "45408b30-aa3a-45n1-bh67-0a0cb8da9080",
"description": "Notify elfs",
"type": "label_change"
},
"conversation": {
"id": "47a57b76-df42-4d8k-927x-80dbe5d87191",
"subject": "Mordor GPS coordinates",
"latest_message_subject": "Fwd: Mordor GPS coordinates",
"organization": {
"id": "93e5e5d5-11a2-4c9b-80b8-94f3c08068cf",
"name": "Fellowship"
},
"team": {
"id": "2f618f9e-d3d4-4a01-b7d5-57124ab366b8",
"name": "Hobbits",
"organization": "93e5e5d5-11a2-4c9b-80b8-94f3c08068cf"
},
"color": null,
"assignees": [
{
"id": "6b52b6b9-9b51-46ad-a4e3-82ef3c45512c",
"name": "Frodo Baggins",
"email": "frodo@fellowship.org",
"unassigned": false,
"closed": false,
"archived": false,
"trashed": false,
"junked": false,
"assigned": true,
"flagged": false,
"snoozed": true
}
],
"assignee_names": "Frodo Baggins",
"assignee_emails": "frodo@fellowship.org",
"users": [
{
"id": "6b52b6b9-9b51-46ad-a4e3-82ef3c45512c",
"name": "Frodo Baggins",
"email": "frodo@fellowship.org",
"unassigned": false,
"closed": false,
"archived": false,
"trashed": false,
"junked": false,
"assigned": true,
"flagged": false,
"snoozed": true
}
],
"attachments_count": 0,
"messages_count": 1,
"authors": [
{
"name": "Samwise Gamgee",
"address": "sam@fellowship.org"
}
],
"drafts_count": 0,
"send_later_messages_count": 0,
"tasks_count": 0,
"completed_tasks_count": 0,
"shared_labels": [
{
"id": "146ff5c4-d5la-3b63-b994-76711fn790lq",
"name": "Elfs"
}
],
"shared_label_names": "Elfs",
"app_url": "missive://mail.missiveapp.com/#inbox/conversations/47a57b76-df42-4d8k-927x-80dbe5d87191",
"web_url": "https://mail.missiveapp.com/#inbox/conversations/47a57b76-df42-4d8k-927x-80dbe5d87191"
},
"latest_message": {
"id": "86ef8bb8-269c-4959-a4f0-213db4e67844",
"subject": "Fwd: Mordor GPS coordinates",
"preview": "Hi Mr. Gamgee, I discovered something really disturbing about the Mordor coordinates we had.",
"type": "email",
"delivered_at": 1548415828,
"updated_at": 1548434556,
"created_at": 1548434555,
"email_message_id": "<cMx4teIvYRDqVI9osfdRZKA@1.lotrmail.net>",
"in_reply_to": [],
"references": [],
"from_field": {
"name": "Samwise Gamgee",
"address": "sam@fellowship.org"
},
"to_fields": [
{
"name": null,
"address": "sam@fellowship.org"
}
],
"cc_fields": [],
"bcc_fields": [],
"reply_to_fields": []
}
}
Error handling and retry
If the webhook request returns an error status code or does not return a response within 15 seconds, the request will be retried up to 5 times over a period of 8 minutes. If a webhook rule fails more than 50 times in a row, the rule will be automatically disabled. You can re-enable it from the Rules settings tab.
To perform work that may take over 15 seconds, you should use a background job solution. See this article to learn about the concept and implementations in various languages.
Request validation
If a validation secret is defined on your rule action, all webhook requests headers will include a X-Hook-Signature
hash signature of the payload. With this signature, you can validate that the request is coming from Missive. To do so, you must compute the signature yourself and compare it to the one provided in the request header.
The signature starts with sha256=
followed by a HMAC hexdigest. Here's some sample code showing how to compute the signature in Ruby:
#
# `secret` is the "Signature secret" you set in your Missive rule action
# `request_body` is the full HTTP request body
#
computed_signature = 'sha256=' + OpenSSL::HMAC.hexdigest(
OpenSSL::Digest.new('sha256'), secret, request_body
)
Make sure to assess equality between the header signature and the one you've computed using a method that prevents timing attacks against regular equality operators. In Ruby, you can use secure_compare.
valid = Rack::Utils.secure_compare(x_hook_signature, computed_signature)