Skip to content
  • There are no suggestions because the search field is empty.

Webhooks

Webhooks let you keep employee data synchronized between Huma and any external service or platform you connect.

 

Table of Contents

 

 


 

Roles and access

Role Access
System role with full access permissions for Organization Can configure and manage webhook integrations

 

💡⛓️‍💥  Interested in Open API? Read this article. 

 

 

Multiple integrations

If you need to configure multiple webhook instances, follow the setup guidance provided here.

 

 

Supported features

Employee profile events 

  • Specific event for changing the email used to log in to a profile.
  • Automated updates when users are added or deleted — a message is sent automatically whenever a user is created or deleted in Huma.
  • Real-time updates when a profile is changed — changes to supported profile fields are sent automatically to the registered URL.
  • Export of current profile state, including custom fields — useful for initialising state in the system connecting via webhook.

 

Position events 

  • Automated updates when positions are created, updated, or deleted

 

Absence events 

  • Automated updates when absences are registered or removed
  • Real-time updates when an absence entry is reviewed or otherwise edited

 

Company, Team & Location events 

  • Updates when a Company, Team, or Location is created, updated, or deleted
  • Membership changes — events are sent whenever users are added to or removed from a Company, Team, or Location

 

 

Can I use webhooks for service "X"?

It is common to use a "middle service" between the webhook and a third-party system. This middle service receives the webhook payload and reformats it to match the requirements of the receiving system. Some customers have their IT department build this service internally. Others use external middleware suppliers.

🔗 For a practical example, see this article.

 

 

 

How to set up a webhook

  1. Go to "Integrations"
  2. Find Webhooks and click "New connection"
  3. Click "Set up"
  4. Enter the URL that should receive the webhook requests and follow the steps 

Additional settings:

  • Client secret (optional) — if set, each request will include a huma-hmac-sha256 header containing a hash of the JSON body, signed with the secret. Use this to verify that requests come from Huma.
  • Access token (optional) — if set, each request will include it as a standard bearer token.
  • Which events to send — choose one or more of:
    • Employee profile events
    • Position events
    • Absence events
    • Company, Team & Location events
  • HTTP method — choose between always sending POST, or using HTTP methods that match the event type: DELETE for deletions, PUT for creations, PATCH for updates, and so on.

 

 

💡 All requests include a huma-topic header and a topic property in the JSON body. Both values are always identical.

💡 All request bodies also include an actor property describing who triggered the event. See Event actor.

⚠️ If a request is not handled within 1 second, it will time out. It is recommended to persist the received data and respond immediately, then process the data in a separate step.

 

 

 

Profile email change event

Because the profile email is used to log in to Huma, changing it follows a separate flow and is sent as its own event with topic user-email-update.

💡 Note: a profile can also have a private email address. Changes to the private email are treated as a normal profile field update and are sent as a users-update event. See Profile events and Supported fields below.

The request body contains a single user object with the following fields:

Field JSON key Notes
User ID id Always present. A unique, stable UUID (RFC 4122). Will not change over the user's lifetime.
Previous email oldEmail Always present.
New email newEmail Always present.
Employment ID employmentId Present if set. Unique at the time of the request, but can be changed or removed later.

 

Example:

{   "topic": "user-email-update",   "user": {     "id": "d96434d7-9506-4d5f-a969-7d1eea8bc3d6",     "oldEmail": "jesper@godmat.no",     "newEmail": "jesper.blom@godmat.no",     "employmentId": "1"   } } 

 

💡 Please note — uniqueness of employment IDs:

  • Huma can guarantee uniqueness if you have always had "Require unique employment IDs" enabled.
  • Huma cannot guarantee uniqueness if the requirement has been disabled at any point. Duplicates may exist even if the requirement has since been re-enabled, unless they have been corrected manually.

 

 

Profile events

For profile data, the topic will be one of:

  • users-create
  • users-update
  • users-delete
  • users-export

 

All profile event request bodies include a users array. Each object in the array always contains id, email, employmentId (if set), and status.

 

Create

Sent as a POST request. Contains full profile objects for all created users.

Example:

{   "topic": "users-create",   "users": [     {       "id": "09d41e51-0963-4763-933b-8c9df093d653",       "status": "ACTIVE",       "givenName": "Ida",       "preferredName": null,       "familyName": "Fossdal",       "email": "ida.fossdal@godmat.no",       "privateEmail": null,       "phone": "+47 955 55 167",       "address": {         "line1": "Fossvegen 82",         "line2": null,         "postalCode": "1823",         "city": "Bergen",         "country": "NO"       },       "birthDate": "1993-07-29",       "nationality": null,       "dietaryRequirements": null,       "funfacts": null,       "interests": null,       "bankAccount": {         "type": "national",         "number": "12345678903",         "country": "NO"       },       "gender": "Female",       "civilStatus": null,       "employmentId": "1",       "firstDayOfWork": "2001-09-14",       "employmentStartDate": "2001-09-14",       "lastDayOfWork": null,       "employmentEndDate": null,       "terminationNoticeDate": null,       "terminationDate": null,       "employmentType": "Permanent",       "employmentPercentage": 100,       "jobTitle": "CEO",       "jobDescription": "Make the decisions",       "identifications": null,       "salary": {         "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",         "periodUnit": "yearly",         "amount": 950000,         "currency": "NOK",         "fromDate": "2020-01-01",         "toDate": null,         "current": true,         "note": null       },       "supervisor": null     }   ],   "actor": {     "type": "user",     "id": "09d41e51-0963-4763-933b-8c9df093d653",     "email": "ida.fossdal@godmat.no",     "name": "Ida Fossdal"   } } 

 

Delete

Sent as a DELETE request. The users objects contain identifiers only.

Example:

{   "topic": "users-delete",   "users": [     {       "id": "d96434d7-9506-4d5f-a969-7d1eea8bc3d6",       "email": "jesper.blom@godmat.no",       "employmentId": "31",       "status": "INACTIVE"     }   ],   "actor": {     "type": "user",     "id": "09d41e51-0963-4763-933b-8c9df093d653",     "email": "ida.fossdal@godmat.no",     "name": "Ida Fossdal"   } } 

 

Update

Sent as a PATCH request. The users objects contain identifiers and only the changed fields.

Example — an employee updating their bank account to use IBAN:

{   "topic": "users-update",   "users": [     {       "id": "d96434d7-9506-4d5f-a969-7d1eea8bc3d6",       "email": "jesper.blom@godmat.no",       "employmentId": "31",       "status": "ACTIVE",       "bankAccount": {         "type": "international",         "iban": "FR7630006000011234567890189",         "bic": "AGRIFRPP"       }     }   ],   "actor": {     "type": "user",     "id": "d96434d7-9506-4d5f-a969-7d1eea8bc3d6",     "email": "jesper.blom@godmat.no",     "name": "Jesper Blom"   } } 

 

Export

Sent as one or more POST requests. Each request contains the full current state of all supported fields for up to 50 users. If your organisation has more than 50 users, the export is split across multiple requests. For example, an export from an organisation with 132 users would result in three requests: two with 50 users each, and one with 32.

⚠️ The field "Children" is not a supported field and will not be included.

 

 

Supported fields

Field JSON key
Email address email — note: changes to the main email are sent as a separate user-email-update event
Status status
Given name givenName
Family name familyName
Preferred name preferredName
Phone number phone
Private email privateEmail
Address address
Date of birth birthDate
Nationality nationality
Dietary restrictions dietaryRequirements
Fun facts funfacts
Interests interests — either null or an array of strings
Bank account number bankAccount — either null or an object containing type, and two additional fields depending on the value of type. If type is national, the other fields are number and country. If type is international, the other fields are iban and bic.
Gender gender
Civil status civilStatus
Identifications identifications — either null or an array of objects. Each object contains id (Huma-internal ID), type (either national or passport), value (the identification number), and country (ISO 3166-1 alpha-2 country code).
Supervisor supervisor — either null or an object containing id and email
Employment ID employmentId

 

 

Position fields

Field JSON key
Employment start date employmentStartDate
Probation end date probationEndDate
First day of work firstDayOfWork
Termination notice date terminationNoticeDate
Last day of work lastDayOfWork
Employment end date employmentEndDate
Employment type employmentType — either null or one of: Permanent, Temporary, Seasonal, Casual, Trainee, Job training program, Consultant, Freelance, Third party, Other
Employment percentage employmentPercentage
Job title jobTitle
Job description jobDescription

 

 

⚠️ Salary (will come as separate events in 2026)

Field JSON key Notes
Salary salary An object containing salary information. Only the current salary is sent.
  salary.id A unique identifier for this salary entry (UUID)
  salary.periodUnit One of hourly, weekly, monthly, or yearly
  salary.amount A decimal number
  salary.currency An ISO 4217 currency code
  salary.fromDate Always present
  salary.toDate Optional
  salary.current A boolean indicating whether this is the employee's current salary
  salary.note Optional free text

 

💡 The salary field is sent through profile event for now.

 

     

    Custom fields

    Any custom fields your organisation has defined will be included in update events when the custom field is the one being updated, and in all export events.

    If an event includes custom fields, the user object will contain a custom property — an object with custom field names as keys and their values. If a custom field has no value, it is included as null.

    Example for an organisation with two custom fields, "Shirt size" and "License plate":

    "custom": {   "shirtSize": "XL",   "licensePlate": null } 

    🔗 See custom fields for details on how field names are determined and what value types are supported.

     

     

    Position events

    For position data, the topic will be one of:

    • positions-create
    • positions-update
    • positions-delete
    • positions-export

    All position event request bodies include a positions array containing an object for each affected position.

     

    Create

    Sent as a POST request. Contains the full position object.

    Example:

    {   "topic": "positions-create",   "positions": [     {       "id": "59307188-bd2d-431a-aa97-97d2b92222dc",       "contractStartDate": "2026-02-18",       "contractEndDate": null,       "firstDayOfWork": "2026-02-18",       "lastDayOfWork": null,       "contractCountry": "NO",       "contractType": "Permanent",       "percentage": 100,       "probationEndDate": "2026-08-18",       "terminationNoticeDate": null,       "title": "CMO",       "description": "Oversees the company's marketing strategy.",       "endNote": null,       "endReason": null,       "wantedEnd": false,       "note": "Team: Development, Company: Tech Inc. Supervisor: Karin Strand!",       "user": {         "id": "e902714f-a3f9-4cd1-ab04-980a443d77ae",         "email": "user-email@company.com"       }     }   ],   "actor": {     "type": "user",     "id": "a558d25a-99d6-45b1-855c-63b052adc5f3",     "email": "admin@company.com",     "name": "Karina Strand"   } } 

     

    Update

    Sent as a PATCH request. Contains only the changed fields.

    Example:

    {   "topic": "positions-update",   "positions": [     {       "id": "5c1de17b-7e47-4827-a1f3-536bb061c2c4",       "contractStartDate": "2021-08-18",       "firstDayOfWork": "2021-08-18",       "contractCountry": "NO",       "contractType": "Trainee",       "percentage": 75,       "probationEndDate": "2022-02-18",       "note": "Team: Development, Company: Tech Inc. Supervisor: Karin Strand!",       "user": {         "id": "e902714f-a3f9-4cd1-ab04-980a443d77ae",         "email": "user-email@company.com"       }     }   ],   "actor": {     "type": "user",     "id": "a558d25a-99d6-45b1-855c-63b052adc5f3",     "email": "admin@company.com",     "name": "Karina Strand"   } } 

     

    Delete

    Sent as a DELETE request. The positions objects contain identifiers only.

    Example:

    {   "topic": "positions-delete",   "positions": [     {       "id": "5c1de17b-7e47-4827-a1f3-536bb061c2c4",       "user": {         "id": "e902714f-a3f9-4cd1-ab04-980a443d77ae",         "email": "user-email@company.com"       }     }   ],   "actor": {     "type": "user",     "id": "a558d25a-99d6-45b1-855c-63b052adc5f3",     "email": "admin@company.com",     "name": "Karina Strand"   } } 

     

    Export

    When you activate an export from the webhook integration page, you select a time period and which users' positions to include. The result is sent as one or more POST requests, each containing up to 50 position entries.

    Example:

    {   "topic": "positions-export",   "positions": [     {       "id": "12425fdc-e743-4e82-84ca-3036d5cbbb0d",       "contractStartDate": "2026-01-20",       "contractEndDate": "2026-07-20",       "firstDayOfWork": "2026-01-20",       "lastDayOfWork": "2026-07-20",       "contractCountry": "NO",       "contractType": "Permanent",       "percentage": 100,       "probationEndDate": "2026-04-20",       "terminationNoticeDate": "2026-06-20",       "title": "Software Engineer",       "description": "This is a description of the position.",       "endNote": "This is an end note.",       "endReason": "employee_terminated",       "wantedEnd": false,       "note": "Team: Development, Company: Tech Inc.",       "user": {         "id": "73ced5dd-8bfb-43e0-982b-4b8bb1382c91",         "email": "ida.fossdal@godmat.no"       }     }   ],   "actor": {     "type": "user",     "id": "a558d25a-99d6-45b1-855c-63b052adc5f3",     "email": "admin@company.com",     "name": "Karina Strand"   } } 

     

     

    Supported fields

    Field JSON key
    Position ID id
    Job title title
    Job description description — either a custom description, or the description defined on the job title entity
    Contract type contractType — either null or one of: Permanent, Temporary, Seasonal, Casual, Trainee, Job training program, Consultant, Freelance, Third party, Other
    Percentage percentage
    Contract country contractCountry
    Note note
    Contract start date contractStartDate
    First day of work firstDayOfWork
    Probation end date probationEndDate
    Termination notice date terminationNoticeDate
    Last day of work lastDayOfWork
    Contract end date contractEndDate
    End reason endReason — either null or one of: The employer has terminated the employee, The employee has resigned, The contract, engagement, or temporary position has expired, Changed payroll system or accountant, Other
    Wanted termination wantedEndtrue or false
    End note endNote

     

     

    Absence events

    For absence data, the topic will be one of:

    • absence-create
    • absence-update
    • absence-delete
    • absence-export

    All absence event request bodies include an absence array. Each object contains all supported fields for the entry.

     

    Create

    Sent as a POST request.

    Example:

    {   "topic": "absence-create",   "absence": [     {       "id": "45be6bce-88f5-4f67-a6de-cbd84df21e1e",       "status": "pending",       "type": {         "name": "vacation"       },       "user": {         "id": "c2c8d497-352a-4c21-bf7c-aefbaec37717",         "email": "patrick.remen@godmat.no"       },       "startDate": "2022-10-24",       "endDate": "2022-10-28",       "grade": 1,       "workRelated": false,       "note": null,       "comment": null,       "reviewedAt": null,       "reviewedBy": null,       "registeredAt": "2022-10-04T11:57:13.819Z",       "registeredBy": {         "id": "c2c8d497-352a-4c21-bf7c-aefbaec37717",         "email": "patrick.remen@godmat.no"       }     }   ],   "actor": {     "type": "user",     "id": "c2c8d497-352a-4c21-bf7c-aefbaec37717",     "email": "patrick.remen@godmat.no",     "name": "Patrick Remen"   } } 

     

    Update

    Sent as a PATCH request. Triggered when a reviewer changes the status, an employee edits their request, or a manager makes changes on behalf of an employee.

    Example:

    {   "topic": "absence-update",   "absence": [     {       "id": "e9b5a57f-2f36-462e-aed2-19c6aa990fce",       "status": "approved",       "type": {         "name": "vacation"       },       "user": {         "id": "c2c8d497-352a-4c21-bf7c-aefbaec37717",         "email": "patrick.remen@godmat.no"       },       "startDate": "2022-10-10",       "endDate": "2022-10-14",       "grade": 1,       "workRelated": false,       "note": null,       "comment": null,       "reviewedAt": "2022-10-05T11:57:13.819Z",       "reviewedBy": {         "id": "d96434d7-9506-4d5f-a969-7d1eea8bc3d6",         "email": "jesper.blom@godmat.no"       },       "registeredAt": "2022-10-04T11:51:08.962Z",       "registeredBy": {         "id": "c2c8d497-352a-4c21-bf7c-aefbaec37717",         "email": "patrick.remen@godmat.no"       }     }   ],   "actor": {     "type": "user",     "id": "d96434d7-9506-4d5f-a969-7d1eea8bc3d6",     "email": "jesper.blom@godmat.no",     "name": "Jesper Blom"   } } 

     

    Delete

    Sent as a DELETE request. The absence objects contain the ID only.

    Example:

    {   "topic": "absence-delete",   "absence": [     {       "id": "e9b5a57f-2f36-462e-aed2-19c6aa990fce"     }   ],   "actor": {     "type": "user",     "id": "d96434d7-9506-4d5f-a969-7d1eea8bc3d6",     "email": "jesper.blom@godmat.no",     "name": "Jesper Blom"   } } 

     

    Export

    When you activate an export from the webhook integration page, you select a time period, which users to include, and which absence types to include. The result is sent as one or more POST requests, each containing up to 50 entries.

    Example:

    {   "topic": "absence-export",   "exportFrom": "2022-10-01",   "exportTo": "2022-12-31",   "absence": [     {       "id": "e9b5a57f-2f36-462e-aed2-19c6aa990fce",       "status": "approved",       "type": {         "name": "vacation"       },       "user": {         "id": "c2c8d497-352a-4c21-bf7c-aefbaec37717",         "email": "patrick.remen@godmat.no"       },       "startDate": "2022-10-10",       "endDate": "2022-10-14",       "grade": 1,       "workRelated": false,       "note": null,       "comment": null,       "reviewedAt": "2022-10-05T11:57:13.819Z",       "reviewedBy": {         "id": "d96434d7-9506-4d5f-a969-7d1eea8bc3d6",         "email": "jesper.blom@godmat.no"       },       "registeredAt": "2022-10-04T11:51:08.962Z",       "registeredBy": {         "id": "c2c8d497-352a-4c21-bf7c-aefbaec37717",         "email": "patrick.remen@godmat.no"       }     }   ],   "actor": {     "type": "user",     "id": "d96434d7-9506-4d5f-a969-7d1eea8bc3d6",     "email": "jesper.blom@godmat.no",     "name": "Jesper Blom"   } } 

     

     

    Supported fields

    Field JSON key
    Entry ID id
    Status status — one of pending, approved, or rejected
    Type type — an object containing name, which is one of: vacation, selfCertifiedSick, sick, paidTimeOff, unpaidTimeOff, sickChild, parentalLeave
    User user — an object containing id and email
    Start date startDate
    End date endDate
    Grade grade — a decimal number, where 1.0 is 100% absence, 0.5 is 50%, etc.
    Work related workRelated
    Note note — added when the entry was registered
    Comment comment — added when the entry was reviewed
    Reviewed at reviewedAt
    Reviewed by reviewedBy — an object containing id and email
    Registered at registeredAt
    Registered by registeredBy — an object containing id and email

     

     

    Company, Team & Location events

    For Company, Team, and Location data, the topic will be one of:

    • groups-create
    • groups-update
    • groups-delete
    • groups-export
    • groups-add-members
    • groups-remove-members

    All event bodies include a groups array. Each group object always contains id, name, and type. The type value will be COMPANY, TEAM, or LOCATION. Company groups may also include organizationNumber.

     

    Create

    Sent as a POST request.

    Example:

    {   "topic": "groups-create",   "groups": [     {       "id": "<group ID>",       "name": "<group name>",       "type": "<COMPANY/TEAM/LOCATION>",       "description": "<optional group description>",       "organizationNumber": "<organization number, Company only>",       "links": [         "<link name>\n<link url>"       ],       "address": {         "line1": "Example street 57",         "line2": "<optional second line>",         "postalCode": "9999",         "city": "Demo city",         "country": "Theoretia"       },       "members": [         {           "id": "<user ID>",           "email": "<user email>"         }       ]     }   ],   "actor": {     "type": "user",     "id": "<user ID>",     "email": "<user email>",     "name": "<user name>"   } } 

     

    Update

    Sent as a PUT request.

    Example:

    {   "topic": "groups-update",   "groups": [     {       "id": "<group ID>",       "name": "<group name>",       "type": "<COMPANY/TEAM/LOCATION>",       "description": "<optional group description>",       "organizationNumber": "<organization number, Company only>",       "links": [         "<link name>\n<link url>"       ],       "address": {         "line1": "Example street 57",         "line2": "<optional second line>",         "postalCode": "9999",         "city": "Demo city",         "country": "Theoretia"       }     }   ],   "actor": {     "type": "user",     "id": "<user ID>",     "email": "<user email>",     "name": "<user name>"   } } 

     

    Delete

    Sent as a DELETE request. Group objects contain id, name, and type only.

    Example:

    {   "topic": "groups-delete",   "groups": [     {       "id": "<group ID>",       "name": "<group name>",       "type": "<COMPANY/TEAM/LOCATION>"     }   ],   "actor": {     "type": "user",     "id": "<user ID>",     "email": "<user email>",     "name": "<user name>"   } } 

     

    Export

    When you activate an export from the webhook integration page, you select which group types to include. The result is sent as one or more POST requests, each containing up to 50 group objects.

    Example:

    {   "topic": "groups-export",   "groups": [     {       "id": "<group ID>",       "name": "<group name>",       "type": "<COMPANY/TEAM/LOCATION>",       "description": "<optional group description>",       "organizationNumber": "<organization number, Company only>",       "links": [         "<link name>\n<link url>"       ],       "address": {         "line1": "Example street 57",         "line2": "<optional second line>",         "postalCode": "9999",         "city": "Demo city",         "country": "Theoretia"       },       "members": [         {           "id": "<user ID>",           "email": "<user email>"         }       ]     }   ],   "actor": {     "type": "user",     "id": "<user ID>",     "email": "<user email>",     "name": "<user name>"   } } 

     

    Add members

    Sent as a PUT request.

    Example:

    {   "topic": "groups-add-members",   "groups": [     {       "id": "<group ID>",       "name": "<group name>",       "type": "<COMPANY/TEAM/LOCATION>",       "members-added": [         {           "id": "<user ID>",           "email": "<user email>"         }       ]     }   ],   "actor": {     "type": "user",     "id": "<user ID>",     "email": "<user email>",     "name": "<user name>"   } } 

     

    Remove members

    Sent as a PUT request.

    Example:

    {   "topic": "groups-remove-members",   "groups": [     {       "id": "<group ID>",       "name": "<group name>",       "type": "<COMPANY/TEAM/LOCATION>",       "members-removed": [         {           "id": "<user ID>",           "email": "<user email>"         }       ]     }   ],   "actor": {     "type": "user",     "id": "<user ID>",     "email": "<user email>",     "name": "<user name>"   } } 

     

     

    Event actor

    Every event body includes an actor object describing who triggered the event. For create, update, and delete events, this is the user who made the change. For export events, it is the user who initiated the export.

    💡 Some actions are triggered by integrations rather than users. In that case, the actor object will have type set to integration.

    Field JSON key Notes
    Actor ID id Always present. A stable UUID. For integration actors, the ID remains the same after disconnect and reconnect, but changes if the connection is removed and recreated.
    Actor type type Always present. Either user or integration.
    Email email Present when type is user. Unique at the time of the request, but can change if the user's email is updated.
    Name name The name of the actor.

     

     

    Security & compliance

    By connecting via webhooks, you authorise Huma to access your webhook endpoint as described in our Terms of Service under Third-Party Platforms.

     

     

    FAQ

    What happens if my endpoint doesn't respond in time?

    Huma expects a response within 1 second. If your endpoint does not respond in time, the request will time out. We recommend acknowledging the request immediately and processing the data asynchronously.

     

    Why am I receiving a users-update event when a position changes?

    When a position change affects the employee's current primary position, Huma also sends a users-update event to keep the deprecated position-related fields on the user profile in sync. This is expected behaviour.

     

    Can I use the same webhook URL for multiple event types?

    Yes. You can configure a single webhook connection to receive any combination of profile, position, absence, and group events. Use the topic field in each request to identify the event type.

     

    What does the grade field in absence events mean?

    grade is a decimal representing the degree of absence. A value of 1.0 means the employee is fully absent, 0.5 means 50%, and so on.

     

    How do I verify that a request actually comes from Huma?

    Set a client secret when configuring your webhook. Each request will then include a huma-hmac-sha256 header containing a hash of the request body signed with your secret. Verify this hash on your end to confirm the request is genuine.

     

    What is the employmentId and can it change?

    employmentId is a unique identifier you assign to employees in Huma. It is unique at the time the request is sent, but it can be changed or removed by a user with the appropriate permissions. Do not assume it is permanently stable across all future requests.

     

    Is the Export code from an absence policy included in webhook payloads?

    No. The Export code is a configuration field on the absence type policy in Huma, and is not included in webhook payloads. Absence events contain the absence type name (e.g. vacation, sick) but not any policy-level configuration such as the Export code.