Webhooks
Ask Magistrate to notify you when specific events happen by passing a webhook_url
when you create an envelope.
How to use webhooks
Creating a webhook endpoint is similar to creating any normal endpoint in your application or website. It's a publicly accessible URL where Magistrate can POST
JSON payloads. You tell Magistrate what the URL is when you create an envelope by passing the webhook_url
attribute. This immediately dispatches a webhook of type webhook_url_verification
.
Your URL should return a 2xx
status code when it receives a POST
request. We recommend that your webhook endpoint quickly return a 2xx
status code and process the JSON payload after returning the successful response to Magistrate's webhook request. Magistrate will automatically retry webhooks that receive a 3xx
, 4xx
, or 5xx
response status code. It will retry it every two hours up to three times.
Magistrate will not retry webhooks of type webhook_url_verification
, and if that fails (i.e., does not return a 2xx
status code), the API call itself will fail with status code 400
.
Magistrate does not guarantee that webhooks will arrive in any particular order, so your application should take care to check the occurred_at
timestamp of the event.
Shape generally
The exact payload for a webhook depends on the webhook's type. But all webhooks are shaped like this:
- Name
id
- Type
- string
- Description
Unique ID of the webhook. This can be used as an idempotency key to ensure you are not processing the same webhook more than once.
- Name
api_version
- Type
- integer
- Description
The API version. This is always
1
.
- Name
type
- Type
- string
- Description
Type of the webhook. This will always be
envelope_signed
orwebhook_url_verification
, but we recommend you check this in your application code because other webhook types will be added over time and will be considered non-breaking changes to the API.
- Name
occurred_at
- Type
- string
- Description
Date and time the event causing the webhook occured. ISO-8601 formatted string.
- Name
data
- Type
- object
- Description
Actual data related to the webhook. Will contain at least an
envelope_id
key. Other data depends on the webhook type.
Magistrate webhook payload
{
"id": "aaa9ad59-33c2-4290-bf66-bab79002b71e",
"api_version": 1,
"type": "envelope_signed",
"occurred_at": "2022-10-10T09:35:41Z",
"data": {
...
}
}
Check signatures
Magistrate signs the webhooks it sends to your endpoint by including a signature in the Magistrate-Signature
header. This allows you to verify that the webhook is authentic.
Magistrate generates signatures using a hash-based message authentication code (HMAC) with SHA-256.
Magistrate-Signature:
t=2022-10-10T14:55:03Z,
v1=d53617a93be26024b3e27f9978d3a6ee20d5e2c2284975a97dd8f35ad088f8d3
To verify the signature, follow these steps:
-
Split the value of the
Magistrate-Signature
header, using the,
character as the separator, to get a list of elements. Then split each element, using the=
character as the separator, to get a prefix and value pair. The value for the prefixt
corresponds to the timestamp, andv1
corresponds to the signature. -
Generate a
signed_payload
string by concatenating:- The timestamp
- The character
.
- The JSON payload, i.e., the request body
-
Calculate the expected signature by computing an HMAC with the SHA256 function and taking the hexadecimal digest. The secret key can be obtained in your integration panel. Use the
signed_payload
string as the message. -
Compare the expected signature to the signature in the header. If it matches, compute the difference between the current timestamp and the received timestamp and decide if the difference is within your tolerance. The delta should be no more than a couple of seconds.
Here is an example of how to verify the signature in your app:
Verifying a request
const signature = req.headers['Magistrate-Signature']
const timestamp = signature.split(",")[0].split("=")[1]
const signed_payload = timestamp + "." + req.body
const hash = crypto.createHmac('sha256', secret).update(signed_payload).digest('hex')
const expected = signature.split(",")[1].split("=")[1]
if (hash === expected) {
// Request is verified
} else {
// Request could not be verified
}
Webhook type reference
There are two webhook types. We will be adding additional webhook types in a backwards-compatible way over time.
Webhook type: envelope_signed
The envelope_signed
webhook type is sent when any party signs an envelope. If there are multiple signature blocks for that party in an envelope, this webhook is sent each time a signature block is signed.
If you create a contract with the autosign
attribute as true
, it will immediately trigger an envelope_signed
webhook for the signature blocks that were automatically signed.
The recommended way to determine if the envelope has been completely signed is to look at value of data.envelope_status
. If its partially_executed
, that means there remain empty signature blocks. If its fully_executed
, that means all signature blocks have been signed.
If you need information about the envelope that is not included with the webhook, you should retrieve the envelope.
The data
attribute has the following shape:
- Name
envelope_id
- Type
- string
- Description
Unique ID of the envelope that is the subject of the webhook.
- Name
signature_id
- Type
- string
- Description
Unique ID of the signature that was just signed.
- Name
envelope_status
- Type
- string
- Description
One of
fully_executed
orpartially_executed
depending on if the envelope has been completed by all parties or not, respectively.
envelolpe_signed webhook payload
{
"id": "f9c62dca-5a5b-4564-a0a9-cd86bbe7fde0",
"api_version": 1,
"type": "envelope_signed",
"occurred_at": "2022-10-10 10:14:01Z",
"data": {
"envelope_id": "891a4c2f-e0d8-4256-ad10-e217f3e6ac12",
"signature_id": "346d3ab0-677b-421f-8e3e-795de74044ad",
"envelope_status": "fully_executed"
}
}
Webhook type: webhook_url_verification
The webhook_url_verification
webhook type is sent immediately when a user passes a webhook_url
parameter in an API call. This tests to make sure the URL is valid and returning a 2xx
status code.
The data
attribute has the following shape:
- Name
user_email
- Type
- string
- Description
The email address of the user who made the API call that triggered this webhook.
webhook_url_verification webhook payload
{
"id": "c0fa00dc-5da0-4bfe-9b46-3a34f729f8cc",
"api_version": 1,
"type": "webhook_url_verification",
"occurred_at": "2022-11-10 12:12:02Z",
"data": {
"user_email": "harry@getmagistrate.com"
}
}