Webhooks are a new feature in Carerix designed to make your hiring process smoother and more efficient.
This product is in BETA release.
What are Webhooks?
Webhooks are like notifications that automatically tell other systems or apps when something happens in your Carerix system. A webhook can instantly update another system. For example:
Candidate applies » notification is sent to a Marketing Automation tool, like Brevo or HubSpot
Publication is updated » notification is sent, like a Multiposter or webbuilder
Placement is created » notification is sent to Backoffice-system like AFAS
Why Use Webhooks?
Save Time: No more manual updates or waiting for information to sync. Webhooks do it instantly.
Customize Actions: Set up webhooks to trigger specific actions in other apps based on what happens in Carerix.
Looking for some examples?
See our article on Creating your first webhook
Supported in MVP1
The following entities & fields will be supported.
You will find entities, fields & usecases that were tested and supported by Carerix.
We actively monitor these fields. Fields that are not listed on this page are not supported, but webhooks might still function.
More fields and use cases will be added in the upcoming months.
List of Entities
(for these entities, Carerix supports webhooks when a new record is created)
List of Entities
(for these entities, Carerix supports webhooks when a new record is created)
Matches
Candidates
Jobs (vacancies)
Contacts
Company
Publications
Placements
Campaigns
List of Fields
(fields per entity supported in first release)
List of Fields
(fields per entity supported in first release)
Entity | Carerix fieldname
Matches | Stage
Matches | Groups (any change)
Matches | Source
Matches | Motivation
Matches | Notes
Candidate | Status
Candidate | Surname
Candidate | Middle name
Candidate | First name
Candidate | First names
Candidate | Surname at birth
Candidate | Date of birth
Candidate | Social security id
Candidate | Notes
Candidate | Job title
Candidate | Experience since
Candidate | Owns a car
Candidate | Contact instructions
Candidate | Last contact
Candidate | Home phone
Candidate | Work Phone
Candidate | Home Mobile
Candidate | Work mobile
Candidate | Email adres
Candidate | URL
Candidate | City private
Candidate | Postal code
Candidate | Full address
Candidate | Country / region
Candidate | City work
Candidate | Postcal code
Candidate | Full adress
Candidate | Country / region
Candidate | Alternative city
Candidate | Postal code
Candidate | Full address
Candidate | Country / region
Candidate | Availability calculated
Candidate | Other Availability date
Candidate | Current salary
Candidate | Currency
Candidate | Current conditions
Candidate | Hobbies/other activities
Candidate | Ambition
Candidate | Keywords
Candidate | Comment
Candidate | Date of birth
Candidate | Place of birth
Candidate | Country
Candidate | Employment
Candidate | Start date contract
Candidate | End date contract
Candidate | Work unit
Candidate | Daily working hoursd
Candidate | Username
Campaigns | Status
Campaigns | Visible
Campaigns | Term (start date)
Campaigns | Term End date
Campaigns | Name
Campaigns | Description
Placements | Start date <> dd-mm-jjjj
Placements | Last date <> dd-mm-jjjj
Placements | Forecast date <> dd-mm-jjjj
Placements | Contract type
Placements | Work unit
Placements | Daily working hours: mo
Placements | Daily working hours: tu
Placements | Daily working hours: we
Placements | Daily working hours: th
Placements | Daily working hours: fr
Placements | Daily working hours: sa
Placements | Daily working hours: su
Placements | Weekly working hours
Placements | Total hours agreed
Placements | Notes
Placements | Invoice frequency
Placements | Term of payment
Placements | Discount percentage
Placements | Invoice reference
Placements | Customer reference
Placements | External project ID
Contacts | Surname
Contacts | Middle name
Contacts | Firstname
Contacts | Initials
Contacts | Gender
Contacts | Professional title
Contacts | Suffix
Contacts | Language
Contacts | Salutation
Contacts | Date of birth
Contacts | Work phone
Contacts | Home phone
Contacts | Work mobile
Contacts | Home mobile
Contacts | E-mail addresses
Contacts | Jobtitlle
Contacts | Department
Contacts | Organization/ Department
Contacts | Source
Contacts | Description
Publication | no name ?
Publication | First publication date
Publication | Publication stops as of
Publication | Title
Publication | Work location
Publication | Introduction
Publication | Organisation/Department
Publication | Requirements
Publication | Offer
Publication | Information
Publication | Applications
Company | Status
Company | Name
Jobs | status dropdown
Jobs | owner
Jobs | Jobtitle
Jobs | notes
Jobs | Brought in by
Jobs | Source
Jobs | Comment
Jobs | Start date
Jobs | End date
Jobs | Contract period
Jobs | Work unit
Jobs | Daily working hours
Jobs | Mo
Jobs | Tu
Jobs | We
Jobs | Th
Jobs | Fr
Jobs | Sa
Jobs | Su
Jobs | Number of openings
Jobs | Purchase rate/Salary - low
Jobs | Purchase rate/Salary - high
Jobs | Salary indication
Jobs | Other conditions
Jobs | Discount percentage
Jobs | Insert invoice lines for this job in collective invoice
Jobs | Invoice reference
Jobs | Customer reference
Jobs | Number of invoice prints
Jobs | Success rate
Jobs | Estimated sales volume
Jobs | Fee percentage
List of webhooks on specific events
(if field matches criteria, notification will be send)
List of webhooks on specific events
(if field matches criteria, notification will be send)
Matches | Matchstage X
Candidates | Status
Candidate | Category
Candidate | Procedure
Campaigns | Status
Contact | Status
Placement | Status
Placement | Contract type
Qualifiers
(Following qualifiers can be used, to trigger a webhook)
Qualifiers
(Following qualifiers can be used, to trigger a webhook)
Equals: specific field exactly matches a value.
Not Equals: specific field does not match a certain value
More qualifiers will follow soon.
Some examples of supported use cases
If Candidate status is set to "Available" » notification
If Placement is created » notification
If Contact emailadres is updated » notification
If Publication is created » notification
If Match is set to Matchstage 2.1 » notification
If Candidate is subscribed/unsubscribed (added or removed) to any of the listed Candidate groups » notification
If one the additional fields of a Candidate is updated » notification
If the Company's Owner dropdown-field is changed » notification
Technical details
Our webhook service consists of three main components:
Application
Webhook
Webhook Event
Here’s a brief overview of each component:
1 Application
An application is a collection of webhooks that share a public/private key pair used for creating security signatures.
2 Webhook
A webhook defines the events you want to receive and specifies the delivery destination. Each webhook is linked to an application.
3 Webhook Event
A webhook event is an HTTP request sent based on the information provided by the application and webhook.
Application Management
Model (excluding system fields like _kind, _id, audit info):
{
"name": "Application for external integration",
"secret": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQLJpFe5pVIDE9fknN1z2rDIgl9uDLqK8oW1MgmI3JwIDAQAB"
}
Field Descriptions:
name: The name of the application, used for human identification.
secret: Contains a public secret used for signature verification.
Webhook Management
Model (excluding system fields like _kind, _id, audit info):
{
"url": "http://example.url",
"filters": [
{
"eventType": "exampleentity:updated",
"condition": "data.exampleAttribute eq 'someValue'"
}
],
"customHeaders": [
{
"name": "Example Header",
"value": "Example Header Value"
}
]
}
Field Descriptions
url: The address where an event should be sent.
customHeaders: An array of objects representing key/value pairs sent as HTTP headers.
reserved names include Cx-Signature, Cx-Payload-Schema-Version, and Content-Type.
filters: An array of objects defining the events to be sent.
Filter Model
{
"eventType": "exampleentity:updated",
"condition": "data.exampleAttribute eq 'someValue'"
}
filters.eventType: Combines entity and action types. Possible action types are: created, updated, and deleted.
The entity name should follow Carerix' database table naming conventions. Example:
candidate
becomescremployee
.filters.condition: A string filter that returns positive results based on event data. Supports two condition types:
metadata.paths
anddata.*
.
Webhook Event
Model:
{
"id": "8469bf71-4942-45ea-98b8-393077288785",
"time": "2024-02-14T14:24:40Z",
"type": "crmatch:updated",
"applicationId": "6fc051df-90e0-4fa4-b78e-af243f0023b3",
"webhookId": "22cc6baf-7d9a-4230-a5fe-8004a9b34a17",
"tenant": "cxdev50streamer",
"data": {
"entityId": "2.3",
"changedFields": [
"attributechanges",
"statusinfo",
"modificationdate"
]
}
}
Field Descriptions:
id: Unique identifier for each event.
time: Event timestamp.
type: Combination of entity and action types. The actual supported entity list can be found [here].
applicationId: Application containing the webhook matched with the event.
webhookId: Webhook matched with the event.
tenant: Tenant name owning this event.
data: Actual event payload.
Data Payload Model:
{
"entityId": "2.3",
"changedFields": [
"attributechanges",
"statusinfo",
"modificationdate"
]
}
data.entityId: Entity that the event belongs to.
data.changedFields: List of changed fields, including those matched from the webhook definition and all fields changed simultaneously.
Webhook Event Evaluation
Evaluation Algorithm:
Type Filtering:
Check if the event type matches the specified entity name and action.
Condition Filtering:
Check if the condition evaluation result against an event is positive.
Positive Match:
The definition is marked positive if both type and condition checks are positive.
Webhooks are marked as matched if any filter definition is positive.
Examples:
Receiving Events for Candidate Updates:
{
"filters": [
{
"eventType": "cremployee:updated"
}
]
}
Receiving Events for Match Creations:
{
"filters": [
{
"eventType": "crmatch:created"
}
]
}
Condition Filtering Examples, Single Field Update:
{
"filters": [
{
"eventType": "cremployee:updated",
"condition": "metadata.paths has any of ['hascar']"
}
]
}
Condition Filtering Examples, Multiple Field Update:
{
"filters": [
{
"eventType": "cremployee:updated",
"condition": "metadata.paths has any of ['hascar', 'notes']"
}
]
}
Webhook verification
We strongly recommend that you verify the webhooks we send to you.
You can add custom headers with a custom signature.
Example:
"customHeaders": [
{
"name": "Custom-Signature",
"value": "FE: Basic Y3g1YXBpY2xpZW50OmN4NWNvbm5lY3RhcGlmZWF0dXJl"
}
]
A major part of securing webhooks involves the verification of the webhook source and destination, as well as the validation of the webhook payload. After analyzing the different webhook authentication strategies available, signature verification stands out as the strongest form of protection for securing webhooks.
Signature verification makes use of the RSA algorithm for authenticating and validating webhooks. The signature of the webhook is calculated on the backend using the webhook payload and previously generated private key.
To authenticate our webhooks using signature verification, we’ll take some required steps which we’ve implemented in different languages below. The required actions are:
Get and store somewhere your webhook application secret
Get the raw body of the request;
Construct RSA public key using stored webhook application secret
Calculate signature from request body using public key
Compare the calculated signature with the one sent in the
Cx-Signature
header, making sure that both values use the same encoding.
Java example
public class SignatureVerification {
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException, SignatureException, InvalidKeyException {
var payload = "<your raw request body>";
var signature = "<your Cx-Signature header value>";
var applicationSecret = "<your webhook application secret>";
var verified = verifySignature(applicationSecret, signature, payload);
System.out.println("Signature is verified: " + verified);
}
private static boolean verifySignature(String applicationSecret, String signature, String payload) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
var publicKeyAsString = applicationSecret
.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("\\n", "")
.replace("-----END PUBLIC KEY-----", "");
var payloadBytes = payload.getBytes(StandardCharsets.UTF_8);
var signatureBytes = Base64.getDecoder().decode(signature);
var publicKeyBytes = Base64.getDecoder().decode(publicKeyAsString);
var spec = new X509EncodedKeySpec(publicKeyBytes);
var keyFactory = KeyFactory.getInstance("RSA");
var publicKey = keyFactory.generatePublic(spec);
var signatureWithPublicKey = Signature.getInstance("SHA256withRSA");
signatureWithPublicKey.initVerify(publicKey);
signatureWithPublicKey.update(payloadBytes);
return signatureWithPublicKey.verify(signatureBytes);
}
}
Node.js example
// Importing Required Modules
const crypto = require('crypto');
function verifySignature(data, signature, applicationSecret) {
const publicKey = crypto.createPublicKey(applicationSecret);
const algorithm = "SHA256";
const verifier = crypto.createVerify(algorithm);
verifier.update(data)
const signatureBuffer = Buffer.from(signature, 'base64');
return verifier.verify(publicKey, signatureBuffer);
}
// Example usage
const data = '<your raw request body>';
const applicationSecret = "<your webhook application secret>";
const signature = "<your Cx-Signature header value>";
let isVerified = verifySignature(data, signature, applicationSecret);
console.log(`Is signature verified: ${isVerified}`);
PHP example
<?php
function verifySignature($data, $signature, $applicationSecret)
{
$publicKey = openssl_pkey_get_public($applicationSecret);
$verificationResult = openssl_verify($data, base64_decode($signature), $publicKey, OPENSSL_ALGO_SHA256);
if ($verificationResult == 1) {
echo "Signature is valid.";
} elseif ($verificationResult == 0) {
echo "Signature is invalid.";
} else {
echo "Error during verification.";
}
}
// Example usage
$data = "<your raw request body>";
$signature = "<your Cx-Signature header value>";
$applicationSecret = "<your webhook application secret>";
verifySignature($data, $signature, $applicationSecret);
?>
Delivery and retry mechanism
Any response status other than 200 indicates a webhook delivery failure.
We will continue attempting to deliver the webhook, according to an exponential backoff mechanism:
1st attempt - 0 seconds
1st retry - 3 seconds after first attempt
2nd retry - after 18 seconds
3rd retry - after 1.8 minute
4th retry - after 10.8 minutes
5th retry- after 1 hours
6th retry- after 2 hours (= latest attempt)
The number of attempts will be 7, including the initial attempt
The maximum amount of time for all retries is limited to 2 hours.
Retries will not be performed if one of successful Http Status Codes is received as an HTTP response code.
Roadmap
Request log
Webhooks of specific additional fields. FE if additional field "Shoesize" is changed » notification
Webhooks on specific groups » FE if groep "Do not send Emails" is changed » notification
Webhooks when attachment is added
More qualifiers, like "contains" or "smaller than"
How to get started
Currently, we roll out webhooks gradually. If you want to start using webhooks, please send a request to your Customer Success Manager.
Usage & costs
Access to webhooks is included in the paid feature bundle known as 'Carerix Datasource'.
The fair usage policy for webhooks will limit each webhook consumer to a maximum number of subscribed webhooks and a monthly limit on notifications. More details will be provided soon.
For further assistance, please contact our support team.