This document has moved to the new Indeed Developer Portal. Please update your records accordingly.

Direct Employer Integration with Indeed

This resource contains integration instructions for direct employers. Any direct client that wants to provide an XML with or without an integration should follow these guidelines. Third party partners that represent a direct employer (i.e. staffing agency, RPO, programmatic platform, or advertising agency) should follow the XML guidelines outlined on this page.

How To Use This Resource

To successfully integrate with Indeed, please review this self-service topic completely. If you have any questions, you can reach out to your Client Success representative. If you don’t have a designated representative, contact us using this web form.

It is important that you complete your integration in the following order:

  1. XML Job Feed
  2. Adding Indeed Apply
  3. Application Data Delivery and Screener Questions
  4. Test your integration end-to-end and make sure you have ongoing monitoring on your side for XML reliability, Indeed Apply delivery, and screener question retrieval.

(Go back to the top)


XML Job Feed

The Indeed XML feed lists job information that will be displayed on Indeed. By maintaining an XML feed, you have greater control over how jobs are displayed. You can also choose to add the Indeed Apply label to jobs.

Using the XML feed

Create and maintain an XML document containing all job information. Indeed monitors the file for changes in one of three ways:

  • Crawling an XML URL
  • Crawling a client-hosted FTP site (SFTP also supported)
  • Receiving the file directly in an Indeed FTP server (zipped files recommended)

Important: You must include all jobs hosted on your career page in the XML feed. Indeed does not accept incomplete XML feeds and does not support partial opt-in of jobs. An XML file that does not include all jobs may be rejected or receive limited exposure to job seekers. All information available to job seekers from your website should be included in the XML. For example, if you list salary on your jobs, then you must include an element for that piece of data, i.e., <salary>. Salary information is not required for indexing if it is not available to job seekers on your website.

XML feed example

The following example shows a basic XML feed containing one job.

Example: Basic XML feed


<?xml version="1.0" encoding="utf-8"?>
<source>
    <publisher>Example Job Site</publisher>
    <publisherurl>http://www.example.com</publisherurl>
    <lastBuildDate>Fri, 10 Dec 2008 22:49:39 GMT</lastBuildDate>
    <job>
        <title><![CDATA[Sales Executive]]></title>
        <date><![CDATA[Fri, 19 Dec 2014 22:49:39 GMT]]></date>
        <referencenumber><![CDATA[unique123131]]></referencenumber>
        <url>
            <![CDATA[http://www.examplesite.com/viewjob.cfm?jobid=unique123131&source=Indeed]]>
        </url>
        <company><![CDATA[ABC Hospital]]></company>
        <city><![CDATA[Phoenix]]></city>
        <state><![CDATA[AZ]]></state>
        <country><![CDATA[US]]></country>
        <postalcode><![CDATA[85003]]></postalcode>
        <streetaddress><![CDATA[123 fake street Phoenix AZ, 85003]]
        <email><![CDATA[example@abccorp.com]]></email>
        <description>
            <![CDATA[Do you have 1-3 years of sales experience? Are you
            relentless at closing the deal? Are you ready for an exciting and
            high-speed career in sales? If so, we want to hear from you! [...]
            We provide competitive compensation, including stock options and a full
            benefit plan. As a fast-growing business, we offer excellent opportunities
            for exciting and challenging work. As our company continues to grow, you
            can expect unlimited career advancement! ]]>
        </description>
        <salary><![CDATA[$50K per year]]></salary>
        <education><![CDATA[Bachelors]]></education>
        <jobtype><![CDATA[fulltime, parttime]]></jobtype>
        <category><![CDATA[Category1, Category2, CategoryN]]></category>
        <experience><![CDATA[5+ years]]></experience>
        <remotetype><![CDATA[COVID-19]]></remotetype>
        <indeed-apply-data>COVERED IN A LATER SECTION</indeed-apply-data>
    </job>
</source>

XML feed elements

The XML feed contains basic elements, used once per feed, and a set of job elements that are used for each job in the feed.

Basic elements


Basic elements table
Element Required Description Example value
<?xml ?> Yes XML Declaration <?xml version="1.0" encoding="utf-8"?>
<source> Yes The root node for the XML feed document.
<publisher> No The name of the company publishing this job. Company Name
<publisherurl> No The URL of the company publishing this job. http://www.example.com
<job> Yes All metadata specific to a job. Include one <job> element for each job to be displayed on Indeed. See following section for details.

Job elements

Note:

  • Job descriptions should be provided inside <![CDATA[]]> sections as raw HTML, just as it would be on the original website. The HTML should be provided as raw characters (<,>,&) and not as XML entities/ escaped characters (&amplt;, &ampgt;, &ampamp;).
  • If clients do not adhere to the following guidance, their jobs may not be included in Indeed search results. Jobs that are missing required fields or that do not meet Indeed Quality rules may be discarded or hidden. Clients should review Indeed Quality rules if they have any concerns over their postings. Clients in need of assistance should contact Indeed via our employer pages.

Job elements table
Element Required Description Example value
<title> Yes The title of the job. Do not include other types of information, such as employment type, job location, job descriptions, copies, or headlines. <![CDATA[Sales Executive]]>
<date> Yes The date on which this job was first published.
Note: If the publish date is posted on your site, the date on the site must match what’s in the XML.
<![CDATA[Fri, 19 Dec 2014 22:49:39 GMT]]>
<referencenumber> Yes A unique identifying number for this job. Indeed uses this element to identify each job. Do not change the number once you’ve set it. <![CDATA[unique123131]]>
<url> Yes The URL for this job listing on your site. Use the URL for the job description page, not the application page. Include the source=Indeed token to track clicks from Indeed. <![CDATA[http://www.examplesite.com/viewjob.cfm?
jobid=unique123131&source=Indeed]]>
<company> Yes The company name to be displayed in search results. For example, if there are subsidiaries or franchises with multiple branded locations under the same company, <company> should be the business unit or brand name in the simplest possible form that job seekers quickly understand. <![CDATA[[ABC Hospital]]>
<city> Yes The city in which this job is located. <![CDATA[Phoenix]]>
<state> Yes The state in which this job is located. Use the appropriate postal abbreviation. If your job is located outside the US, use the corresponding geographic designation such as province or region. <![CDATA[AZ]]>
<country> Yes The country in which this job is located. <![CDATA[US]]>
<postalcode> Yes, if on the job details page. The postal code in which this job is located. <![CDATA[85003]]>
<streetaddress> Yes, if on the job details page. The street address of the job’s primary work location. Please include the street name and number. If possible, provide the full address including city, state, and postal code. Street address may be used by Indeed to improve the precision of location-based job search and may also be displayed to job seekers. <![CDATA[1234 Sunny Lane
Phoenix, AZ 85003]]>
<email> No The email address to which you want your Indeed Apply applications sent. <![CDATA[example@abccorp.com]]>
<description> Yes The description for this job listing. Ensure the information in the <description> matches the details on the <url> page. This field will be the source of the raw text displayed to job seekers on Indeed, and should include all job-relevant information – including text that may also be provided in other fields in the XML, e.g., education, experience.
Note: Job descriptions require HTML formatting. For a list of supported HTML elements, see Formatting Guidelines.
<![CDATA[
Do you have 1-3 years of sales
experience? [...] ]]>
<salary> Yes, if on the job details page. The salary offered for this job. Best practices are as follows:

  • Provide data in a single <salary> element. If the salary is a range use the following example format: $10 – $20 / hour
  • Always specify a pay period, e.g., per year, per week, per hour, etc.
  • Keep number formats as simple as possible
  • Include a currency symbol
  • Do not use any commas, spaces, apostrophes, etc.
  • Do not use shorthand expressions, e.g., “k” to express thousands
  • Avoid putting multiple salaries in the job title or description
  • Inputting Salary Amounts Guidelines

NOTE: If a job does not have a salary, leave the field blank in the XML for that job. Salary ranges that are unreasonably wide will be removed.

<![CDATA[$50000 per year]]>
OR
<![CDATA[$4,000-$5,000 / month]]>
<education> Yes, if on the job details page. The desired education level for this job. <![CDATA[Bachelors]]>
<jobtype> Yes, if on the job details page. The type of job, full- or part-time. <![CDATA[fulltime, parttime]]>
<category> No A comma-delimited list of job categories, used to aid job seekers when searching. While this element is not required, it’s highly encouraged to include for job management or as a way to reflect additional information found on the job details page. For example, you may find it useful to include facility or department information in this element. <![CDATA[Category1, Category2, CategoryN]]>
<experience> Yes, if on the job details page. The desired experience for this job. <![CDATA[5+ years]]>
<tracking_url> No A unique URL for each job in order to track clicks on Indeed. Indeed creates a GET request to this URL each time the job is clicked. <![CDATA[https://www.examplesite.com/
trackjob1234]]>
<remotetype> No Specifies the type of remote work being offered. Please include one of the following:

  • Fully remote (The employer intends all work for the job to be done remotely or from home.)
  • COVID-19 (These jobs are temporarily remote during the pandemic, but will return to the office when the pandemic ends.)
  • WFH Flexible (Available for US jobs ONLY: The employer gives employees the option to work from home occasionally as a benefit.)

Please see the FAQ below for additional text that can be included in job descriptions and how to properly send remote jobs.
Note: The data collected from this field will not be used to determine location. Please see the XML Feed FAQ section for information on posting jobs remotely.

<![CDATA[COVID-19]]>
<lastactivitydate> No The most recent timestamp of any action that was taken on this job within your system. This action could include reviewing candidates, modifying the job, etc. <![CDATA[Fri, 19 Dec 2014 22:49:39 GMT]]>

Formatting guidelines

Indeed expects same HTML formatting from your website when you provide job descriptions in XML. Include your formatting in CDATA tags.
Note: We do not support escaped HTML entities. For example, use < instead of &amplt;.
Supported tags include but are not limited to the following examples:


Formatting guidelines table
Tag Description
<b> Bold
<h1> to <h6> Headers
Note: Text in header tags transform to consistent sizes when displayed on Indeed pages.
<br> Line break
Note: Indeed automatically inserts line breaks between paragraphs.
<p> Paragraph
<ul> Unordered list (bullets)
<li> List item
<strong> Strong text (bold)
<em> Emphasized text (italics)
<table>, <tbody>, <th>, <tr>, <td> Simple tables

Additionally, we support computed style nodes like the following:

  • <font style="font-weight:bold">Some bold text</font> will result in bold text.
  • <div><h2 style="display:inline">Label: </h2> Text</div> will display “Label: Text” in-line, despite the fact that <h2> is a block element by default.
  • A paragraph tag must have positive top/bottom margin/padding. This is the <p> tag’s default behavior

Formatting example

Formatting for an example job description


<description><![CDATA[
<h2 id="job_description">Job Description:</h2>
 <ul>
 <li>Do you have 1-3 years of sales experience?</li>
 <li> Are you relentless at closing the deal? </li>
 <li>Are you ready for an exciting and high-speed career in sales? If so, we want to hear from you!</li></ul>
 <font style="font-weight:bold">Benefits</font>
 <p>We provide competitive compensation, including stock options and a full benefit plan. As a fast-growing business, we offer excellent opportunities for exciting and challenging work. As our company continues to grow, you can expect unlimited career advancement! </p>
]]>
</description>

How it looks on Indeed

Job Description:

  • Do you have 1-3 years of sales experience?
  • Are you relentless at closing the deal?
  • Are you ready for an exciting and high-speed career in sales? If so, we want to hear from you!

Benefits

We provide competitive compensation, including stock options and a full benefit plan. As a fast-growing business, we offer excellent opportunities for exciting and challenging work. As our company continues to grow, you can expect unlimited career advancement!

Common issues

The following problems can cause Indeed to reject your XML feed or can cause jobs to not appear in Indeed search results.


Common issues table
Issue Solution
Incorrect special character encoding Check the feed URL using the “view source” function in your browser and ensure special characters such as brackets (< >) show up correctly. Verify that the feed is using an XML Declaration like UTF-8 character encoding. Your file must have a header that declares encoding. You can use an encoding other than UTF-8, although UTF-8 is the most common.
Jobs missing from the feed or job counts differing between the feed and career sites Include every job in the feed for each client. Anything published and available on the web should be in the feed. Remember that Indeed is a search engine and indexes the more comprehensive source.
Incomplete or empty job descriptions Include all text related to the job. For example, “required qualifications” may be a separate category in your database, but for Indeed’s purposes, it should be included in the <description> field.
Jobs that are scams or suspected scams Indeed works to exclude suspected scams. Ensure that positions have well-written descriptions. If submitting jobs for another company, vet the company to ensure that it is legitimate and the listed jobs are actual open positions.
Old jobs in the file Do not include old or inactive jobs in the XML. Once a job has been filled, remove the role from the XML file. If Indeed notices old/inactive jobs being sent over, we’ll ask that the behavior be corrected if you want to continue utilizing the XML.

XML Feed FAQ

What are the options for delivering the feed?

Indeed monitors the file for changes in one of three ways:

  • Crawling an XML URL
  • Crawling a client hosted FTP site (SFTP also supported)
  • Receiving the file directly in an Indeed FTP server (zipped files recommended)

How often does Indeed index the XML feed?

For XML being crawled on a URL or ATS provided FTP site, Indeed will refresh the job data 4 times a day every 6 hours from the time of the last request. For Indeed hosted FTPs: we’ll refresh the XML feed when a new file is received up to every 2 hours. If more frequent file uploads occur, previous runs may cease and prevent job updates from occurring.

What metadata can be included?

You can include any fields you like (ex. <job_type>, <branch_id> ) as long as the standard fields are present.

Will every job in the feed appear in Indeed search results?

Visibility in search results is based on Indeed’s visibility rules. Our Search Quality team prioritizes jobs that are legitimate, unique, have detailed descriptions and locations, and are easy to apply to. Jobs that do not meet these criteria may be hidden from search results.

If I’m using Indeed Apply and allowing job seekers to apply directly from Indeed, why must I provide a URL?

We require a URL that points to the job description (not apply page), for 3 reasons:

  • If Indeed Apply fails, we direct the job seeker back to the job URL.
  • The job seeker can click to see the original job from Indeed at any time.
  • Our aggregation engine needs an active URL to confirm job content and job activity.

What happens if I have the same job in multiple languages?

Provide the job in every language you currently have it as a unique job in the XML. If you duplicate the reference number in the XML, only the first appearance of the job appears on Indeed.

What happens if I have the same job in multiple countries?

Provide the job in every location where there is an open position. Region-wide postings that are not region-wide jobs are rejected for organic visibility on Indeed.

What happens if I have a statewide/country-wide job?

Indeed requires city, state/province, country, and postal code elements. If these elements are not provided, the job does not receive organic visibility by default.

If you have legitimate region-wide postings or remote work opportunities, include them in the file and have your clients request organic visibility. If your client has an Indeed account, they can log in to get support. Clients without an account can submit questions to Indeed directly by visiting our website.

How can I specify whether a job is a remote position?

Include the <remotetype> element from the table above and indicate one of the three following options:

  • COVID-19
  • WFH Flexible (US ONLY)
  • Fully remote

Additionally, in order to identify roles in one of these three distinct ways, there are certain phrases employers can include in job descriptions:

To be considered a “temporarily remote due to COVID-19” job, include one of the following phrases:
“Work remotely temporarily due to COVID-19”
“Work from home during coronavirus”
“Can start remotely due to COVID-19”

To be considered as a job having “work from home flexibility”, please include one of the following phrases:
“Flexible work from home options available”
“Work from home days possible”
“Options for working from home”

To be considered a “fully remote” job, include one of the following phrases:
“This is a remote position”
“Employees will be working remotely”
“Remote work allowed”

In summary, there are three differentiated options that Indeed uses to accurately identify jobs:

  • Use “fully remote” when the employer intends all work for the job to be done remotely or from home.
  • Use “work from home flexibility” when the employer gives employees the option to work from home occasionally as a benefit.
  • For jobs that are temporarily remote during the pandemic, use the “Temporarily remote due to COVID-19” option.

How do I post a remote job and utilize the <remotetype> element?
To properly post remote jobs, you’ll need to utilize the elements that Indeed uses to capture location data: <city>, <state>, <country>, and <postalcode>.

If you want to post a job remotely in the US, use this XML:


<city><![CDATA[Remote]]></city>
<state><![CDATA[]]></state>
<country><![CDATA[US]]></country>
<postalcode><![CDATA[]]></postalcode> 

Please note how in the example above that the <state> and <postalcode> elements are still present but contain no information. This is how you should provide the data in the <job> element for jobs you’re posting remotely. If you do not leave the <state> and <postalcode> blank, jobs will not post as Remote positions.

To post a job that is temporarily remote due to COVID-19 statewide in Arizona, take advantage of the <remotetype> element. The example XML below illustrates how to post this information:


<city><![CDATA[Remote]]></city>
<state><![CDATA[AZ]]></state>
<country><![CDATA[US]]></country>
<postalcode><![CDATA[]]></postalcode> 
<remotetype><![CDATA[COVID-19]]></remotetype>

Please note in the example above that the <postalcode> element is still present but contains no information. This is how you should provide the data in the <job> element for jobs you are posting remotely and due to the COVID-19 global pandemic. If you do not leave the <postalcode> blank, the job will not post as a remote position.

(Go back to the top)


Adding Indeed Apply

Use the Indeed Apply (IA) API to mark your jobs with the Easily Apply label and allow job seekers to apply without leaving Indeed.

The IA API takes approximately two to three weeks to implement from start to deployment.

You can implement the IA API in one of two ways:

  • If you maintain an Indeed XML feed, you must add an IA element to your feed. See Adding IA using the XML feed for instructions.
  • If you do not maintain an Indeed XML feed, you can add the IA HTML button to the job description pages on your website. See Adding IA using the HTML button for instructions.

Generating an API token

Before implementing the Indeed Apply API, generate an API token by logging in to your Indeed Advertiser account or creating a new account.

Please select the Indeed Apply option when creating your token.

Note: If you use OAuth elsewhere at Indeed, you must maintain a separate token specifically for your Indeed Apply integration.

Adding IA using the XML feed

If you maintain an Indeed XML feed, add Indeed Apply configuration attributes to an <indeed-apply-data> element in your existing feed.

Indeed Apply configuration attributes are outlined in the IA Configuration parameters table.

IA XML element example

The following example shows a basic XML feed containing one job and the Indeed Apply element.
Note: The basic job elements are omitted for clarity, but must be present in your feed.

Basic XML feed example


<?xml version="1.0" encoding="utf-8"?>
<source>
    <publisher/>
    <publisherurl/>
    <lastBuildDate/>
    <job>
        <title/>
        <date/>
        <referencenumber/>
        <url/>
        <company/>
        <sourcename/>
        <city/>
        <state/>
        <country/>
        <email/>
        <postalcode/>
        <description/>
        <salary/>
        <education/>
        <jobtype/>
        <category/>
        <experience/>
        <indeed-apply-data>
            <![CDATA[indeed-apply-apiToken=1234ABCDE&indeed-apply-jobTitle=Professional+B
            asket+Weaver&indeed-apply-jobId=Sample+ID&indeed-apply-jobCompanyName=My+Favo
            rite+Company&indeed-apply-jobLocation=Austin+TX&indeed-apply-jobUrl=http%3A%2
            F%2Fwww.indeed.com&indeed-apply-postUrl=https%3A%2F%2Fhookb.in%2FPxOjJqJELNH8
            lZLZDkpz&indeed-apply-questions=https%3A%2F%2Fpastebin.com%2Fraw%2F0vXq9q9b%2
            3]]>
        </indeed-apply-data>
    </job>
</source>

IA XML element restrictions

The following restrictions apply when configuring Indeed Apply using the XML feed:

  • Attributes must be URL encoded.
  • If an Indeed Apply field is included in the XML feed, it must not be blank.
  • Data attributes must include the prefix indeed-apply-. Do not use data-indeed-apply- as a prefix.
  • All standard configuration attributes can be passed using the XML feed with the following exceptions. These attributes only work when using the HTML button:
  • onapplied
  • onclick
  • continueUrl

Adding IA using the HTML button

If you do not maintain an Indeed XML feed, you can implement Indeed Apply by adding an HTML button to job description pages on your site. Add Indeed Apply configuration attributes to a span element with the class indeed-apply-widget and include JavaScript to enable it.

The Indeed Apply button is not optimized for single-page applications (SPAs) or a webpage that hosts a button that loads the bootstrap.js script multiple times without reloading the entire page.

Note: If you maintain an XML feed, use the XML element instructions to enable Indeed Apply for your jobs on Indeed. Using this HTML method will only apply to jobs on your site.

Indeed Apply configuration attributes are outlined in the IA Configuration parameters table.

IA HTML button example

The following example shows the markup required for the Indeed Apply HTML button, including the JavaScript to enable the feature.

HTML button example


<?xml version="1.0" encoding="utf-8"?>
 
<span class="indeed-apply-widget"
    data-indeed-apply-apitoken="INSERT YOUR APITOKEN HERE"
    data-indeed-apply-jobid="7775e2bc62b7f77e"
    data-indeed-apply-joblocation="New York, NY 10110"
    data-indeed-apply-jobcompanyName="Your Company"
    data-indeed-apply-jobtitle="Test Engineer"
    data-indeed-apply-joburl="http://www.yourcompany.com/careers/yourjob123.html"
    data-indeed-apply-posturl="http://www.yourcompany.com/process-applications"
    data-indeed-apply-jobmeta="right-rail-apply-button"></span>
 
<script>(function(d, s, id) {
var js, iajs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)){return;}
js = d.createElement(s); js.id = id;js.async = true;
js.src = "https://apply.indeed.com/indeedapply/static/scripts/app/bootstrap.js";
iajs.parentNode.insertBefore(js, iajs);
}(document, 'script', 'indeed-apply-js'));
</script>

IA configuration parameters

When you use either the XML feed or the HTML button, set up the Indeed Apply API using the following configuration parameters.

Note: You can add all of these parameters to the Indeed Apply button as HTML5 data attributes. You must include the prefix data-indeed-apply- to the data attributes.


List of parameters table
Parameter name Required Description Example
joburl No The canonical URL to the complete job description. Encode this URL in XML files.
Note: For applications on Indeed, the joburl will be set in the apply button to the specific URL on Indeed where the apply is taking place.
http%3A%2F%2Fwww.yourcompany.com
%2F%0Acareers%2Fyourjob123.html
jobid No The ID of the job, used for your own internal tracking.
Note: This field can contain a maximum of 256 ASCII characters.
7775e2bc62b7f77e
jobtitle Yes The title of the job to display externally.
Note:The value of this field this should match the <title> field in the XML.
Test Engineer
jobcompanyname No The name of the company. Your Company
joblocation No The location of the job. New York, NY 10110
jobmeta No Any arbitrary information you want to provide. This information is not displayed externally, but it will be sent when using the apply via post URL. right-rail-apply-button
apitoken Yes The public API token provided by Indeed. your-api-token
email No The employer email used to send the applications.
This is an encrypted value. See the Encryption and decryption section for more information.
This field is required if postUrl is not provided.
Note: This field is NOT permitted for ATS integrations. This field may only be used by direct employer integrations.
b18d0be4c173dfa2b7cb7856e7c7b6f
02a563867a9df67ca208c8b9654966299
locale No Determines the language used when sending the email to the employer if email is provided. The default language is English (en).
Note: This field will not affect the confirmation email sent to the applicant.
es
posturl Yes The URL to which Indeed will post the application data. Encode this URL in XML files.
Note: If email is not provided, postUrl is required.
http%3A%2F%2Fwww.yourcompany.com
%2Fprocess-applications
phone No A string value indicating whether the phone number field should be displayed on the job.
Acceptable values are optional, hidden, or required. The default value is optional.
optional
coverletter No A string value indicating if the message or coverletter field is required.
Acceptable values are optional, hidden, or required. The default value is optional.
required
resume No Specifies whether to require a resume, make a resume optional, or to hide the resume upload option from the user.
Acceptable values are optional, hidden, or required. The default value is required.
If you select optional or hidden, you must include screener questions.
You must support .pdf, .doc, .docx, .rtf, and .txt formats for resumes.
required
name No A string value indicating if the name field in the apply form should be split into first and last name (name="firstlastname") or if a single field for the full name is sufficient (name="fullname"). The default value renders a single field for the full name. firstlastname
onapplied No A comma-delimited list of global JavaScript functions to call when the user has applied to the job.
The first and only argument to this function will be the HTMLElement element of this button.
Note: This attribute only works when implementing Indeed Apply using the HTML button.
on_applied_callback
onclick No A comma-delimited list of global JavaScript functions to call when the user clicks on the button.
The first and only argument to this function is the HTMLElement element of this button.
Note: This attribute only works when implementing Indeed Apply using the HTML button.
on_click_callback
advnum No The advertiser number to use when attributing an application conversion. 1432700306306892
questions No A URL which returns a JSON-formatted string of questions to be asked during the Indeed Apply application process. Refer to Including screener questions for more information about creating questions.
continueurl No A URL that appears after the job seeker clicks Continue on the application confirmation page.
Note: This attribute only works when implementing Indeed Apply using the HTML button.
http%3A%2F%2Fwww.apply.com
%2Fafter-the-apply
noButtonUI No A boolean flag. When set to true, it disables the standard rendering styles of the Indeed Apply button (typically an orange rectangle). Instead, an unstyled button element will be added to the page. This allows the Indeed Apply button’s appearance to be customized to align with the look-and-feel of the context in which it appears.
Note: This attribute only works when implementing Indeed Apply using the HTML button.
true|false
onappliedstatus No A comma-delimited list of global JavaScript functions to call when the Indeed Apply button is rendered for a job.

The first argument to this function is the HTMLElement element of this button. The second argument to this function is a status flag that is set to 1 if the job seeker currently viewing the job has already applied to the job for which the Indeed Apply button is configured.
Note: This attribute only works when implementing Indeed Apply using the HTML button.

<span class="indeed-apply-
widget"...data-indeed-apply-
onAppliedStatus="cb"...</span>

var cb = function(buttonElement,
payload) { var applied = payload &&
payload.applied === 1;
if (applied) { ... }};

closeHandler No A comma-delimited list of global JavaScript functions to call when a job seeker clicks the ‘close’ link that appears after they complete the Indeed Apply workflow and submit an application for the job the HTML button is configured for.

The first and only argument to this function is the HTMLElement element of this button.
Note: This attribute only works when implementing Indeed Apply using the HTML button.

skipContinue No A boolean flag. When set to ‘true’ this will disable the default screen that appears after a job seeker has submitted an application to the job for which the button is configured.

When used in tandem with the ontinueUrl parameter, this will effectively redirect the job seeker’s entire browser window to the provided continueUrl after an application has been submitted (instead of just keeping the job seeker on the page the button appears on).
Note: This attribute only works when implementing Indeed Apply using the HTML button.

data-indeed-apply-
skipcontinue="true"
data-indeed-apply-
continueurl="https://www.google.com"

(Go back to the top)


Screener questions

Screener Questions help you learn more about your job seekers during the application process. Format these questions in JSON and post them to a URL so Indeed Apply can retrieve them.

Before you begin

Considerations

  • You can provide a maximum of 500 questions. However, our data indicates that a sharp drop-off in conversion occurs when more than 20 questions are asked.
  • Questions files should be no larger than 1 MB.
  • Questions files are cached server-side by unique question URLs and refreshed hourly.
  • Use the en_US locale to format limit, min, or max. Use a period for the decimal point. Do not use thousands separators.
  • The format of type=date impacts how the application is passed to the third party as well as the parsing of min and max. The job seeker still enters the date based on their locale, not the specified format, and validation error messages are in their locale’s format.
  • For type=date, use yyyy instead of yy in the format to prevent confusion.

Note: Verify the syntax of your JSON file and preview the look of your screener questions using the Indeed Apply Questions tool.

Best practices

  • Only include questions that are relevant to the job.
  • Include as few screener questions as possible. Remember that job seekers will answer these questions on mobile devices.
  • Use the “pagebreak” question type to split your application into logical sections. Indeed inserts pagebreaks by default if none are included in your JSON, but this can split your application up in unintended ways.
  • Do not repeat questions that can be answered from a job seeker’s resume, or have already been collected during the Indeed Apply application process, e.g., basic contact details.
  • Follow local laws when determining which questions to ask. Consult your legal department about questions your local laws may prohibit.
  • Provide guidance to job seekers when answers require a specific format.

JSON for screener questions

This section lists the parameters used in building all question types. For examples of specific question types, refer to Screener question types.

JSON screener question parameters


JSON screener question parameters table
Name Required? Description Allowed values Example
id Yes Unique ID for this question. any string strengths
type Yes Describes the type of question. Refer to the following sections for a full explanation of each question type. textarea

text

select

hierarchical

multiselect

date

file

information

pagebreak

textarea
question No for type=information and type=pagebreak

Yes for all other types

The question text that applicants see. any string Veteran status?
text Yes for type=information

No for all other types.

Text that applicants see. any string The following questions are optional.
options Yes for type=select and type=multiselect The list of options available in the drop-down menu. JSON [{
"value":"1",
"label":"Female"
}]
value Yes for type=select and type=multiselect The value corresponding to each option that will be returned for questions with drop-down menus. any string 1
label Yes for type=select and type=multiselect The text for options in any drop-down menus. any string Female
required No Allows you to set a question as required. When required:true is present, Indeed Apply forces a non-empty text field or a non-empty selection. When the required parameter is not present, questions are optional. If a question is optional, a possible answer value is “”. true "required":true
format Yes for type=date
No for type=text
The accepted format of the input.
If used with type:text, the question will accept only integer, decimal, or numeric_text validation answers. If used with type:date, the question will only accept SimpleDateFormat with MM.
Text formats:

  • integer
  • decimal
  • numeric_text
  • other locale specific formats (please use Unicode CLDR as a guide)

Date formats:

  • integer
  • dd/MM/yyyy
integer,
dd/MM/yyyy
limit No For type=text and type=textarea, the character limit for the answer. any integer 100
min No For format=integer or format=decimal, the minimum value for the answer. For type=date, the date that the answer must be on or after. any integer for format=integer

any decimal for format=decimal

any date for type=date (in the specified format)

0
max No For format=integer or format=decimal the maximum value for the answer. For type=date, the date the answer must be on or before. any integer for format=integer

any decimal for format=decimal

any date for type=date (in the specified format)

100
condition No Marks a question as conditional, depending on the answer to a previous select question. Specify the id of the previous question as well as the option value that activates this question.
For example, you might ask the applicant if they served in the military. If they answer yes, you display a conditional question that asks what branch they served in.
JSON "condition": {
"id": "parent1",
"value": 0}

JSON post example

Currently, the JSON post contains ‘screener questions’ and their ‘answers’ in 2 formats:

  • The Legacy* format
  • The Current format

Both formats are described below. In the future, we will discontinue the “Legacy” format.

The Legacy* Format

In the Legacy format, the screener questions and their answers are a part of the ‘questions’ section in the JSON file. 

  • question:
  • questions: the full questions list as described in the previous section
  • answers: the full answers list
  • url: the URL from which the questions were retrieved
  • retrievedOnMillis: the datetime in milliseconds at which the questions were retrieved

The Current Format

In the Current format, the screener questions and their answers are a part of the ‘questionsAndAnswers’ section in the JSON file.

  • questionsAndAnswers: (Improved format)
  • questionsAndAnswers: A list of
  • question: question as described in the previous section
  • answer: the answer given to the above question
  • url: the URL from which the questions were retrieved
  • retrievedOnMillis: the datetime in milliseconds at which the questions were retrieved

Click this link to view or download a full example JSON post file. (Contains both the Legacy and Current formats.)

*Legacy format: We will discontinue the Legacy format in future. In case you use the Legacy format to read ‘Screener questions and their answers’, you are requested to make changes as soon as possible to ensure your Indeed Apply integration continues to receive the complete and correct information. If you are an existing Employer or ATS that uses the Legacy format and wants to migrate to the Current format – then you can refer this additional guide for migration.

Screener question types

textarea

A question that displays a multi-line text entry field. Used for questions with long-form answers.

textarea example

{
  "id":"felonytext",
  "type":"textarea",
  "question":"If you have been convicted of a felony, please explain the circumstances around the conviction:"
}

text

A question that displays a single-line text entry field. Used for questions with shorter answers.

Note: Please see the examples below as well as the previous table for more information on the different formats available for text questions: integer, decimal, numeric_text.

text examples

No format specification:


{
  "id": "city",
  "type": "text",
  "question": "What city are you located in?",
  "required": true
}

Integer: Displays whole numbers; does not allow for decimals or leading zeroes


{
  "id":"age",
  "type":"text",
  "question":"Age?",
  "format":"integer",
  "min":"16",
  "max":"75"
}

Numeric text: Allows for numbers with leading zeroes; does not allow for decimals


{
  "id": "ssn",
  "type": "text",
  "format": "numeric_text",
  "question": "Enter last 4 digits of your SSN.",
  "required" : false
}

Decimal: Displays numbers with decimals; allows for leading zeroes


{
  "id": "gpa",
  "type": "text",
  "format":"decimal",
  "question": "What was your GPA?",
  "required": true
}

select

A question that displays a drop-down menu that allows the applicant to select a single answer. Used for questions with multiple choice answers.

Note: If you include 5 or fewer answer options, they will appear as radio buttons. If you include more than 5 options, they will appear in a drop-down menu.

select example

{
  "id": "gender",
  "type": "select",
  "question": "Gender?",
  "options": [{
      "value": "0",
      "label": "Decline to answer"
    },
    {
      "value": "1",
      "label": "Male"
    },
    {
      "value": "2",
      "label": "Female"
    }
  ]
}

conditional

A question that is or is not displayed based on responses to previous questions. For example, you might ask an applicant if they are at least 18 years of age. If they answer yes, you ask if they can provide required work documentation.

conditional example

[{
    "id": "profile-atLeast18",
    "question": "Are you at least 18 years of age?",
    "required": true,
    "options": [{
        "value": "1",
        "label": "Yes"
      },
      {
        "value": "0",
        "label": "No"
      }
    ],
    "type": "select"
  },
  {
    "id": "profile-permit",
    "question": "Can you provide a work permit?",
    "required": true,
    "condition": {
      "id": "profile-atLeast18",
      "value": "0"
    },
    "options": [{
        "value": "1",
        "label": "Yes"
      },
      {
        "value": "0",
        "label": "No"
      }
    ],
    "type": "select"
  }
]

hierarchical

A question that displays additional questions and responses based on previously selected answers. For example, you might ask an applicant to choose a state. Then, depending on what they select, you could offer them a drop-down list of cities within that state. Each hierarchical question is limited to 3 levels, for example: state/city/county.

Note: Hierarchical questions are similar to conditional questions. However, hierarchical questions may be better suited to certain question types where an initial selection defines potential answers for subsequent questions. Using the hierarchical functionality reduces the total number of questions needed to obtain related information.

hierarchical example

[{
  "id": "hierarchical",
  "type": "hierarchical",
  "question": "State",
  "required": true,
  "options": [{
    "value": "0",
    "label": "California"
  }, {
    "value": "1",
    "label": "Texas"
  }, {
    "value": "2",
    "label": "New York"
  }],
  "hierarchicalOptions": [{
      "id": "cali_cities",
      "options": [{
        "value": "0",
        "label": "San Francisco"
      }, {
        "value": "1",
        "label": "Los Angeles"
      }],
      "condition": {
        "id": "hierarchical",
        "value": "0"
      }
    }, {
      "id": "texas_cities",
      "options": [{
        "value": "0",
        "label": "San Antonio"
      }, {
        "value": "1",
        "label": "Austin"
      }],
      "condition": {
        "id": "hierarchical",
        "value": "1"
      }
    },
    {
      "id": "sa_zipcodes",
      "options": [{
        "value": "0",
        "label": "78212"
      }, {
        "value": "1",
        "label": "78209"
      }],
      "condition": {
        "id": "texas_cities",
        "value": "0"
      }
    }
  ]
}]

multiselect

A question that displays a list of checkboxes that allows the applicant to select multiple answers. Used for questions with multiple answers.

multiselect example

{
  "id": "favoritecolors",
  "type": "multiselect",
  "question": "Select your two favorite colors:",
  "options": [{
      "value": "0",
      "label": "Maize"
    },
    {
      "value": "1",
      "label": "Blue"
    },
    {
      "value": "2",
      "label": "Green"
    }
  ]
}

date

A question that displays a text field that only accepts date entry. Used for questions that must be answered with a date.

Note: format is required when using this screener question type. The format must be dd/MM/yyyy or another locale specific format that meets Unicode CLDR formatting. Indeed uses the SimpleDateFormat, so month must be formatted as MM. Using mm will result in misconfiguration.

date example

{
  "id":"startdate",
  "required":true,
  "type":"date",
  "question":"Start date?",
  "format":"dd/MM/yyyy",
  "min":"01/02/2014",
  "max":"03/04/2014"
}

file

A question that displays a file upload interface. Used for questions that require a file upload as an answer, such as certifications, portfolios, or example work. As detailed in Application data delivery options, the answer data returned in the JSON POST request will contain 3 fields: contentType, data, and fileName.

Accepted file types: doc, docx, gif, jfif, jif, jpe, jpeg, jpg, pdf, png, rtf, tif, tiff, txt
File size limit: 5 MB. The maximum combined limit per application is 15MB, including resume file.

Note: Do not use this question type to acquire resumes. Instead, use the “Resume” Indeed Apply configuration parameter.

file example

{
  "id": "file2",
  "type": "file",
  "question": "Please attach a resume file.",
  "required": true,
  "min":"1",
  "max": "3"
}

information

A text display that does not require a response. Used to include explanatory text or provide section headings. You can include the following HTML elements in the text: <b>, <p>, <br>, <li>, <ul>, <ol>, <a href=" ">. Only HTTP and HTTPS protocols are allowed in URLs. Links open in a new tab.

Note: Do not force line breaks. Indeed automatically inserts line breaks between paragraphs.

information example

[{
  "id": "first_header",
  "type": "information",
  "text": "The next set of questions are <b> optional </b> and are for recording purposes only. 
 Make sure to view the <a href='http://www.eeoc.gov/employers/upload/poster_screen_reader_optimized.pdf'> EEO is the Law</a> poster.",
  "fontsize": 8
}]

pagebreak

Used to group questions on a page. All questions included between two pagebreak types appear on the same page. You can group up to 20 questions on the same page.

pagebreak example

[{
    "id": "page1_open",
    "type": "pagebreak"
  },
  {
    "id": "question_sample",
    "type": "text",
    "question": "Age?"
  },
  {
    "id": "page1_close",
    "type": "pagebreak"
  }
]

Testing your screener questions?

Verify the syntax of your JSON file and preview the look of your screener questions using the Indeed Apply Questions tool.

Test the entire Indeed Apply application flow by using our external testing tool. This can include the full screener question process.

(Go back to the top)


Application data delivery

You can choose to receive Indeed Apply applications from job seekers through email or postUrl.

PostUrl

If you process applications programmatically, specify a URL where Indeed Apply will send a POST request. The indeed-apply-postUrl data attribute must be a string containing the URL where Indeed will POST the application data.

PostUrl example


<indeed-apply-data><![CDATA[indeed-apply-apiToken=1234ABCDE&indeed-apply
-jobTitle=Professional+Basket+Weaver&indeed-apply-jobId=Sample+ID&indeed
-apply-jobCompanyName=My+Favorite+Company&indeed-apply-jobLocation=Austi
n+TX&indeed-apply-jobUrl=http%3A%2F%2Fwww.indeed.com&indeed-apply-postUr
l=https%3A%2F%2Fhookb.in%2FPxOjJqJELNH8lZLZDkpz&indeed-apply-questions=h
ttps%3A%2F%2Fpastebin.com%2Fraw%2F0vXq9q9b%23]]></indeed-apply-data>

Because Indeed sends the application data as the raw body of the HTTP POST request, the request cannot be processed like a typical form. The body of the request contains a JSON document that must be read and parsed. Not all JSON fields are provided, so you should use a robust JSON parser that treats missing fields as empty and ignores unrecognized fields.

Note: There is no maximum size for JSON data payload.

The post body is encoded as UTF-8 and contains an authenticity header that is used to verify that Indeed is sending you the application.

A file portion of the Applicant field contains 3 fields: contentType, data, and fileName.

  • ContentType is determined based on the fileName.
  • The data field contains the raw resume file, which is Base64 encoded.
  • The following filetypes must be supported by the third party: txt, pdf, doc, docx, rtf.

Note: Do not redirect the POST to another URL, e.g., via a 301/302 redirect. Indeed Apply does not handle redirects.

Expected response

Indeed expects a HTTP 2xx response code in response to the POST. If we do NOT receive a HTTP2xx response either through a connect timeout, post timeout, or invalid HTTP response, we will attempt to resend the application. Indeed uses an increasing standoff method for our automatic resends. After the last automatic retry, if we are still unsuccessful, we will terminally fail the application. For additional guidance on Duplicate handling and expired positions please see monitoring Integration health.

We do NOT expect partners to perform any validation on the content of the job application during the POST. If you wish to do validation on the job content and disqualify the applicant, that should occur downstream of the POST. Any failures that are related to partner validation of job seeker data can lead to the integration being disabled.

JSON application data

JSON Resume upload example


{ 
   "applicant":{ 
      "email":"john.doe@indeed.com",
      "fullName":"John Doe",
      "phoneNumber":"555-555-4321",
      "verified":true,
      "sponsored":true,
      "indeedTargetedad":false,
"resume":{ 
         "file":{ 
            "contentType":"text/plain",
            "data":"SGVsbG8h",
            "fileName":"resume.txt"
         }
      }
   },
   "appliedOnMillis":1325276227653,
   "job":{ 
      "jobCompany":"Your Company",
      "jobId":"7775e2bc62b7f77e",
      "jobLocation":"New York, NY 10110",
      "jobMeta":"",
      "jobTitle":"Test Engineer",
      "jobUrl":"http://www.yourcompany.com/careers/yourjob123.html"
   },
   "locale":"en_US"
}

JSON Indeed Resume example


{ 
   "locale":"en_US",
   "appliedOnMillis":1324051581711,
   "job":{ 
      "jobId":"7775e2bc62b7f77e",
      "jobTitle":"Test Engineer",
      "jobCompany":"Your Company",
      "jobLocation":"New York, NY 10110",
      "jobUrl":"http://www.yourcompany.com/careers/yourjob123.html",
      "jobMeta":""
   },
   "applicant":{ 
      "fullName":"John Doe",
      "email":"john.doe@indeed.com",
      "phoneNumber":"555-555-4321",
      "coverletter":"coverletter - text",
      "verified":true,
       "sponsored":true,
      "indeedTargetedad":false,
      "resume":{ 
         "text":"resume - text",
         "html":"resume - html",
         "json":{ 
            "firstName":"John",
            "lastName":"Doe",
            "headline":"headline",
            "summary":"summary",
            "publicProfileUrl":"http://www.indeed.com/r/123456",
            "additionalInfo":"me-additionalinfo",
            "phoneNumber":"555-555-4321",
            "location":{ 
               "city":"Austin, TX"
            },
            "skills":"HTML, JavaScript",
            "positions":{ 
               "_total":1,
               "values":[ 
                  { 
                     "title":"Product Manager",
                     "company":"Indeed",
                     "location":"Austin, TX",
                     "startDateMonth":"09",
                     "startDateYear":"2007",
                     "endDateMonth":"-1",
                     "endDateYear":"-1",
                     "endCurrent":true,
                     "description":"I am the current product manager for Indeed Apply."
                  }
               ]
            },
            "educations":{ 
               "_total":1,
               "values":[ 
                  { 
                     "degree":"B.A.",
                     "field":"Computer Science",
                     "school":"University of Texas, Austin",
                     "location":"Austin, TX",
                     "startDate":"2002",
                     "endDate":"2006",
                     "endCurrent":false
                  }
               ]
            },
            "links":{ 
               "_total":1,
               "values":[ 
                  { 
                     "url":"http://www.indeed.com"
                  }
               ]
            },
            "awards":{ 
               "_total":1,
               "values":[ 
                  { 
                     "title":"Best PM at Indeed",
                     "dateMonth":"04",
                     "dateYear":"2008",
                     "description":"Best PM is voted on by Indeed employees and 
given to the PM with the most votes."
                  }
               ]
            },
            "certifications":{ 
               "_total":1,
               "values":[ 
                  { 
                     "title":"cert-title",
                     "startDateMonth":"02",
                     "startDateYear":"2007",
                     "endDateMonth":"02",
                     "endDateYear":"2008",
                     "endCurrent":false,
                     "description":"cert-description"
                  }
               ]
            },
            "associations":{ 
               "_total":1,
               "values":[ 
                  { 
                     "title":"group-title",
                     "startDateMonth":"01",
                     "startDateYear":"2009",
                     "endDateMonth":"-1",
                     "endDateYear":"-1",
                     "endCurrent":true,
                     "description":"group-description"
                  }
               ]
            },
            "patents":{ 
               "_total":1,
               "values":[ 
                  { 
                     "patentNumber":"patent-number",
                     "title":"patent-title",
                     "url":"patent-url",
                     "dateMonth":"02",
                     "dateYear":"2009",
                     "description":"patent-description"
                  }
               ]
            },
            "publications":{ 
               "_total":1,
               "values":[ 
                  { 
                     "title":"pub-title",
                     "url":"pub-url",
                     "dateDay":"14",
                     "dateMonth":"10",
                     "dateYear":"2004",
                     "description":"pub-description"
                  }
               ]
            },
            "militaryServices":{ 
               "_total":1,
               "values":[ 
                  { 
                     "serviceCountry":"mil-country",
                     "branch":"mil-branch",
                     "rank":"mil-rank",
                     "startDateMonth":"02",
                     "startDateYear":"2003",
                     "endDateMonth":"12",
                     "endDateYear":"2008",
                     "endCurrent":false,
                     "commendations":"mil-commendations",
                     "description":"mil-description"
                  }
               ]
            }
         },
         "file":{ 
            "contentType":"application/octet-stream",
            "data":"SGVsbG8h=",
            "fileName":"John_Doe.pdf"
         }
      }
   }
}

IA JSON fields

Top-level fields


Top-level fields table
Field name Description Example
id Unique ID for the application as assigned by Indeed.
Include this ID with the application status when sharing disposition data with Indeed.
5156eb63c9a0a8ac<br />9358c3a444a2818c<br />8a5ffdbcba5960ec<br />0cace3277f6b99df
appliedOnMillis The date and time the user applied expressed in standard Unix time. 1324051581711
job A job object representing the data provided by your button’s HTML data attributes. See Job object fields
applicant An applicant object representing the applicant. See Applicant object fields
analytics

An object containing the following information:

  • ip – IP address of the user
  • referrer – page the Easily Apply button is on if the button is present
  • useragent – device/useragent of the user
  • targetedApplyAd – returns true for Indeed Apply ads served on Indeed
  • sponsored – returns true if the job is sponsored on the Indeed search engine results page, and returns false if the job is organic, meaning not sponsored, on Indeed

Note: sponsored returns empty/absent if the job click did not originate on Indeed, such as when a user applies from a third-party website or if the job seeker was directed to apply through Indeed’s Targeted Ads (ITA) product. Third-party sites cannot specify whether a job is sponsored.

To track sponsored job clicks on third-party sites, enable URL tracking. Because JSON responses do not include the “sponsored” parameter, you must also enable XML-only responses. Sponsored job tracking from third-party websites must be configured per job in your client’s Advertiser accounts and appended to the joburls, which can then be tracked by the ATS.

locale The locale that was used when applying to the job. en_US

Job object fields

Note: These fields are based on the button configuration.


Job object fields table
Field name Description Example
jobUrl The canonical URL to the complete job description.
Note: For applications on Indeed, the jobUrl received in the application JSON will be set to the specific URL on Indeed where the apply happened.
http://www.yourcompany.com/

careers/yourjob123.html
jobId The ID of the job, useful for your own internal tracking. 7775e2bc62b7f77e
jobTitle The title of the job to display. Test Engineer
jobCompany The name of the company.

Note: This is called jobCompanyName in the data-attributes.

Your Company
jobLocation The location of the job. New York, NY 10110
jobMeta Arbitrary information provided in the original button configuration. right-rail-apply-button

Applicant fields


Applicant fields table
Name Always provided? Description Example
fullName Yes The name of the applicant. If the user is using their Indeed Resume, this will be their firstName and lastName. John Doe
email Yes The email of the applicant. john.doe@indeed.com
phoneNumber No The phoneNumber if provided by the applicant. 555-555-4321
coverletter No The cover letter of the applicant. If a user did not provide a cover letter, this field will not be present in the JSON object. My cover letter
resume No An object representing the user’s resume. See the Resume fields section
verified Yes

A flag indicating whether a job seeker’s email address is verified. Will display true if:

  • the user is logged into a verified account, and their email address on the application matches the email address associated with the account, or
  • the user is logged out but their email has been verified by a one-time password

All other cases, the flag will be set to false.

true

Resume fields


Resume fields table
Field name Resume upload Indeed Resume Description
file Yes Yes An object containing the binary resume file.
text No Yes A text representation of the resume. Only provided if the user is using their Indeed Resume.
html No Yes A representation of the resume. Only provided if the user is using their Indeed Resume.
json No Yes A JSON structured representation of the resume data. See Indeed resume below.

Resume file fields


Resume file fields table
Name Description Example
data The file’s raw binary bytes encoded using base 64. SGVsbG8h=
fileName The filename of the uploaded resume. The filename will be auto generated when using the Indeed Resume. resume.txt
contentType The content type identified using the resume file’s extension. application/octet-stream

Indeed Resume fields

An array-like object that contains a _total field and a values field. The _total field is an integer indicating the length of the array. The values field is a JSON array containing the _total objects.


Indeed Resume fields table
Field name Type Description
firstName string The applicant’s first name.
lastName string The applicant’s last name.
headline string The applicant’s resume headline.
summary string The applicant’s resume summary.
publicProfileUrl url If the Indeed Resume is public, the URL to view the user’s public resume.
additionalInfo string Any additional info.
phoneNumber string The phone number of the user if included on the user’s Indeed Resume.
location object JSON object representing the user’s location if provided.
location.city string The applicant’s city.
location.country string The applicant’s country.
location.postalCode string The applicant’s postal code.
Personal details object Personal details supplied by applicant.
Note: These are only applicable in certain markets as noted on each field.
skills string The applicant’s skills.
positions array-like An array-like object of position objects.
educations array-like An array-like object of education objects.
links array-like An array-like object of link objects.
awards array-like An array-like object of award objects.
certifications array-like An array-like object of certification objects.
associations array-like An array-like object of association objects.
patents array-like An array-like object of patent objects.
publications array-like An array-like object of publication objects.
militaryServices array-like An array-like object of military service objects.

Personal details fields


Personal details fields table
Field Name Type Applicable Markets Description Example
highestLevelOfEducation Single Value AE, AU, BE, BR, CA, CL, CO, CR, CZ, DK, EC, ES, GB, HK, HU, IE, IT, LU, MX, NG, NL, NO, PA, PE, PL, PT, RO, RU, SE, TR, TW, UA, UY, VE, VN,ZA A dropdown with localized levels of education for each corresponding market, where a job seeker can select their highest level. GCSE or equivalent
Diploma of Higher Education
employmentEligibility Single Value AE, AU, BH, EG, GB, HK, IT, KW, MA, NZ, OM, QA, RU, SA, SG Asks if job seekers are eligible to work in a country. Yes
highestCareerLevel Single value FR, HK, IN, KR, VN, ZA Job seekers can select their highest career level from 4 options. New Grad
industry Multi Value AE, AR, BH, BR, CL, CN, CO, CR, EC, EG, ES, FR, GB, IE, IN, KR, KW, LU, MA, MX, NG, OM, PA, PE, QA, RU, SA, TR, TW, UA, UY, VE, ZA A drop-down where job seekers can select the industry in which they work/specialize. Arts & Entertainment
driversLicense Multi Value AR, BE, CL, CO, CR, CZ, EC, ES, GB, IT, JP, MX, NL, PA, PE, RU, TR, UY, VE, ZA A dropdown with localized Driver License options for each corresponding market. Light Vehicles
dateOfBirth Date AE, AR, BH, BR, CK, CN, CO, CR, EC, EG, ES, FR, HK, ID, IN, IT, JP, KR, KW, MA, MX, MY, NG, OM, PA, PE, PT, QA, RU, SA, SG, TR, TW, UA, UY, VE, VN, ZA 3 dropdowns – date, month and year. Order is localized per market. DD-MM-YYYY
educationDescription Open text CH, DE, NO, SE, UA, UY, VN, VN Job seekers can describe their education. Open text
gender Single Value JP The job seeker’s gender. Female
disability Single Value BR, IT, MX, ZA A dropdown with different disability options (BR) or yes/no for remaining markets. Cognitive
OR
Yes
ethnicity Single Value ZA A dropdown with ethnicity options. African
veteranStatus Single Value KR A job seeker’s veteran status. Applicable
NYSCStatus Single Value NG A dropdown for a job seeker’s NYSC status. Ongoing
employmentSupportStatus Single Value KR A job seeker’s employment support status. Applicable
willingToTravel Single Value AR, CL, CO, CR, EC, ES, MX, PA, PE, UY, VE A dropdown for a job seekers’ willingness to travel. Yes
europeanUnionWorkPermit Single Value IE Asks job seekers if they have a European Work Permit. Yes
citizenship Single Value PH, SG, ZA A dropdown for a job seeker’s citizenship. South African Citizen
IDP Checkbox UA Asks job seekers whether they are an internally displaced migrant. IDP (Internally Displaced Migrants)
employmentEligibilityMultiCountries Multi Value ES, IN A dropdown that asks job seekers which countries they are eligible to work in. Afghanistan
idNumber Numeric BR, IT, TR, ZA Asks job seekers to type in their ID Number. Numeric value
totalYearsOfExperience Numeric ID, IN Asks job seekers about their years of experience. 3
hobbiesAndInterests Open text CZ, HU, KR, LU, PL, RO Asks job seekers about their hobbies and interests. Open text

Indeed resume position fields


Indeed resume position fields table
Field name Type Description Example
title string The title of the job. Product Manager
company string The company’s name. Indeed
location string The location of the position. Austin, TX
description string The description of the position. ——–
startDateMonth integer An integer (1-12) representing the starting month (-1 if not provided). 9
startDateYear integer The year of the start date ( -1 if not provided). 2007
endDateMonth integer 1-12 integer representing the starting month (-1 if not provided). -1
endDateYear integer The year of the end date (-1 if not provided). -1
endCurrent boolean A flag indicating if this is a current position. true

Indeed resume education fields


Indeed resume education fields table
Field name Type Description Example
degree string The degree level attained for this education listing. B.A.
field string The degree field studied for this education listing. Computer Science
school string The institution for this education listing. University of Texas
location string The institution location. Austin, TX
startDateYear integer The year of the start date ( -1 if not provided). 2007
endDateYear integer The year of the end date (-1 if not provided). -1
endCurrent boolean A flag indicating if this education is in progress. true

Indeed resume link fields table
Field name Type Description Example
url string The URL of the link. https://www.indeed.com

Indeed resume award fields


Indeed resume award fields table
Field name Type Description Example
title string The title of this award. Best PM at Indeed
description string The description for this award. Awarded for being the best PM in my company.
dateMonth integer An integer (1-12) representing the starting month (-1 if not provided). 9
dateYear integer The year of the start date ( -1 if not provided). 2007

Indeed resume certification fields


Indeed resume certification fields table
Field name Type Description Example
title string The title of this certification. PMP
description string The description of this certification. Project Management Professional certification
startDateMonth integer An integer (1-12) representing the starting month (-1 if not provided). 9
startDateYear integer The year of the start date ( -1 if not provided). 2007
endDateMonth integer An integer (1-12) representing the ending month (-1 if not provided). -1
endDateYear integer The year of the end date (-1 if not provided). -1
endCurrent boolean A flag indicating if this is a current certification. true

Indeed resume association groups fields


Indeed resume association groups fields table
Field name Type Description Example
title string The title of this association. Society for Technical Communication
description string A description of this association. A professional association for technical communication professionals.
startDateMonth integer An integer (1-12) representing the starting month (-1 if not provided). 9
startDateYear integer The year of the start date ( -1 if not provided). 2007
endDateMonth integer An integer (1-12) representing the ending month (-1 if not provided). -1
endDateYear integer The year of the end date (-1 if not provided). -1
endCurrent boolean A flag indicating if this is a current association. true

Indeed resume patent fields


Indeed resume patent fields table
Field name Type Description Example
title string The title of this patent. ——–
description string The description of this patent. ——–
patentNumber string The patent number. ——–
url string The URL for this patent. ——–
dateMonth integer An integer (1-12) representing the starting month (-1 if not provided). 9
dateYear integer The year of the start date ( -1 if not provided). 2007

Indeed resume publication fields


Indeed resume publication fields table
Field name Type Description Example
title string The title of this publication ——–
description string A description of this publication. ——–
url string A URL for this publication. ——–
dateDay integer The day of the month (-1 if not provided). 9
dateMonth integer An integer (1-12) representing the month (-1 if not provided). 9
dateYear integer The year of the date ( -1 if not provided). 2007

Indeed resume military service fields


Indeed resume military service fields table
Field name Type Description Example
serviceBranch string The service branch for this service entry. ——–
branch string The branch for this service entry. ——–
rank string The rank for this service entry. ——–
description string A description for this service entry. ——–
commendations string Any commendations earned for this service entry. ——–
startDateMonth integer An integer (1-12) representing the starting month (-1 if not provided). 9
startDateYear integer The year of the start date ( -1 if not provided). 2007
endDateMonth integer An integer (1-12) representing the starting month (-1 if not provided). -1
endDateYear integer The year of the end date (-1 if not provided). -1
endCurrent boolean A flag indicating if this is a current position. true

POST authenticity

The post request sent to your postUrl contains an HTTP header that can be used to verify the authenticity of the post. Using the shared API secret, Indeed Apply computes a message signature using the HMAC-SHA1 algorithm. This signature is sent as an X-Indeed-Signature HTTP header. The code examples below demonstrate how the message signature is generated.

Using C# (version 4.0)


using System;
usingSystem.Diagnostics;
usingSystem.Security.Cryptography;
usingSystem.Text;
 
classMainClass {
  publicstatic void Main (string[] args) {
    String message = getMessage();
    String apiSecret = "your api secret key";
    String signature = computeSignature(message, apiSecret);
    if(signature.Equals("m7I9OcotC2GxmVEVAufv5TD7lEk=")) {
      Console.WriteLine("B64 HMAC SHA1: "+signature);
    } elseConsole.WriteLine("invalid value: "+signature);
  }
   
  staticstring computeSignature(string input, String key) {
      byte[] keyBytes = Encoding.UTF8.GetBytes(key);
      HMACSHA1 myhmacsha1 = newHMACSHA1(keyBytes);
      byte[] inputBytes = Encoding.UTF8.GetBytes(input);
      byte[] hash = myhmacsha1.ComputeHash(inputBytes);
      returnSystem.Convert.ToBase64String(hash);
  }
   
  staticstring getMessage() {
    return"{"locale":"en_US","applicant":{"fullName":"John 
Doe","email":"john.doe@example.com"}}";
  }
   
}

Using Java (version 1.8)


import javax.crypto.Mac;
importjavax.crypto.spec.*;
importjavax.crypto.SecretKey;
importjava.util.Base64;
 
publicclass Main {
 
    publicstatic void main(String[] args) {
 
        String message = getMessage();
        String apiSecret = "your api secret key";
        String signature = computeSignature(message, apiSecret);
        if(!signature.equals("m7I9OcotC2GxmVEVAufv5TD7lEk="))
            System.out.println("invalid value "+signature);
        elseSystem.out.println("B64 HMAC SHA1: "+signature);
 
    }
 
    staticString computeSignature(String message, String apiSecret) {
        try{
            finalbyte[] keyBytes = apiSecret.getBytes();
            finalSecretKey signingKey = new SecretKeySpec(keyBytes, "HmacSHA1");
            finalMac mac = Mac.getInstance("HmacSHA1");
            mac.init(signingKey);
            returnnew 
String(Base64.getEncoder().encode(mac.doFinal(message.getBytes("UTF-8"))));
        } catch(Exception e) {
            System.out.println(e.getMessage());
            thrownew RuntimeException(e);
        }
    }
 
    publicstatic String getMessage() {
        return"{"locale":"en_US","applicant":{"fullName":"John 
Doe","email":"john.doe@example.com"}}";
    }
}

Using Perl (version 5.0)


use Digest::SHA qw(hmac_sha1_base64);
useEncode qw(encode);
 
# your secrete key
my$key  = "your api secret key";
# test message
my$message = get_message();
# compute signature
my$signature = hmac_sha1_b64_string($key, $message);
 
if($signature eq "m7I9OcotC2GxmVEVAufv5TD7lEk=") {
    print"B64 HMAC SHA1: " . $signature, "n";
} else{
    print"invalid value! ", $signature, "n";
}
 
subhmac_sha1_b64_string {
    my($key, $data) = @_;
    my$keybtes = encode("UTF8", $key);
    my$databytes = encode("UTF8", $message);
    my$b64digest = hmac_sha1_base64($databytes, $keybtes);
    # Perl does not pad b64 output, so we have to do it manually
    while(length($b64digest) % 4) {
        $b64digest.= '=';
    }
   return$b64digest;
}
 
subget_message {
    return"{"locale":"en_US","applicant":{"fullName":"John 
Doe","email":"john.doe@example.com"}}";
}

Using PHP (version 7.0)


function sign($str, $key) {
    $opts=  OPENSSL_RAW_DATA;
    $digest= hash_hmac("sha1", $str, $key, $raw_output = TRUE);
    $signature= base64_encode($digest);
    return$signature;
}
 
$api_secret= "your api secret key";
$message= "{"locale":"en_US","applicant":{"fullName":"John 
Doe","email":"john.doe@example.com"}}";
 
$signature= sign($message,$api_secret);
 
if( $signature!= "m7I9OcotC2GxmVEVAufv5TD7lEk=")
    print("invalid value ". $signature);
elseprint("B64 HMAC SHA1: " . $signature);

Using Python (version 2.7)


from hashlib import sha1
importhmac
importbase64
 
# your secret key
secret ="your api secret key".encode("utf-8")
# test message
message ="{"locale":"en_US","applicant":{"fullName":"John 
Doe","email":"john.doe@example.com"}}".encode('UTF-8')
# compute the hash
message_hashed =hmac.new(secret, message, sha1)
digest =message_hashed.digest()
# b64 encode the hash...this is the message authentication value
signature =base64.b64encode(digest)
ifsignature != "m7I9OcotC2GxmVEVAufv5TD7lEk=":
    print"invalid value "+signature
else:
    print'B64 HMAC SHA1: ' + signature

Using Python (version 3.6)


from hashlib import sha1
importhmac
importbase64
 
# your secret key
secret ="your api secret key".encode("utf-8")
# test message
message ="{"locale":"en_US","applicant":{"fullName":"John 
Doe","email":"john.doe@example.com"}}".encode("UTF-8")
# compute the hash
message_hashed =hmac.new(secret, message, sha1)
# b64 encode the hash...this is the message authentication value
signature =base64.b64encode(message_hashed.digest()).decode("UTF-8")
ifsignature != "m7I9OcotC2GxmVEVAufv5TD7lEk=":
    print("invalid value "+signature)
else:
    print("B64 HMAC SHA1: "+ signature)

Email

If you choose to receive applications via email, you must set the email configuration attribute in your button’s configuration. When a user completes the application, Indeed sends an email containing the user’s full name, email address, and cover letter as well as their resume as an attachment. If the user applies with an Indeed Resume, the version of the resume is directly included in the email and a PDF version is attached. The email address must be encrypted.

Encrypted email example


<span class="indeed-apply-widget"
    data-indeed-apply-apiToken="8f57d522dc544a737f70ad5828d5ace1"
    data-indeed-apply-jobLocation="New York, NY 10110"
    data-indeed-apply-jobCompanyName="Your Company"
    data-indeed-apply-jobTitle="Test Engineer"
    data-indeed-apply-email="b18d0be4c173dfa2b7cb7856e7c7b6f02a563867a9df67ca208c8b9654966299">
</span>

Encryption and decryption

When using Indeed Apply through email, you must encrypt the email to which Indeed sends the applications. Indeed expects the email to be encrypted using the AES algorithm with your 128-bit secret key. The cipher mode is CBC with PKCS5 padding. The initialization vector is 16 bytes of 00.

Note: Do not include more than one email address in the data-indeed-apply-email attribute for any given job in your XML feed. This will result in errors that will remove Indeed Apply from this job.

To encrypt your emails:

  1. Using your secret key, generate a 128-bit secret key using the first 16 bytes.
  2. Read the bytes of the plain-text email encoded in UTF-8.
  3. Encrypt the email using the AES algorithm and your 128-bit key. Be sure to use CBC mode and PKCS5 padding.
  4. Convert the encrypted bytes to a hex string.
  5. Use this hex string as your data-indeed-apply-email attribute.

You then use the encrypted email in place of the plain-text email. Indeed Apply will recognize you are using an encrypted email.

Encrypted email example


<span class="indeed-apply-widget"
	data-indeed-apply-apiToken="8e94c9959e5021fc7f70ad5828d5ace1"
	data-indeed-apply-jobLocation="Austin TX"
	data-indeed-apply-jobCompanyName="Your Company"
	data-indeed-apply-jobTitle="Engineer"
	data-indeed-apply-email="b18d0be4c173dfa2b7cb7856e7c7b6f02a563867a9df67ca208c8b9654966299">
</span>

Encryption and decryption examples

Using C# (version 4.0)


using System.Text;
using System.IO;
using System;
using System.Security.Cryptography;

public class IA_email_encryption_test {

  public static void Main(string[] args) {
    
    string email = "john.doe@example.com";
    string key = "your api secret key";
    
    // only use first 16 bytes of the key
    byte[] keybytes = Encoding.UTF8.GetBytes(key);
    byte[] truncatedkeybytes = new byte[16];
    Array.Copy(keybytes , truncatedkeybytes , 16);
    // initialization vector is all 0's; no additonal initilization required
    byte[] iv = new byte[16];
    
    byte[] ciphertext = Encrypt(email, truncatedkeybytes, iv);
    
    string hexciphertext = ByteArrayToHexString(ciphertext);
    
    if(!hexciphertext.Equals( "eaaacff9df2e4c2a63083a303d4521f0bd41e375232a2895310179bc030addfb")) {
      Console.WriteLine("invalid encrypted value!");
    } else {
      Console.WriteLine("hex encoded encrypted email: "+hexciphertext);
      // we decrypt merely as an exercise
      string decrypted = Decrypt(ciphertext, truncatedkeybytes, iv);
      Console.WriteLine("Decrypted E-mail: "+decrypted);
    }
  }  
  
  public static byte[] Encrypt(string plainText, byte[] key, byte[] iv ) {
   
    var cypher = new AesManaged();
    cypher.Mode = CipherMode.CBC;
    cypher.Padding = PaddingMode.PKCS7;
    cypher.KeySize = 128;
    cypher.BlockSize = 128;
    cypher.Key = key;
    cypher.IV = iv;

    var icTransformer = cypher.CreateEncryptor();
    var msTemp = new MemoryStream();

    var csEncrypt = new CryptoStream(msTemp, icTransformer, CryptoStreamMode.Write);
    var sw = new StreamWriter(csEncrypt);
    sw.Write(plainText);
    sw.Close();
    sw.Dispose();

    csEncrypt.Clear();
    csEncrypt.Dispose();

    byte[] bResult = msTemp.ToArray();
    
    return bResult;
  }
  
  public static string Decrypt(byte[] ciphertext, byte[] key, byte[] iv ) {
    
    var cypher = new AesManaged();
    cypher.Mode = CipherMode.CBC;
    cypher.Padding = PaddingMode.PKCS7;
    cypher.KeySize = 128;
    cypher.BlockSize = 128;
    cypher.Key = key;
    cypher.IV = iv;

    var icTransformer = cypher.CreateDecryptor();
    var msTemp = new MemoryStream(ciphertext);

    var csDecrypt = new CryptoStream(msTemp, icTransformer, CryptoStreamMode.Read);
    var sr = new StreamReader(csDecrypt);
    
    string plaintext = sr.ReadToEnd();

    csDecrypt.Clear();
    csDecrypt.Dispose();

    return plaintext;
  }
  

  private static string ByteArrayToHexString(byte[] bytes)
  {
      StringBuilder sbHex = new StringBuilder();
      foreach (byte b in bytes)
          sbHex.AppendFormat("{0:x2}", b);
      return sbHex.ToString();
  }
  
}

Using Java (version 1.8)


import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.lang.RuntimeException;
import javax.crypto.Cipher;
import javax.crypto.spec.*;
import javax.crypto.spec.SecretKeySpec;

public class Main {

    public static void main(String[] args) {

        String email = "john.doe@example.com";
        String apiSecret = "your api secret key";
        String encrypted_email = encrypt(email, apiSecret);
        String decrypted_email = decrypt(encrypted_email, apiSecret);
        if(encrypted_email.equals("eaaacff9df2e4c2a63083a303d4521f0bd41e375232a2895310179bc030addfb")) {
            System.out.println("B64 encoded encrypted email: "+encrypted_email);
            System.out.println("decrypted email: "+decrypted_email);
        } else {
            System.out.println("invalid encrypted value!");
        }

    }

    static String encrypt(String message, String apiSecret) {
        try {
            // get api secret bytes
            byte[] keyBytes = apiSecret.getBytes(Charset.forName("UTF-8"));
            // get message bytes
            byte[] message_bytes = message.getBytes("UTF-8");
            // note that we only use the first 16 bytes of the the key
            SecretKeySpec key = new SecretKeySpec(keyBytes, 0, 16, "AES");
            // get appropriate cipher using PKCS5 padding
            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);
            // encrypt the message
            byte[] email_encrypted = cipher.doFinal(message_bytes);
            // this is the value that should be sent to Indeed
            return bytesToHexString(email_encrypted);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new RuntimeException(e);
        }
    }

    static String decrypt(String message, String apiSecret) {
        try {
            // get api secret bytes
            byte[] keyBytes = apiSecret.getBytes(Charset.forName("UTF-8"));
            // get message bytes
            byte[] message_bytes = message.getBytes(Charset.forName("UTF-8"));
            // convert from b64 encoding
            message_bytes = decodeHex(message_bytes);
            // Create a SecretKeySpec using api secret
            // note that we only use the first 16 bytes of the the key
            SecretKeySpec key = new SecretKeySpec(keyBytes, 0, 16, "AES");
            // get appropriate cipher using PKCS5 padding
            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);
            // decrypt the message
            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;
        }
    }

}

Using Perl (version 5.0)


use Crypt::CBC;
use Encode;

# your secret key
my $secret = encode('UTF-8', 'your api secret key');
# truncate key to 16 bytes
my $key = substr($secret, 0, 16);
# initialization vector of zeros
my $iv = "\0" x 16;
# create cipher
my $cipher = Crypt::CBC->new( -literal_key => 1,
 -header => 'none',
 -key => $key,
 -keysize => 16,
 -iv => $iv,
 -cipher => "Crypt::OpenSSL::AES"
 );
# Encrypt the UTF-8 encoded string into a hex version of the data
my $email_encrypted = $cipher->encrypt_hex(encode('UTF-8', 'john.doe@example.com'));

if($email_encrypted eq 'eaaacff9df2e4c2a63083a303d4521f0bd41e375232a2895310179bc030addfb') {
	print "Hex value of encrypted: $email_encryptedn";
	# Decrypt the hex string to see if it's still intact
	my $email_decrypted = $cipher->decrypt_hex($email_encrypted);
	print "Decrypted: $email_decryptedn";
} else {
	print "invalild encrypted value! $email_encryptedn";
}

Using PHP (version 7.0)


function pkcs5_pad ($text) {
    $blocksize = 16;
    $pad = $blocksize - (strlen($text) % $blocksize);
    $text .= str_repeat(chr($pad), $pad);
    return $text;
}

function pkcs5_unpad($text) {
    $pad = ord($text{strlen($text)-1});
    if ($pad > strlen($text)) return false;
    if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) return false;
    return substr($text, 0, -1 * $pad);
}

function encrypt($str, $key) {
    $iv = str_repeat("\0", 16);
    $str = pkcs5_pad($str);
    $opts =  OPENSSL_RAW_DATA;
    $encrypted = openssl_encrypt($str, 'AES-128-CBC', $key, $opts, $iv);
    return $encrypted;
}

function decrypt($str, $key) {
    $iv = str_repeat(""\0", 16);
    $opts =  OPENSSL_RAW_DATA;
    $decrypted = openssl_decrypt($str, 'AES-128-CBC', $key, $opts, $iv);
    return pkcs5_unpad($decrypted);
}

$api_secret = "your api secret key";
$email_address = "john.doe@example.com";

// truncate api-secret to first 16 bytes
$newkey = mb_strcut($api_secret, 0, 16, "UTF8");
// encrypt
$encrypted = encrypt($email_address, $newkey);
// we decrypt merely as an exercise
$decrypted = decrypt($encrypted, $newkey);
// this is the value to send to Indeed
$encryptedhex = bin2hex($encrypted);
if($encryptedhex != "eaaacff9df2e4c2a63083a303d4521f0bd41e375232a2895310179bc030addfba655e21c3309d9343206ae55866764e8")
    print("invalid encrypted hex value!");
print("Hex value of encrypted: " . $encryptedhex . "n");
print("Decrypted: " . $decrypted . "n");

Using Python (version 2.7)


# https://pypi.python.org/pypi/pycryptodome/3.5.1
from Crypto.Cipher import AES
# https://pypi.python.org/pypi/pkcs7/0.1.2
from pkcs7 import PKCS7Encoder
# your secret key
secret = 'your api secret key'.encode('utf-8')
# truncate key to 16 bytes
key_bytes = secret[0:16]
# initialization vector of zeros
iv = '\0' * 16
# the email address to encrypt
message_plaintext = 'john.doe@example.com'
# pad the plaintext to 16 byte boundary
PKCS7encoder = PKCS7Encoder()
message_plaintext_padded = PKCS7encoder.encode(message_plaintext);
# encrypt the message bytes
cipher = AES.new(key_bytes, AES.MODE_CBC, iv)
message_encrypted_raw = cipher.encrypt(message_plaintext_padded)
# this is the value that should be sent to Indeed
message_encrypted_hex = message_encrypted_raw.encode('hex')
# we need a new instance for decrypt because the ciphers are stateful
decipher = AES.new(key_bytes, AES.MODE_CBC, iv)
# we decrypt here simply as an exercise
message_decrypted_raw = decipher.decrypt(message_encrypted_raw)
# strip padding
message_decrypted = PKCS7encoder.decode(message_decrypted_raw)
# confirm encrypted value
if message_encrypted_hex == "eaaacff9df2e4c2a63083a303d4521f0bd41e375232a2895310179bc030addfb":
  print 'Hex value of encrypted: ' + message_encrypted_hex
  print 'Decrypted: '+message_decrypted
else: 
  print 'invalild encrypted value! ' + message_encrypted_hex

Using Python (version 3.6)


# https://pypi.python.org/pypi/pycryptodome/3.5.1
from Crypto.Cipher import AES
# https://pypi.python.org/pypi/pkcs7/0.1.2
from pkcs7 import PKCS7Encoder
# your secret key
secret = 'your api secret key'.encode('utf-8')
# truncate key to 16 bytes
key_bytes = secret[0:16]
# initialization vector of zeros
iv = bytes('\0' * 16, encoding='UTF-8')
# the email address to encrypt
message_plaintext = 'john.doe@example.com'
# pad the plaintext to 16 byte boundary
PKCS7encoder = PKCS7Encoder()
message_plaintext_padded = PKCS7encoder.encode(message_plaintext)
# encrypt the message bytes
message_bytes = message_plaintext_padded.encode('UTF-8')
cipher = AES.new(key_bytes, AES.MODE_CBC, iv)
message_encrypted_raw = cipher.encrypt(message_bytes)
# this is the value that should be sent to Indeed
message_encrypted_hex = message_encrypted_raw.hex()
# we decrypt here simply as an exercise
decipher = AES.new(key_bytes, AES.MODE_CBC, iv)
message_decrypted_raw = decipher.decrypt(message_encrypted_raw).decode('UTF-8')
# strip padding
message_decrypted = PKCS7encoder.decode(message_decrypted_raw)
# confirm encrypted value
if message_encrypted_hex == "eaaacff9df2e4c2a63083a303d4521f0bd41e375232a2895310179bc030addfb":
  print('Hex value of encrypted: ' + message_encrypted_hex)
  print('Decrypted: ' + message_decrypted)
else: 
  print('invalild encrypted value! ' + message_encrypted_hex)

(Go back to the top)


Testing and Monitoring Your IA Integration

We want to help you provide the best possible experience for job seekers and employers who use Indeed. Review the following sections to avoid issues with your integration.

Testing IA

Test your Indeed Apply code using the Indeed Apply test tool. Using the test tool, you can enter job metadata and generate the appropriate XML element or HTML code. You can also enter your own XML element or HTML code and verify that Indeed reads the metadata correctly.

Monitoring integration health

When integrating with Indeed Apply, you should set up monitoring to ensure:

  • The integration successfully delivers job applications
  • Questions files are consistently available and valid

Indeed monitors whether applications are delivered successfully to our partners, along with other health indicators. If any problems arise, Indeed will contact you. In some cases, Indeed will disable the Apply feature for some or all of your jobs until issues are fixed.

Note: Undelivered applications are not lost. In case of failure, retry attempts are made automatically at periodic intervals after the original apply. If delivery is not possible, applications are retained for 30 days and retry attempts can be made on request.

To avoid integration issues, make sure you are returning HTTP status code 200 for all applications that are successfully received. Indeed Apply considers any other HTTP status codes, post timeouts or connect timeouts to be failures.

Additionally, return the following statuses in these conditions:

  • 409 (Conflict): Use if there is a duplicate application already in your system.
  • We define duplicate as an application from the same job seeker email, to the same jobid, within 120 days.
  • Note: Applications with a status of 409 are presumed to be duplicate applications and will not be included in automatic resends.
  • 410 (Gone): Use if a job Indeed attempts to post to is expired or no longer available.

If your jobs use screener questions, also ensure the pages that host those files:

  • are consistently available
  • do not redirect
  • are properly formed

Common integration issues

The following common issues may cause integration errors with POST or Question URLs:


Common issues table
Issue Solution
Redirecting to another location, e.g., via 301 redirects

Ensure the POST and Question URLs do not include redirects.

If you must include a protocol change (i.e. HTTP to HTTPS), be sure to:

  • send a 301 redirect error
  • include the precise HTTPS version of your URL in the location header

Any alternative behavior will cause errors.

Expired SSL certificate Renew your SSL certificate. For more information, see the List of Trusted Root SSL Certificates.
Misconfigured SSL

Use an SSL server test to analyze and help diagnose the problem, e.g., https://www.ssllabs.com/ssltest/

Make sure to:

  • send the full certificate chain
  • check that none of the certificates in the chain require additional downloads

Any alternative behavior will cause errors.

Question’s JSON is invalid or doesn’t follow Indeed’s requirements definition Review the screener question requirements. Use the Test Indeed Apply Questions tool to preview changes.
Other issues accessing the resource (404, 500 errors, timeouts)

Implement strategies to ensure your resources reliably scale to
accommodate high-traffic periods. Additionally, use appropriate HTTP response codes to help us investigate any issues that may occur.

As Indeed does not have a post size limit, please ensure you’re able to handle any size post from Indeed. If you are unable to accommodate this request, please return an HTTP 413 error to indicate the post was too large.

XML and integration checklist

Review the following checklist before submitting your XML feed to your Customer Success representative. Following this checklist ensures the submission process is efficient for you and Indeed.

  1. Check the top of the XML file to make sure version, encoding, and publisher information are present.
    
     <?xml version=”1.0” encoding=”utf-8”?>
        <source>
        <publisher> Example Job Site</publisher>
        <publisherurl>http://www.examplejobsite.com</publisherurl>
        <lastbuilddate>Thu, 15 Oct 2015 09:44:37 GMT</lastbuilddate>
    
  2. Include all companies in the XML file. Indeed already has a list of most jobs, so any missing companies will prevent the file from going live.
  3. Ensure you have included all jobs available on your website; this includes jobs from sub-brands or subsidiaries of the parent company. Discrepancies in job volume between career portals and what’s in the XML may result in lowered visibility for jobs coming through the provided XML.
    Note: Every job needs to have a unique URL in the <url> tag.
  4. Confirm that all the following required fields are present and properly formatted as outlined in the XML Feed Elements section.
  5. Remove all TEST jobs from the file. Otherwise it will be rejected.
  6. Make sure you test the Indeed Apply data you’re including in the feed. If you have any trouble, contact your Alliances Manager or Customer Success representative and they’ll troubleshoot with you.
    • Use the Indeed Apply button test tool and the IA code in the XML to confirm the feed is working properly.
    • Ensure that all URLs (joburl, posturl, questions) included in metadata are fully URL encoded.
    • Verify that your analytics field can categorize applications as organic, sponsored, or Indeed Targeted Ad.
      For more information, refer to Indeed Apply top-level JSON fields.
    • Make sure every job has Indeed Apply included in the <job> node.
    • Ensure you’ve properly encrypted the email address if you use email as your delivery method.
    • Check that your SSL certificate is valid and up-to-date.
    • Verify your question JSON using the question test tool.
      Note: The test tool does not provide sponsored data information.
    • Make sure your screener questions are in line with our best practices.
  7. After completing all of the preceding steps, you can either:
    • Upload the XML to Indeed’s FTP. (If you need an account, let your Customer Success representative know.)
    • Update the file hosted on either an FTP or a URL get request.
  8. Contact your Customer Success representative so they can review before submission.