closePostedPositionProfile
closePostedPositionProfile
mutation will return an error if your software attempts to close a job ad that has already been closed.Errors will be returned with the following structure:{
"errors": [
{
"message": "Job ad is already closed",
"locations": [{ "line": 2, "column": 3 }],
"path": ["closePostedPositionProfile"],
"extensions": {
"code": "FORBIDDEN"
}
}
],
"data": {
"closePostedPositionProfile": null
}
}
PositionProfileClosed
event whenever a job ad has been closed.
It’s recommended that you update your software’s internal state based on PositionProfileClosed
.
Review the Managing job ads guide for further information on a job ad’s lifecycle.PostingRequester
type.
This information was intended to help hirers understand which recruitment agency was responsible for a job ad, for jobs posted outside of the SEEK API.
This functionality has seen limited usage, and is prone to confusion.
Most SEEK hirers do not use recruitment agencies in this way, and so these changes will not affect the majority of users.This change will affect the following fields:PostingRequester.roleCode
will no longer have Agency
as a valid value; it will always return Company
.
This field is now deprecated, and will be removed at a later date.PostingRequester.id
will no longer return an ID for a recruitment agency; it will now always be the ID of the hirer.PostingRequester.name
will no longer return the name of a recruitment agency; it will now always be the name of the hirer.HiringOrganization.seekApiCapabilities
will now never return null
for agencies, as the HiringOrganization
type will not be accessible for agency accounts.hiringOrganization
query will not return information for recruitment agencies.
If your software has stored IDs for recruitment agencies, they will no longer work.RATE_LIMITED
error code.
Similarly, when a rate limit is exceeded on an attachment download endpoint, the SEEK API will return a 429 Too Many Requests
status code.
We recommend that you update your software to handle these error scenarios gracefully.
Refer to the GraphQL error response documentation for more information on how to handle errors.If you consistently encounter rate limiting or are planning to significantly increase your request volume, contact SEEK’s support team .
We’ll work with you to resolve the issue and adjust rate limits if necessary.query ($id: String!) {
candidateProfile(id: $id) {
candidate {
person {
communication {
address {
# Select other address fields as necessary
formattedAddress
countryCode
}
}
}
}
}
}
Cremorne VIC 3121 AU
),
or as broad as a country (Poland
).
If you wish to use this attribute,
your software will need to account for these differences in granularity.
You may retrieve other address fields as appropriate;
note that street-level detail is not currently available.inferLocation
query, now making the countryCode
value mandatory for all requests.This field accepts a two-letter ISO 3166-1:2013 country code of the location, in uppercase.Previously, countryCode
was optional, but subsequent testing has demonstrated that countryCode
significantly improves the quality of inference and avoids cases of incorrect locations being returned that impact hirer experience.No impact to existing implementations is expected.Content-Type: application/json
header.
This will be changed to Content-Type: application/json; charset=utf-8
, as recommended by the specification.
The encoding of the body is not changing, and will continue to be UTF-8.
We advise your software not to take hard dependencies on the exact format of the Content-Type
response header, as it may change in the future.
For example, application/graphql-response+json; charset=utf-8
may be used in the future.
We advise you to check that your software is resilient to changes in the Content-Type
response header before the 23rd March 2024.variables
as a JSON-stringified object.
This may look like {"query": "...", "variables": "{...}"}
.
This support will be removed, as it is not supported by the specification .
We require your software to use the standard request body format.
This may look like {"query": "...", "variables": {...}}
.
We advise you to check that your software is not using this non-standard request format before the 23rd March 2024.CommissionOnly
pay type will be removed from the SEEK API.
This pay type sees near-zero usage and can lead to compliance issues with local labour laws and our terms of use.From this date, if a hirer selects the ‘Commission only’ pay option in your software, the SEEK API will fail their subsequent request to post a job ad.
We highly recommend that you remove or disable this option from your job posting workflow.
See our pay type documentation for more information on valid pay types.updatePostedPositionProfile
mutation will be updated with stricter synchronous validation of the end
date.
Your software will receive a BAD_USER_INPUT
error if the supplied date exceeds the maximum duration of the job ad,
with a response that looks similar to the following:{
"errors": [
{
"message": "Invalid posting end date",
"extensions": {
"code": "BAD_USER_INPUT",
"invalidFields": {
"/input/positionProfile/postingInstructions/0/end": "Must not be more than 30 days from 2020-01-01T00:00:00.000Z"
}
}
}
]
}
expires_in
of the partner token response.If your software has hardcoded the token’s expiry or you are not currently caching partner tokens, you must update it to cache dynamically as described in our partner token documentation.When do partners need to make this change by?In line with the SEEK API terms , this change needs to be completed within 30 days (before the 2nd of June) to avoid hirer impact.
It is estimated to take less than 1 day of effort.
Reach out if you have any concerns with the above change.
Subscribe to our release notes and status page to be notified of future updates.replayWebhookSubscription
mutation with a new eventIds
argument that can be used to replay events by their IDs.mutation (
$webhookSubscription: ReplayWebhookSubscription_SubscriptionInput!
$eventIds: [String!]
) {
replayWebhookSubscription(
input: { webhookSubscription: $webhookSubscription, eventIds: $eventIds }
) {
webhookSubscription {
id {
value
}
}
}
}
String
input fields.
Previously, string lengths were measured and specified in terms of bytes in UTF-8 encoding.
This was stricter than common validation approaches on the web,
including the HTML maxlength
attribute and JavaScript String.length
property .Now, the SEEK API measures and specifies string lengths in terms of Unicode code points or colloquially characters.
This is a closer match to the graphemes visible to an end user,
and should provide more equitable support for other scripts and special characters.See string lengths for more information.ApplicationMethodInput.applicationEmail
field is ignored when posting or updating a job ad.
Remove this field from your requests, even if you are sending a null
value:{
"postingInstructions": [
- {
- "applicationEmail": null
- }
]
}
ApplicationMethod.applicationEmail
field is `null`ed out when querying a job ad.
Remove this field from your requests:query {
positionProfile {
postingInstructions {
applicationMethods {
- applicationEmail {
- address
- }
applicationUri
}
}
}
}
Code | Name |
---|---|
HK | Hong Kong |
ID | Indonesia |
MY | Malaysia |
PH | The Philippines |
SG | Singapore |
TH | Thailand |
locationSuggestions
query, you will automatically receive our new locations and will not have to modify your integration.
If you’re caching locations or using a static mapping to map from your internal location hierarchy,
we will contact you at a future date to refresh your data before we remove support for deprecated locations.hirerId
field.This field is only available on signed webhook subscriptions.
This will allow your software to efficiently filter or forward events on a per-hirer basis for partner-scoped subscriptions instead of requiring a follow up query.ApplicationQuestionInput.questionHtml
field has been increased to 1,000 bytes in UTF-8 encoding.We’ve modified this limit to support compliance questions that are non-trivial to reword due to legal implications;
we still discourage long questions in the general case as they negatively impact the candidate experience.
Note that the increase does not apply to the ApplicationPrivacyConsentInput.descriptionHtml
field.See our questionnaire limits for more information.replayWebhookSubscription
mutation to replay events that were emitted prior to a subscription or a hirer relationship being created.
This allows you to backfill events for a hirer without having to contact SEEK.To accommodate this change, the fields in replayWebhookSubscription
filter input are now mandatory.
In addition, a hirerId
must be provided for partner-scoped subscriptions when the field replayDeliveredEventsIndicator
is true
.This is also available in the Developer Dashboard’s webhooks page and can be triggered by toggling the Include delivered events
checkbox and providing a hirer.AdvertisementDetails
position description has been lowered from 20,000 bytes to 15,000 bytes in UTF-8 encoding.
This aligns the SEEK API with the corresponding limit on the SEEK Employer website .Our analysis of job posting behaviour over the past 6 months indicates that fewer than 0.005% of job ads would be affected.
If your software includes validations for the previous limit you’re encouraged to update to the new limit.containerNode
’s parent.
If you don’t have any preference for the panel’s width, we recommend that you add a max-width: 822px
style to the parent of the containerNode
.<div style="max-width: 822px;">
<div id="seekWidget1ContainerDiv"></div>
</div>
PostedPositionProfile.seekCreatedBySelfIndicator
field allows you to identify whether your software posted a given job ad.See the updated Job ads posted outside of your software documentation for guidance on using this field.CandidateProfile.associatedPositionOpenings
field,
which was generally unintuitive and inefficiently retrieved all position profiles for the opening.The new CandidateProfile.associatedPositionProfile
field allows you to directly select the position associated with a candidate application or profile purchase:query ($id: String!) {
candidateProfile(id: $id) {
+ associatedPositionProfile {
- associatedPositionOpenings {
- positionOpening {
- positionProfiles {
seekHirerJobReference
positionOrganizations {
id {
value
}
}
- positionUri
- }
- }
- positionUri
}
}
}
hiringOrganizations
query and calculating a diff.To make this easier, we’ve introduced a new HirerRelationshipChanged
event type to the SEEK API.
Like existing event types, you can create a webhook subscription that will listen for new HirerRelationshipChanged
events and use them to automatically update your software.A sample event might look like this:{
"events": [
{
"id": "seekAnzPublicTest:event:events:RJrWs6Kw13TvACTTXG6qZg",
"type": "HirerRelationshipChanged",
"createDateTime": "2020-10-20T23:13:58.804Z",
"hirerId": "seekAnzPublicTest:organization:seek:93WyyF1h"
}
],
"subscriptionId": "seekAnzPublicTest:webhookSubscription:events:RNzsabxEX56cuRepCD9A8j",
"url": "https://example.com/webhook"
}
hirerId
contained in the event to get the current state of the relationship from the hiringOrganization
query.For more information, see the events section of the hirer relationships documentation.theme
properties provided to the render method.
All the theme properties are optional and have default values.Here is an example of how to specify the theme properties:SEEKAdPostingWidget.render(document.getElementById('seekWidget1ContainerDiv'), {
mode: 'Create',
onChange: function (event) {},
getAuthToken: function () {
return Promise.resolve('browser token');
},
draftAdvertisement: {
positionTitle: 'Developer',
jobCategoryId: 'seekAnzPublicTest:jobCategory:seek:2EFstqFvP',
positionLocationId: 'seekAnzPublicTest:location:seek:2TCFhBtw9',
hirerJobReference: 'Premium521'
},
theme: {
selectionColor: '#e82b85',
linkColor: '#e82b85',
contractBarPrimaryBackgroundColor: '#e82b85',
contractBarSecondaryBackgroundColor: '#f6d2e0',
errorColor: '#ff0000'
}
});
String
input fields of the createApplicationQuestionnaire
mutation from 2,048 to 255 bytes in UTF-8 encoding.
This aligns with the default limit for the SEEK API.self
query to return information about an access token’s organizations.This can be a convenient alternative to the hiringOrganization
query when working with browser tokens.
Instead of needing to specify the hirer ID explicitly, it returns the SEEK hirer the browser token is scoped to.paymentDueExcludingTax
property in the onChange
callback for the Ad Selection Panel which will give your software the pricing information needed to update invoicing systems if necessary.SEEKAdPostingWidget.render(document.getElementById('seekWidget1ContainerDiv'), {
mode: 'Create',
onChange: function (event) {
const { advertisement } = event;
const { paymentDueExcludingTax } = advertisement;
console.log(`$${paymentDueExcludingTax.value} ${paymentDueExcludingTax.currency} will be invoiced to the hirer`);
},
getAuthToken: function () {
return Promise.resolve('browser token');
},
draftAdvertisement: {...},
});
updateWebhookSubscriptionDeliveryConfiguration
.Webhook subscriptions must be unique based on their schemeId
, eventTypeCode
, hirerId
& url
.
Attempting to create a duplicate webhook subscription with createWebhookSubscription
would correctly return a mutation conflict.
However, we didn’t properly handle updating a webhook subscription’s url
to conflict with an existing subscription.💥 If your software uses updateWebhookSubscriptionDeliveryConfiguration
,
update the selection set to account for this change:mutation($input: UpdateWebhookSubscriptionDeliveryConfigurationInput!) {
updateWebhookSubscriptionDeliveryConfiguration(input: $input) {
- webhookSubscription {
- url
- maxEventsPerAttempt
- }
+ __typename
+ ... on UpdateWebhookSubscriptionDeliveryConfigurationPayload_Success {
+ webhookSubscription {
+ url
+ maxEventsPerAttempt
+ }
+ }
+ ... on UpdateWebhookSubscriptionDeliveryConfigurationPayload_Conflict {
+ conflictingWebhookSubscription {
+ id {
+ value
+ }
+ }
}
}
}
if (
// Option 1: test for existence of conflict field
response.data?.conflictingWebhookSubscription
// Option 2: test name of the response type
response.data?.__typename === 'CreateWebhookSubscriptionDeliveryConfigurationPayload_Conflict'
) {
// Handle conflict here
}
HiringOrganization
object now has a seekApiCapabilities
field.
This allows you to query a hirer’s active relationships and allowed application methods.You can retrieve a HiringOrganization
using either the hiringOrganization
query or the seekAnzAdvertiser
query:hiringOrganizations
query allows you to list all the SEEK hirers you have an active relationship with.
You can optionally filter on the hirer’s name or specific relationship types.You can use this to retrieve a complete list of your SEEK hirers, including their identifiers and API capabilities:String
mutation input fields is now documented in the SEEK API’s request limits.
Exceptions to this default are explicitly documented in the GraphQL schema.An operation containing an input field that exceeds its length limit will receive a BAD_USER_INPUT
error response.PositionProfileClosed
event that’s emitted whenever a job ad has been closed.It’s recommended that you update your software’s internal state based on PositionProfileClosed
events instead of scheduled end dates.
This ensures your software remains synchronised with SEEK, particularly when a hirer contacts our Customer Service team to close a job ad early.This is an example of a webhook body containing a PositionProfileClosed
event:{
"events": [
{
"id": "seekAnzPublicTest:event:events:5dEQGJWnR6mSyUwnL14VGA",
"type": "PositionProfileClosed",
// The date the job ad was closed
"createDateTime": "2019-09-20T21:02:27.101Z",
// This can be passed to the `positionProfile` query to retrieve the job ad's final state
"positionProfileId": "seekAnzPublicTest:positionProfile:jobAd:26d9DVAzs"
}
],
"subscriptionId": "seekAnzPublicTest:webhookSubscription:events:9H6GD9v2o8hQw7aBBG2sAU",
"url": "https://example.com/webhook"
}
updateWebhookSubscriptionDeliveryConfiguration
mutation.
Previously, this mutation required the signingAlgorithmCode
as a mandatory string, which in turn required that secret
was also provided, which meant that the secret string for webhook signing had to be included in every request to update a webhook subscription.
This made simple updates like changing the maxAttemptsPerEvent
unnecessarily difficult.To allow easier update actions, this mutation has been split in two.
To update maxEventsPerAttempt
or url
, continue to use the updateWebhookSubscriptionDeliveryConfiguration
mutation as before.
To make changes to the signing config options, use the new updateWebhookSubscriptionSigningConfiguration
mutation, which takes the signingAlgorithmCode
and secret
options.
Both mutations still return the full WebhookSubscription
.mutation updateWebhookDeliveryConfig(
$webhookSubscriptionId: String!
$url: String!
$maxEventsPerAttempt: Int
) {
updateWebhookSubscriptionDeliveryConfiguration(
input: {
webhookSubscription: {
id: $webhookSubscriptionId
url: $url
maxEventsPerAttempt: $maxEventsPerAttempt
}
}
) {
... on UpdateWebhookSubscriptionDeliveryConfigurationPayload_Success {
webhookSubscription {
id {
value
}
url
maxEventsPerAttempt
}
}
... on UpdateWebhookSubscriptionDeliveryConfigurationPayload_Conflict {
conflictingWebhookSubscription {
id {
value
}
}
}
}
}
seekAnzHirerAdvertisementCreationProducts
, seekAnzHirerAdvertisementModificationProducts
and seekAnzHirerAdvertisementModificationProductsAlt
queries have been extended to include a field named visibilityCode
. It has 3 possible values:Always
indicates that the message should always be visible.ProductSelected
indicates that the message should be visible when the product is selected.ProductNotSelected
indicates that the message should be visible when the product is not selected.query seekAnzHirerAdvertisementProducts(
$advertisementId: String!
$hirerId: String!
$draftAdvertisement: SeekAnzAdProductAdvertisementDraftInput!
) {
seekAnzHirerAdvertisementModificationProducts(
hirerId: $hirerId
advertisementId: $advertisementId
draftAdvertisement: $draftAdvertisement
) {
name
messages {
visibilityCode
content
}
}
}
query seekAnzHirerAdvertisementProducts(
$advertisementId: String!
$hirerId: String!
$draftAdvertisement: SeekAnzAdProductAdvertisementDraftInput!
) {
seekAnzHirerAdvertisementCreationProducts(
hirerId: $hirerId
draftAdvertisement: $draftAdvertisement
) {
...productFields
}
seekAnzHirerAdvertisementModificationProducts(
hirerId: $hirerId
advertisementId: $advertisementId
draftAdvertisement: $draftAdvertisement
) {
...productFields
}
}
fragment productFields on SeekAnzAdProduct {
name
features {
brandingIndicator
searchBulletPointsIndicator
}
}
onChange
event raised by the Ad Selection Panel.SEEKAdPostingWidget.render(document.getElementById('seekWidget1ContainerDiv'), {
mode: 'Create',
onChange: function (event) {
const { advertisement } = event;
const { features } = advertisement;
const { brandingIndicator, searchBulletPointsIndicator } = features;
console.log(`Branding ${brandingIndicator : 'is' : 'is not'} supported`);
console.log(`Search bullet points ${searchBulletPointsIndicator : 'are' : 'are not'} supported`);
if (brandingIndicator) {
// show field to select a brand
} else {
// hide brand field
}
if (searchBulletPointsIndicator) {
// show fields to enter bullet points
} else {
// hide bullet point fields
}
},
getAuthToken: function () {
return Promise.resolve('browser token');
},
draftAdvertisement: {
positionTitle: 'Developer',
jobCategoryId: 'seekAnzPublicTest:jobCategory:seek:2EFstqFvP',
positionLocationId: 'seekAnzPublicTest:location:seek:2TCFhBtw9',
hirerJobReference: 'Premium521',
},
});
replayWebhookSubscription
,
which resends undelivered events from the past 90 days to your subscription endpoint.This makes it easy for you to recover from downtime without building a bespoke replay mechanism on top of the events
query.CandidateProfile
object:certifications
lists certifications and licences the candidate holds.education.descriptions
adds free-text descriptions to the candidate’s education history.createWebhookSubscription
and uploadCandidate
mutations.
If your software creates webhook subscriptions,
update the selection set to account for this change:mutation($input: CreateWebhookSubscriptionInput!) {
createWebhookSubscription(input: $input) {
- webhookSubscription {
- id {
- value
- }
- }
+ __typename
+ ... on CreateWebhookSubscriptionPayload_Success {
+ webhookSubscription {
+ id {
+ value
+ }
+ }
+ }
+ ... on CreateWebhookSubscriptionPayload_Conflict {
+ conflictingWebhookSubscription {
+ id {
+ value
+ }
+ }
}
}
}
if (
- // Old: make assumptions based on semi-structured errors array
- response.errors?.some(
- (err) =>
- err.extensions.code === 'BAD_USER_INPUT' &&
- err.message === 'Subscription already exists',
- )
+ // Option 1: test for existence of conflict field
+ response.data?.conflictingWebhookSubscription
+ // Option 2: test name of the response type
+ response.data?.__typename === 'CreateWebhookSubscriptionPayload_Conflict'
) {
// Handle conflict here
}
CandidateProfile
object:employment
includes multiple roles from the candidate’s employment history,
along with a description of their achievements and responsibilities in each role.education
describes educational programs that the candidate has completed and is currently pursuing.qualifications
lists the self-asserted skills of the candidate.query ($id: String!) {
candidateProfile(id: $id) {
employment {
positionHistories {
descriptions
}
}
education {
educationDegrees {
name
}
}
qualifications {
competencyName
}
}
}