Near-realtime integration with Youforce webhooks

Introduction

In a nutshell, webhooks technology functions as a messaging system that enhances the integration experience between two systems. It minimizes waiting times, making it particularly well-suited for integrations where immediate updates are crucial.

For example, when a mutation happens in HR Core, like an update in the organization unit of a particular employment, our services send a message through an HTTPS POST to a web address you have set up in advance. This message includes detailed information about what happened, using a similar format to the domain APIs. This way, integrators can handle the information easily and consistently.

Unlike the classic API consumption paradigm, where the consumer needs to keep polling for changes, webhooks provide a reactive integration that allows the consumer to simply wait for the changes to arrive, resulting in a faster integration with minimal waiting times.

Youforce webhooks

The Youforce webhooks, like the APIs, are divided into domains. Each domain has its own webhook publisher with events. Applications can subscribe to one or more events in the Visma Developer Portal.

If you want to know how to integrate with webhooks and more details about Visma Connect, refer to the section: Webhook Dispatcher

Youforce Publisher-Subscriber model

Webhook security

Securing webhooks is vital for protecting your data flow. When your Webhook subscription is setup, you will receive a unique “secret” for that particular integration, this will allow the consumer to validate that the webhook message received was really sent by our Webhook Dispatcher and not by a third actor. This validation can be done by verifying the header called “X-VWD-Signature-V1” including in each of our webhook responses.

For detailed guidance on implementing this measure, refer to the section Using a Webhook Secret.

Webhook message

A webhook message is composed of structured data, in our case in JSON format, detailing the specific event and relevant information.

In the header of the message, you will find some information provided by Visma Connect. The most relevant for our integration are:

  • “X-Vwd-Event-Id”: “entity _CHANGED” - Type of event that we are sending, usually associated to an entity to indicate which type of record is impacted. For example: EMPLOYMENT_CHANGED or ASSIGNMENT_CHANGED
  • “X-VWD-Signature-V1”: “teLIZbhIjwd065G5Grr0fvRrir+nJi9KG/C4aQ=” - Message encrypted with the secret provided in Visma Connect so you can check the integrity of the message

The information related to the webhook itself can be found in the content of the event.

These are the possible Type of Events that we have: ‘ASSIGNMENT_CHANGED’, ‘COSTALLOCATION_CHANGED’, ‘EMPLOYMENTEXTENSION_CHANGED’, ‘EMPLOYMENTWORKSCHEDULE_CHANGED’, ‘EMPLOYMENTTYPE_CHANGED’, ‘EMPLOYMENT_CHANGED’, ‘JOBPROFILE_CHANGED’, ‘LEAVEENTITLEMENTCHANGE_CHANGED’, ‘LEAVEENTITLEMENT_CHANGED’, ‘LEAVEHOURS_CHANGED’, ‘MATERNITYLEAVE_CHANGED’, ‘ORGANIZATIONALUNIT_CHANGED’, ‘PERSONEXTENSION_CHANGED’, ‘PERSON_CHANGED’, ‘ROLEASSIGNMENT_CHANGED’, ‘SALARYDETAIL_CHANGED’, ‘SICKLEAVE_CHANGED’ & ‘WORKPATTERN_CHANGED’

Useful information in the payload:

  • id: identificator of the record that is impacted by the event
  • operation: type of operations made over the record. Possible values:
    • Insert
    • Update
    • Delete
  • changedFields: in case of an ‘Update’ operation, a list of fields that are impacted with a change will be shown
  • timestamp: date and time of when the event has been processed in the API’s side
  • value: updated content of the record. For more details about this content, please, check the section “Domain API’s”

There are some fields that are shown in the output of the api that are not shown in the value field of the webhooks. These fields are calculated ones which don’t bring any information from the HR Core. However, this information can be found in the metadata of the webhook message:

  • isDeleted/isActive: this information can be found in the operation of the message. If the operation is ‘Deleted’ then the record has status isDeleted=true/isActive=false.
  • latestSync: this field shows when the information was synchronized with the api. You can find this information in the timestamp field.

Note: For updates within the value of the record, you will receive an operation type ‘update’, showing in the field ‘changedFields’ the old or new values depending on the action and it’s the integrator the one in charge of interpreting this information. For example:

  • if there is a new sickleave period, you will receive a webhook of type “SICKLEAVE_CHANGED”, with operation ‘update’, including in the ‘changedFields’ the new period that has been added within the ‘newValue’ only.
  • if a sickleave period is removed, you will receive a webhook of type “SICKLEAVE_CHANGED”, with operation ‘update’, including in the ‘changedFields’ the old period that has been removed within the ‘oldValue’ only.

Take into account that you might receive several webhooks with the same event and operation: the message with the latest update date will contain the latest valid synchronization data.

Example of an Update operation for a “EMPLOYMENT_CHANGED” type of event:

{
     "id": "843847 5",
     "operation": "Update",
     "tenantId": "123456",
     "changedFields": {
         "hireDate": {
            "oldValue": "2025-07-03",
            "newValue": "2024-07-03"
         },
         "contractType": {
            "oldValue": "4163",
            "newValue": "6262"
         },
         "contractTypeName": {
            "oldValue": "Contract Type",
            "newValue": "Contract Type ED"
         },
         "workingAmount.amountOfWork": {
            "oldValue": 62690.0,
            "newValue": 40.0
         },
         "originalHireDate": {
            "newValue": "2023-07-03"
         },
         "dischargeDate": {
            "newValue": "2030-07-03"
         }
     },
     "timestamp": "2025-07-03T10:12:35.4877275+00:00",
     "value": {
         "id": "843847 5",
         "personCode": "843847",
         "personId": "843847",
         "contractCode": "5",
         "validFrom": "1900-01-01",
         "validUntil": "9999-12-31",
         "employmentCode": "5",
         "contractId": "5",
         "originalHireDate": "2023-07-03",
         "hireDate": "2024-07-03",
         "dischargeDate": "2030-07-03",
         "company": "23625 101",
         "employmentType": "327",
         "employmentTypeName": "Employment Type",
         "contractType": "6262",
         "contractTypeName": "Contract Type ED",
         "jobProfile": "518869",
         "jobProfileName": "Job Profile",
         "organizationUnit": "94649",
         "payrollInstitutionCode": "101",
         "payrollClientCode": "23625",
         "payrollRegistrationNumber": "1",
         "classification": "7194",
         "classificationName": "Classification Code",
         "emailAddresses": [],
         "phoneNumbers": [],
         "organizationUnitCode": "OrgUnit",
         "organizationUnitName": "Organization Unit",
         "workingAmount": {
            "amountOfWork": 40.0,
            "parttimePercentage": 100.0,
            "unitOfWork": "Hours",
            "periodOfWork": "Week"
         },
         "extensions": []
     }
}