Job Sync API guide (BETA)

Use the Job Sync API to submit job postings to Indeed, and update or expire those job postings in Indeed.

🚧

Closed BETA:

During BETA, Indeed can support a limited number of ATS partners.

Indeed maintains a waiting list. To indicate your interest, submit an integration request. Indeed keeps the request on file and will reach out when ready to onboard you.

📘

Note:

By using this API and its documentation and building an integration, you agree to the Additional API Terms and Guidelines.

Job Sync API reference

For Job Sync API reference information, see the Job Sync API reference.

Before you start

Use the client credentials flow (2-legged OAuth) to get a client ID and secret for your application, which you exchange for an access token. Use this token for authentication when you call the Job Sync API. The token expires after one hour.

To call the API, POST the request to the following endpoint:

POST https://apis.indeed.com/graphql

📘

Note:

Use the POST method for all queries and mutations. The API does not support the GET method.

In the POST request body, include the mutation or query, an optional operation name, and variable inputs:

{
  "query": "...",
  "operationName": "...",
  "variables": {
    "myVariable": "someValue",
    ...
  }
}

Job Sync API overview

📘

Note:

For information about how to authenticate and call the API, see Before you start.

Use the Job Sync API to submit job postings to Indeed, and update or expire those job postings in Indeed.

To submit a job posting, you provide details about the job. In addition to a job title, description, location, and benefits for the job, you provide details about the job source, including the sourceName.

The sourceName is the name for a group of jobs, such as a parent organization, that are managed together and that is hiring for the role. Choose a unique sourceName for each client delineation that you have.

So, if an employer has multiple job groups that separate people manage, choose a unique sourceName for each job group. For example, if subsidiaries or franchises exist with multiple branded locations under the same company, those jobs have the same value in the sourceName field. The sourceName must be unique across all job groups. A sourceName can have only one sourceType, which is the type of organization.

The API accepts a complete job posting. If accepted, the API returns an Indeed employer job ID, which is the unique ID for the posting, in the sourcedPostingId field. Pending spam and fraud detection, Indeed indexes and makes the job available on Indeed in from minutes to hours.

The API rejects the job posting if it has missing or malformed data, which causes an error at call time. The API returns null in the sourcedPostingId field and an error in the standard GraphQL errors array.

To update a job posting, provide the same values for the jobPostingId and sourceName fields and OAuth client ID that you used when you submitted the job posting. You must also provide all required job details even if you are not changing those. The API returns the same unique ID, the Indeed employer job ID, that Indeed generated for the submitted job posting.

To expire a job posting, provide the same Indeed employer job ID that Indeed generated for the submitted job posting in the sourcedPostingId field. The API returns an internal tracking ID from logrepo and a response code that indicates the success or failure of the operation.

📘

Note:

Jobs that you manage through the Job Sync API support the same Indeed Apply capabilities that the Indeed Apply XML feed supports.

Submit a job posting

createSourcedJobPostings(input: 
  CreateSourcedJobPostingsInput): 
  CreateSourcedJobPostingsPayload

To submit a job posting, call the createSourcedJobPostings mutation with the CreateSourcedJobPostingsInput input object. In the jobPostings field in this input object:

  • The body and metadata fields are required
  • The applyMethod field is optional

Provide a job title, description, location, benefits for the job, details about the job source, including the source name. The sourceName is the name for a group of jobs, such as a parent organization, that are managed together and that is hiring for the role. Choose a unique value for each client delineation that you have. So, if an employer has multiple job groups that separate people manage, choose a unique value for each job group. For example, if subsidiaries or franchises exist with multiple branded locations under the same company, those jobs have same value in the sourceName field. The sourceName must be unique across all job groups and can have only one sourceType, which is the type of organization.

Mutation {
  createSourcedJobPostings(input: {
    jobPostings: [{
      body: {
        title: "title 1"
        description: "description 1"
        location: {
          country: "US"
          cityRegionPostal: "Syracuse, New York 13209"
        }
        benefits: []
      }
      metadata: {
        jobSource: {
          companyName: "Company"
          companyWebsite: "https://www.mycompany.com"
          sourceName: "Source"
          sourceType: "Employer"
          contacts: {
            contactType: "contact"
            contactInfo: {
              contactEmail: "[email protected]"
            }
          }
        }
        jobPostingId: "JobId1"
        datePublished: "2023-01-02T12:00Z"
        url: "http://example.com/careers/job1.html"
      }
    }]
  }) {
    results {
      jobPosting {
        sourcedPostingId
      }
    }
  }
}

The API returns the CreateSourcedJobPostingsPayload return type with a unique sourcedPostingId that Indeed generates for each submitted job posting.

The value in sourcedPostingId depends on whether the API accepts or rejects the posting:

  • The API accepts a complete job posting. The sourcedPostingId value is the Indeed employer job ID, which you use to expire the job. Pending spam and fraud detection, Indeed indexes and makes the job available on Indeed in from minutes to hours.
  • The API rejects the job posting if it has missing or malformed data, which causes an error at call time. The sourcedPostingId value is null, and the API returns an error in the standard GraphQL errors array.

Update a job posting

createSourcedJobPostings(input: 
  CreateSourcedJobPostingsInput): 
  CreateSourcedJobPostingsPayload

To update a job posting, call the createSourcedJobPostings mutation with the CreateSourcedJobPostingsInput input object. In the jobPostings field in the input object:

  • The body and metadata fields are required
  • The applyMethod field is optional

In the input object, you must specify the same values for the jobPostingId and sourceName fields and OAuth client ID that you used when you submitted the job posting. You must specify all required job details even if you are not changing those.

Mutation {
  createSourcedJobPostings(input: {
    jobPostings: [{
      body: {
        title: "title 1"
        description: "description 1"
        location: {
          country: "US"
          cityRegionPostal: "Syracuse, New York 13209"
        }
        benefits: []
      }
      metadata: {
        jobSource: {
          companyName: "Company"
          sourceName: "Source"
          sourceType: "Employer"
        }
        jobPostingId: "JobId1"
        datePublished: "2023-01-02T12:00Z"
        url: "http://example.com/careers/job1.html"
      }
    }]
  }) {
    results {
      jobPosting {
        sourcedPostingId
      }
    }
  }
}

The mutation returns the CreateSourcedJobPostingsPayload return type with the same sourcedPostingId value that Indeed generated for the job posting when it was submitted. This value is the Indeed employer job ID, which you use to expire the job.

Expire a job posting

expireSourcedJobsBySourcedPostingId(input: 
  ExpireSourcedJobsBySourcedPostingIdInput!): 
  ExpireSourcedJobsBySourcedPostingIdPayload

Call the API by using the expireSourcedJobsBySourcedPostingId mutation with the ExpireSourcedJobsBySourcedPostingIdInput input object with the sourcedPostingId from the submitted job posting.

Mutation {
  expireSourcedJobsBySourcedPostingId(input: {
      jobs: {
        sourcedPostingId: "JobId1"
      }
    }]
  }) {
    results {
      trackingKey
    }
  }
}

The mutation returns the ExpireSourcedJobsBySourcedPostingIdPayload return type with a trackingKey, which is an internal tracking ID from logrepo, and the ExpireSourcedJobResultInfo object, which includes the unique job ID.

Indeed does not verify whether the job exists before responding. The response is always ACCEPTED.

Frequently asked questions

How does this API differ from the Indeed Apply XML feed?

Jobs that you manage through the Job Sync API support the same Indeed Apply capabilities that the Indeed Apply XML feed supports. If you're being sent to this guide, use the Job Sync API to submit job postings to Indeed rather than building an XML integration.

How do I update a job?

Call the Job Sync API with the updates to your job. You must specify the same values for the jobPostingId and sourceName fields and OAuth client ID that you used when you submitted the job posting.

Indeed deduplicates on those two fields to determine uniqueness. You must specify all required job details even if your are not changing those.

How do I reactivate an expired job?

Call the Job Sync API with the same jobPostingId and sourceName as the expired job, just as if you were updating an open job. To reflect the date the job was reopened in your ATS, update the datePublished field value.

📘

Important:

You can reactivate a job for 30 days after it's expired. After that time, Indeed might archive statistics and configuration related to the job, though you might receive the same sourcedPostingId.

How do I define a salary range or a fixed salary?

To define a salary range, enter the minimum salary in the minimumMinor field, and enter the maximum salary in maximumMinor field.

To define a salary with a minimum salary only, enter the minimum salary in the minimumMinor field.

To define a fixed salary, enter the fixed salary in the minimumMinor and maximumMinor fields.

How do I add a client/employer?

Create the jobs with a unique sourceName for that client.

The sourceName is the name for a group of jobs, such as a parent organization, that are managed together and that is hiring for the role. Choose a unique source name value for each client delineation that you have.

So, if an employer has multiple job groups that separate people manage, choose a unique value for each job group. For example, if subsidiaries or franchises exist with multiple branded locations under the same company, those jobs have the same value in this field. The value must be unique across all job groups and can have only one sourceType, which is the type of organization.

For example, to create uniqueness among branches that manage their jobs separately, follow this example.

The ConvenienceMart company has two branches and three stores. So that these branches and stores can manage their jobs separately, define the following combinations of companyName and sourceName fields:

Branch Store companyName and sourceName definitions
Tokyo Shibuya station
companyName: "ConvenienceMart Tokyo branch, Shibuya station store"
sourceName: "ConvenienceMart Tokyo branch, Shibuya station store"
Shinjuku station
companyName: "ConvenienceMart Tokyo branch, Shinjuku station store"
sourceName: "ConvenienceMart Tokyo branch, Shinjuku station store"
Osaka Osaka station
companyName: "ConvenienceMart Osaka branch, Osaka station store"
sourceName: "ConvenienceMart Osaka branch, Osaka station store"

How long before a job posting appears on Indeed?

Most jobs take from one to two hours to become searchable by job seekers.

What data do I include in jobPostingId and jobRequisitionId?

Include this data in the jobPostingId and jobRequisitionId fields:

Field Value
jobPostingId

Unique ID across your ATS. Can be a UUID if you use one.

If you repost a job and persist this ID, you can open a previously expired job.

jobRequisitionId

Human-readable ID, and not required to be unique across the ATS.

Ideally, unique ID across one of your clients, bounded by sourceName.

The recruiter likely remembers this ID when they distinguish two jobs with the same title.

See also