Applicant tracking system integration guide

Purpose

To provide an integrator with a guide to which People First API calls are needed to integrate an Applicant Tracking System (ATS) and People First together, so that appointed applicants can be automatically set up in People First with all of their relevant data from the ATS.

This document assumes reader has knowledge of People First terminology and is familiar with API authentication methods, general API usage, and HTTP status codes.

Data overview

The following section lists the data which is required/optional to create a new employee in People First – this may change depending on the region being used.

Required data for new employee

  • Title
  • First Name
  • Last Name
  • Sex
  • Date of Birth
  • Employment Start Date
  • Personal reference (mandatory if using manual personal references, leave blank if using automated personal references)
  • Email Address
  • Job reference / Job title / Department reference

Optional data for new employee

  • Additional names
  • Known as (will default to First name)
  • Previous last name
  • Social Security number (Legislation & Social Security number in correct format – both mandatory)
  • Address
  • Contact details
  • Right to Work – made up of Right to Work Status, Certificates of sponsorship, EU settlement status, Passports, Residency permits, Visas, Work permits
  • Driver details
  • Salary (will default to Job value if not specified)
  • Hours & Basis (will default to Job values if not specified)
  • Working Pattern (will default to Job value if not specified)
  • Schemes & Benefits (will default to Job value if not specified)
  • Attachment Files (can be added against many of the above)

People First/ATS Setup

If using People First import APIs, then person, job and department references need to be on. Person references need to be manual, and job references also manual if jobs are being created as part of this process.

If not using People First import APIs, People First should be configured with person, job and department references all turned on. They can be automatically generated or manually but if they are on, it will make life easier.

If it is possible to store the job reference/title within the ATS, so that when the applicant gets appointed, we know which People First job they are going into, that will simplify things a lot. Job references are preferred over job titles because the former will be unique whilst the latter may not be.

Alternatively, a job in People First can be created when the applicant is appointed – it would help if the ATS stored the People First department reference/name into which the applicant was going to be appointed into. Department references are preferred over department names because the former will be unique whilst the latter may not be.

Creating a new employee using PF non-import APIs

In the following sections PFBASEURI refers to People First Base URI – see resources section above.

In the API calls, date values are specified in format YYYY-MM-DD

Error codes – successful requests will return status codes of 200 or 201. API calls which return 400 means the body of the request has something wrong with it. API calls which return 401 or 404 generally mean there is an authorisation issue. 412 errors will occur on PUT requests where the If-Match header is not included or does not specify a valid eTag.

All the following API calls contain sample data which is not real!

Authentication

To make most of these API calls, the ATS will need to use an authentication token from a People First user with an HR Administrator role. Creating a user requires a System Administrator role.

This is a problem because building an integration based on a real user’s authentication is a security risk and the authentication token will need regenerating after a short period of time.

We should create a new PAT token role specifically to use with these API calls which can be used by the ATS. This has the advantage that we can lock down access to other areas, and it is tenant environment specific, so access between the ATS and individual tenant environments can be controlled. The lifetime of the token is also much longer so the code can assume that the token does not need to be renewed before making requests.

Current PAT Token roles include HRMIntegration & IAMIntegration, which will allow some of the APIs in this document to be used with a PAT token. However, most of the HRM APIs cannot yet be used with a PAT Token.

List of APIs

  • Create a person record.
  • Add sensitive information details.
  • Add address & contact details.
  • Add right to work details (up to 7 things including passports, permits etc.)
  • Add driver details.
  • Create the job / get the job details.
  • Add the person into a job.
  • Add salary details.
  • Add hours and basis details.
  • Add working pattern details.
  • Add schemes and benefits details.
  • Give the person access to People First by creating a user.

Create a person record.

Get new person resource template.

To create a new person in People First, firstly we need to make some API calls to get the available reference data values and check the person reference number setup and format.

To get new person resource template, make API call:

GET PFBASEURI/api/v1/hrm/people/resourcetemplate?annotate=t

Sample response:

{
    "meta": {
        "links": {
            "self": {
                "href": "/hrm/people/resourcetemplate?annotate=t"
            }
        },
        "person.personalReference": {
            "mandatory": "true"
        },
        "person.startDate": {
            "mandatory": "true"
        },
        "person.lastName": {
            "mandatory": "true"
        },
        "person.firstName": {
            "mandatory": "true"
        },
        "person.title": {
            "mandatory": "true",
            "values": [
                {
                    "value": "Dr",
                    "id": "cf14f246-385f-4fb3-b90f-a1254ef5520e",
                    "code": "TITLE0006"
                },
                {
                    "value": "Master",
                    "id": "52413460-9861-4f72-84cd-ade9013cf0fe",
                    "code": "TITLE_8"
                },
                {
                    "value": "Miss",
                    "id": "5175ae20-63d7-48e3-824d-72d35d1e960c",
                    "code": "TITLE0004"
                },
                {
                    "value": "Mr",
                    "id": "9e188b9d-737b-4c9d-92bb-199d8a6fba5c",
                    "code": "TITLE0001"
                },
                {
                    "value": "Mrs",
                    "id": "930fe73a-c2d5-446c-9819-75823d4fd7fe",
                    "code": "TITLE0005"
                },
                {
                    "value": "Ms",
                    "id": "77165d3e-aebb-41fd-891e-5fc7ce169ace",
                    "code": "TITLE0003"
                },
                {
                    "value": "Professor",
                    "id": "1a564fa5-4de3-4a6a-bca3-2869c20414eb",
                    "code": "TITLE0002"
                },
                {
                    "value": "Reverend",
                    "id": "46e6767a-d187-4df2-b75c-ade9013cf15c",
                    "code": "TITLE_9"
                },

           ]
        },
        "person.socialSecurityNumbers": {
            "mandatory": "true",
            "links": {
                "template": {
                    "href": "/hrm/people/resourcetemplate?organisationId=00000000-0000-0000-0000-000000000000"
                }
            }
        },
        "person.socialSecurityNumbers.legislation": {
            "mandatory": "true",
            "values": [
                {
                    "value": "Isle of Man",
                    "id": "6895aa29-fe9d-4ee8-a349-91f19554677f",
                    "code": "IOM"
                },
                {
                    "value": "Malaysia",
                    "id": "96bf4445-11fe-4ab2-910e-a34101d3a00a",
                    "code": "MYS"
                },
                {
                    "value": "Other",
                    "id": "909e4ce5-9acd-44b7-9d21-a9f671f45f62",
                    "code": "OTHER"
                },
                {
                    "value": "Republic of Ireland",
                    "id": "9f1a256d-6a8e-4d59-b7a6-e7b4e9dae64e",
                    "code": "ROI"
                },
                {
                    "value": "Singapore",
                    "id": "630de51f-f7c8-407c-8439-201ee9bbb6ee",
                    "code": "SG"
                },
                {
                    "value": "States of Guernsey",
                    "id": "b98ef498-d2e7-4d50-871a-7313253ef007",
                    "code": "SOG"
                },
                {
                    "value": "States of Jersey",
                    "id": "c23f94c9-232e-4875-a9e4-84d9d4a1ab57",
                    "code": "SOJ"
                },
                {
                    "value": "United Kingdom",
                    "id": "47c23873-057b-4b22-b2d9-a1a31ccec3fb",
                    "code": "UK"
                },
                {
                    "value": "United States of America",
                    "id": "b1291fff-e37c-4323-a395-812cfd159395",
                    "code": "US"
                }
            ]
        },
        "person.socialSecurityNumbers.socialSecurityNumber": {
            "mandatory": "true"
        },
        "person.pronouns": {
            "values": [
                {
                    "value": "He/Him",
                    "id": "eefac58f-030e-419f-9bf0-4f454e79838d",
                    "code": "GP1"
                },
                {
                    "value": "She/Her",
                    "id": "6b43db2e-0de7-4238-870e-e0094afa1e49",
                    "code": "GP2"
                },
                {
                    "value": "They/Them",
                    "id": "cc0edab2-535c-4537-8fc9-68f95f077547",
                    "code": "GP3"
                },
            ]
        }
    },
    "data": {
        "person": {
            "_links": {
                "sensitiveInformationTemplate": {
                    "href": "/hrm/people/sensitiveinformation/resourcetemplate"
                }
            },
            "firstName": "",
            "lastName": "",
            "title": "",
            "otherNames": "",
            "knownAs": "",
            "pronouns": "",
            "previousLastName": "",
            "startDate": "",
            "personalReference": "",
            "socialSecurityNumbers": [
                {
                    "legislation": "",
                    "socialSecurityNumber": "",
                    "_status": "new"
                }
            ]
        }
    }
}

From the response, you can see that fields person.title, person.socialSecurityNumbers.legislation etc have a set of possible values. Each value contains a value and an id property. When we create a person via the API we use the id of the particular item not the value so if the ATS uses the values, you need to match each one to an id for People First. This process of mapping the values to the ids will need to be done for many of the APIs to follow

Create a new person record.

Mandatory fields:

  • Title
  • First Name
  • Last Name
  • Sex
  • Date of Birth
  • Employment Start Date

Personal reference is mandatory if using Manual personal references, leave blank if using Automated personal references. Using API can check personal reference number setup using api call

GET PFBASEURI/api/v1/hrm/personreferencenumberpolicy?annotate=t

If personal reference is specified, it must match the format. In the format string, C means Alphanumeric characters A-Z, 0-9. N means numeric 0-9.

To create the person, perform an api call of type POST.

POST PFBASEURI/api/v1/hrm/people?annotate=t 

with sample body:

{
    "person": {
        "firstName": "Alexander",
        "lastName": "Botham",
        "otherNames": "",
        "knownAs": "",
        "previousLastName": "",
        "startDate": "2024-04-04",
        "personalReference": "V30001",
        "socialSecurityNumbers": [{
                "legislation": "47c23873-057b-4b22-b2d9-a1a31ccec3fb",
                "socialSecurityNumber": "JS100900D"
            }
        ],
        "title": "9e188b9d-737b-4c9d-92bb-199d8a6fba5c",
        "pronouns": ""
    }
}

From the response, get the person.Id, ie. "personId": "db753242-60e6-491c-a06c-b14800e00d46", - we need this for future API calls. This will be referred to with <personid>

Add sensitive information details.

Get sensitive information resource template.

Get resource template for sensitive information by making API call:

GET PFBASEURI/api/v1/hrm/people/<personid>/sensitiveinformation?annotate=t

The response will contain many list values for the sensitive information fields – map values to ids for those fields that need to be updated.

From the response headers, get the eTag property – this is a token which needs to be passed in the next PUT request to ensure the data is the most up to date.

Create a sensitive information record.

Mandatory fields – personid. For UK payrolls, legalGender and birthdate should be included.

If the data fields have values from the previous get request for the person, be sure to specify same values for those fields in the PUT API request that follows to ensure no data is ‘lost’. Then any changes should be made on top of existing values. Leave any other fields as blank.

PUT PFBASEURI/api/v1/hrm/people/<personid>/sensitiveinformation?annotate=t 

with sample body:

{
    "sensitiveInformation": {
        "personId": "db753242-60e6-491c-a06c-b14800e00d46",
        "disabilityDescription": "",
        "birthDate": "1979-09-10",
        "birthDateVerifiedDate": "",
        "veteranStatus": "",
        "id": "96139956-c8f8-4ce2-987e-b14800e00e1e",
        "maritalStatus": "5a8346f3-4246-429d-b74d-cfa4bb1d4d82",
        "religion": "0037c30d-a620-4dbe-a0a6-f826b1d35b1a",
        "nationality": "024f874f-c47e-4d76-a696-4462dad3770d",
        "countryOfCitizenship": "8827f405-7a89-47bb-a2ed-d51db1e151d3",
        "countryOfBirth": "8827f405-7a89-47bb-a2ed-d51db1e151d3",
        "gender": "b0ec5a9f-41f5-4fd6-bcdb-f421d5b1dc88",
        "legalGender": "60b3a483-0212-474a-8d4e-2410b1b46df8",
        "ethnicOrigin": "db6c17a8-410d-4b5f-ab09-851ecf4606e4",
        "sexualOrientation": "d666462e-1251-4dff-843b-30832a43e75b"
    }
}

Add address.

Get person address resource template.

Get resource template for person address by making API call:

GET PFBASEURI/api/v1/hrm/people/<personid>/address?annotate=t

From the response headers, get the eTag property – this is a token which needs to be passed in the next PUT request to ensure the data is the most up to date.

Create a person address record

Mandatory fields – personid, countryId. For UK addresses, address lines 2,4 and 6 (postcode) are mandatory.

For UK addresses, the postcode will be validated to check if it is valid.

PUT PFBASEURI/api/v1/hrm/people/<personid>/address?annotate=t 

with sample body:

{
    "address": {
        "addressLine1": "",
        "addressLine2": "1801 Eastwood Road",
        "addressLine3": "Kimberley",
        "addressLine4": "Nottingham",
        "addressLine5": "",
        "addressLine6": "NG16 2BD",
        "formattedAddress": "",
        "id": "db753242-60e6-491c-a06c-b14800e00d46",
        "countryId": "5c586b7e-9417-4465-ab37-c8bb1471f967",
        "stateId": ""
    }
}

Add contact information.

Get person contact information resource template.

Get resource template for person address by making API call:

GET PFBASEURI/api/v1/hrm/people/<personid>/contactinfo?annotate=t

From the response headers, get the eTag property – this is a token which needs to be passed in the next PUT request to ensure the data is the most up to date.

Create a person contact information record.

Mandatory fields – personid. The calling code ids are mandatory if their associated phone number is not blank. The ids for the calling codes can be worked out from the previous get request.

PUT PFBASEURI/api/v1/hrm/people/<personid>/contactinfo?annotate=t

with sample body:

{
    "personcontacts": {
        "companyNumber": "",
        "companyMobile": "",
        "personalNumber": "",
        "personalMobile": "07800343222",
        "workEmail": "",
        "personalEmail": "alex.botham34@dfghfjhghfdj.co.uk",
        "linkedInProfile": "",
        "twitterProfile": "",
        "skypeProfile": "",
        "id": "db753242-60e6-491c-a06c-b14800e00d46",
        "companyCallingCodeId": "799cd434-ba72-4c15-ae6f-33eb874a20c7",
        "companyMobileCallingCodeId": "799cd434-ba72-4c15-ae6f-33eb874a20c7",
        "personalCallingCodeId": "799cd434-ba72-4c15-ae6f-33eb874a20c7",
        "personalMobileCallingCodeId": "799cd434-ba72-4c15-ae6f-33eb874a20c7"
    }
}

Add right to work details

Right to work information can consist of any of the following:

  • Right To Work Status
  • Certificates of Sponsorship
  • EU settlement Status
  • Passports
  • Residency Permits
  • Visas
  • Work Permits

Separate API calls need to be made for each of the above, all being optional.

Get person right to work status resource template.

People First only holds one right to work status record per person.

Get resource template for person right to work by making API call:

GET PFBASEURI/api/v1/hrm/people/<personid>/righttowork?annotate=t

From the response headers, get the eTag property – this is a token which needs to be passed in the next PUT request to ensure the data is the most up to date.

Create a person right to work status information record.

Mandatory fields – for UK, personid & rightToWorkProcessingStatusId. For US, many more fields.

Use the previous get request to work out the rightToWorkProcessingStatusId. For UK, there is only one field to update.

PUT PFBASEURI/api/v1/hrm/people/<personid>/righttowork?annotate=t 

with sample body:

{
    "righttowork": {
        "personId": "db753242-60e6-491c-a06c-b14800e00d46",
        "alienNumber": "",
        "i94Number": "",
        "nationalRegistrationIdentityCard": "",
        "foreignIdentityNumber": "",
        "foreignIdentityNumberExpiryDate": "",
        "incomeTaxReferenceNumber": "",
        "assignedTaxReferenceNumber": "",
        "taxReferenceNumber": "",
        "residencyTypeId": "",
        "i9Status": "",
        "usRightToWorkStatusId": "",
        "rightToWorkProcessingStatusId": "cb98119e-ebe0-4447-92a9-311bd34f5c83"
    }
}

Get person certificate of sponsorship resource template.

People First can hold multiple certificates of sponsorship records against a person.

Get resource template for person certificate of sponsorship by making API call:

GET PFBASEURI/api/v1/hrm/people/<personid>/sponsorshipcertificates/resourceTemplate?annotate=t

Create a person certificate of sponsorship information record

Mandatory fields – certificateNumber, assignmentDate, expiryDate and countryId

Use the previous get request to work out the countryId.

POST PFBASEURI/api/v1/hrm/people/<personid>/sponsorshipcertificates?annotate=t 

with sample body:

{
    "sponsorshipcertificates": {
        "personId": "",
        "certificateNumber": "345",
        "assignmentDate": "2024-04-09",
        "expiryDate": "2026-04-09",
        "comments": "",
        "countryId": "5c586b7e-9417-4465-ab37-c8bb1471f967"
    }
}

If attaching an attachment, we need the id of the newly created record. This can be obtained from the response of the POST request.

Get person EU settlement status resource template.

People First can hold multiple EU settlement status records against a person.

Get resource template for person EU settlement status by making API call:

GET PFBASEURI/api/v1/hrm/people/<personid>/settlementstatuses/resourceTemplate?annotate=t

Create a person EU settlement status information record.

Mandatory fields – settledTypeId

Use the previous get request to work out the settledTypeId value.

POST PFBASEURI/api/v1/hrm/people/<personid>/settlementstatuses?annotate=t

with sample body:

{
    "settlementstatuses": {
        "personId": "",
        "issueDate": "2024-04-09",
        "settlementStatus": "45454454",
        "comments": "",
        "settledTypeId": "88e532f1-b1a0-4b55-95fe-d24f1b8411b9"
    }
}

If attaching an attachment, we need the id of the newly created record. This can be obtained from the response of the POST request.

Get person passport resource template.

People First can hold multiple passport records against a person.

Get resource template for person passport by making API call:

GET PFBASEURI/api/v1/hrm/people/<personid>/passports/resourceTemplate?annotate=t

Create a person passport information record.

Mandatory fields – issuingCountry, issueDate, expiryDate

Use the previous get request to work out the issuingCountry value.

POST PFBASEURI/api/v1/hrm/people/<personid>/passports?annotate=t

with sample body:

{
    "passports": {
        "expiryDate": "2034-04-09",
        "issueDate": "2024-04-09",
        "passportNumber": "180766009",
        "personId": "",
        "issuingCountry": "5c586b7e-9417-4465-ab37-c8bb1471f967"
    }
}

If attaching an attachment, we need the id of the newly created record. This can be obtained from the response of the POST request.

Get person residency permit resource template.

People First can hold multiple residency permit records against a person.

Get resource template for person residency permit by making API call:

GET PFBASEURI/api/v1/hrm/people/<personid>/residencyPermits/resourceTemplate?annotate=t

Create a person residency permit information record.

Mandatory fields – countryId, issueDate, expiryDate. US specific - permanentResidencyCategoryId

Use the previous get request to work out the countryId value.

POST PFBASEURI/api/v1/hrm/people/<personid>/residencyPermits?annotate=t

with sample body:

{
    "residencypermits": {
        "expiryDate": "2026-04-09",
        "issueDate": "2024-04-09",
        "permitNumber": "3455",
        "personId": "",
        "countryId": "5c586b7e-9417-4465-ab37-c8bb1471f967",
        "permanentResidencyCategoryId": ""
    }
}

If attaching an attachment, we need the id of the newly created record. This can be obtained from the response of the POST request.

Get person visa resource template

People First can hold multiple visa records against a person.

Get resource template for person visa by making API call

GET PFBASEURI/api/v1/hrm/people/<personid>/visas/resourceTemplate?annotate=t

Create a person visa information record

Mandatory fields – issueDate & expiryDate

Use the previous get request to work out the issuingCountryId value.

POST PFBASEURI/api/v1/hrm/people/<personid>/visas?annotate=t

with sample body:

{
    "visas": {
        "expiryDate": "2028-04-09",
        "issueDate": "2024-04-09",
        "visaReference": "V5656565",
        "personId": "",
        "visaTypeId": "",
        "issuingCountryId": "5c586b7e-9417-4465-ab37-c8bb1471f967"
    }
}

If attaching an attachment, we need the id of the newly created record. This can be obtained from the response of the POST request.

Get person work permit resource template.

People First can hold multiple work permit records against a person.

Get resource template for person work permit by making API call.

GET PFBASEURI/api/v1/hrm/people/<personid>/workpermits/resourceTemplate?annotate=t

Create a person work permit information record.

Mandatory fields – countryId, issueDate, expiryDate

Use the previous get request to work out the countryId and uKWorkPermitType values.

POST PFBASEURI/api/v1/hrm/people/<personid>/workpermits?annotate=t

with sample body:

{
    "workpermits": {
        "personId": "",
        "workPermit": "45454545454",
        "issueDate": "2024-04-09",
        "expiryDate": "2027-04-09",
        "indefiniteLeave": false,
        "singaporeWorkPermitType": "",
        "countryId": "5c586b7e-9417-4465-ab37-c8bb1471f967",
        "uKWorkPermitType": "142fe13a-2d12-478b-b72c-d86de8c553f7"
    }
}

If attaching an attachment, we need the id of the newly created record. This can be obtained from the response of the POST request.

Get person driver details resource template.

Get resource template for person driver details by making API call.

GET PFBASEURI/api/v1/hrm/people/<personid>/drivers/resourceTemplate?annotate=t

Create a person driver details information record.

Mandatory fields – countryId. Also, if any of the Insurance fields are not blank then insuranceValidTo is mandatory. If licenceNumber is not blank, then validTo is mandatory.

Use the previous get request to work out the countryId and issuingStateId (US Only) values.

POST PFBASEURI/api/v1/hrm/people/<personid>/drivers?annotate=t

with sample body:

{
    "persondrivers": {
        "dateVerified": "2024-04-05",
        "disqualificationEndDate": "",
        "disqualificationStartDate": "",
        "isCurrentlyDisqualified": false,
        "licenceNumber": "WIDDO9876533AAAA",
        "carRegistrationNumber": "FH154RT",
        "documentDiscriminator": "",
        "nameOnLicence": "Alexander Botham",
        "validFrom": "2015-03-10",
        "validTo": "2050-03-10",
        "insuranceDateVerified": "2024-04-05",
        "insuranceValidFrom": "2023-03-10",
        "insuranceValidTo": "2025-03-10",
        "internationalDrivingPermitType": "",
        "internationalDrivingPermitExpiryDate": "",
        "countryId": "5c586b7e-9417-4465-ab37-c8bb1471f967",
        "issuingStateId": ""
    }
}

If attaching an attachment, we need the id of the newly created record. This can be obtained from the response of the POST request.

Finding/Creating a job in People First

Once we have created a new person record for the appointed applicant, we need to attach the person to a job in the organization structure. The ATS may or may not have information to identify in People First which job the new person is to be attached to but here are some options to find/create the job in People First before the new person can be attached.

Get People First jobid from job reference/title (or both).

If the ATS has the PF job reference number (which should be unique), one API call should return the id of the job – replace xxx with the job reference. Similarly, if the ATS knows the Job Title, it can use that in an API call as follows:

GET PFBASEURI/api/v1/hrm/odata/Jobs?$filter=ReferenceNumber eq 'xxx' and Title eq ‘yyy’

The $filter part of the API request above can be altered if the Job Reference Number or Title are not known.

Sample Response:

{
    "@odata.context": "https://peoplefirst-dev.com/api/v1/hrm/odata/$metadata#Jobs",
    "value": [
        {
            "Id": "642e8653-95f8-425a-83ae-a87f009d0b87",
            "ReferenceNumber": "xxx",
            "Name": "Manager",
            "StartDate": "2024-04-04T00:00:00Z",
            "EndDate": null
        }
    ]
}

The Id is the jobid providing there is a match.

Creating a People First Job.

If the job into which we want to put the person does not exist, then a new job can be created using the APIs. In People First jobs are within a department so we need to know a department to put them into.

To make the ATS integration easier, it might be easier to create a dedicated department in People First for the ATS created jobs, and then these jobs can be moved to other departments, at a later date, by HR administrators in People First.

People First departments have a name and a reference number – it is recommended that reference numbers are turned on to make the process of finding the departments easier.

People First jobs also have titles and reference numbers – it is recommended that reference numbers are turned on for jobs. They can be autogenerated or manually added but we need to cater for both scenarios here. If creating jobs in People First from the ATS we recommend setting job reference numbers to autogenerate.

Find the People First department id.

If the ATS has the PF department reference number (which should be unique), one API call should return the id of the department – replace xxx with the department reference. Similarly, if the ATS knows the Department Name, it can also use that in an API call as follows:

GET PFBASEURI/api/v1/hrm/odata/units?$filter=StructureReference eq 'xxx' and Name eq 'yyy'

The $filter part of the API request above can be altered if the Department Reference Number or Name are not known.

In the response, the Id is the department id providing there is a match.

Get the new job resource template.

Get resource template for a new job by making API call:

GET PFBASEURI/api/v1/hrm/ structure/<departmentId>/resourcetemplate?type=Job

Replace <departmentId> with the department Id obtained earlier.

Create a new job.

Mandatory fields - name, startDate (set to the employee start date), parentStructureId (set to <departmentId>), type (set to "Job").

StructureReference is mandatory if using Manual job references, leave blank if using Automated job references. Using API can check job reference number setup using api call:

GET PFBASEURI/api/v1/hrm/jobreferencenumberpolicy?annotate=t

If structureReference is specified, it must match the format. In the format string, C means Alphanumeric characters A-Z, 0-9. N means numeric 0-9.

To create the job, make API call (Replace <departmentId> with the department Id obtained earlier):

POST PFBASEURI/api/v1/hrm/structure/<departmentId>?type=Job&annotate=t

with sample body:

{
    "structureitem": {
        "name": "This will appear as the employee’s job title",
        "startDate": "2024-04-04",
        "endDate": "",
        "parentStructureId": "da6de970-7902-4046-8915-a90400ccbc7f",
        "quantity": 1,
        "regionCode": "",
        "type": "Job",
        "structureReference": "",
        "companyRegistrationNumber": "",
        "reportingUnit": ""
    }
}

Providing the request is successful, the response will contain the structureId which is the new job id and if job reference numbers, are being autogenerated, the new reference number which is the structureReference property.

Attaching the person to the job

Get the new occupancy resource template

Get resource template for a new occupancy by making API call:

GET PFBASEURI/api/v1/hrm/people/<personId>/occupancies/resourceTemplate?annotate=t

Attaching a person to the job (creating an occupancy).

To attach the person to the job at a start date, make the following API call (structureId is the job id obtained earlier):

Mandatory fields – structureId, startDate, isFirstOccupancy

Use the previous get request to work out the occupancyStatus & expectedEndReason values, although these fields are both optional.

POST PFBASEURI/api/v1/hrm/people/<personId>/occupancies?annotate=t

with same body:

{
    "occupancies": {
        "structureId": "642e8653-95f8-425a-83ae-a87f009d0b87",
        "occupancyTitle": "",
        "startDate": "2024-04-04",
        "endDate": "",
        "expectedEndDate": "",
        "occupancyStatus": "",
        "additionalInformation": "",
        "isFirstOccupancy": true,
        "personId": "",
        "expectedEndReason": "",
        "location": ""
    }
}

From the response get the occupancyId which we will need to add in further data such as the salary, hours and basis, and the working pattern.

Adding employee salary details

Salaries in People First can be held at department, job and occupancy (person in job) levels. If held at department or job level, the occupancy will inherit those values if it has no values of its’ own. This document will only cover occupancy salaries.

The salary data for People First occupancies can change over time, and we call these effective dated records, revisions. A salary record can be a straight rate of pay with a frequency, or it can be derived from a grade and payscale. There are extra steps to using the latter and we will cover those.

Get occupancy salary resource template.

Get resource template for occupancy salary by making API call:

GET PFBASEURI/api/v1/hrm/occupancies/<occupancyId>/salary/effdate/<startdate>?annotate=t&mode=revision

Replace <occupancyid> with the occupancyId from attaching the person to the job. Replace <startdate> with the date the person was attached to the job (in format YYYY-MM-DD).

From the response headers, get the eTag property – this is a token which needs to be passed in the next PUT request to ensure the data is the most up to date.

Update the occupancy salary record (for salary not based on grade/payscale)

Mandatory fields – occupancyId, structureId, fullTimeSalary, effDate, revisionStartDate, currency & fullTimeSalaryFrequency.

Use the previous get request to work out the fullTimeSalaryFrequency, currency & payrollFrequency values.

Set occupancyid & structureId values to <occupancyid> value. Set effDate & revisionStartDate to the <startdate> value in same format.

PUT PFBASEURI/api/v1/hrm/occupancies/<occupancyId>/salary/effdate/<startdate>?annotate=t

with sample body:

{
    "salary": {
        "occupancyId": "53895dde-a676-4547-88a7-b14800e4c196",
        "isSalaryOverride": false,
        "nextIncrementalDate": "",
        "structureId": "53895dde-a676-4547-88a7-b14800e4c196",
        "proRatedRateOfPay": 0,
        "fteValue": 1,
        "fullTimeSalary": 50000,
        "revisionEndDate": "",
        "revisionStartDate": "2024-04-04",
        "personId": "db753242-60e6-491c-a06c-b14800e00d46",
        "monthlyVariableComponent": "",
        "isGradeActive": false,
        "_status": "",
        "effDate": "2024-04-04",
        "fullTimeSalaryFrequency": "d1adc920-29d7-4e68-95f7-3a015636c6bf",
        "currency": "9b89ba73-1a80-44a5-8eb7-c1d1b1802059",
        "payScale": "",
        "salaryOverrideReason": "",
        "grade": "",
        "payrollFrequency": "fcb64d08-5914-4c43-8387-7a03564746b0",
        "changeReason": ""
    }
}

Update the occupancy salary record (for salary based on grade/payscale).

The salary can be based on a grade and a payscale. A rate of pay is held against the payscale and used as a default for the occupancy salary. This salary value can still be overridden on the occupancy salary record.

Mandatory fields – occupancyId, structureId, fullTimeSalary, effDate, revisionStartDate, currency, fullTimeSalaryFrequency, grade, payScale. salaryOverrideReason is mandatory if isSalaryOverride is true.

Use the previous get request to work out the fullTimeSalaryFrequency, currency, payrollFrequency, grade and salaryOverrideReason values.

We need to get the payscale id for the payscale – this is grade dependent so make an API call to get the list of payscales for the grade at the <startdate>. Replace <gradeId> with the grade id.

GET PFBASEURI/api/v1/hrm/grades/<gradeId>/effdate/<startdate>/payscales

From the response, find the matching payscale and assign the payScale value in the next request to the id of the payscale record.

Set occupancyid & structureId values to <occupancyid> value. Set effDate & revisionStartDate to the <startdate> value in same format.

PUT PFBASEURI/api/v1/hrm/occupancies/<occupancyid>/salary/effdate/<startdate>?annotate=t

with sample body:

{
    "salary": {
        "occupancyId": "53895dde-a676-4547-88a7-b14800e4c196",
        "isSalaryOverride": false,
        "nextIncrementalDate": "2025-04-04",
        "structureId": "53895dde-a676-4547-88a7-b14800e4c196",
        "proRatedRateOfPay": 50000,
        "fteValue": 1,
        "fullTimeSalary": 41000,
        "revisionEndDate": "",
        "revisionStartDate": "2024-04-04",
        "personId": "db753242-60e6-491c-a06c-b14800e00d46",
        "monthlyVariableComponent": "",
        "isGradeActive": true,
        "_status": "",
        "effDate": "2024-04-04",
        "fullTimeSalaryFrequency": "d1adc920-29d7-4e68-95f7-3a015636c6bf",
        "currency": "9b89ba73-1a80-44a5-8eb7-c1d1b1802059",
        "payScale": "ad54a7e7-80ed-4129-a48d-af2d007c80b5",
        "salaryOverrideReason": "",
        "grade": "b1d8b187-a793-43d7-80ce-af2d007c3531",
        "payrollFrequency": "fcb64d08-5914-4c43-8387-7a03564746b0",
        "changeReason": ""
    }
}

Adding employee hours & basis details

In People First, hours & basis data groups together the following data items:

Contractual hours, FTE hours, Annual weeks worked, Standard day in hours, Category, Basis, Type, Employment is term time only.

Hours & basis data in People First can be held at organization, department, job and occupancy (person in job) levels. If data is held at organization, department or job level, the occupancy will inherit those values if it has no values of its’ own. This document will only cover occupancy hours & basis data.

The hours & basis data for People First occupancies can change over time, and we call these effective dated records, revisions.

Get occupancy hours & basis resource template.

Get resource template for occupancy hours & basis by making API call:

GET PFBASEURI/api/v1/hrm/occupancies/<occupancyid>/hoursbasis/effdate/<startdate>?annotate=t&mode=revision

Replace <occupancyid> with the occupancyId from attaching the person to the job. Replace <startdate> with the date the person was attached to the job (in format YYYY-MM-DD).

From the response headers, get the eTag property – this is a token which needs to be passed in the next PUT request to ensure the data is the most up to date.

Update the occupancy hours & basis record.

Mandatory fields – occupancyId, structureId, effDate, revisionStartDate, _id, annualWeeksWorked, fteHours, contractHours, employeeIsTermTimeOnly, lengthOfStandardWorkday, basis, category, type.

For the annualWeeksWorked, fteHours, contractHours, employeeIsTermTimeOnly, lengthOfStandardWorkday, basis, category & type fields, the meta data in the previous GET request will show whether these fields are inherited by looking at the state property.

In the PUT request, if these fields are not to be changed then set the value to __INHERIT__ for each property not to be changed. Specify the new values for those properties that are to be changed.

Use the previous GET request to work out the ids for the basis, category, type values if these values are to be changed.

Set occupancyid & structureId values to <occupancyid> value. Set effDate & revisionStartDate to the <startdate> value in same format.

PUT PFBASEURI/api/v1/hrm/occupancies/<occupancyid>/hoursbasis/effdate/<startdate>?annotate=t

with sample body:

{
    "hoursbasis": {
        "_id": "53895dde-a676-4547-88a7-b14800e4c196",
        "occupancyId": "53895dde-a676-4547-88a7-b14800e4c196",
        "structureId": "53895dde-a676-4547-88a7-b14800e4c196",
        "annualWeeksWorked": "__INHERIT__",
        "fteHours": "__INHERIT__",
        "contractHours": 35,
        "employeeIsTermTimeOnly": "__INHERIT__",
        "lengthOfStandardWorkday": "__INHERIT__",
        "fteValue": 1,
        "revisionEndDate": "",
        "revisionStartDate": "2024-04-04",
        "effDate": "2024-04-04",
        "fteCalculation": "",
        "basis": "__INHERIT__",
        "category": "__INHERIT__",
        "type": "__INHERIT__"
    }
}

In the example above, only the contractHours is being overridden to 35 hours.

Adding employee working pattern details

Working pattern data in People First can be held at organization, department, job and occupancy (person in job) levels. If data is held at organization, department or job level, the occupancy will inherit those values if it has no values of its’ own. This document will only cover occupancy working pattern data.

The working pattern data for People First occupancies can change over time, and we call these effective dated records, revisions.

The working pattern consists of a set of hours worked for each day in the week. Normally, patterns last for a week, or a number of weeks. Most patterns in the UK are designed to start on a Monday.

The hours are specified in an HH:MM so 7 and half hours is 07:30.

Get occupancy working pattern resource template.

Get resource template for occupancy working pattern by making API call:

GET PFBASEURI/api/v1/hrm/occupancies/<occupancyid>/patterns/v2/patterntype/WP/effdate/<startdate??effDate=<startdate>&annotate=t&mode=revision

Replace <occupancyid> with the occupancyId from attaching the person to the job. Replace <startdate> with the date the person was attached to the job (in format YYYY-MM-DD).

From the response headers, get the eTag property – this is a token which needs to be passed in the next PUT request to ensure the data is the most up to date.

Update the occupancy working pattern record.

In the previous GET request, the days property in the response provides the inherited working pattern in terms of what the daily breakdown of hours is.

If the pattern needs to be changed, for each day in the pattern that needs changing we need to do the following API calls. For each amended day, if it is a working day, ie. Hours is not 00:00 then make this API call setting the totalHoursAndMinutes to the hours and minutes for that day:

POST PFBASEURI/api/v1/hrm/workingpatterns/shifts/workhoursshift?annotate=t

with sample body:

{
    "workingPatternWorkHourShift": {
        "totalHoursAndMinutes": "07:00",
        "dayId": "",
        "shiftTypeCode": "workHoursShift",
        "shiftTypeId": "00000000-0000-0000-0000-000000000000",
        "startTime": "",
        "endTime": "",
        "overnight": false,
        "isFullDay": false
    }
}

The response will return an id which we need to keep for the days API request.

If the amended day is a non-working day, then make this API call with the totalHoursAndMinutes set to 00:00:

POST PFBASEURI/api/v1/hrm/workingpatterns/shifts/nonworkingshift?annotate=t

with sample body:

{
    "workingPatternNonWorkingDayShift": {
        "totalHoursAndMinutes": "00:00",
        "dayId": "",
        "shiftTypeCode": "nonWorkingDayShift",
        "shiftTypeId": "00000000-0000-0000-0000-000000000000"
    }
}

The response will return an id which we need to keep for the days API request.

For each working or non-working day amended, make an API call to generate a new day record (replace 10aa5af0-bdf1-44d4-b560-b15200bc812a with the id from the previous workhoursshift / nonworkingshift API call response):

POST PFBASEURI/api/v1/hrm/workingpatterns/days?annotate=t

with sample body:

{
    "structurepatterns.pattern.day": {
        "shiftIds": ["10aa5af0-bdf1-44d4-b560-b15200bc812a"]
    }
}

The response will return an id which we need to keep for the next API request.

Finally, we can update the working pattern for the occupancy by making the following PUT request.

Mandatory fields – occupancyId, startDate, name, dayIds, days

In the body, set occupancyid value to <occupancyid> value. Set startDate to the <startdate> value in same format.

The dayIds and days in the body should contain the list of dayIds from the previous POST requests plus any of the existing dayIds ones that have not been modified. For each day in the days array, we need the total hours.

PUT PFBASEURI/api/v1/hrm/occupancies/<occupancyId>/patterns/v2/patterntype/WP/effdate/<startdate??effDate=<startdate>&annotate=t

with sample body:

{
    "structurepatterns": {
        "averageHoursWorked": 37.5,
        "days": [{
                "dayId": "1f002b06-d287-4569-8d7e-abf1007f01a5",
                "dayNumber": 1,
                "totalHours": "07:30",
                "_status": ""
            }, {
                "dayId": "9d00319c-1327-4985-bdf5-abf1007f01a5",
                "dayNumber": 2,
                "totalHours": "07:30",
                "_status": ""
            }, {
                "dayId": "393ae96e-b277-4924-b833-abf1007f01a5",
                "dayNumber": 3,
                "totalHours": "07:30",
                "_status": ""
            }, {
                "dayId": "cb81674e-7b25-423f-a1cc-abf1007f01a5",
                "dayNumber": 4,
                "totalHours": "07:30",
                "_status": ""
            }, {
                "dayId": "187cf832-24d4-4f46-af42-abf1007f01a5",
                "dayNumber": 5,
                "totalHours": "07:30",
                "_status": ""
            }, {
                "dayId": "c788488a-b5ef-4f91-9e69-abf1007f01a5",
                "dayNumber": 6,
                "totalHours": "00:00",
                "_status": ""
            }, {
                "dayId": "06e35366-27eb-4581-b562-abf1007f01a5",
                "dayNumber": 7,
                "totalHours": "00:00",
                "_status": ""
            }
        ],
        "_status": "",
        "occupancyId": "cda3d25a-0457-4a17-b082-abae0099c0ff",
        "startDate": "2020-05-01",
        "endDate": "",
        "startDayNumber": 5,
        "name": "Mon-Fri 9-5.30pm",
        "dayIds": ["563e73bd-c382-467a-beb8-b15200bd0420", "9d00319c-1327-4985-bdf5-abf1007f01a5", "393ae96e-b277-4924-b833-abf1007f01a5", "cb81674e-7b25-423f-a1cc-abf1007f01a5", "187cf832-24d4-4f46-af42-abf1007f01a5", "c788488a-b5ef-4f91-9e69-abf1007f01a5", "06e35366-27eb-4581-b562-abf1007f01a5"],
        "effDate": "2020-05-01"
    }
}

Adding employee schemes & benefit details

Schemes and Benefits (S&Bs) comprise Items and Choices, from which values can be paid in People First Payroll , or in an external Payroll application. In People First, an Item is something like Car Allowance, Gym Membership, Healthcare or London Allowance. The choices can be a table of values, a list of values, a fixed value, or for some Items such as Salary, no choice because the value comes from elsewhere.

Choice values can also be overridden with a custom choice value. Values are either cash or percentage.

Each Item, when attached a person in a job (occupancy), has a timeline of choices so occupancy schemes and benefit items are always referred to with an effective date.

If using not People First payroll, pension details should be stored in People First Schemes and Benefits. But if using People First Payroll, pension details are held separately so API calls may be needed to manage those separately.

Get available occupancy scheme & benefit items.

To add a scheme & benefit for an occupancy at an effective we firstly need to get the id of the S&B item within People First. Do this by making API call:

GET PFBASEURI/api/v1/hrm/occupancies/<occupancyId>/schemeAndBenefit/available/effectiveDate/<effectivedate>

Replace <occupancyid> with the occupancyId from attaching the person to the job. Replace <effectivedate> with the date the S&B needs to be attached – if this is for a new occupancy then use the date the person was attached to the job (in format YYYY-MM-DD). If doing this for an existing person, you may want to use the payroll period start date (in format YYYY-MM-DD).

Response will look something like this:

{
    "meta": {
        "links": {
            "self": {
                "href": "/hrm/occupancies/f68787d3-2919-476d-8c1b-b15e005ed1df/schemeAndBenefit/available/effectiveDate/2024-04-26"
            },
            "first": {
                "href": "/hrm/occupancies/f68787d3-2919-476d-8c1b-b15e005ed1df/schemeAndBenefit/available/effectiveDate/2024-04-26?page%5BLimit%5D=200&page%5BOffset%5D=0"
            },
            "last": {
                "href": "/hrm/occupancies/f68787d3-2919-476d-8c1b-b15e005ed1df/schemeAndBenefit/available/effectiveDate/2024-04-26?page%5BLimit%5D=200&page%5BOffset%5D=0"
            }
        }
    },
    "data": {
        "schemeAndBenefitAvailbleItems": [
            {
                "_links": {
                    "self": {
                        "href": "/hrm/schemesAndBenefits/4fd34f32-428a-4550-9dba-afd00076e0ab"
                    },
                    "revisionTypeHistory": {
                        "href": "/hrm/occupancies/f68787d3-2919-476d-8c1b-b15e005ed1df/schemeAndBenefit/item/4fd34f32-428a-4550-9dba-afd00076e0ab"
                    }
                },
                "id": "4fd34f32-428a-4550-9dba-afd00076e0ab",
                "value": "Car Allowance"
            },
            {
                "_links": {
                    "self": {
                        "href": "/hrm/schemesAndBenefits/32f6f113-a893-4425-ab16-afd00077b40f"
                    },
                    "revisionTypeHistory": {
                        "href": "/hrm/occupancies/f68787d3-2919-476d-8c1b-b15e005ed1df/schemeAndBenefit/item/32f6f113-a893-4425-ab16-afd00077b40f"
                    }
                },
                "id": "32f6f113-a893-4425-ab16-afd00077b40f",
                "value": "Fire Warden"
            },
            {
                "_links": {
                    "self": {
                        "href": "/hrm/schemesAndBenefits/f0a9e970-d5d5-4c7f-9c45-afd000781c77"
                    },
                    "revisionTypeHistory": {
                        "href": "/hrm/occupancies/f68787d3-2919-476d-8c1b-b15e005ed1df/schemeAndBenefit/item/f0a9e970-d5d5-4c7f-9c45-afd000781c77"
                    }
                },
                "id": "f0a9e970-d5d5-4c7f-9c45-afd000781c77",
                "value": "First Aider"
            },
            {
                "_links": {
                    "self": {
                        "href": "/hrm/schemesAndBenefits/65579a90-2e1c-4c4a-9069-b0ed01021094"
                    },
                    "revisionTypeHistory": {
                        "href": "/hrm/occupancies/f68787d3-2919-476d-8c1b-b15e005ed1df/schemeAndBenefit/item/65579a90-2e1c-4c4a-9069-b0ed01021094"
                    }
                },
                "id": "65579a90-2e1c-4c4a-9069-b0ed01021094",
                "value": "Flex Holiday Buy"
            },
            {
                "_links": {
                    "self": {
                        "href": "/hrm/schemesAndBenefits/aeae287b-1dcf-4331-a596-aeaf00a57eb2"
                    },
                    "revisionTypeHistory": {
                        "href": "/hrm/occupancies/f68787d3-2919-476d-8c1b-b15e005ed1df/schemeAndBenefit/item/aeae287b-1dcf-4331-a596-aeaf00a57eb2"
                    }
                },
                "id": "aeae287b-1dcf-4331-a596-aeaf00a57eb2",
                "value": "Salary"
            }
        ]
    }
}

You should be able to loop through the schemeAndBenefitAvailbleItems values and find a match for the item value. We need to get the item id.

Find the choice for the scheme & benefit item.

We need to try and match the choice against the list of choices in People First.

Firstly, make a request to get the choices for the itemid in the previous step. We also need the occupancy id in the uri:

GET PFBASEURI/api/v1/hrm/occupancies/<occupancyId>/schemeAndBenefit/item/<itemId>/effectiveDate/<effectivedate>?annotate=t&mode=revision

The response for a table-based scheme and benefit item looks like this:

{
    "meta": {
        "links": {
            "self": {
                "href": "/hrm/occupancies/d2d7c2b1-edb3-49b9-accf-aead00752a60/schemeAndBenefit/item/4fd34f32-428a-4550-9dba-afd00076e0ab/effectiveDate/2023-05-01?annotate=t&mode=revision"
            }
        },
        "schemeAndBenefit.startDate": {
            "disabled": "true"
        },
        "schemeAndBenefit.actualCash": {
            "disabled": "true"
        },
        "schemeAndBenefit.actualPercentage": {
            "disabled": "true"
        },
        "schemeAndBenefit.occupancyId": {
            "disabled": "true"
        },
        "schemeAndBenefit.itemId": {
            "disabled": "true",
            "values": [
                {
                    "value": "Car Allowance",
                    "id": "4fd34f32-428a-4550-9dba-afd00076e0ab"
                }
            ]
        },
        "schemeAndBenefit.customPercentage": {
            "disabled": "true",
            "hidden": "true"
        },
        "schemeAndBenefit.customCash": {
            "mandatory": "true"
        },
        "schemeAndBenefit.choiceId": {
            "hidden": "true",
            "disabled": "true",
            "values": []
        },
        "schemeAndBenefit.fixedCash": {
            "disabled": "true",
            "hidden": "true"
        },
        "schemeAndBenefit.fixedPercentage": {
            "disabled": "true",
            "hidden": "true"
        },
        "schemeAndBenefit.tableChoiceFormatChoiceNameId": {
            "values": [
                {
                    "id": "c125e7d1-750a-4c6e-a200-afd000776906",
                    "identifier": "c125e7d1-750a-4c6e-a200-afd000776906",
                    "value": "Level 1 - 5000",
                    "cash": 5000.000000,
                    "percentage": null
                },
                {
                    "id": "0fe88646-97e0-43f6-9d62-afd000776906",
                    "identifier": "0fe88646-97e0-43f6-9d62-afd000776906",
                    "value": "Level 2 - 10000",
                    "cash": 10000.000000,
                    "percentage": null
                },
                {
                    "id": "1ea0dfb5-3d66-4a5b-99a3-afd000776906",
                    "identifier": "1ea0dfb5-3d66-4a5b-99a3-afd000776906",
                    "value": "Level 3 - 15000",
                    "cash": 15000.000000,
                    "percentage": null
                },
                {
                    "id": "41bab961-0c96-46e2-9a81-afd000776906",
                    "identifier": "41bab961-0c96-46e2-9a81-afd000776906",
                    "value": "Level 4 - 20000",
                    "cash": 20000.000000,
                    "percentage": null
                },
                {
                    "id": "e68d1c0f-91c1-499c-b53e-afd000776906",
                    "identifier": "e68d1c0f-91c1-499c-b53e-afd000776906",
                    "value": "Level 5 - 25000",
                    "cash": 25000.000000,
                    "percentage": null
                }
            ]
        },
        "inheritance": {
            "state": "root",
            "inhPath": {
                "href": "/hrm/occupancies/d2d7c2b1-edb3-49b9-accf-aead00752a60/schemeAndBenefit/item/4fd34f32-428a-4550-9dba-afd00076e0ab/effectiveDate/2023-05-01/inheritancePath"
            }
        }
    },
    "data": {
        "schemeAndBenefit": {
            "_links": {
                "self": {
                    "href": "/hrm/occupancies/d2d7c2b1-edb3-49b9-accf-aead00752a60/schemeAndBenefit/item/4fd34f32-428a-4550-9dba-afd00076e0ab/effectiveDate/2023-05-01"
                },
                "attachments": {
                    "href": "/hrm/occupancies/d2d7c2b1-edb3-49b9-accf-aead00752a60/schemesbenefits/item/4fd34f32-428a-4550-9dba-afd00076e0ab/attachments",
                    "template": "/hrm/occupancies/d2d7c2b1-edb3-49b9-accf-aead00752a60/schemesbenefits/item/4fd34f32-428a-4550-9dba-afd00076e0ab/attachments/resourcetemplate"
                },
                "revisionTypeHistory": {
                    "href": "/hrm/occupancies/d2d7c2b1-edb3-49b9-accf-aead00752a60/schemeAndBenefit/item/4fd34f32-428a-4550-9dba-afd00076e0ab"
                },
                "revisionHistory": {
                    "href": "/hrm/occupancies/d2d7c2b1-edb3-49b9-accf-aead00752a60/schemeAndBenefit?effectiveDate=2023-05-01"
                },
                "strucItem": {
                    "href": "/hrm/structure/d2d7c2b1-edb3-49b9-accf-aead00752a60/effDate/2023-05-01"
                }
            },
            "occupancyId": "d2d7c2b1-edb3-49b9-accf-aead00752a60",
            "startDate": "2023-05-01",
            "endDate": null,
            "itemId": "4fd34f32-428a-4550-9dba-afd00076e0ab",
            "customCash": null,
            "customPercentage": null,
            "fixedCash": null,
            "fixedPercentage": null,
            "tableChoiceFormatChoiceNameId": null,
            "choiceId": null,
            "_status": null,
            "itemType": "schemebenefittable",
            "actualCash": null,
            "actualPercentage": null,
            "schemeAndBenefitSupplement": null
        }
    }
}

In the example above, there is an item called ‘Car Allowance’ with 5 choices – ‘Level 1 - 5000‘, ‘Level 2 – 10000’, ‘Level 3 – 15000’, ‘Level 4 – 20000’ & ‘Level 5 – 25000’. These have associated cash values of 5000, 10000, 15000, 20000 & 25000.

Sample response for fixed choice item (in this case cash of 100)

{
{
    "meta": {
        "links": {
            "self": {
                "href": "/hrm/occupancies/38bdea67-bdd3-434c-ad40-b093006f732f/schemeAndBenefit/item/32f6f113-a893-4425-ab16-afd00077b40f/effectiveDate/2023-05-01?annotate=t&mode=revision"
            }
        },
        "schemeAndBenefit.startDate": {
            "disabled": "true"
        },
        "schemeAndBenefit.actualCash": {
            "disabled": "true"
        },
        "schemeAndBenefit.actualPercentage": {
            "disabled": "true"
        },
        "schemeAndBenefit.occupancyId": {
            "disabled": "true"
        },
        "schemeAndBenefit.itemId": {
            "disabled": "true",
            "values": [
                {
                    "value": "Fire Warden",
                    "id": "32f6f113-a893-4425-ab16-afd00077b40f"
                }
            ]
        },
        "schemeAndBenefit.tableChoiceFormatChoiceNameId": {
            "disabled": "true",
            "hidden": "true",
            "values": []
        },
        "schemeAndBenefit.customPercentage": {
            "disabled": "true",
            "hidden": "true"
        },
        "schemeAndBenefit.customCash": {
            "mandatory": "true"
        },
        "schemeAndBenefit.choiceId": {
            "disabled": "true",
            "hidden": "true",
            "values": []
        },
        "schemeAndBenefit.fixedCash": {
            "disabled": "true",
            "mandatory": "true"
        },
        "schemeAndBenefit.fixedPercentage": {
            "disabled": "true",
            "hidden": "true"
        },
        "inheritance": {
            "state": "root",
            "inhPath": {
                "href": "/hrm/occupancies/38bdea67-bdd3-434c-ad40-b093006f732f/schemeAndBenefit/item/32f6f113-a893-4425-ab16-afd00077b40f/effectiveDate/2023-05-01/inheritancePath"
            }
        }
    },
    "data": {
        "schemeAndBenefit": {
            "_links": {
                "self": {
                    "href": "/hrm/occupancies/38bdea67-bdd3-434c-ad40-b093006f732f/schemeAndBenefit/item/32f6f113-a893-4425-ab16-afd00077b40f/effectiveDate/2023-05-01"
                },
                "attachments": {
                    "href": "/hrm/occupancies/38bdea67-bdd3-434c-ad40-b093006f732f/schemesbenefits/item/32f6f113-a893-4425-ab16-afd00077b40f/attachments",
                    "template": "/hrm/occupancies/38bdea67-bdd3-434c-ad40-b093006f732f/schemesbenefits/item/32f6f113-a893-4425-ab16-afd00077b40f/attachments/resourcetemplate"
                },
                "revisionTypeHistory": {
                    "href": "/hrm/occupancies/38bdea67-bdd3-434c-ad40-b093006f732f/schemeAndBenefit/item/32f6f113-a893-4425-ab16-afd00077b40f"
                },
                "revisionHistory": {
                    "href": "/hrm/occupancies/38bdea67-bdd3-434c-ad40-b093006f732f/schemeAndBenefit?effectiveDate=2023-05-01"
                },
                "strucItem": {
                    "href": "/hrm/structure/38bdea67-bdd3-434c-ad40-b093006f732f/effDate/2023-05-01"
                }
            },
            "occupancyId": "38bdea67-bdd3-434c-ad40-b093006f732f",
            "startDate": "2023-05-01",
            "endDate": null,
            "itemId": "32f6f113-a893-4425-ab16-afd00077b40f",
            "customCash": null,
            "customPercentage": null,
            "fixedCash": 100.000000,
            "fixedPercentage": null,
            "tableChoiceFormatChoiceNameId": null,
            "choiceId": null,
            "_status": null,
            "itemType": "schemebenefitfixedvalue",
            "actualCash": 100.000000,
            "actualPercentage": null,
            "schemeAndBenefitSupplement": null
        }
    }
}

From the response headers, get the eTag property – this is a token which needs to be passed in the next PUT request to ensure the data is the most up to date.

Matching the choice (or not).

The process of matching the choice value is something like this:

Look at schemeAndBenefit.choiceId in choice response. If there are values check the percentage property - if not empty then choice input type is percentage not cash. Try and match the value to the choice.

If choice not matched, look at schemeAndBenefit.tableChoiceFormatChoiceNameId in choice response. If there are values check the percentage property - if not empty then choice input type is percentage not cash. Try and match the value to the choice.

If choice not matched, look at data.schemeAndBenefit.itemType in choice response. If this is schemebenefitfixedvalue get the data.schemeAndBenefit.fixedCash & data.schemeAndBenefit.fixedPercentage values. This is the default value for the choice. If fixedPercentage is not empty then input type will be percentage not cash.

If choice not matched, look at data.schemeAndBenefit.itemType in choice response. If this is schemebenefitnoinput then we don't need a choice.

Else if choice still not matched, must be a custom choice. From the values analysed earlier for schemeAndBenefit.choiceId and schemeAndBenefit.tableChoiceFormatChoiceNameId, we will know whether this is a cash or percentage custom choice value.

Add the occupancy scheme & benefit.

PUT PFBASEURI/api/v1/hrm/occupancies/<occupancyId>/schemeAndBenefit/item/<itemId>/effectiveDate/<effectivedate>?annotate=t

Example body with table value:

{
    "schemeAndBenefit": {
        "occupancyId": "d2d7c2b1-edb3-49b9-accf-aead00752a60",
        "startDate": "2023-05-01",
        "endDate": null,
        "customCash": null,
        "customPercentage": null,
        "fixedCash": null,
        "fixedPercentage": null,
        "_status": null,
        "itemType": "schemebenefittable",
        "actualCash": null,
        "actualPercentage": null,
        "schemeAndBenefitSupplement": null,
        "effectiveDate": "2023-05-01",
        "itemId": "4fd34f32-428a-4550-9dba-afd00076e0ab",
        "choiceId": null,
        "tableChoiceFormatChoiceNameId": "0fe88646-97e0-43f6-9d62-afd000776906"
    }
}

If attaching an attachment, we need the id of the newly created record. This can be obtained from the response of the PUT request.

Example PUT body with table choice item with custom choice of 8000 cash:

{
    "schemeAndBenefit": {
        "occupancyId": "38bdea67-bdd3-434c-ad40-b093006f732f",
        "startDate": "2023-05-01",
        "endDate": null,
        "customCash": 8000,
        "customPercentage": null,
        "fixedCash": null,
        "fixedPercentage": null,
        "_status": null,
        "itemType": "schemebenefittable",
        "actualCash": null,
        "actualPercentage": null,
        "schemeAndBenefitSupplement": null,
        "effectiveDate": "2023-05-01",
        "itemId": "4fd34f32-428a-4550-9dba-afd00076e0ab",
        "choiceId": null,
        "tableChoiceFormatChoiceNameId": null
    }
}

Example PUT body with fixed choice item (with value 100 cash):

{
    "schemeAndBenefit": {
        "occupancyId": "38bdea67-bdd3-434c-ad40-b093006f732f",
        "startDate": "2023-05-01",
        "endDate": null,
        "customCash": null,
        "customPercentage": null,
        "fixedCash": 100,
        "fixedPercentage": null,
        "_status": null,
        "itemType": "schemebenefitfixedvalue",
        "actualCash": 100,
        "actualPercentage": null,
        "schemeAndBenefitSupplement": null,
        "effectiveDate": "2023-05-01",
        "itemId": "32f6f113-a893-4425-ab16-afd00077b40f",
        "tableChoiceFormatChoiceNameId": null,
        "choiceId": null
    }
}

Example PUT body with fixed choice item (overridden with custom cash of 150):

{
    "schemeAndBenefit": {
        "occupancyId": "38bdea67-bdd3-434c-ad40-b093006f732f",
        "startDate": "2023-05-01",
        "endDate": null,
        "customCash": 150,
        "customPercentage": null,
        "fixedCash": 100,
        "fixedPercentage": null,
        "_status": null,
        "itemType": "schemebenefitfixedvalue",
        "actualCash": 100,
        "actualPercentage": null,
        "schemeAndBenefitSupplement": null,
        "effectiveDate": "2023-05-01",
        "itemId": "32f6f113-a893-4425-ab16-afd00077b40f",
        "tableChoiceFormatChoiceNameId": null,
        "choiceId": null
    }
}

Adding Attachment data

Many of the data areas in People First allow attachments to be added against that data area. The APIs work in a similar way whichever area they are in so we will cover these APIs in one section.

An attachment is a file attachment. People First only supports ‘whiltelisted’ types and currently only supports files up to 10Mb. To add an attachment using the APIs, the attachment file content needs to be converted to base64 and loaded into the API request body as a stream.

For example, in Powershell you can use the following statement to read in the file content, and convert to base64 - $contents is then used as the filedata in the request body for the POST:

$contents = [Convert]::ToBase64String((Get-Content -Encoding Byte -Path $file))

Get the new attachment resource template

Get resource template for a new attachment by making one of the followjng API calls – the uri differs depending on which area is being used – the id in the chevrons should be replaced with the Id from the PUT/POST request for the appropriate area.

Person attachment
GET PFBASEURI/api/v1/hrm/people/<personId>/attachments/resourcetemplate?annotate=t
Sensitive information attachment
GET PFBASEURI/api/v1/hrm/sensitiveinformation/<personId>/attachments/resourcetemplate?annotate=t
Right to work attachment
GET PFBASEURI/api/v1/hrm/people/<personId>/righttowork/attachments/resourcetemplate?annotate=t
Certificate of sponsorship attachment
GET PFBASEURI/api/v1/hrm/sponsorshipcertificates/<sponsorshipCertificateId>/attachments/resourcetemplate?annotate=t
Settlement status attachment
GET PFBASEURI/api/v1/hrm/settlementstatuses/<settlementstatusId>/attachments/resourcetemplate?annotate=t
Passport attachment
GET PFBASEURI/api/v1/hrm/passports/<passportId>/attachments/resourcetemplate?annotate=t
Residency permit attachment
GET PFBASEURI/api/v1/hrm/residencypermits/<residencypermitId>/attachments/resourcetemplate?annotate=t
Visa attachment
GET PFBASEURI/api/v1/hrm/visas/<visaId>/attachments/resourcetemplate?annotate=t
Work permit attachment
GET PFBASEURI/api/v1/hrm/workpermits/<workpermitsId>/attachments/resourcetemplate?annotate=t
Driver details attachment
GET PFBASEURI/api/v1/hrm/persondrivers/<driverdetailsid>/attachments/resourcetemplate?annotate=t
Occupancy attachment
GET PFBASEURI/api/v1/hrm/occupancies/<occupancyId>/attachments/resourcetemplate?annotate=t
Occupancy salary attachment
GET PFBASEURI/api/v1/hrm/occupancies/<occupancyId>/salary/attachments/resourcetemplate?annotate=t
Occupancy scheme and benefit attachment
GET PFBASEURI/api/v1/hrm/occupancies/<occupancyId>/schemesbenefits/item/<itemId>/attachments/resourcetemplate?annotate=t

Create an attachment record

Mandatory fields – documentName, filename, fileData, visibleInSelfService.

The attachment uri is depending on the area:

Person
POST PFBASEURI/api/v1/hrm/people/<personId>/attachments?annotate=t
Sensitive information
POST PFBASEURI/api/v1/hrm/people/<personId>/sensitiveinformation/attachments?annotate=t
Right to work attachment
POST PFBASEURI/api/v1/hrm/people/<personId>/righttowork/attachments?annotate=t
Certificate of sponsorship attachment
POST PFBASEURI/api/v1/hrm/sponsorshipcertificates/<sponsorshipCertificateId>/attachments?annotate=t
Settlement status attachment
POST PFBASEURI/api/v1/hrm/settlementstatuses/<settlementstatusId>/attachments?annotate=t
Passport attachment
POST PFBASEURI/api/v1/hrm/passports/<passportId>/attachments?annotate=t
Residency permit attachment
POST PFBASEURI/api/v1/hrm/residencypermits/<residencypermitId>/attachments?annotate=t
Visa attachment
POST PFBASEURI/api/v1/hrm/visas/<visaId>/attachments?annotate=t
Work permit attachment
POST PFBASEURI/api/v1/hrm/workpermits/<workpermitsId>/attachments?annotate=t
Driver details attachment
POST PFBASEURI/api/v1/hrm/persondrivers/<driverdetailsid>/attachments?annotate=t
Occupancy attachment
POST PFBASEURI/api/v1/hrm/occupancies/<occupancyId>/attachments?annotate=t
Occupancy salary attachment
POST PFBASEURI/api/v1/hrm/occupancies/<occupancyId>/salary/attachments?annotate=t
Occupancy scheme and benefit attachment
POST PFBASEURI/api/v1/hrm/occupancies/<occupancyId>/schemesbenefits/item/<itemId>/attachments?annotate=t

For example, creating a person attachment – make the following request:

POST PFBASEURI/api/v1/hrm/people/<personId>/drivers?annotate=t

with sample body:

{
    "attachments": {
        "visibleInSelfService": true,
        "fileData": "JVBERi0xEJBNTNBMUY0MjRGQzk2RkUzPjw1NDY4N0MxMzBBNTA4MjRCQTUzQTFGNDI0RkM5NkZFMz5dIC9QcmV2IDU5NDIvWFJlZlN0bSA1NjQ3Pj4NCnN0YXJ0eHJlZg0KNjYzNw0KJSVFT0Y=",
        "documentName": "TestForm.pdf",
        "filename": "TestForm.pdf",
        "authorId": ""
    }
}

Inviting the employee to access the People First application.

This process will create a People First user record and send an email invitation for the appointed applicant / new employee to sign up and login to People First.

In People First there are several different user roles which can be assigned to a user – these allow the user to access various parts of the People First application. For this process, we need to just provide the basic access which is a role called ‘Standard’.

Get the new user resource template.

Get resource template for a new People First user by making API call:

GET PFBASEURI/api/v1/iam/users/resourcetemplate?annotate=t

Create a new user record.

Mandatory - email, activeFlag, roles (at least one role must be specified).

Use GET request to get the id for 'Standard' role. This is the minimum necessary for the user to login once they are signed up. Any other roles should be assigned by an administrator in People First later.

Set the personId property in the body to <personid> used beforehand.

POST PFBASEURI/api/v1/iam/users?annotate=t

with sample body:

{
    "user": {
        "roles": [{
                "id": "a77e44a5-e970-4b65-8c2e-0150764efc7f",
                "active": true
            }
        ],
        "linkedIdentities": "",
        "activeFlag": true,
        "email": "sampleemail@xyz.co.uk",
        "personId": "db753242-60e6-491c-a06c-b14800e00d46"
    }
}

Creating a new employee using PF import APIs

Authentication

To use the import APIs, a PAT Token with a HRM Imports role can be used. TODO Check what users import requires.

List of APIs

This document assumes ATS->People First integration is one way with ATS making calls to People First only.

Essentially the ATS needs to make API calls to do the following to get an appointed applicant into People First:

  • Create a person record
  • Add sensitive information details
  • Add address & contact details
  • Add right to work details (up to 7 things including passports, permits etc.)
  • Add driver details
  • Create the job / get the job details
  • Add the person into a job
  • Add salary details
  • Add hours and basis details
  • Add working pattern details
  • Add schemes and benefits details
  • Give the person access to People First by creating a user

Alternatively, the People First import APIs can be called. This is less API calls but does require polling to check when import files have validated and imported. The import APIs can handle multiple import records at once which might be easier to manage. Also, any import files can be viewed within People First (by admin users) so any files failing validation can be fixed and re-imported. The People First imports relevant to the data from the ATS include:

  • People (includes sensitive information, address & contact details)
  • Right to work
  • Driver details
  • Job (if job is to be created)
  • Assign Job (add person into the job)
  • Salary for people
  • Salary for people on grade & payscale
  • Hours & basis for people
  • Working patterns
  • Schemes and Benefits for people
  • Create user for a person

People First has a set of import APIs which are used for onboarding data. There are many different import types such as People, Job, Assign Job, Driver details etc. Each type has a different file import layout. The import file templates can be downloaded within People First – these provide guidance on filling in the fields including which ones are mandatory.

The import APIs take the file contents and firstly validate the contents and import the data if the file content passes validation. The loading of the files is recorded in People First in the Administration->Imports and Exports->Imports area.

The process of importing for each import type is the same and will be described before examples of loading each import are given.

Import Process - General Steps

These are the general steps for an external application to call a People First import API:

  • Make the import file according to the People First layout for the import type.
  • Save the import file as a UTF8 csv file (not UTF8 BOM).
  • Convert file contents as base64 string & make People First API call to create a new import – get the id of the import.
  • Make People First API call to check new import’s status – repeat until status is ‘ReadyToImport’ or ‘RecordValidationFailed’.
  • If status is ‘RecordValidationFailed’, perform error processing and end this processing.
  • If status is ‘ReadyToImport’, make People First API call to import the data.
  • Make People First API call to check import’s status – repeat until status is ‘Imported’.

Importing a new person

Make the person import file

The import file fields need to be populated like the example below with a line of headings and then a line for each person to be created.This file needs saving as a UTF8 csv file.

If any of the data contains commas, which we are using as the delimiter, the individual data in that field can be wrapped in double quotes. It is possible to wrap all fields in double quotes but beware some of the imports such as User will not work with double quotes around the fields.

Personal reference number,Title,First name,Last name,Start date,Reckonable service date,Additional names,Known as,Previous last name,Pronouns,Legislation,Social security number,Date of birth,Date of birth verified,Gender,Legal gender,Marital status,Religion,Nationality,Country of citizenship,Sexual orientation,Ethnic origin / Race,Veteran status,Company phone number,Company phone number country code,Company cell/mobile number,Company cell/mobile number country code,Personal phone number,Personal phone number country code,Personal cell/mobile number,Personal cell/mobile number country code,Company email,Personal email,LinkedIn profile link,Twitter link,Skype,Address line 1,Address line 2,Address line 3,Address line 4,Address line 5,Address line 6,CountryF12345,Mr,Kenneth,Stannard,2024-04-01,,,Malcolm,Ken,,United Kingdom,JE987080A,1997-09-01,2024-04-01,Male,Male,Single,,,,,,,0115 9456 123,44,,,0115 9932419,44,07780 400500,44,,ken.stannard345@hdjfhdhjdshhd.co.uk,,https://twitter.com/kstannard345,kenstannard345,,1 Kimberley Road,Watnall,Nottingham,Notts,NG16 2JH,United Kingdom

Create a new import

Firstly, the person file content needs to be converted to base64 and loaded into the API request body as a stream.

For example, in Powershell you can use the following statement to read in the file content, and convert to base64 - $contents is then used as the fileData in the request body for the POST:

$contents = [Convert]::ToBase64String((Get-Content -Encoding Byte -Path $file))

Make the following API call to create the import:

POST PFBASEURI/api/v1/hrm/importsessions/importtemplates/Person?annotate=t

with sample body:

{
    "importsessions": {
        "fileData": "UGVyc29u…b20va3N0YW5uYXJkMzQ1LGtlbnN0YW5uYXJkMzQ1LZWQgS2luZ2RvbQ0K",
        "documentName": "PeopleImportTest.csv"
    }
}

From the response, get the data.importsessions.id property which is needed to check the status of the import.

Check import status – validation

Replace <importsessionId> in the following uri with the id from the previous step.

POST PFBASEURI/api/v1/hrm/importsessions/<importsessionId>

In the response, check property completionStatus. If this is ‘RecordValidationFailed‘, then there is something wrong with the file format or the data – this needs further investigation.

If the completionStatus is ReadyToImport, then we can proceed with importing the file.

If the completionStatus is PreValidating, then the import is file still being checked so wait a few seconds and repeat this GET request.

Importing the file

To import the file and create the data in People First, make API call:

POST PFBASEURI/api/v1/hrm/importsessions/importing?annotate=t

with sample body:

{
    "importsessions": {
        "id": "<importsessionId>"
    }
}

Replace <importsessionId> with the value from previous step.

Check import status – import

Replace <importsessionId> in the following uri with the id from the previous step.

GET PFBASEURI/api/v1/hrm/importsessions/<importsessionId>

In the response, check property completionStatus. If this is ‘Imported‘ then the file has been imported. Check importFailureCount to see if any errors occurred. Any errors can be investigated in the People First application, or there are further API errors to return the details of the errors.

If the response completionStatus is ‘Importing’ then wait a few seconds and repeat this GET request.

Further Imports

Further imports can be performed to import the rest of the data. There is a logical order to the imports as data for one import type may be dependent on the import of another type.

The import types and the order in which they should be done are:

  • Person
  • RightToWork
  • DriverDetail
  • RightToWorkDocumentationInfo
  • Job (if creating a job as part of this process)
  • Occupancy
  • OccupancyHoursAndBasis
  • OccupancySalary
  • OccupancySalaryGrade
  • WorkingPatternsAndShifts
  • SchemesAndBenefitsForPerson
  • User

The steps for importing a new person should be followed for the other import types, replacing Person in the POST importsession uri with the name of the import type. For User import, replace hrm with iam also

POST PFBASEURI/api/v1/hrm/importsessions/importtemplates/Person?annotate=t

Other useful APIs

Creating a department

Finding a parent department / organization

Creating a department requires a parent department or organization.

I the parent is a department then make api call to find department matching reference number xxx:

GET PFBASEURI/api/v1/hrm/odata/Units?$filter=StructureReference eq 'xxx'

From the response get the Id which is the department id


          {
            "value": [{
              "Id": "1506be34-3cd7-46ba-ac67-acd100fde2ce",
              "StructureReference": "xxx",
              "Name": "Top Department",
              "FinanceReferenceNumber": "AUTO001",
              "StartDate": "1990-01-01T00:00:00Z",
              "EndDate": null
            }]
          }
        

If the parent is the organization, then People First only has one organization per environment so make this odata query to get the organization id to use as the parent. The id of the organization is different per People First environment.

GET PFBASEURI/api/v1/hrm/odata/Organisations

Sample Response:


          {
            "value": [{
              "Id": "7d4ff72f-6681-41f1-9e18-acd100e57c8d",
              "Name": "Wid",
              "StartDate": "1900-01-01T00:00:00Z",
              "EndDate": null
            }]
          }
        

Creating a new department

To create the department firstly get resource template for the parent:

GET PFBASEURI/api/v1/hrm/structure/<ParentDeptIdOrOrgId>/resourcetemplate?type=Unit&annotate=t

<ParentDeptIdOrOrgId> is id of parent org or department obtained earlier:

To create the new department make post request with sample body:

Mandatory fields - name, startDate, parentStructureId, quantity (default to 1), type. If department reference numbers are set to Manual, then structureReference is mandatory and must adhere to correct format.

Quantity can be used to create more than one department if department reference numbers are set to Autogenerate.

Start date of the department has to be on or after the parent's start date.

POST PFBASEURI/api/v1/hrm/structure/<ParentDeptIdOrOrgId>?type=Unit&annotate=t

          {
            "structureitem": {
              "name": "Special Projects Assistant",
              "startDate": "2024-05-22",
              "endDate": "",
              "parentStructureId": "a34d6b57-c65d-4898-8ba1-ad74007d1600",
              "quantity": 1,
              "structureReference": "S60006",
              "companyRegistrationNumber": "",
              "type": "Unit",
              "reportingUnit": "Special Projects"
            }
          }
        

In the POST response, the id of the new department can be obtained and used to create a job.

Creating attachments

Adding attachment data

Many of the data areas in People First allow attachments to be added against that data area. The APIs work in a similar way whichever area they are in so we will cover these APIs in one section.

An attachment is a file attachment. People First only supports ‘whiltelisted’ types and currently only supports files up to 10Mb. To add an attachment using the APIs, the attachment file content needs to be converted to base64 and loaded into the API request body as a stream.

For example, in Powershell you can use the following statement to read in the file content, and convert to base64 - $contents is then used as the filedata in the request body for the POST:

$contents = [Convert]::ToBase64String((Get-Content -Encoding Byte -Path $file))

Get the new attachment resource template.

Get resource template for a new attachment by making one of the followjng API calls – the uri differs depending on which area is being used – the id in the chevrons should be replaced with the Id from the PUT/POST request for the appropriate area.

Person attachment

GET PFBASEURI/api/v1/hrm/people/<personid>/attachments/resourcetemplate?annotate=t

Sensitive information attachment

GET PFBASEURI/api/v1/hrm/sensitiveinformation/<personid>/attachments/resourcetemplate?annotate=t

Right to work attachment

GET PFBASEURI/api/v1/hrm/people/<personid>/righttowork/attachments/resourcetemplate?annotate=t

Certificate of sponsorship attachment

GET PFBASEURI/api/v1/hrm/sponsorshipcertificates/<sponsorshipCertificateId>/attachments/resourcetemplate?annotate=t

Settlement status attachment

GET PFBASEURI/api/v1/hrm/settlementstatuses/<settlementstatusId>/attachments/resourcetemplate?annotate=t

Passport attachment

GET PFBASEURI/api/v1/hrm/passports/<passportId>/attachments/resourcetemplate?annotate=t

Residency permit attachment

GET PFBASEURI/api/v1/hrm/residencypermits/<residencypermitId>/attachments/resourcetemplate?annotate=t

Visa attachment

GET PFBASEURI/api/v1/hrm/visas/<visaId>/attachments/resourcetemplate?annotate=t

Work permit attachment

GET PFBASEURI/api/v1/hrm/workpermits/<workpermitId>/attachments/resourcetemplate?annotate=t

Driver details attachment

GET PFBASEURI/api/v1/hrm/occupancies/<occupancyid>/attachments/resourcetemplate?annotate=t

Occupancy attachment

GET PFBASEURI/api/v1/hrm/occupancies/<occupancyid>/attachments/resourcetemplate?annotate=t

Occupancy salary attachment

GET PFBASEURI/api/v1/hrm/occupancies/<occupancyid>/salary/attachments/resourcetemplate?annotate=t

Occupancy scheme and benefit attachment

GET PFBASEURI/api/v1/hrm/occupancies/<occupancyid>/schemesbenefits/item//<itemid>/attachments/resourcetemplate?annotate=t

Create an attachment record.

Mandatory fields – documentName, filename, fileData, visibleInSelfService.

The attachment uri is depending on the area:

Person

POST PFBASEURI/api/v1/hrm/people/<personid>/attachments/resourcetemplate?annotate=t

Sensitive information

POST PFBASEURI/api/v1/hrm/people/<personid>/sensitiveinformation/attachments?annotate=t

Right to work attachment

POST PFBASEURI/api/v1/hrm/people/<personid>/righttowork/attachments?annotate=t

Certificate of sponsorship attachment

POST PFBASEURI/api/v1/hrm/sponsorshipcertificates/<sponsorshipCertificateId>/attachments?annotate=t

Settlement status attachment

POST PFBASEURI/api/v1/hrm/settlementstatuses/<settlementstatusId>/attachments?annotate=t

Passport attachment

POST PFBASEURI/api/v1/hrm/passports/<passportId>/attachments?annotate=t

Residency permit attachment

POST PFBASEURI/api/v1/hrm/residencypermits/<residencypermitId>/attachments?annotate=t

Visa attachment

POST PFBASEURI/api/v1/hrm/visas/<visaId>/attachments?annotate=t

Work permit attachment

POST PFBASEURI/api/v1/hrm/workpermits/<workpermitId>/attachments?annotate=t

Driver details attachment

POST PFBASEURI/api/v1/hrm/persondrivers/<driverdetailsid>/attachments?annotate=t

Occupancy attachment

POST PFBASEURI/api/v1/hrm/occupancies/<occupancyid>/attachments?annotate=t

Occupancy attachment

POST PFBASEURI/api/v1/hrm/occupancies/<occupancyid>/salary/attachments?annotate=t

Occupancy scheme and benefit attachment

POST PFBASEURI/api/v1/hrm/occupancies/<occupancyid>/schemesbenefits/item/<itemid>/attachments/resourcetemplate?annotate=t

For example, creating a person attachment – make the following request:

POST PFBASEURI/api/v1/hrm/people/<personid>/drivers?annotate=t with sample body (the fileData has been shortened in this example!):

          {
            "attachments": {
              "visibleInSelfService": true,
              "fileData": "JVBERi0xEJBNTNBMUY0MjRGQzk2RkUzPjw1NDY4N0MxMzBBNTA4MjRCQTUzQTFGNDI0RkM5NkZFMz5dIC9QcmV2IDU5NDIvWFJlZlN0bSA1NjQ3Pj4NCnN0YXJ0eHJlZg0KNjYzNw0KJSVFT0Y=",
              "documentName": "TestForm.pdf",
              "filename": "TestForm.pdf",
              "authorId": ""
            }
          }