Creating and submitting an EOR employment

This guide will show you how to create a draft employment, update the job details, and submit the employment to kick off the employment onboarding and contract generation.

Note for Reseller partners using the API - you will need to use the X-Oyster-Customer-Id header for all of the calls in this guide. For more information, see the Reseller guide to using the Oyster API.


1. Create Employment

First you need to create an employment record, which represents the start of the hiring process for an engagement. In your request, you will need to include the employment’s ISO-3166 Alpha country code, full legal name, email, and nationality.

Example Request

curl --request POST \
     --url https://api.oysterhr.com/v0.1/hiring/employments/ \
     --header 'accept: application/json' \
     --header 'authorization: Bearer BEARER_TOKEN_GOES_HERE' \
     --header 'content-type: application/json' \
     --data '
{
  "personalDetails": {
    "fullLegalName": "Test Hire",
    "email": "[email protected]",
    "nationality": "US"
  },
  "countryCode": "US",
  "subdivisionCode": "CA"
}
'

Response

If successful, the API will return a 200 Created response with the newly created employment details, including an id that you will need for future updates and submission. The employment will then be in a draft phase and ready to continue filling the contractual details.

Example Response

{
  "data": {
    "engagementId": "urY7zKOm",
    "countryCode": "US",
    "subdivisionCode": "CA",
    "personalDetails": {
      "fullLegalName": "Test Hire",
      "email": "[email protected]",
      "nationality": "US",
      "workPermit": null
    },
    "manager": {
      "managerRole": null,
      "managerName": null,
      "managerEmailAddress": null,
      "managerPhoneNumber": null,
      "managerIsExpenseApprover": false
    },
    "role": {
      "newHireStatus": "new_hire",
      "seniorityLevel": null,
      "roleTypeId": null,
      "role": null,
      "jobDescription": null,
      "startDate": null,
      "endDate": null,
      "employmentType": null,
      "probationPeriod": null,
      "terminationNotice": null,
      "resignationNotice": null
    },
    "compensation": {
      "commissionPlanOffered": null,
      "commissionPlan": null,
      "salary": {
        "decimal": "",
        "currencyCode": "USD"
      },
      "paidHolidayDays": null,
      "bonuses": [],
      "allowances": [],
      "reimbursementBudgets": [],
      "remoteWorkCosts": null,
      "privateNotes": null,
      "sickPay": null
    },
    "documents": [],
    "defaultSigner": null
  }
}

2. Update Employment

Once you’ve created the employment, you will need to update the employment with details related to the job position. In the request body, only include the fields you want to update (e.g., job_title, annual_salary, etc.).

Example Request

curl --request PATCH \
     --url https://api.oysterhr.com/v0.1/hiring/employments/urY7zKOm \
     --header 'accept: application/json' \
     --header 'authorization: Bearer BEARER_TOKEN_GOES_HERE' \
     --header 'content-type: application/json' \
     --data '
{
  "role": {
    "role": "Senior Software Engineer"
  },
  "compensation": {
    "salary": {
      "decimal": "95000",
      "currencyCode": "USD"
    },
  }
}
'

To successfully submit an Employment in the next step, certain objects are required based on the Employment's designated country and employmentType. The schema includes 5 principle objects, some of which are required for employment submission:

NameRequired?
managerNo
roleYes
personalDetailsYes
compensationYes
defaultSignerYes

Within the required objects, not all items are required. The following tables show the required items for each required object. For more information about required fields for the different objects in the following tables, see the documentation.

Within the role object, the following are required:

NameTypeNotes
seniorityLevelfield
roleTypeIdfieldThis can be looked up using the Role Types endpoint.
rolefield
jobDescriptionfield
startDatefield
endDatefield
employmentTypefieldThis must be either FULL_TIME or PART_TIME.
fullTimeHoursPerWeekobjectOnly required for FULL_TIME employments.
partTimeDaysPerWeekobjectOnly required for PART_TIME employments.
partTimeHoursPerWeekobjectOnly required for PART_TIME employments.
probationPeriodobject
terminationNoticeobjectThis field is required in: Australia, UK, Ireland, India.
resignationNoticeobjectThis field is required in: Australia, UK, Ireland, India.
salaryobject

Within the compensation object, the following are required:

NameTypeNotes
salaryobject
paidHolidayDaysfield
remoteWorkCostsobject
sickPayobjectThis field is required in: UK, Ireland, Netherlands.

Within the defaultSigner object, the following are required:

NameTypeNotes
phoneobject

Response

A successful update returns the modified employment details. The status will still be draft until the employment is submitted in the following step.

Example Response

{
  "data": {
    "engagementId": "urY7zKOm",
    "countryCode": "US",
    "subdivisionCode": "CA",
    "personalDetails": {
      "fullLegalName": "Test Hire",
      "email": "[email protected]",
      "nationality": "US",
      "workPermit": null
    },
    "manager": {
      "managerRole": null,
      "managerName": null,
      "managerEmailAddress": null,
      "managerPhoneNumber": null,
      "managerIsExpenseApprover": false
    },
    "role": {
      "newHireStatus": "new_hire",
      "seniorityLevel": "SENIOR",
      "roleTypeId": null,
      "role": "Senior Software Engineer",
      "jobDescription": null,
      "startDate": null,
      "endDate": null,
      "employmentType": null,
      "probationPeriod": null,
      "terminationNotice": null,
      "resignationNotice": null,
      "fullTimeHoursPerWeek": null
    },
    "compensation": {
      "commissionPlanOffered": null,
      "commissionPlan": null,
      "salary": {
        "decimal": "95000",
        "currencyCode": "USD"
      },
      "paidHolidayDays": null,
      "bonuses": [],
      "allowances": [],
      "reimbursementBudgets": [],
      "remoteWorkCosts": null,
      "privateNotes": null,
      "sickPay": null
    },
    "documents": [],
    "defaultSigner": null
  }
}

Optional steps

Depending on the desired contract conditions, the following optional endpoints can be used:


3. Submit Employment

Once all the necessary information is submitted, you can submit the employment for processing. This marks the employment as In Progress, at which point the employment onboarding can take place before the contracts are sent out for signature.

Example Request

curl --request POST \
     --url https://api.oysterhr.com/v0.1/hiring/employments/urY7zKOm/submit \
     --header 'accept: application/json' \
     --header 'authorization: Bearer BEARER_TOKEN_GOES_HERE'

Response

If successful, you will receive a 200 response with the employment information.

Example Response

{
  "data": {
    "engagementId": "urY7zKOm",
    "countryCode": "US",
    "subdivisionCode": "CA",
    "personalDetails": {
      "fullLegalName": "Test Hire",
      "email": "[email protected]",
      "nationality": "US",
      "workPermit": null
    },
    "manager": {
      "managerRole": null,
      "managerName": null,
      "managerEmailAddress": null,
      "managerPhoneNumber": null,
      "managerIsExpenseApprover": false
    },
    "role": {
      "newHireStatus": "new_hire",
      "seniorityLevel": "SENIOR",
      "roleTypeId": 05,
      "role": "Senior Software Engineer",
      "jobDescription": "job description",
      "startDate": "2024-10-14",
      "endDate": null,
      "employmentType": "FULL_TIME",
      "probationPeriod": {
        "value": 12,
        "unit": "MONTHS"
      },
      "terminationNotice": null,
      "resignationNotice": null,
      "fullTimeHoursPerWeek": 40
    },
    "compensation": {
      "commissionPlanOffered": null,
      "commissionPlan": null,
      "salary": {
        "decimal": "95000",
        "currencyCode": "USD"
      },
      "paidHolidayDays": 14,
      "bonuses": [],
      "allowances": [],
      "reimbursementBudgets": [],
      "remoteWorkCosts": {
        "allowancePolicy": {
          "allowancePolicy": "MONTHLY_ALLOWANCE",
          "amount": null,
          "statutoryAmount": null
        },
        "equipmentBudget": null,
        "equipmentListOwnedByTeamMember": null,
        "equipmentListProvidedByCustomer": {
          "equipmentList": [
            "KEYBOARD",
            "MOUSE",
            "PRINTER"
          ],
          "equipmentOther": null
        },
        "equipmentOneTimePayment": null
      },
      "privateNotes": null,
      "sickPay": null
    },
    "documents": [],
    "defaultSigner": {
      "fullName": "Graham Vandervort",
      "email": "[email protected]",
      "jobTitle": "Engineering Manager",
      "phone": {
        "countryCode": "US",
        "number": "555 654 5568"
      }
    }
  }
}

Notes:

  • Unless otherwise configured using the Benefits API or UI, hires submitted via API will have statutory Benefits applied.
  • In countries that require values for Termination Notice, Resignation Notice and Sick Pay, statutory values will be applied.
    • Applying non-statutory values for these fields will be added in a future API update. In the meantime if you want to apply non-statutory values for any of these fields, please get in touch with Oyster.

Conclusion

Once you have successfully submitted an employment and it is in the In Progress state, the employment onboarding can begin. That can either be achieved via the platform by sending the team member an invitation or via API by following the Completing EOR employment onboarding via API guide.