Send Candidates API guide
Sync candidate applications with Indeed.
By using this API and its documentation and building an integration, you agree to the Additional API Terms and Guidelines.
API overview
The Send Candidates API submits and tracks candidate applications in three steps: initialize, upload attachments, and submit.
Initializing stages an application version with Indeed, generates attachment upload URLs, and returns a unique applicationVersionId. You then have five minutes to upload attachments and submit.
The applicationIdentifier object contains the fields that uniquely identify an application:
| Field | Required | Description |
|---|---|---|
indeedRegistrationId | ✅ | Unique ID linking an Indeed employer to a partner employer. Provided during registration. |
atsCandidateId | ⬜ | ID for a candidate profile associated with one or more ATS applications. |
atsApplicationId | ✅ | Unique ID for the application in the ATS. |
job.sourcedPostingId | ✅ | Job posting ID that createSourcedJobPostings returns. |
Together these fields define one application, and each initialize call with the same applicationIdentifier creates a new version of it. Every field counts, including the optional ones: an application with an atsCandidateId differs from one that omits it, even if all other fields match.
When you upload attachments:
- Each file must be 6 MB (6,291,456 bytes) or less, and all attachments together 15 MB (15,728,640 bytes) or less.
- Each attachment must have a valid Base64-encoded MD5 checksum, and no two may share the same hash.
- Include at most one
RESUMEand oneCOVER_LETTER. UseOTHER_RESUMEorOTHER_COVER_LETTERfor additional files. - Indeed scans every attachment and removes unsafe files.
Indeed does not publish answers about protected demographic information, such as race, gender, age, or disability status.
Deleting an application permanently removes it and all its versions from Indeed. You cannot reinitialize it.
Avoid concurrent mutations (initialize, submit, delete) on the same application. Rapid successive calls can cause race conditions, unexpected data states, and uncertainty about which version is published.
API steps
After you integrate the Send Candidates API, complete these steps to sync candidate applications with Indeed.
Optionally, delete application to permanently remove an application and all its versions.
1. Authenticate
When you become an Indeed partner, Indeed creates an app for your integration. Sign in to Partner Console (opens in a new window) to view the app and your OAuth credentials: client ID, secret, and a 3-legged OAuth authorization code. Exchange those credentials for an access token to authenticate API calls.
Each Candidate Sync API operation requires an OAuth token:
| API and operations | OAuth token type |
|---|---|
| Authenticate with a 3-legged OAuth token that represents an employer and has the employer.ats_candidate.sync scope. This token links the employer's Indeed account to their ATS account. An Indeed administrator or owner must create it. If registerEmployer returns a missing scope error, the token might not be associated with an employer. |
| Authenticate with a 2-legged OAuth token, which requires no user interaction. |
Securely store access tokens in your ATS, and don't share them between users. Indeed trusts that your system is the source of truth for a job. If you use a user's access token for a job that another user posted, Indeed might grant that user access to the other user's job on Indeed.
After you get an access token, include this token in the query or mutation. Indeed recommends that you refresh your access tokens before they expire to avoid asking users to sign in every time they need to view updated job statuses.
See Integrate with Indeed and call APIs and Scopes.
2. Register employer
The Employer Registration API enables you to register an employer.
Request – Register employer
To register an employer and return registration information, call registerEmployer.
Authenticate with a 3-legged OAuth token that represents an employer and has the employer.ats_candidate.sync scope. This token links the employer's Indeed account to their ATS account. An Indeed administrator or owner must create it. If registerEmployer returns a missing scope error, the token might not be associated with an employer.
Provide these input fields in RegisterEmployerInput:
| Field | Required | Description |
|---|---|---|
Type: | ✅ | An ID you provide to uniquely identify the employer. You can register one |
Type: | ✅ | The name you provide for the employer. Employers see this name on Indeed. |
Response – Register employer
The API returns an EmployerRegistration. Store its id for later Candidate Sync API calls, or query findRegisteredEmployers with the partnerEmployerId to get it again.
3. Update registration
Update the registration to enable features.
4. Initialize application and upload attachments
Stage an application version with Indeed, generate attachment upload URLs, and upload files to those URLs.
Request — Initialize application
To initialize an application, call initialize.
Authenticate with a 2-legged OAuth token. Your application authenticates directly with Indeed's authorization server without user interaction.
To identify the employer on Indeed, set indeedRegistrationId (opens in a new window) to the id that registerEmployer returns.
The employer must have the sendApplications feature enabled.
For information about managing these IDs, see Employer Registration API.
Provide these input fields:
| Field | Required | Description |
|---|---|---|
| ✅ | Unique ID for the application on Indeed. | |
| ✅ | Complete applicant details. | |
Type: | ⬜ | Screener questions and applicant answers, each as a plain text string. |
| ✅ | Current application disposition status. See Indeed standard disposition statuses for mapping examples. | |
|
Type: | ✅ | Direct link to the application in your system. |
|
Type: | ⬜ | Direct link to the candidate profile in your system. |
mutation InitializeApplication($input: InitializeAtsSyncCandidateSyncApplicationInput!) { atsSyncCandidateSync { application { initialize(input: $input) { applicationVersionId attachments { fileType fileName contentType contentLength fileChecksum { checksum } url } } } }}Response — Initialize application
| Field | Description |
|---|---|
|
Type: | New application version, used when submitting. |
| Uploads file data for each attached file. |
For each attachment returned in the initialize response, upload the file data with a PUT request to url. Include these headers matching the applicant.attachments values from the initialize mutation:
| Header | Value source | Description |
|---|---|---|
Content-Type | contentType | Original media type of the file attachment. |
Content-Length | contentLength | File size in bytes. |
Content-MD5 | fileChecksum.checksum | MD5 hash. Base64-encode the |
5. Submit application
Authenticate with a 2-legged OAuth token. Your application authenticates directly with Indeed's authorization server without user interaction.
Submit an application version to Indeed. Versions are published asynchronously in submission order.
To identify the employer on Indeed, set indeedRegistrationId to the id that registerEmployer returns.
The employer must have the sendApplications feature enabled.
For information about managing these IDs, see Employer Registration API.
Request — Submit application
To submit an application, call the application.submit mutation.
Provide these input fields:
| Field | Required | Description |
|---|---|---|
|
Type: | ✅ | Links to the Indeed employer account. |
|
Type: | ✅ | Version ID that application.initialize returns. |
mutation SubmitApplication($input: SubmitAtsSyncCandidateSyncApplicationInput!) { atsSyncCandidateSync { application { submit(input: $input) { applicationVersionId } } }}Response — Submit application
| Field | Description |
|---|---|
|
Type: | Same as the input value. Log for audit purposes if needed. |
Call within five minutes of initialization, and upload all attachments first. You can still submit when an attachment is missing or failed to process, but findStatuses returns a FILE_NOT_UPLOADED error. Processing is asynchronous but maintains submission order.
6. Track application status
Authenticate with a 2-legged OAuth token. Your application authenticates directly with Indeed's authorization server without user interaction.
After submission, query application version status to check processing and identify errors.
Request — Find application status
To query application version status with pagination, call findStatuses.
Use this query to track publishing progress and check bulk status with version history.
| Field | Filters by |
|---|---|
|
Type: | Employers. |
| Application IDs. | |
|
Type: | Application versions. |
|
Type: | Statuses. |
query FindApplicationStatuses($input: AtsSyncCandidateSyncApplicationFindStatusesInput!$first: Int $after: String $last: Int $before: String) { atsSyncCandidateSync { application { findStatuses(input: $input first: $first after: $after last: $last before: $before) { applicationVersionStatuses { applicationVersionId applicationIdentifier { indeedRegistrationId atsCandidateId atsApplicationId job { sourcedPostingId } } status processingStatus errors } pageInfo { hasNextPage hasPreviousPage startCursor endCursor } } } }}7. Delete application
Authenticate with a 2-legged OAuth token. Your application authenticates directly with Indeed's authorization server without user interaction.
Permanently remove an application and all its versions from Indeed.
Request — Delete application
To delete an application, call the application.delete mutation.
This operation is permanent. All application versions are removed from Indeed, and you cannot create versions afterward.
To identify the employer on Indeed, set indeedRegistrationId (opens in a new window) to the id that registerEmployer returns.
The employer must have the sendApplications feature enabled.
For information about managing these IDs, see Employer Registration API.
| Field | Required | Description |
|---|---|---|
| ✅ | Unique ID for the application. | |
|
Type: | ✅ | Timestamp when the application was deleted. |
mutation DeleteApplication($input: DeleteAtsSyncCandidateSyncApplicationInput!) { atsSyncCandidateSync { application { delete(input: $input) { applicationVersionId } } }}Response — Delete application
| Field | Description |
|---|---|
|
Type: | Unique ID for this deletion. References the final version of the deleted application. |
See also
Guides
- Best practices — Recommendations for using the API.
- Data types and file handling — Handle data types, file attachments, and upload requirements.
- Troubleshoot GraphQL errors — Diagnose GraphQL errors returned by the API.
GraphQL API references
registerEmployer— Registers an employer. Authenticate with a 3-legged OAuth token that represents an employer and theemployer.ats_candidate.syncscope.application.initialize— Stages an application version for publishing to Indeed. Authenticate with a 2‑legged OAuth token.application.submit— Submits an application version to Indeed for publishing. Authenticate with a 2‑legged OAuth token.findStatuses— Returns the status of each application version. Authenticate with a 2‑legged OAuth token.application.delete— Permanently deletes an application and all its versions from Indeed. Authenticate with a 2‑legged OAuth token.