Set up webhooks
This guide covers how to create, retrieve, and delete webhook subscriptions, validate HMAC signatures, and handle webhook expiration.
Before you begin
- Obtain a valid access token. See Authenticate.
- Required scopes:
connector-protimeapi-webhooks.readandconnector-protimeapi-webhooks.write. - Your destination endpoint must be reachable over HTTPS and able to return a success status code.
- See Webhook lifecycle for background on event delivery, retries, and expiration.
Create a webhook
Create a webhook by sending a request to the webhooks endpoint with the destination URL and collection name.
https://<tenant>.myprotime.eu/connector/protimeapi/api/v1/webhooks
Host: <tenant>.myprotime.eu
Authorization: Bearer eyJ...Uc
Content-Type: application/json
User-Agent: YourService/v1 (YourCompany){
"destinationUrl": "https://www.your-company.com/protime/clockings",
"collectionName": "clockings"
}A successful response returns 201 Created. The Location header contains the webhook URI and the response body includes a private webhook key.
Retrieve a list of webhooks
Retrieve your webhooks with optional filters on collection-name or status.
https://<tenant>.myprotime.eu/connector/protimeapi/api/v1/webhooks?filter=<filter-expression>
Host: <tenant>.myprotime.eu
Authorization: Bearer eyJ...Uc{
"value": [
{
"id": "a7d853ea-89eb-4735-83d1-b891c6fde398",
"validUntil": "2025-03-31T12:30:00+02:00",
"status": "Enabled",
"destinationUrl": "https://www.your-company.com/protime/clockings",
"collectionName": "clockings"
}
]
}Filter by status:
GET /connector/protimeapi/api/v1/webhooks?filter=status%20eq%20'Disabled' HTTP/1.1
Host: <tenant>.myprotime.euRetrieve a webhook by ID
GET /connector/protimeapi/api/v1/webhooks/{id} HTTP/1.1
Host: <tenant>.myprotime.eu
Authorization: Bearer eyJ...UcDelete a webhook
Soft-delete a webhook to stop receiving events. You can still query debugging endpoints after deletion.
https://<tenant>.myprotime.eu/connector/protimeapi/api/v1/webhooks/{id}
Host: <tenant>.myprotime.eu
Authorization: Bearer eyJ...UcValidate the HMAC signature
Every webhook event includes an Authorization header with an HMAC-SHA256 signature. Validate it to confirm the request came from Protime and that the payload was not tampered with.
The header format is: Authorization: HMAC-SHA256 {signature}
Example validation in C#:
private async Task<bool> ProtimeAuthHeaderIsValid(AuthenticationHeaderValue protimeAuthHeaderValue)
{
if (protimeAuthHeaderValue.Scheme == "HMAC-SHA256")
{
var requestBody = await GetJsonRequestBody();
const string webhookKey = "privateWebhookKey";
using var hmacSha256 = new HMACSHA256(Encoding.UTF8.GetBytes(webhookKey));
var bytes = Encoding.UTF8.GetBytes(requestBody);
var hash = hmacSha256.ComputeHash(bytes);
var calculatedHmacSignature = Convert.ToBase64String(hash);
return protimeAuthHeaderValue.Parameter == calculatedHmacSignature;
}
return false;
}Handle webhook expiration
A webhook becomes Disabled when its validUntil is reached or when all delivery retries are exhausted. Treat both cases identically – the renewal procedure is the same.
Monitor the validUntil property (returned at creation and on any GET) so you know when expiration is imminent, and monitor the status property to detect disablement caused by delivery failures.
Renewal procedure
- Re-synchronize the data using the collection’s GET list endpoints (or a fresh delta initial request) to cover the period since the webhook was last delivering events. Events from that period are not replayed by Protime, so this step fills the gap.
- POST to
/webhookswith the samedestinationUrlandcollectionNameas the original subscription. The system re-enables the existing subscription rather than creating a duplicate. - Store the new private webhook key returned in the response. It immediately replaces the old key for HMAC signature validation – the old key stops matching inbound signatures the moment the new one is issued.
- Store the new
validUntilreturned in the response and use it to schedule the next renewal.
https://<tenant>.myprotime.eu/connector/protimeapi/api/v1/webhooks
{
"destinationUrl": "https://www.your-company.com/protime/clockings",
"collectionName": "clockings"
}destinationUrl + collectionName pair is the durable identifier for renewal. The webhook id may change. Do not rely on the original id to address the renewed subscription.Add external references to webhooks
Include the externalReferences query parameter when creating the webhook. The webhook events will then include the specified external references in the payload.
Predefined external reference:
POST /connector/protimeapi/api/v1/webhooks?externalReferences=(people,@badge-number) HTTP/1.1
Host: <tenant>.myprotime.eu
Content-Type: application/json{
"destinationUrl": "https://www.your-company.com/protime/clockings",
"collectionName": "clockings"
}Custom external reference:
POST /connector/protimeapi/api/v1/webhooks?externalReferences=(activity-definitions,actDef) HTTP/1.1
Host: <tenant>.myprotime.eu
Content-Type: application/json{
"destinationUrl": "https://www.your-company.com/protime/clockings",
"collectionName": "clockings"
}Handle duplicate events
Some actions in Protime trigger multiple webhook events due to automatic calculations. Use the changeVersion property on each event to determine whether a received object is newer than one you already processed. If the changeVersion is older (string comparison), ignore it.
Related
- Webhooks reference – properties, retry schedule, supported collections
- Webhook lifecycle – event model, delivery guarantees, and retry strategy
- Use external references – predefined and custom external reference patterns