Webhooks
You can use Webhooks to subscribe to certain events when they occur. Webhooks provide a way to respond to real-time events as they happen without having to constantly poll the API. When an event occurs that matches your webhook scope, a POST HTTP request will be sent to your webhook URL.
Setup
To quickly get started testing webhooks, you can use something like RequestBin to inspect and explore the payload.
Check out the Core API Reference on how to create a webhook.
Retries
The POST HTTP request to your URL expects an HTTP 200 response code. Any other response code that is not exactly a 200 will result in the Webhook to retry with an exponential backoff strategy with a max of 10 attempts. A webhook with a total error count above 25 will be disabled. Total error count is reset with each successful response.
Scopes
Scope | Description |
---|---|
* | Matches all events. |
project.* | Matches all project events. |
project.created | Fires when a project is created. |
project.updated | Fires when a project is updated. |
project.label_added | Fires when a label is added to a project |
project.contact_created | Fires when a contact is added to a project |
project.contact_updated | Fires when any edits are made to a project's contact |
project.merged | Fires when a project is merged with another project |
project.deleted | Fires when a project is deleted. |
photo.* | Matches all photo events. |
photo.created | Fires when a photo is created and processed by our system. |
photo.updated | Fires when any edits (annotations) are made to a photo. |
photo.tag_added | Fires when a tag is added to a photo |
comment.* | Matches all comment events. |
comment.created | Fires when a new comment is created. |
document.* | Matches all document events |
document.created | Fires when a document is created for a project |
video.* | Matches all video events |
video.created | Fires when a video is created for a project |
todo_list.* | Matches all todo_list (checklist) events |
todo_list.created | Fires when a todo list (checklist) is created |
todo_list.completed | Fires when a todo list (checklist) is completed |
todo_list.deleted | Fires when a todo list (checklist) is deleted |
task.* | Matches all checklist task events |
task.completed | Fires when a checklist task is completed. Note: This does not apply to Project Tasks |
Example Request Body
{
"event_type": "project.created" - (String) This will correspond to the event and scope that triggered the webhook.
"created_at": 1661361759 - (Integer) This is the integer timestamp when the webhook request was sent.
"payload": {...} - (Object) This is the object that corresponds to the event that occurred, and will typically match the structure of the associated object. e.g. "project.*" webhook payloads will match the Project object.
"webhook_id": 42 - (Integer) This is the id of the webhook object that the webhook request came from.
}
Validating your payload
Because your webhook URL is open to the public, for security reasons, we recommend validating that the request came from CompanyCam by using the token
parameter you supplied calling the create webhook endpoint with the X-CompanyCam-Signature
header from the event.
To validate that the data came from CompanyCam, you need to calculate the base64 encoded HMAC hash of the request body using the SHA1 algorithm and your webhook token as the key. If the value matches the header's signature, you can be sure the request was sent from CompanyCam.
const crypto = require('crypto');
const webhookToken = 'YOUR_WEBHOOK_TOKEN';
function validateFrontSignature(data, signature) {
var hash = crypto.createHmac('sha1', webhookToken)
.update(data)
.digest('base64');
return crypto.timingSafeEqual(Buffer.from(hash), Buffer.from(signature));
}
// Get response...
const receivedData = res.body; // raw body of the request
const isValid = validateFrontSignature(receivedData, receivedSignature);
Updated 7 days ago