Webhooks
Version 2 of the API includes Webhooks that allow you to subscribe to events that take place in your IntelAgree subscription. Instead of polling the IntelAgree API for changes, you can subscribe to a Webhook event, which will send an HTTP request to an endpoint that you specify in real-time whenever your subscribed event occurs, sending details of the event. Use the endpoints listed below to manage your Webhook subscriptions.
Get Webhook EventTypes
The first step is to choose which EventType you want to be notified about. For now, the IntelAgree API supports only one type of event: "Contract.Executed", which is triggered every time a contract in your subscription gets to the Executed state. In the future, more EventTypes will be added. To get a list of the EventTypes that are currently available, you can call the GET /webhooks/eventTypes operation.
Add a Webhook Subscription
To add a new subscription to a Webhook event, you must first deploly a publicly available and secure (HTTPS) endpoint that can handle the POST requests that will come from the Webhook. Then, you call the POST /webhooks operation with the following information in the request body:
"webhookEventType": Required string //e.g. "Contract.Executed"
"targetUrl": Required string //e.g. "https://yourdomain.com/api/webhookhander"
"businessKeyType": Optional string //e.g. "Salesforce"
The BusinessKeyType is an optional parameter that allows you to filter your Webhook subscription so that you only receive notifications for events on entities that have a business key from a particular system. For instance, if you only want to be notified about contracts that were created from a Salesforce integration, you would specify "Salesforce" as the BusinessKeyType on the Webhook.
Receiving and Validating Webhook Messages
Once you have added a Webhook subscription, the targetUrl that you specified will receive a POST each time your subscribed event occurs that includes the following content:
Headers:
x-intelagree-timestamp: This will contain the UTC timestamp at the time the POST was sent, following the RFC1123 standard
x-intelagree-signature: An HMAC signature that can be used to validate the message
Request Body:
"webhookId": integer // the ID of the webhook subscription that the message is for
"eventType": string // the specific type of event that occurred. e.g. "Contract.Executed"
"objectId": integer // the ID of the object that where the event occurred. For "Contract.Executed" events, this is a Contract ID.
"objectUrl": string // the resource URL where the object (e.g. the Contract) can be retrieved through the IntelAgree API.
"businessKeys": array of strings // any business keys attached to the object where the event occurred.
You can use the x-intelagree-timestamp and x-intelagree-signatures to ensure that the webhook requests have actually come from IntelAgree and they haven't been manipulated or replayed by a 3rd party. To do so, perform the following validation steps: rTo ensure that the message originates from IntelAgree and has not bee manipulated, peform the following validation steps.
Reject any request where either the x-intelagree-timestamp or x-intelagree-signature headers are missing.
Reject any request where the x-intelagree-timestamp signature is older than 5 minutes.
Create a string that concatenates together the value of the x-intelagree-timestamp header and the request body. ("<timestamp" + "<body>")
Create a SHA-256 hash of the resulting string, using your API subscription key as the encryption key. (This is the same key that you provide in the "Ocp-Apim-Subscription-Key" with each call to the IntelAgree API).
Convert the SHA-256 hash to Base64.
Compare the result to the value of the x-intelagree-signature header. If they do not match, reject the request.
Below is an example implementation of the suggested validations in C#:
public static void ValidateIntelAgreeRequest(string timestampHeader, string signatureHeader, string requestBody, string subscriptionKey)
{
if(string.IsNullOrEmpty(timestampHeader) || string.IsNullOrEmpty(signatureHeader))
{
throw new UnauthorizedAccessException("Required headers not provided");
}
if (DateTime.TryParse(timestampHeader, CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out var receivedTimestamp))
{
if (receivedTimestamp < DateTime.UtcNow.AddMinutes(-5))
{
throw new UnauthorizedAccessException("Timestamp is older than 5 minutes");
}
}
else
{
throw new UnauthorizedAccessException("Timestamp is in an incorrect format");
}
byte[] hash = HMACSHA256.HashData(Encoding.UTF8.GetBytes(subscriptionKey), Encoding.UTF8.GetBytes(timestampHeader + requestBody));
string hash64 = Convert.ToBase64String(hash);
if (hash64 != signatureHeader)
{
throw new UnauthorizedAccessException("Signature does not match original request");
}
}
Retries
If IntelAgree attempts to send a Webhook message and does not receive a successful response in the 200s range, it will attempt to re-send the message up to 5 times, with increasing wait times between retries.