Youforce Webhooks

Introduction

Webhooks are a messaging mechanism that improves the integration experience between two systems by minimizing waiting times — making them especially well suited for integrations where immediate updates matter.

Unlike the classic API consumption model, where the consumer has to keep polling for changes, webhooks provide a reactive integration: the consumer simply waits for changes to arrive, resulting in a faster integration with minimal waiting times.

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


Youforce Webhooks Model

Like the Youforce APIs, webhooks are organized by domain. Each domain has its own webhook publisher with its own set of events. Applications can subscribe to one or more events through the Visma Developer Portal.

To receive events, you need to:

  1. Subscribe to the correct event(s) from the Youforce Publisher application in the Visma Connect Developer Portal.
  2. Provide the Client ID you created, so we can authorize you to receive those events.

Once subscribed, you will start receiving all matching changes as they occur.

For full details on integrating with webhooks and Visma Connect, see Webhook Dispatcher.

Youforce Publisher-Subscriber model

Security

Securing webhooks is essential for protecting your data flow. When your webhook subscription is set up, you receive a unique secret for that specific integration. This secret allows you to validate that a received webhook message genuinely came from our Webhook Dispatcher, and not from a third party.

Validation is done by verifying the X-VWD-Signature-V1 header included in every webhook message we send — this header contains the message encrypted with your secret.

For detailed implementation guidance, see Using a Webhook Secret.


Webhook Message Structure

A webhook message is structured data — in our case, JSON — describing a specific event and its relevant information.

Headers

The message header includes information provided by Visma Connect. The most relevant headers for our integration are:

Header Description Example
X-Vwd-Event-Id Type of event being sent, usually tied to the entity impacted EMPLOYMENT_CHANGED
X-Vwd-Signature-V1 The message, encrypted with your secret, used to verify message integrity teLIZbhIjwd065G5Grr0fvRrir+nJi9KG/C4aQ=
X-Vwd-Subscription-Id The Subscription Id associated with your integration in Visma Connect ec33107c-xxx-a87a13f17dfa
X-Vwd-Tenant-Id Visma Connect’s own tenant GUID. For the Youforce tenant Id, check the message body instead (see below) 1ca1c6c8-xxx-14e138b2cffc

Event types

The following event types can be received, each tied to a specific entity:

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

Payload fields

The information about the change itself is found in the body of the message:

Field Description
id Identifier of the record impacted by the event
tenantId Youforce tenant Id (7 digits)
operation Type of change made to the record — see Webhook Operations below
changedFields For an Update operation, the list of fields impacted by the change
timestamp Date and time the event was processed on the API side
value The updated content of the record. See the relevant domain API documentation for details on this content’s structure

Webhook Operations

Operation When it’s triggered changedFields included?
Insert A new entity becomes visible to the subscriber No
Update A field on an entity changes, and the entity remains visible Yes
Delete An entity is deleted No
Authorize An entity becomes visible to the subscriber because it now matches their filter No
Unauthorize An entity stops being visible to the subscriber because it no longer matches their filter No

Handling Update Operations

For Update operations, the changedFields object lists each changed field along with its oldValue and/or newValue, depending on the type of change. It is the integrator’s responsibility to interpret this information correctly.

Examples:

  • If a new sick leave period is added, you’ll receive a SICKLEAVE_CHANGED webhook with operation: Update, where changedFields includes the new period only in newValue.
  • If a sick leave period is removed, you’ll receive a SICKLEAVE_CHANGED webhook with operation: Update, where changedFields includes the removed period only in oldValue.

Duplicate or repeated webhooks

You may receive several webhooks for the same event and operation. When this happens, the message with the latest timestamp contains the most up-to-date, valid synchronization data.


Fields Not Present in the API Response

Some fields returned by the API are calculated fields that don’t originate from HR Core, so they are not included in the value field of a webhook message. This information can instead be derived from the webhook’s metadata:

Field How to derive it from the webhook
isDeleted / isActive Derived from the operation field. If operation is Delete, the record has isDeleted: true / isActive: false.
latestSync Corresponds to the webhook’s timestamp field — this reflects when the information was last synchronized.

Responding to Webhook Messages

  • Always return an HTTP 200 status code once you’ve received and accepted the message. Returning 200 tells Visma Connect the message was delivered successfully and it will not be redelivered — what your system does with it afterward is entirely up to you.
  • Messages must be processed within 5 seconds. If your endpoint doesn’t respond within this window, Visma Connect will assume something went wrong and will retry delivery.

Example: Update Operation

Example payload for an EMPLOYMENT_CHANGED event with operation: Update:

{
     "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": []
     }
}

Summary of Key Behaviors

Scenario Behavior
Endpoint doesn’t respond within 5 seconds Message delivery is retried
Endpoint responds with 200 Message is considered delivered; no redelivery
Same event/operation received more than once The message with the latest timestamp holds the valid data
Field is a calculated field not present in HR Core Not included in value; derive isDeleted/isActive from operation, and latestSync from timestamp
Entity starts/stops matching your subscription filter Triggers Authorize / Unauthorize respectively, rather than Insert/Delete