Migrating SEEK Application Export

The retired SEEK Application Export API allowed a partner to retrieve candidate applications for a hirer, including associated documents and screening question responses. It was also known as “Optimised Apply on SEEK” or simply “SAE”.
SAE had a number of shortcomings:
  • It required partners to explicitly poll for new applications on a hirer-by-hirer basis. For partners with a large number of hirers this lead to wasted resources for both the partner and SEEK.
  • It had limited extensibility for passing richer candidate profile data, document types and application questionnaire responses.
  • Its design had little in common with the retired Job Posting API or the new SEEK API. This required duplicated integration effort from partners.
The following documentation compares SAE with the SEEK API for application export. For more general information, see the Optimised Apply use case documentation.

Event delivery

The SEEK API replaces per-hirer polling with a new event mechanism. A CandidateApplicationCreated event is emitted whenever a candidate submits an application on SEEK. Your software can trigger an export of said application from this event.
CandidateApplicationCreated events can be consumed in three ways:
  1. Creating a partner-scoped webhook subscription that will receive candidate applications for all of your SEEK hirers. This is the recommended option if it fits with your software architecture.
  2. Creating a separate webhook subscription for each SEEK hirer using Optimised Apply.
    This replicates the per-hirer event delivery of SAE. However, it requires that you create the appropriate webhook subscription as part of onboarding a new hirer.
  3. Polling an event stream for candidate applications across all your SEEK hirers. This is a fallback for partners that don’t have the capability to receive webhooks.
    You should avoid this option if at all possible; the SEEK API only permits infrequent polling which will degrade the experience for your hirers. See “why webhooks” for an explanation of why frequent polling is harmful.
If you plan to pilot your SEEK API build with a subset of your SEEK hirers, you may start off with hirer-scoped webhook subscriptions. SEEK will only send CandidateApplicationCreated events that relate to the elected hirers, which makes it easier to monitor the status of your pilot and track down potential issues.
Before you scale your build to all of your SEEK hirers, we recommend switching over to a partner-scoped webhook subscription to reduce per-request overhead and avoid additional steps when onboarding or offboarding a hirer. You should create the partner-scoped webhook subscription before deleting your existing webhook subscriptions so that your software does not miss any events in between.

Data structure

The SEEK API replaces SAE’s JSON and XML responses with a GraphQL schema based on HR Open Standards . For most fields there’s a direct mapping from the previous JSON structure to GraphQL.
You could use SAE’s test.api.seek.com.au to compare data structures with the SEEK API’s Playground environment. They both point to the same internal mock data but use different identifiers:
SAE application ID
Advertiser ID
SEEK API candidate application profile
800000000
10000
seekAnzPublicTest:candidateProfile:apply:7DtW6Q68gk2R4okNGhvg1Y
800000001
10000
seekAnzPublicTest:candidateProfile:apply:4QM5fWQbdekL9gPtPZrzex
800000003
10001
seekAnzPublicTest:candidateProfile:apply:8LKX1QrkJk5JuU2AfW6tsc
800000004
10001
seekAnzPublicTest:candidateProfile:apply:UHeZTe27g1ZJZoHMiwzmPJ
The following annotated examples compare SAE application ID 800000001 against the SEEK API.

Comparison

This table compares the data structures of a candidate application in SAE with the SEEK API CandidateProfile  object.
SAE field
Deprecated
ID
SEEK no longer assigns sequential IDs to candidate applications.
  • Use profileId.value to uniquely identify an application.
  • Use the opaque cursor string for event polling.
CandidateApplicationProfileID
profileId.value
This is a SEEK API migration feature enabled by the &include=ObjectIdentifiers query parameter.
DateSubmitted
Use createDateTime for an RFC 3339 equivalent.
JobReference
associatedPositionProfile.seekHirerJobReference
Email
person.communication.email.address
FirstName
person.name.given
LastName
person.name.family
JobSeekerID
Use candidate.documentId.value to uniquely identify an individual candidate across multiple candidate applications.
Phone
person.communication.phone.formattedNumber
PrimaryJobSeekingActivity
Use the most recent entry in employment.
.IsNewToWorkForce
Candidates that are new to the workforce will have an empty employment.
.CompanyName
employment[].organization
.JobTitle
employment[].positionHistories[].title
.TimeInRole
Use the number of months between employment[].positionHistories[].start and .end.
Attachments
attachments
.Href
attachments[].url
.Type
attachments[].seekRoleCodeCode
.DateUploaded
File metadata is not available over GraphQL.
The SEEK API supports efficient HEAD requests to retrieve the same information over HTTP.
.Size
File metadata is not available over GraphQL.
The SEEK API supports efficient HEAD requests to retrieve the same information over HTTP.
.HasVirus
The SEEK API will automatically filter out attachments with viruses.
.Hash
Hashes have been removed from both SAE and the SEEK API.

Querying SAE

This retrieves application ID 800000001 from test.api.seek.com:
RequestResponse (JSON)Response (XML)
Copy
GET /v1/advertiser/applications?afterId=800000000&beforeId=800000002&include=ObjectIdentifiers,PrimaryJobSeekingInfo
Host: test.api.seek.com.au

Querying the SEEK API

This is an example query to illustrate how SAE’s fields are represented in the SEEK API. You can remove unneeded fields or select new SEEK API fields based on your requirements.
QueryVariablesResult
query ($id: String!) {
  candidateProfile(id: $id) {
    profileId {
      value
    }
    createDateTime
    associatedPositionProfile {
      profileId {
        value
      }
      seekHirerJobReference
      positionOrganizations {
        id {
          value
        }
        seekAnzAdvertiserId
      }
    }
    candidate {
      documentId {
        value
      }
      person {
        name {
          given
          family
        }
        communication {
          phone {
            formattedNumber
          }
          email {
            address
          }
        }
      }
    }
    employment {
      organization {
        name
      }
      positionHistories {
        start
        end
        title
      }
    }
    attachments {
      seekRoleCode
      url
    }
  }
}

Transitioning existing hirers

The SEEK API and SAE can be safely run in parallel for the same hirer. Each candidate application will appear in both integrations but with a different identifier and timestamp. This requires care to avoid duplicate candidate applications appearing in your software.
SEEK supports three methods to transition existing hirers from SAE to the SEEK API. You can choose the method that best fits your software’s architecture.

Method 1: Deduplicating applications

SAE could return candidate application profile IDs in addition to its legacy identifiers. Your software could opt-in to this by adding &include=ObjectIdentifiers,PrimaryJobSeekingInfo to your SAE request URLs.
You can export candidate applications from both integrations. If you receive a candidate application profile ID that has already been exported, you can either retain the latest copy or filter it out if your software does not support updates. Once you validate your SEEK API integration is working correctly you can safely disable your SAE integration.
This is the recommended method if it’s feasible to modify your existing SAE integration.

Method 2: Filtering by job ad

You could continue to use SAE for existing job ads while starting to use the SEEK API for newly posted ads. Your software will need to filter candidate applications based on their associated position to ensure they came from the intended integration.
This is the recommended method if your software supports multiple applications from the same candidate to the same position. However, this requires running your SAE integration until the hirer’s existing job ads have closed.

Method 3: Deduplicating candidates

You can export candidate applications from both integrations and deduplicate based on the candidate’s email address. SEEK requires candidates to sign in with their email address before using SEEK’s Apply Form. This allows the candidate’s email address to uniquely identify them across both integrations.
While SEEK doesn’t prevent multiple applications from the same candidate to the same position, this is rare in practice. If your software is already deduplicating candidates this is the simplest method.

Potential gotchas

Serving attachment downloads

Attachments may be downloaded one of two ways:
  • At the time of candidate application.
    In this scenario, your software retrieves the application and its related attachments upfront, and does not need to make any subsequent calls to SEEK. This allows you to cleanly cut over from SAE to the SEEK API without any disruption to existing application data.
  • On demand.
    In this scenario, your software keeps track of the attachment download URLs associated with each application. This means that it will have to store a different URL based on whether the application was retrieved from SAE or the SEEK API, and be able to download attachments from either API, including using the appropriate credentials.
    Support for SAE attachment downloads may be dropped after a reasonable period of time. An attachment will remain for 180 days after the close date of its associated job ad.

Integer identifier continuity

We recommend that you use our new string object identifiers as they provide important benefits. However, if it’s not immediately feasible to switch your software over to a more expansive data type, you can generate your own backward-compatible identifiers. This gives you more control in selecting the appropriate data type for now and also evolving your software in future.
Database systems often support collision-safe number generation. The following MySQL example generates a numeric identifier using an AUTO_INCREMENT column in place of the old SAE application ID, and also applies a unique constraint on the new object identifier for deduplication.
SQL
Copy
-- Simplified representation of an existing table in your database
CREATE TABLE candidate_application (
  old_numeric_id INT  NOT NULL,
  new_object_id  TEXT NOT NULL,

  PRIMARY KEY (old_numeric_id),
  UNIQUE KEY  (new_object_id)
);

-- A new table for generating your own incremental identifiers
CREATE TABLE candidate_application_id_generator (
  id INT NOT NULL AUTO_INCREMENT,

  PRIMARY KEY (id)
);
-- Start your own identifiers at a reasonable jump from existing SAE identifiers
ALTER TABLE
  candidate_application_id_generator AUTO_INCREMENT = 123;
-- For SEEK API applications, generate and insert a numeric identifier
-- This is rudimentary and will throw an error on a duplicate object identifier
INSERT INTO candidate_application_id_generator (id) VALUES (DEFAULT);
INSERT INTO candidate_application (old_numeric_id, new_object_id)
VALUES
  (
    LAST_INSERT_ID(), -- This is safe even with concurrent connections
    'seekAnzPublicTest:candidateProfile:apply:7DtW6Q68gk2R4okNGhvg1Y'
  );