Teamtailor’s Company Webhooks allow you to receive real-time notifications when data changes in Teamtailor. This enables seamless integration with your existing systems without constantly polling the API.
Company Webhooks are ideal for:
To use Company Webhooks, you need:
You can create multiple webhook subscriptions with different event filters to organize your integrations efficiently.
Company Webhooks use a consistent naming pattern for events:
resource_name.action
Where:
* resource_name
is the object type (candidate, job, etc.)
* action
is what occurred (create, update, destroy)
candidate.create
- New candidate createdcandidate.update
- Candidate information updatedcandidate.destroy
- Candidate deletedjob.create
- New job createdjob.update
- Job information updatedjob.destroy
- Job deletedjob_application.create
- New application submittedjob_application.update
- Application updated (e.g., stage change)job_application.destroy
- Application deletedWhen an event occurs, Teamtailor sends a JSON payload to your endpoint containing details about the event.
{
"payload": {
"event_name": "job.update",
"data": {
"id": "2",
"type": "jobs",
"attributes": {
"title": "IT Designer 1",
"body": "<p>Job description...</p>",
"company-name": "Teamtailor",
"cover-letter-requirement": "cover_letter_optional",
"created-at": "2023-02-08T10:10:13.611+01:00",
"employment-level": "none",
"employment-type": "none",
"human-status": "archived",
"internal": false,
"remote-status": "none",
"status": "archived",
"tags": [],
"updated-at": "2023-02-22T22:10:48.705+01:00"
}
}
},
"signature": "YzU1N2FhOTUwMjlkNTFiMGM5NjIxNTEyODc5NGY5ZjgxZWNkMmNkZTZhNmIxYmI2YmM3NmVmYmQ1ZGZiMDg0Zg=="
}
The standard payload structure includes:
payload
: Object containing:
event_name
: The type of event (e.g., “job.update”)data
: Resource data with:
id
: Resource identifiertype
: Resource type (e.g., “jobs”, “candidates”)attributes
: Resource-specific attributessignature
: Base64-encoded signature for verificationFor destroy
events, the data structure is simpler but follows the same overall structure.
Each resource type includes different attributes in the payload:
Each webhook request includes these headers:
TT-Signature
: Signature for verifying webhook authenticityAuthorization
: Bearer token (for partner webhooks, if applicable)teamtailor-api-token
: API token (if applicable)Teamtailor uses multiple security measures to ensure webhook deliveries are secure and authentic.
Each webhook request includes:
TT-Signature
header containing the signatureThis allows you to verify that the webhook is legitimately from Teamtailor.
All webhook endpoints must use HTTPS to ensure data is encrypted in transit. Teamtailor will not send webhooks to non-HTTPS URLs.
Based on the implementation in tt-webhooks
, the following headers may be present:
const headers = {
"TT-Signature": signature,
};
if (providerKey) {
headers.authorization = `Bearer ${providerKey}`;
}
if (apiKey) {
headers["teamtailor-api-token"] = apiKey;
}
The standard header for signature verification is TT-Signature
.
If your endpoint is temporarily unavailable or returns a non-2xx status code, Teamtailor will retry the webhook delivery:
After multiple failed attempts, if the webhook still fails to deliver, it will be logged as a failed delivery.
To validate the authenticity of webhooks sent by Teamtailor, each request includes a TT-Signature
header and a signature field in the payload. This allows you to verify the webhook came from Teamtailor.
The signature is a Base64-encoded hexadecimal string. In the example payload:
"signature": "YzU1N2FhOTUwMjlkNTFiMGM5NjIxNTEyODc5NGY5ZjgxZWNkMmNkZTZhNmIxYmI2YmM3NmVmYmQ1ZGZiMDg0Zg=="
Based on the code in the tt-webhooks
repository, the signature verification should follow this pattern:
const crypto = require('crypto');
// Get this from your webhook setup in Teamtailor
const SECRET_KEY = 'your_webhook_signature_key';
function verifyWebhookSignature(requestBody, signatureHeader) {
const { payload } = requestBody;
// Calculate expected signature
// The exact calculation method may vary - check with Teamtailor for the exact formula
const hmac = crypto.createHmac('sha256', SECRET_KEY)
.update(payload.data.id.toString())
.digest('hex');
const expectedSignature = Buffer.from(hmac).toString('base64');
// Compare signatures
return signatureHeader === expectedSignature;
}
// In your webhook handler
app.post('/webhook', (req, res) => {
const signature = req.headers['tt-signature'];
if (!verifyWebhookSignature(req.body, signature)) {
return res.status(401).send('Invalid signature');
}
// Process the webhook...
res.status(200).send('Webhook processed');
});
<?php
// Get this from your webhook setup in Teamtailor
$secretKey = 'your_webhook_signature_key';
function verifySignature($requestBody, $signatureHeader, $secretKey) {
$id = $requestBody['payload']['data']['id'];
// Calculate the HMAC using SHA-256
$hmac = hash_hmac('sha256', $id, $secretKey, true);
// Convert to base64
$expectedSignature = base64_encode(bin2hex($hmac));
return hash_equals($signatureHeader, $expectedSignature);
}
// Webhook handler
$requestBody = json_decode(file_get_contents('php://input'), true);
$signature = $_SERVER['HTTP_TT_SIGNATURE'];
if (!verifySignature($requestBody, $signature, $secretKey)) {
http_response_code(401);
echo 'Invalid signature';
exit;
}
// Process the webhook...
http_response_code(200);
echo 'Webhook processed';
Follow these best practices to ensure reliable and secure webhook integration with Teamtailor.
Webhooks might be delivered multiple times, especially during retries: - Use a unique identifier (like the event ID) to detect duplicates - Make your webhook processing idempotent