Careers sites

An app can host one or more careers sites, e.g. one for graduate recruitment, one for a specific country, etc.

Each site might support:

A tenant can designate (via some settings app) any site as the "primary", i.e. the main careers site.

Other apps will typically target the primary board when they create links to jobs (or to the site itself), e.g. links in:

Implementing the APIs

Produced APIs

These are APIs that your app exposes for other apps to consume them.

If your app hosts any board that the tenant may want to mark as the primary board (even in the future), or that other apps may want to generate links to, then it must declare some details about that board to other apps by producing (as non-SoT):
Response

-- CODE language-json --
[
 {
   "id": 12,
   "label": "Graduate site",
   "homePage": "http://example.com"
 }
]

User Interface

Header /common area

Most sites have some kind of header or common area at the top of the page where the candidate's login status etc. is displayed.

Your site should inject HTML for the general buttons in this area, by consuming:

Response

-- CODE language-json --
[
 {
   "app": "myapp",
  "actions": [
     {
       "name": "refer",
       "uri": "https://referrals.com/jobs/1022?tracker=106645",
       "type": "button",
       "label": "Refer a friend",
       "textColor": "dddddd",
       "backgroundColor": "010203",
       "disabled": false
     },
     {
       "name": "share",
       "uri": "https://sharing.com/jobs/1022?tracker=106645",
       "type": "button",
       "label": "Share this job",
       "textColor": "dddddd",
       "backgroundColor": "010203",
       "disabled": false
     }
   ]
 }
]

You should also implement GET /actions/byCandidate/me/general for when the candidate is logged in.

Job details page

Your site likely serves a "job details page" where the candidate can read the job description and click to apply.

LoggedIn filter

If your site supports login (a site that doesn't should only display publicly visible jobs), then this page should sit behind a loggedIn filter (as per our defined conventions).

This way a candidate who was logged in at another app (e.g. UberApply) and then linked to here (e.g. by clicking "View job details"), will be asked to log in, which should happen invisibly, and can then (for example) see internal details for the job if they are an internal.

Fetch details for job

Your site should parse the job's ID from the URL, then use it to consume APIs to get details about the job.

Response

-- CODE language-json --
{
   "id": 10334355,
   "status": "active",
   "org": 102234,
   "availability": {
       "availableInternally": true,
       "availableExternally": false,
       "applicationCloseDates": {
           "closeDate": "2015-11-05T13:15:30Z",
           "internalCloseDate": "2015-11-05T13:15:30Z",
           "externalCloseDate": "2015-11-05T13:15:30Z"
       },
       "jobPublishDates": {
           "publishDate": "2015-11-05T13:15:30Z"
       }
   },
   "code": "1022NH",
   "externalId": "SAP-1022",
   "title": "Creative Director",
   "shortSummary": "One of the most exciting positions ever offered",
   "country": "AU",
   "categories": [
       {
           "category": 1022,
           "values": [
               10024
           ]
       },
       {
           "category": 1026,
           "values": [
               10044,
               10025,
               10029
           ]
       }
  ]
}

You should display an indicator to show if the job is internal only (to guide internals not to share it).
Your site can render the job using the following logic to handle internal candidates:
Example

-- CODE language-js --
if (`your site supports login`)
  if (`the candidate is logged in`)
    if (`the candidate is internal`)
      if (`the job is visible internally`)
        return the job, with its internal details
      else
        return "sorry, this job is not available to internal candidates"
    else (`public job seeker`)
      if (`the job is visible externally`)
        return the job, with its external details
      else
        return "sorry, this job is not visible to external candidates"
  else
    if (`the job is visible externally`)
      return the job, with its external details
    else (`if the job is visible internally`)
      redirect to self with loggedIn param // they may be internal
      the loggedIn filter fires and forces login
    else // not visible at all
      return "sorry, this job is no longer available"

The job's description is in safe markdown and needs to be converted to HTML before display.
Your site should retrieve details of all of the job-related actions (apply button, share button, etc.) and render them:
Request

-- CODE language-json --
[
 {
   "app": "myapp",
   "actions": [
     {
       "name": "refer",
       "uri": "https://referrals.com/jobs/1022?tracker=106645",
       "type": "button",
       "label": "Refer a friend",
       "textColor": "dddddd",
       "backgroundColor": "010203",
       "disabled": false
     },
     {
       "name": "share",
       "uri": "https://sharing.com/jobs/1022?tracker=106645",
       "type": "button",
       "label": "Share this job",
       "textColor": "dddddd",
       "backgroundColor": "010203",
       "disabled": false
     }
   ]
 }
]

You should also implement GET /actions/byCandidate/me/jobs/{job} for when the candidate is logged in.

Job search UI

Most sites will display a keyword search box and a number of different filters such as location or expertise to allow the user to search for jobs.

To populate a search UI like that, your board can consume the category APIs.

Response

-- CODE language-json --
[
 {
   "id": 10022,
   "name": "Classification",
   "jobRules": {
     "canMultiSelect": true,
     "leafSelectionOnly": false,
     "mandatory": true
   },
   "candidateRules": {
     "canMultiSelect": true,
     "leafSelectionOnly": false,
     "message": "Please choose carefully",
     "mandatory": true
   }
 },
 {
   "id": 10032,
   "key": "LOCATION",
   "name": "Location",
   "jobRules": {
     "canMultiSelect": true,
     "leafSelectionOnly": false,
     "mandatory": true
   },
   "candidateRules": {
     "canMultiSelect": true,
     "leafSelectionOnly": false,
     "message": "Please choose carefully",
     "mandatory": true
   }
 },
 {
   "id": 10034,
   "name": "Nursing specialization",
   "jobRules": {
     "canMultiSelect": true,
     "leafSelectionOnly": false,
     "mandatory": true
   },
   "candidateRules": {
     "canMultiSelect": true,
     "leafSelectionOnly": false,
     "message": "Please choose carefully",
     "mandatory": true
   }
 }
]

Response

-- CODE language-json --
[
   {
       "id": 10034,
       "name": "Wellington",
       "available": true
   },
   {
       "id": 10032,
       "name": "Auckland",
       "available": true,
       "values": [
           {
               "id": 10036,
               "name": "North Shore",
               "available": true,
               "values": [
                   {
                       "id": 10037,
                       "name": "Takapuna",
                       "available": true
                   }
               ]
           }
       ]
   }
]

Job list/search results pages

To search / fetch lists of jobs, your site consumes one of:

GET /jobs

POST /jobs/searches

Response

-- CODE language-json --
{
 "total": 2,
 "results": [
   {
     "id": 10334355,
     "status": "active",
     "availability": {
       "availableInternally": true,
       "availableExternally": false,
       "applicationCloseDates": {
         "closeDate": "2015-11-05T13:15:30Z",
         "internalCloseDate": "2015-11-05T13:15:30Z",
         "externalCloseDate": "2015-11-05T13:15:30Z"
       }
     },
     "code": "1022NH",
     "title": "Creative Director",
     "country": "AU",
     "shortSummary": "An amazing opportunity",
     "categories": [
       {
         "category": 1022,
         "values": [
           10024
         ]
       },
       {
         "category": 1026,
         "values": [
           10044,
           10025,
           10029
         ]
       }
     ]
   },
   {
     "id": 10334356,
     "status": "active",
     "availability": {
       "availableInternally": true,
       "availableExternally": false,
       "applicationCloseDates": {
         "closeDate": "2015-11-05T13:15:30Z",
         "internalCloseDate": "2015-11-05T13:15:30Z",
         "externalCloseDate": "2015-11-05T13:15:30Z"
       }
     },
     "code": "1024NH",
     "title": "Creative Lackey",
     "country": "US",
     "shortSummary": "An amazing opportunity, unrivalled for enjoyment",
     "categories": [
       {
         "category": 1022,
         "values": [
           10024
         ]
       },
       {
         "category": 1026,
         "values": [
           10044,
           10025,
           10029
         ]
       }
     ]
   }
 ]
}

Your site should make sure not to display the wrong jobs to the wrong candidates by restricting for availableInternally or availableExternally depending on whether a candidate is logged in and if so whether they are internal or not. This restriction could be done:

  • by passing availableInternally = true to the search
  • by fetching all jobs then filtering out based on the value of availableInternally

Obviously for security reasons it must not be done client-side.

Handling trackers

Normally your site should handle trackers as described in Trackers.

This means:

  • creating session trackers
  • attaching the session tracker to all links your board emits
  • passing the session tracker to all tracker-aware APIs that your board consumes

Add