Introduction
Welcome to the Engage API documentation.
API Sandbox
Honeydew can provide a sandbox account and authentication credentials for testing. Email support@honeydew-health.com to request a sandbox account.
Rate Limiting
Coming soon
To ensure our platform remains stable and available to everyone, the Engage API will be soon be rate-limited. We ask developers to use industry standard techniques for limiting calls, caching results and re- trying requests responsibly. Calls to our API will be managed by request-based limits, allowing up to 40 requests per minute using a leaky bucket algorithm. You’ll be able to see the current rate using the rate limit header, for example:
X-Engage-Api-Rate-Limit: 32/40
In this example 32 is the current request count and 40 is the bucket size. The request count decreases according to the leak rate (in this case 1.5 requests per second), so after waiting 10 seconds the response would be down to 17/40, and 0/40 after 48 seconds.
When a request goes over the rate limit, a "HTTP 429 - Too Many Requests" response is given from the API, this will be provided with a Retry-After header with a value in seconds.
X-Engage-Api-Rate-Limit: 40/40
X-Engage-Api-Retry-After: 1.5
Authentication
OAuth 2.0 Token Bearer
Engage supports bearer token authentication with a client credentials grant type. Within Engage you can generate API Client Applications, each of which has a unique id and secret. Your app should authenticate with this id and secret to obtain a JWT token. That token can be passed as a bearer token to authorise subsequent API requests. The token has a lifetime of up to 2 hours, once expired you will need to authenticate again to obtain a new token.
Authorising your requests
After authenticating and obtaining a token provide this token with all requests as the following header parameter.
curl /example -H "Authorization: Bearer abc"
Header Parameters
| Parameter | Type | Description |
|---|---|---|
| Authorization | string | required Bearer abc |
Obtain a token
HTTP Request
POST /auth/token
Authenticate with the API and obtain a JWT token
curl -X POST /auth/token -H "Content-Type: application/json" -d '{
"grant_type": "client_credentials",
"client_id": "123",
"client_secret": "abc"
}'
Example JSON Response:
{
"access_token": "abc",
"token_type": "Bearer",
"expires_in": 7200,
"created_at": 1691747914
}
JSON Parameters
| Parameter | Type | Description |
|---|---|---|
| grant_type | string | required The type of grant requested |
| client_id | integer | required Your API Client Application ID |
| client_secret | integer | required Your API Client Application Secret |
Verify a token
HTTP Request
POST /auth/token/info
curl -X POST /auth/token/info -H "Authorization: abc"
Example JSON Response:
{
"resource_owner_id": null,
"scope": [],
"expires_in": 6540,
"application": {
"uid": “abc”
},
"created_at": 1653667738
}
Header Parameters
| Name | Type | Description |
|---|---|---|
| Authorization | string | required Your authorization token |
Revoke a token
HTTP Request
POST /auth/revoke
curl -X POST /auth/revoke -H "Content-Type: application/json" -H "Authorization: Basic abc" -d '{
"token": "abc"
}'
Header Parameters
| Name | Type | Description |
|---|---|---|
| Authorization | string | required Basic HTTP Authentication with your Base64 encoded "client_id:client_secret" |
JSON Parameters
| Name | Type | Description |
|---|---|---|
| token | string | required Your token |
API Keys
Deprecated
This is a simple API Key that should be provided along with any requests to the API via QueryString in the format /?api_key={your api key}.
As all API requests are made over SSL this value is always encrypted. You can view or generate a new API Key on your Engage account under Administration > Preferences > Data API.
IP Whitelisting
Deprecated
All requests will be validated against a defined list of IP addresses, you can configure these addresses on your Engage account under Administration > Preferences > Data API.
Employees
Get an employee
GET /api/v1/employees/{employee_id}
curl -X GET /api/v1/employees/123 \
-H "Authorization: Bearer abc"
Example JSON Response:
{
"employee_id": "123",
"first_name": "Joe",
"surname": "Bloggs",
"date_of_birth": "1980-04-23",
"email": "joe.bloggs@example.com",
"job_title": "Administrative Assistant",
"department_name": "HR",
"start_date": "2023-08-01",
"end_date": "2023-08-30",
"first_manager_id": "456",
"employment_terms": "Standard",
"calendar_name": "Mon-Fri 8hr",
"custom_fields": {
"pay_group": "PG001",
"sick_pay_policy": "SSP",
"country": "Scotland",
"secondary_employee_id": "38475"
}
}
Check if an employee exists
GET /api/v1/employees/exists?employee_id={employee_id}
curl -X GET /api/v1/employees/exists?employee_id={employee_id} \
-H "Authorization: Bearer abc"
Example JSON Response:
{
exists: true
}
Will return a value of true + HTTP 200 if employee exists, false + HTTP 404 if employee doesn't exist.
Create an employee
POST /api/v1/employees
curl -X POST /api/v1/employees \
-H "Authorization: Bearer abc" \
-H "Content-Type: application/json" \
-d '{
"employee_id": "123",
"first_name": "Joe",
"surname": "Bloggs",
"date_of_birth": "1980-04-23",
"email": "joe.bloggs@example.com",
"job_title": "Administrative Assistant",
"department_name": "HR",
"start_date": "2023-08-01",
"first_manager_id": "456",
"employment_terms": "Standard",
"calendar_name": "Mon-Fri 8hr",
"needs_engage_login": "true",
"send_account_activation_email": "false",
"custom_fields": {
"pay_group": "PG001",
"sick_pay_policy": "SSP",
"country": "Scotland",
"secondary_employee_id": "38475"
}
}'
JSON Parameters
| Name | Type | Description |
|---|---|---|
| employee_id | string | required Your unique identifier for the employee. |
| first_name | string | required |
| middle_name | string | |
| surname | string | required |
| date_of_birth | date | Must be YYYY-MM-DD format. |
| string | required* Required if needs_engage_login true. | |
| mobile | string | |
| job_title | string | Must match an existing job title. Reporting by job title must be enabled in company settings if provided. Invalid values ignored. |
| department_name | string | required* Must match an existing department name. Must provide one of department_id, department_name or department_external_id. |
| department_id | integer | required* Must match an existing department id. Must provide one of department_id, department_name or department_external_id. |
| department_external_id | string | required* Must match an existing department external_id. Must provide one of department_id, department_name or department_external_id. |
| start_date | date | required Must be YYYY-MM-DD format. Employees start date in current role (not overall employment). |
| end_date | date | Must be YYYY-MM-DD format. Employees end date in current role. |
| first_manager_id | integer | Must match an existing employee id. |
| second_manager_id | integer | Must match an existing employee id. |
| employment_terms | string | Must match existing employment terms. |
| fte | decimal | Full-Time Equivalent for the employee's current role. Valid range: 0.01 to 2.00. |
| hourly_rate | decimal | Must be greater than 0. Up to 2 decimal places, e.g. 19.75 |
| calendar_name | string | Must match existing calendar name. |
| needs_engage_login | boolean | Creates an Engage login for the employee, email required. |
| send_account_activation_email | boolean | required* Required if needs_engage_login provided. |
| custom_fields | string | Key/value pairs of existing custom fields. Key must be snake case. |
Update an employee
PUT /api/v1/employees
curl -X PUT /api/v1/employees \
-H "Authorization: Bearer abc" \
-H "Content-Type: application/json" \
-d '{
"employee_id": "123",
"first_name": "Joe",
"surname": "Bloggs",
"date_of_birth": "1980-04-23",
"email": "joe.bloggs@example.com",
"job_title": "Administrative Assistant",
"department_name": "HR",
"start_date": "2023-08-01",
"end_date": "2023-08-30",
"first_manager_id": "456",
"employment_terms": "Standard",
"calendar_name": "Mon-Fri 8hr",
"custom_fields": {
"pay_group": "PG001",
"sick_pay_policy": "SSP",
"country": "Scotland",
"secondary_employee_id": "38475"
}
}'
JSON Parameters
| Name | Type | Description |
|---|---|---|
| employee_id | string | required Your unique identifier for the employee. |
| first_name | string | required |
| middle_name | string | |
| surname | string | required |
| date_of_birth | date | Must be YYYY-MM-DD format. |
| string | required* Required if needs_engage_login true. | |
| mobile | string | |
| job_title | string | Must match an existing job title. Reporting by job title must be enabled in company settings if provided. Invalid values ignored. |
| department_name | string | required* Must match an existing department name. Must provide one of department_id, department_name or department_external_id. |
| department_id | integer | required* Must match an existing department id. Must provide one of department_id, department_name or department_external_id. |
| department_external_id | string | required* Must match an existing department external_id. Must provide one of department_id, department_name or department_external_id. |
| start_date | date | required* Must be YYYY-MM-DD format. Employees start date in current role (not overall employment). Required unless end_date is provided and updating employee to leaver. |
| end_date | date | Must be YYYY-MM-DD format. Employees end date in current role. Ignored if new start date is provided. |
| first_manager_id | integer | Must match an existing employee id. |
| second_manager_id | integer | Must match an existing employee id. |
| employment_terms | string | Must match existing employment terms. |
| fte | decimal | Full-Time Equivalent for the employee's current role. Valid range: 0.01 to 2.00. |
| hourly_rate | decimal | Must be greater than 0. Up to 2 decimal places, e.g. 19.75 |
| calendar_name | string | Must match existing calendar name. |
| needs_engage_login | boolean | Creates an Engage login for the employee, email required. |
| send_account_activation_email | boolean | required* Required if needs_engage_login provided. |
| custom_fields | string | Key/value pairs of existing custom fields. Key must be snake case. |
Employee logins
If you need for the employee to login to Engage, you can provide the needs_engage_login and send_account_activation_email fields to provision their user account. By default the employee will not be able to login.
send_account_activation_email
For companies with SSO enabled, this will send a welcome email to the employee advising them that they can now login with their company email.
For companies without SSO enabled, this will send a welcome email to the employee with a secure link from which they can set their password and login.
New starters
Recommended additional minimum values for new starters
- first_manager_id
- second_manager_id
New managers
Recommended additional minimum values for new managers
- mobile
- first_manager_id
- second_manager_id
Leavers
Recommended additional minimum values for leavers
- end_date
Transfers
Recommended additional minimum values for transfers
- start_date
- department_name
- first_manager_id
- second_manager_id
Job Titles
Create a job title
POST /api/v1/job_titles
curl -X POST /api/v1/job_titles \
-H "Authorization: Bearer abc" \
-H "Content-Type: application/json" \
-d '{
"title": "abc"
}'
JSON Parameters
| Name | Type | Description |
|---|---|---|
| title | string | required Unique job title. |
Departments
List departments
GET /api/v1/departments
curl -X GET /api/v1/departments \
-H "Authorization: Bearer abc"
Example JSON Response:
[
{
"id": "1",
"external_id": "abc1",
"name": "abc",
"parent_department_id": null,
"parent_department_external_id": null,
"parent_department": null,
"created_at": "2022-09-01T14:15:59.000+01:00",
"updated_at": "2022-09-01T14:15:59.000+01:00",
"retired_at": null
},
{
"id": "2",
"external_id": "xyz2",
"name": "xyz",
"parent_department_id": "1",
"parent_department_external_id": "abc1",
“parent_department": "abc",
"created_at": "2022-09-01T14:15:59.000+01:00",
"updated_at": "2022-09-01T14:15:59.000+01:00",
"retired_at": null
}
]
Query Parameters
| Name | Type | Description |
|---|---|---|
| parent_department_id | integer | Id of parent department to filter by. |
| parent_department_external_id | string | Your id of parent department to filter by. |
Get a department
GET /api/v1/departments/{id}
GET /api/v1/departments/external_id/{id}
Using our Id:
curl -X GET /api/v1/departments/123 \
-H "Authorization: Bearer abc"
Using your Id:
curl -X GET /api/v1/departments/external_id/abc123 \
-H "Authorization: Bearer abc"
Example JSON Response:
{
"id": "123",
"external_id": "abc123",
"name": "abc",
"parent_department_id": null,
"parent_department_external_id": null,
"parent_department": null,
"created_at": "2022-09-01T14:15:59.000+01:00",
"updated_at": "2023-08-01T14:15:59.000+01:00",
"retired_at": null
}
Check if a department exists
GET /api/v1/departments/exists
curl -X GET /api/v1/departments/exists?name={name} \
-H "Authorization: Bearer abc"
Example JSON Response:
{
exists: true
}
Query Parameters
| Name | Type | Description |
|---|---|---|
| external_id | string | Your id of the department. |
| name | string | The name of the department. |
Will return a value of true + HTTP 200 if department exists, false + HTTP 404 if department doesn't exist.
Create a department
POST /api/v1/departments/
curl -X POST /api/v1/departments \
-H "Authorization: Bearer abc" \
-H "Content-Type: application/json" \
-d '{
"name": "abc",
"external_id": "abc123",
"parent_department_id": null,
"parent_department_external_id": null,
"parent_department": null,
}'
JSON Parameters
| Name | Type | Description |
|---|---|---|
| name | string | required Unique department name. |
| external_id | string | Your unique identifier for the department, 25 character max. |
| parent_department | string | Name of the existing parent department. |
| parent_department_id | string | Id of the existing parent department. |
| parent_department_external_id | string | Your unique identifier for the existing parent department. |
Update a department
PUT /api/v1/departments/{id}
PUT /api/v1/departments/external_id/{external_id}
Using our id:
curl -X PUT /api/v1/departments/123 \
-H "Authorization: Bearer abc" \
-H "Content-Type: application/json" \
-d '{
"name": "abc"
}'
Using your id:
curl -X PUT /api/v1/departments/external_id/abc123 \
-H "Authorization: Bearer abc" \
-H "Content-Type: application/json" \
-d '{
"name": "abc"
}'
Example JSON Response:
{
"id": "123",
"external_id": "abc123",
"name": "abc",
"parent_department_id": null,
"parent_department_external_id": null,
"parent_department": null,
"created_at": "2022-09-01T14:15:59.000+01:00",
"updated_at": "2023-08-01T14:15:59.000+01:00",
"retired_at": null
}
JSON Parameters
| Name | Type | Description |
|---|---|---|
| name | string | required Unique department name. |
| external_id | string | Your unique identifier for the department, 25 character max. |
| parent_department | string | Name of the existing parent department. |
| parent_department_id | string | Id of the existing parent department. |
| parent_department_external_id | string | Your unique identifier for the existing parent department. |
Retire a department
PUT /api/v1/departments/{id}/retire
PUT /api/v1/departments/external_id/{external_id}/retire
Using our id:
curl -X PUT /api/v1/departments/123/retire \
-H "Authorization: Bearer abc" \
-H "Content-Type: application/json" \
-d '{
"retire_at": "2023-08-01",
"employee_action": "retire"
}'
Using your id:
curl -X PUT /api/v1/departments/external_id/abc123/retire \
-H "Authorization: Bearer abc" \
-H "Content-Type: application/json" \
-d '{
"retire_at": "2023-08-01",
"employee_action": "transfer",
"transfer_department_external_id": "abc123"
}'
Example JSON Response:
{
"id": "123",
"external_id": "abc123",
"name": "abc",
"parent_department_id": null,
"parent_department_external_id": null,
"parent_department": null,
"created_at": "2022-09-01T14:15:59.000+01:00",
"updated_at": "2023-08-01T14:15:59.000+01:00",
"retired_at": "2023-08-01T00:00:00.000+01:00"
}
JSON Parameters
| Name | Type | Description |
|---|---|---|
| retire_at | date | required Must be YYYY-MM-DD format. |
| employee_action | string | retire or transfer. Defaults to retire. |
| sub_department_action | string | retire or promote. Defaults to retire. |
| transfer_department_id | integer | required* Required if employee action = transfer and transfer_department_external_id not provided. |
| transfer_department_external_id | string | required* Required if employee action = transfer and transfer_department_id not provided. |
Employee Action
| Name | Description |
|---|---|
| retire | Employees current role will be ended. |
| transfer | Employees current role will be ended and a new role started at transfer department. |
Sub Department Action
| Name | Description |
|---|---|
| retire | Sub departments will be retired. |
| promote | Sub departments will be promoted to level of retiring department. |
Absences
List absences
GET /api/v1/absences
curl -X GET /api/v1/absences?start_date=2019-04-18 \
-H "Authorization: Bearer abc"
Example JSON Response:
[
{
"absence_id": "372846",
"employee_id": "11223344",
"start_date": "2019-04-18",
"confirmed_return_date": null,
"end_date": null,
"created_at": "2019-04-18 18:01:57",
"updated_at": "2019-04-18 18:01:57",
"absence_cause": "Flu",
"absence_cause_category": "Infections",
"absence_cause_periods": [
{
"absence_cause_period_id": 77,
"absence_cause": "Flu",
"absence_cause_category": "Infections",
"start_date": "2019-04-18",
"end_date": "2019-05-01",
"half_day_start": 0,
"half_day_end": 0,
},
{
"absence_cause_period_id": 76,
"absence_cause": "Morning sickness",
"absence_cause_category": "Pregnancy related",
"start_date": "2019-05-02",
"end_date": null,
"half_day_start": 0,
"half_day_end": 1,
},
],
"half_day_start": 0,
"half_day_end": 1,
},
{
"absence_id": "372847",
"employee_id": "11223344",
"start_date": "2020-04-18",
"confirmed_return_date": "2020-04-19",
"end_date": "2020-04-18",
"created_at": "2020-04-18 18:01:57",
"updated_at": "2020-04-19 18:01:57",
"absence_cause": "Flu",
"absence_cause_category": "Infections",
"absence_cause_periods": [
{
"absence_cause_period_id": 76,
"absence_cause": "Flu",
"absence_cause_category": "Infections,
"start_date": "2020-04-18",
"end_date": "2020-04-19"
},
"half_day_start": "0",
"half_day_end": "0",
}
]
Query Parameters
| Name | Type | Description |
|---|---|---|
| start_date | date | Must be YYYY-MM-DD format. Matches equal to or greater than. |
| confirmed_return_date | date | Must be YYYY-MM-DD format. Matches equal to or greater than. |
| created_at | date | Must be YYYY-MM-DD format. Matches equal to or greater than. |
| updated_at | date | Must be YYYY-MM-DD format. Matches equal to or greater than. |
Errors
The Engage API will return a HTTP 200 response code for all successful requests. You should check the response code to determine the success of each request.
Some common error responses that you may encounter include:
| Code | Name | Description |
|---|---|---|
| 400 | Bad Request | Your request is invalid, most commonly a validation issue |
| 401 | Unauthorized | Your authentication is invalid |
| 403 | Forbidden | You cannot perform that action |
| 404 | Not Found | The resource that you requested could not be found |
| 406 | Not Acceptable | Your requested format isn't supported |
| 429 | Too Many Requests | You have made too many requests in a short period of time See Rate Limiting |
| 500 | Internal Server Error | We're having a problem processing your request. Please try again later or contact support if persistent. |
| 503 | Service Unavailable | We're temporarily offline. Please try again later |
Most errors will include a JSON body with further details.
Webhooks
Allow your system to receive live events from Engage.
Absence events can occur at any time of the day or night and on any day of the week. Knowing when to fetch a new data set is not always easy and fetching large sets of data means more data processing at the receiving end. Using webhooks, Engage can tell you when something happens, optimising the data flows.
The specific actions your webhook endpoint may take differs based upon the event. Some examples include:
- Creating a new absence record
- Updating the absence dates and reasons Logging a confirmed return date
- Deleting a previously recorded return date Removing an absence record
Configuring Webhooks
You can manage webhooks on your Engage account under Administration > Data API > Webhooks.
New webhook endpoints will be authorised through our Firewall by support.
If using bearer token authentication please provide the following to support for configuration:
- Full Authentication API documentation with credentials, including:
- Authentication url
- Expected HTTP headers / HTTP body
- User id / secret
- Example HTTP response
- Token refresh url (optional)
- Expected HTTP headers / HTTP body
- User id / secret
- Example HTTP response
- Authentication url
Webhook Authentication
HMAC Signature
Webhooks carry a HMAC signature which can be used to verify the authenticity of the request. This will be provided as the HTTP header:
X-Engage-API-Signature: t=epoch,v1=hmac
To verify the signature, you should split this value to obtain the epoch timestamp and the hmac separately. In future, there may be multiple versions of the HMAC so be sure to programatically select the correct HMAC version.
The v1 HMAC uses the SHA256 hash algorithm with your api key as the secret. The content is comprised of the epoch timestamp and the HTTP body payload separated by a period.
Here’s an example of creating the hash in Ruby:
OpenSSL::HMAC.hexdigest('SHA256', api_key, "#{timestamp}.#{body}")
If you construct your own hash with the same timestamp and the received body this should match the received signature, allowing you to verify the integrity of the HTTP body and the time validity of the request. If either the header epoch value doesn’t match the hash epoch value, or the body doesn’t match the hash body then the signatures will not match.
OAuth 2.0 Bearer Token
Webhooks can be configured to authenticate against OAuth 2.0 bearer token authentication to retrieve a token from your servers, which will then be included in webhook request headers.
Please provide support with your Authentication API documentation and test/production credentials for verification of compatibility and setup.
New Absence
HTTP POST {your_url}
Headers
| Name | Type | Description |
|---|---|---|
| Content-Type | string | application/json |
| X-Engage-API-Version | string | v1 |
| X-Engage-API-Webhook-Event | string | Absence.Created |
| X-Engage-API-Signature | string | epoch=x,v1=y See HMAC Signature |
| Authorization | string | Bearer abc (if applicable, See OAuth 2.0 Bearer Token) |
Example JSON body:
"event": {
"name": "Absence.Created",
"object_type": "Absence",
"object_id": 123,
"object": {
"absence_id": 123,
"employee_id": "456",
"start_date": "2022-06-15",
"end_date": null,
"expected_end_date": "2022-06-17",
"confirmed_return_date": null,
"half_day_start": 1,
"half_day_end": 0,
"absence_cause": null,
"absence_cause_category": null,
"medical_appointment_arranged": null,
"medical_appointment_date": null,
"created_at": "2022-06-15T08:21:56.000+00:00",
"updated_at": "2022-06-15T09:35:25.000+00:00"
}
}
Updated Absence
HTTP POST {your_url}
Headers
| Name | Type | Description |
|---|---|---|
| Content-Type | string | application/json |
| X-Engage-API-Version | string | v1 |
| X-Engage-API-Webhook-Event | string | Absence.Updated |
| X-Engage-API-Signature | string | epoch=x,v1=y See HMAC Signature |
| Authorization | string | Bearer abc (if applicable, See OAuth 2.0 Bearer Token) |
Example JSON body:
"event": {
"name": "Absence.Updated",
"object_type": "Absence",
"object_id": 123,
"object": {
"absence_id": 123,
"employee_id": "456",
"start_date": "2022-06-15",
"end_date": null,
"expected_end_date": "2022-06-17",
"confirmed_return_date": null,
"half_day_start": 1,
"half_day_end": 0,
"absence_cause": null,
"absence_cause_category": null,
"medical_appointment_arranged": null,
"medical_appointment_date": null,
"created_at": "2022-06-15T08:21:56.000+00:00",
"updated_at": "2022-06-15T09:35:25.000+00:00"
}
}
Deleted Absence
HTTP POST {your_url}
Headers
| Name | Type | Description |
|---|---|---|
| Content-Type | string | application/json |
| X-Engage-API-Version | string | v1 |
| X-Engage-API-Webhook-Event | string | Absence.Deleted |
| X-Engage-API-Signature | string | epoch=x,v1=y See HMAC Signature |
| Authorization | string | Bearer abc (if applicable, See OAuth 2.0 Bearer Token) |
Example JSON body:
"event": {
"name": "Absence.Deleted",
"object_type": "Absence",
"object_id": 123,
"object": {
"id": 123
}
}
Best Practices
Receiving webhooks
After your webhook endpoint is created, Engage sends a HTTP POST to your endpoint url every time the subscribed events occur. The request body will be a JSON Event object detailing the event and the associated object.
Your service should ingest the webhook and return a HTTP 200 response as fast as possible. Any non HTTP 200 response (including redirects) will be treated as an error response by Engage. A common pattern is to store the payload in a message queue for later processing by a background worker. This reduces the chance of the request timing out, and the webhook delivery counting as a failure.
Implementing reconciliation jobs
Webhook delivery cannot be guaranteed, therefore we recommend that you implement regular reconciliation tasks to fetch and update data from the Engage API.
Frequency of retries
Webhooks have a timeout on HTTP response of 5 seconds - if your service doesn’t return a response within that time, or returns a non HTTP 200 response Engage will retry the webhook up to 5 times.
The first retry will run 30 seconds later, then 1m 45s, 4m 30s and finally 10 minutes after the initial request at which point it will fail permanently.
Managing webhook API versions
Add logic to your code so that it handles webhooks differently depending on their API version. To check the API version, your app can use the X-Engage-API-Version request header in every webhook POST request.
You should select the API version you are using in the Company Preferences DATA API section in Engage.