Apply with Indeed
Create and deploy an Apply with Indeed button for Partner ATSs and employers.
- By using this API and its documentation and building an integration, you agree to the Additional API Terms and Guidelines.
Introduction
Apply with Indeed (AWI) enables you to create and deploy an Apply with Indeed button to jobs that you post through either the Job Sync API or XML integration method. After you integrate AWI, job seekers can click an Apply with Indeed button on an employer career page listing to apply with their saved Indeed profile data in their Indeed account.
Prerequisites
Before you start
-
To use AWI, the job must be posted using the Job Sync API or XML feeds and must have Indeed Apply enabled. See the Job Sync API guide or XML feed guide to understand how to post jobs and enable Indeed Apply for a job .
-
Open an Integration Request for AWI.
- To request a new partnership, use this Request Form.
- Indeed generates a
partnerApiTokenfor AWI.
AWI provisioning
Credentials are accessible through the Partner Console.
- Indeed provisions AWI access credentials.
- OAuth token/secret: Use these credentials to generate access tokens that authenticate requests to our GraphQL API.
- Partner API token/secret: Use these credentials for AWI. These credentials are separate from your Indeed Apply API token that you use to post jobs on Indeed. In Partner Console, this token appears as Apply With Indeed Token.
AWI integration options recommendation
Use one of these methods to enable the Apply with Indeed button on ATS pages:
-
Add our SDK/JavaScript to your webpage code for fast and easy development.
Use this method if you can easily make changes to your front-end code and want to leave button design and error handling to the SDK.
-
This method provides more flexibility because it returns an apply form URL that can be integrated anywhere on your webpage.
Use this method if you can easily call indeed GraphQL APIs from your back-end system and don’t mind implementing the button UI and handling errors.
Indeed partners must identify how they are posting jobs to Indeed and enabling Indeed Apply – whether they are using the Job Sync API or XML feed. The input parameters for adding an Apply with Indeed button depend on this distinction.
AWI JavaScript
AWI JavaScript enables the Apply with Indeed button on ATS job pages.
Load the JavaScript
To load the AWI JavaScript into an ATS job page, add a <script> tag to the page, as this code sample shows.
You can also include a <meta charset> tag if necessary for page encoding.
<!DOCTYPE html><html> <head> ... <!-- Load the AWI JavaScript --> <script src="https://apply.indeed.com/indeedapply/static/scripts/app/awi-bootstrap.js"></script> ... </head>...</html>Enable the Apply with Indeed button
After loading the script, you can enable the Apply with Indeed button by adding an HTML element with the appropriate attributes. This code sample shows you how to do that.
Parameters vary depending on which job posting method is used, Job Sync Api or XML feed.
Job Sync API code sample
<!DOCTYPE html><html> <head> ... <!-- Step 1: Load the script --> <script src="https://apply.indeed.com/indeedapply/static/scripts/app/awi-bootstrap.js"></script> ... </head> <body> ... <!-- Step 2: Specify where to display the **Apply with Indeed** button --> <div data-indeed-apply-widget-type="<WIDGET-TYPE>" data-indeed-apply-sourceJobPostingId="<JobId>" data-indeed-apply-partnerApiToken="<PartnerApiToken>" data-indeed-apply-encryptedJobUrl="<Encrypted Job URL>" data-indeed-apply-encryptedContinueUrl="<ContinueURL>" data-indeed-apply-hl="en" data-indeed-apply-co="US" data-indeed-apply-newTab="true" ></div> ... </body></html>XML Feed code sample
<body> ... <!-- Step 2: Specify where to display the **Apply with Indeed** button --> <div data-indeed-apply-widget-type="<WIDGET-TYPE>" data-indeed-apply-encryptedSourceName="<SourceName>" data-indeed-apply-encryptedFeedUrl="<FeedUrl>" data-indeed-apply-encryptedReferenceId="<ReferenceId or ReferenceNumber>" data-indeed-apply-partnerApiToken="<PartnerApiToken>" data-indeed-apply-encryptedJobUrl="<Encrypted Job URL>" data-indeed-apply-encryptedContinueUrl="<ContinueURL>" data-indeed-apply-hl="en" data-indeed-apply-co="US" data-indeed-apply-newTab="true" ></div> ... </body>Specify parameters
Replace the parameters in angle brackets (<>) in the previous code snippet with your values.
Required parameters are different for Job Sync API and XML feed.
This table describes the data-indeed-apply-* attributes:
| Attribute | Required | Encrypted | Description | Example |
|---|---|---|---|---|
Type: String | Required | No | Type of Apply with Indeed button. Today the only supported value is "AWI". | AWI |
Type: String | Required for Job Sync API | No | The Indeed employer job ID, which the Job Sync API generates when you create a job posting. data-indeed-apply-sourceJobPostingId is also referred to as sourcePostingId in Job Sync API guide - Response – Create job posting. | 57caad99-6441-46ec-913c-e018e5013689 |
Type: String | Required for XML feed | Yes | The encrypted Source name of the XML feed, which is the parent organization hiring for the role. | 1d76ab187297cf4c284e2621c2c7462fbfb216704ed0fdc325de0baf6dca5718 |
Type: String | Required for XML feed | Yes | The encrypted feed URL of the XML feed, which is the URL for the job listing on your site. | 0906256350d8ed657d9f70ffe91e84d4a117328ab5d42c22ccbac1689af2d1cb |
Type: String | Required for XML feed | Yes | The encrypted reference ID of the XML feed job, which is the unique identifying number for the instance of the job. | 1d76ab187297cf4c284e2621c2c7462fbfb216704ed0fdc325de0baf6dca5718 |
Type: String | Required | No | Partner API Token | 98922e8fa1355c944b0f7efc6ae9b182ebb1f3ed8ce0b36ea40b33a9b73e2211 |
Type: String | Required | Yes | Encrypted public job description page URL where the Apply with Indeed button was loaded | 0906256350d8ed657d9f70ffe91e84d4a117328ab5d42c22ccbac1689af2d1cb |
Type: String | Optional | Yes | Encrypted continue URL where applicants will be redirected when they click the Continue button on the post apply screen after successfully submitting the application | 0906256350d8ed657d9f70ffe91e84d4a117328ab5d42c22ccbac1689af2d1cb |
Type: String | Optional | Yes | Encrypted exit URL where applicants will be redirected when they exit the Indeed Apply form without completing their application by clicking the exit link in the Indeed Apply form | 0906256350d8ed657d9f70ffe91e84d4a117328ab5d42c22ccbac1689af2d1cb |
Type: String | Optional | No | Language in which apply form is served supported languages | en |
Type: String | Optional | No | Applicant country code [supported countries] | US |
Type: String | Optional | No | Name of JavaScript method that runs when an applicant selects Apply with Indeed | _onClick |
Type: String | Optional | No | Name of JavaScript method that runs after Apply with Indeed button successfully loads | _onButtonReady |
Type: Boolean | Optional | No | Button CSS is not loaded and partners are responsible for styling the button. | true |
Type: Boolean | Optional | No | Whether the application form must be opened in a new tab | false |
Some of the above parameters need to be encrypted using the secret associated with the partnerApiToken.
Callback methods
onClick:- The callback method accepts the
HTMLElementbutton as the only argument. This callback is called with theHTMLElementbutton.
- The callback method accepts the
onReady:- The callback method accepts two arguments:
HTMLElementbutton andbuttonLoadStatus.buttonLoadStatusis an object that contains these fields:success: Whether the button load succeeds or failsmessage: success/error messageerror_code: error code when the button load fails
- The callback method accepts two arguments:
Handle attribute encryption
- When you provide any attribute with
yesin the Encrypted column in the previous table, you encrypt the attribute. To encrypt the attribute, use the AES algorithm with your 128-bit secret key, which is the secret associated with the generatedpartnerApiToken. The cipher mode is CBC with PKCS5 padding. The initialization vector is 16 bytes of 00. - To encrypt the attribute:
- Use the first 16 bytes of your secret key to generate a 128-bit secret key. Your secret key is the secret associated with the generated
partnerApiToken. - Read the bytes of the plain-text attribute encoded in UTF-8.
- Encrypt the attribute using the AES algorithm and your 128-bit key. Be sure to use CBC mode and PKCS5 padding.
- Convert the encrypted bytes to a hex string.
- Use this hex string as your
data-indeed-apply-{attribute-name}attribute. - Use the encrypted data in place of the
plain-textattribute. Indeed Apply recognizes that you are sending encrypted data.
- Use the first 16 bytes of your secret key to generate a 128-bit secret key. Your secret key is the secret associated with the generated
- To encrypt and decrypt data, please refer to the following sample:
import java.nio.charset.Charset;import java.lang.RuntimeException;import javax.crypto.Cipher;import javax.crypto.spec.*;import javax.crypto.spec.SecretKeySpec;
public class EncryptionTest {
public static void main(String[] args) {
String url = "YOUR_URL"; String apiSecret = "YOUR_API_SECRET"; String encrypted_url = encrypt(url, apiSecret); String decrypted_url = decrypt(encrypted_url, apiSecret);
System.out.println(encrypted_url); System.out.println(decrypted_url); }
static String encrypt(String message, String apiSecret) { try { byte[] keyBytes = apiSecret.getBytes(Charset.forName("UTF-8")); byte[] message_bytes = message.getBytes("UTF-8"); SecretKeySpec key = new SecretKeySpec(keyBytes, 0, 16, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); IvParameterSpec ivspec = new IvParameterSpec(new byte[] { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }); cipher.init(Cipher.ENCRYPT_MODE, key, ivspec); byte[] email_encrypted = cipher.doFinal(message_bytes); return bytesToHexString(email_encrypted); } catch (Exception e) { System.out.println(e.getMessage()); throw new RuntimeException(e); } }
static String decrypt(String message, String apiSecret) { try { byte[] keyBytes = apiSecret.getBytes(Charset.forName("UTF-8")); byte[] message_bytes = message.getBytes(Charset.forName("UTF-8")); message_bytes = decodeHex(message_bytes); SecretKeySpec key = new SecretKeySpec(keyBytes, 0, 16, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); IvParameterSpec ivspec = new IvParameterSpec(new byte[] { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }); cipher.init(Cipher.DECRYPT_MODE, key, ivspec); byte[] email_decrypted = cipher.doFinal(message_bytes); return new String(email_decrypted, "UTF-8"); } catch (Exception e) { System.out.println(e.getMessage()); throw new RuntimeException(e); } }
static String bytesToHexString(byte[] in) { final StringBuilder builder = new StringBuilder(); for (byte b: in) { builder.append(String.format("%02x", b)); } return builder.toString(); }
static byte[] decodeHex(byte[] data) throws Exception { String text = new String(data, "UTF-8"); char[] chars = text.toCharArray();
int len = chars.length; byte[] out = new byte[len >> 1]; int i = 0;
for (int j = 0; j < len; ++i) { int f = toDigit(chars[j], j) << 4; ++j; f |= toDigit(chars[j], j); ++j; out[i] = (byte)(f & 255); } return out; }
static int toDigit(char ch, int index) throws Exception { int digit = Character.digit(ch, 16); if (digit == -1) { throw new Exception("Illegal hexadecimal character " + ch + " at index " + index); } else { return digit; } }}Job Sync API sample data
<divdata-indeed-apply-widget-type="<WIDGET-TYPE>"data-indeed-apply-sourceJobPostingId="<JobId>"data-indeed-apply-partnerApiToken="<PartnerApiToken>"data-indeed-apply-encryptedJobUrl="b18d0be4c173dfa2b7cb7856e7c7b6f02a563867a9df67ca208c8b9654966299"data-indeed-apply-encryptedContinueUrl="417856e7c173dfa2b7cb7856e7c7b6f02a563867a9df67ca208c8b9654966299"data-indeed-apply-encryptedExitUrl="2b7cb78563dfa2b7cb7856e7c7b6f02a563867a9df67ca208c8b9654966299"></div>XML feed sample data
<divdata-indeed-apply-widget-type="<WIDGET-TYPE>"data-indeed-apply-encryptedSourceName="1d76ab187297cf4c284e2621c2c7462fbfb216704ed0fdc325de0baf6dca5718"data-indeed-apply-encryptedFeedUrl="b18d0be4c173dfa2b7cb7856e7c7b6f02a563867a9df67ca208c8b9654966299"data-indeed-apply-encryptedReferenceId="<ReferenceId>"data-indeed-apply-partnerApiToken="<PartnerApiToken>"data-indeed-apply-encryptedJobUrl="b18d0be4c173dfa2b7cb7856e7c7b6f02a563867a9df67ca208c8b9654966299"data-indeed-apply-encryptedContinueUrl="417856e7c173dfa2b7cb7856e7c7b6f02a563867a9df67ca208c8b9654966299"data-indeed-apply-encryptedExitUrl="2b7cb78563dfa2b7cb7856e7c7b6f02a563867a9df67ca208c8b9654966299"></div>Do not include multiple URLs in any attribute field (encryptedJobUrl, encryptedContinueUrl, encryptedExitUrl, encryptedFeedUrl) for your job in your button configuration. Including multiple URLs results in an error, which displays the Apply with Indeed button in a grey, deactivated state.
Button design
This image shows a successful Apply with Indeed button.
This image shows an unsuccessful Apply with Indeed button.
If an issue occurs, see the AWI Javascript-specific errors and troubleshooting guide.
The generated Apply With Indeed button should match the size and presentation of the other Apply buttons.
applyUrlForEmployers mutation
Use this mutation to create an Indeed Apply URL for an Apply with Indeed button load. This should be called on every Apply with Indeed button load.
Integrate with Indeed APIs
When you become an Indeed partner, Indeed sets up an app for your integration. Sign in to Partner Console to view your app and OAuth credentials (client ID, secret, and authorization code for 3-legged OAuth). Exchange credentials for an access token to authenticate API calls.
Create Apply with Indeed URL
To create an Apply with Indeed URL (otherwise known as, Indeed Apply URL), call the ApplyUrlMutations.applyUrlForEmployers mutation. Provide inputs to the mutation to identify the specific job for which the Apply with Indeed button is required. The inputs for XML feed differ from those for Job Sync API.
Job Sync API inputs
sourcedPostingId*: the Indeed employer job ID, which the Job Sync API generates when you create a job postingjobUrl*: the public job description page URL where the Apply with Indeed button was loadedcontinueUrl: the continue URL where applicants are redirected when they click the Continue button on the success screenexitUrl: the exit URL where applicants are redirected when they exit the Indeed Apply form
* - required inputs
XML feed inputs
sourceName*: the parent organization name hiring for the role (e.g. Test Company Name, Indeed Japan)feedUrl*: the feed URL of your XML jobsreferenceId*: the <referenceNumber> or <referenceId> of the XML feedjobUrl*: the public job description page URL where the Apply with Indeed button was loadedcontinueUrl: the continue URL where applicants are redirected when they click the Continue button on the success screenexitUrl: the exit URL where applicants are redirected when they exit the Indeed Apply form
* - required inputs
The Apply with Indeed URL needs to be generated every time an Apply with Indeed button is rendered. The URL is not reusable and it is valid only once.
Request
Job Sync API request code sample
mutation { applyUrl { createApplyUrlForEmployers( input: { jobId: { sourceJobPostingId: "jobId" } jobUrl: "http://example.com/careers/job1.html" continueUrl: "http://example.com/careers/indeedapply-continue.html" exitUrl: "http://example.com/careers" } ) { applyUrl } }}XML feed request code sample
mutation { applyUrl { createApplyUrlForEmployers( input: { xmlFeedParams: { sourceName: "sourceName", feedUrl: "feedUrl", referenceId: "referenceNumber" } jobUrl: "http://example.com/careers/job1.html" continueUrl: "http://example.com/careers/indeedapply-continue.html" exitUrl: "http://example.com/careers" } ) { applyUrl } }}The mutation returns an applyUrl, which you can use on the Apply with Indeed button on the ATS job page.
Response
The following is a response code sample.
{ applyUrl: "https://smartapply.indeed.com/beta/indeedapply/applybyapplyablejobid?indeedApplyableJobId=b957be31-16ed-4f65-9376-cf383594eee5-Y21ocWEx"}Headers
| Header | Meaning | Required / Optional | Details | Example |
|---|---|---|---|---|
authorization | Access token | Required | Provides authorization for accessing mutation. Get an access token | Bearer eyJrEIOeWQiOiI5NzVkOWZkMC01NzE3LTQzMzQtOTM |
indeed-co | Country | Optional | The country for this request [supported countries] | US |
indeed-locale | Locale | Optional | The client’s locale for the originating request | en-US (format) |
indeed-user-agent | Applicant’s user agent string | Optional | The user-agent for the originating browser request | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 |
indeed-user-ip | Applicant’s IP | Optional | The client’s IP for the originating browser request | 192.168.0.0 |
Integrate button design with mutation
Mutation clients can use the script provided below to enable button CSS provided by Indeed.
<!DOCTYPE html><html><head> ... <!-- Step 1: Load the script --> <script src="https://apply.indeed.com/indeedapply/static/scripts/app/buttonStyles.js" ></script></head><body> ... <!-- Step 2: Specify data-style as indeed-apply-button for the button where you want to enable button style --> <button data-style="indeed-apply-button">Apply Now</button></body></html>This image shows the Apply with Indeed button after applying the CSS by using the previous script.
To disable the button in case of any failures, you can add the attribute aria-disabled=true to the button element.
<!-- Set aria-disabled attribute to true to disabled the button --><button data-style="indeed-apply-button" aria-disabled=true>Apply Now</button>This image shows the Apply with Indeed button after applying the attribute by using the previous script.
Button translations
To change the language for the Apply with Indeed button, specify the language in the script by using a query parameter (that is, hl=ja or hl=es). Use the [supported languages] for providing values for the hl query parameter.
<!DOCTYPE html><html><head> ... <!-- Step 1: Specify query parameter --> <script src="https://apply.indeed.com/indeedapply/static/scripts/app/buttonStyles.js" ></script></head><body> ... <!-- Step 2: Specify data-style as indeed-apply-button for the button where you want to enable button style --> <button data-style="indeed-apply-button">Apply Now</button></body></html>This image shows the Japanese Apply with Indeed button after applying the attribute by using the previous script.
Troubleshoot errors
When a request fails, the data field is null and the errors field contains information about the failure. Common errors include GRAPHQL_PARSE_FAILED, BAD_USER_INPUT (with sub-codes such as JOB_NOT_FOUND, PARTNER_DATA_NOT_FOUND), and INTERNAL_SERVER_ERROR.
If a request fails and you do not receive a URL, retry the request without showing the Apply with Indeed button. When you receive a URL, enable the button again.
For detailed error descriptions, sub-codes, and resolution steps, see Troubleshoot Indeed Apply errors.