apply_id
- Indeed ApplyId. String, exactly 64 characters long.
disposition_timestamp
- ISO-8601 format date and time when a disposition activity occurred.
Timezone information is required.
status
- Normalized disposition status, e.g. "HIRED".
See the "Field Definitions" section below.
Full code examples for using the API are below.
Partners should set up a scheduled job that runs periodically to generate a report of applications
with status changes.
An example would be a csv with headers:
disposition_timestamp
,
apply_id
and
status
.
NEW -> REJECTED
is valid, NEW -> NEW -> REJECTED
is not.
Note that the csv file should only contain applications that have had a change in status. Here are examples of correct and incorrect csv file uploads for a given series of application status changes.
Sample Correct XML (for legacy integrations only)
disposition_timestamp | apply_id | status |
---|---|---|
2019-01-01T01:00:00z | appid001 | NEW |
disposition_timestamp | apply_id | status |
---|---|---|
2019-01-02T01:00:00z | appid002 | NEW |
disposition_timestamp | apply_id | status |
---|---|---|
2019-01-03T01:00:00z | appid001 | CONTACTED |
2019-01-03T01:00:00z | appid003 | NEW |
disposition_timestamp | apply_id | status |
---|---|---|
2019-01-01T01:00:00z | appid001 | NEW |
disposition_timestamp | apply_id | status |
---|---|---|
2019-01-01T01:00:00z | appid001 | NEW |
2019-01-02T01:00:00z | appid002 | NEW |
disposition_timestamp | apply_id | status |
---|---|---|
2019-01-02T01:00:00z | appid002 | NEW |
2019-01-03T01:00:00z | appid001 | CONTACTED |
2019-01-03T01:00:00z | appid003 | NEW |
This example is incorrect for 2 reasons:
You should only submit data ONLY where an apply's status has changed. In other words, each unique row (disposition_timestamp, apply_id, status) should be uploaded only once.
Field | Required? | Description | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
apply_id | Yes |
The unique identifier for the job application that is used to reference the employer, candidate, job, and more.
This is the |
||||||||||||||
status | Yes |
IMPORTANT: Read this carefully. Normalized application status. Indeed uses the Status field to understand what happens to applications once they are in your ATS. There are 6 different statuses we look for (see below). You must map all of your ATS's statuses into these 6 Indeed Statuses. It is absolutely crucial you accurately map the statuses from your ATS into the 6 categories. Without an accurate mapping, Indeed cannot reliably determine what happens to an application. If you support custom statuses in your ATS, please mention this to your Indeed Alliances manager.
If you are unable to comply with this step, please contact your Indeed Alliances manager. |
||||||||||||||
disposition_timestamp | Yes | ISO 8601 format timestamp with timezone information for when the status change occurred.
E.x. November 5, 1994 at 8:15 am Eastern Time would be: 1994-11-05T08:15:30-05:00
|
Our API allows your organization to programmatically deposit disposition information. The integration takes two steps:
1. Obtain a presigned Amazon S3 URL by POST
request to this API using the assigned API Key.
2. Make a PUT
request to upload the file to the URL returned in Step 1.
Note: To prevent uploading files with the same name, use a naming convention that allows you to distinguish your files from other files in your organization.
To receive the signed S3 bucket URL, create a POST
request to our API with the
file names you are uploading.
A presigned upload URL will be returned for each file. Requirements and responses are
described below.
Content-Type: application/json
Accept: application/json
token: <YOUR API KEY>
file_names
file_names
sent
and values corresponding to the presigned S3 URL. See examples below for details.
Error
will be returned and give more information.
Once you have the presigned URL, you can upload files to the AWS Bucket using a PUT
request.
An example of doing so is shown below, however you may also refer to the
official AWS documentation.
Use a unix-based system with bash and the curl
command.
# Get the presigned URLs
curl \
-H "Content-Type: application/json" \
-H "token: XXXXXXXXX" \
-H "Accept: application/json" \
--request POST \
--data '{"file_names":["test_file_1.csv","test_file_2.csv"]}' \
https://indeed-atsdi.com/api/get_upload_url
##### API Response #####
# {
# "test_file_1.csv": "https://blah.s3.amazonaws.com/presigned_url_1",
# "test_file_2.csv": "https://blah.s3.amazonaws.com/presigned_url_2"
# }
##### END Response #####
# Upload files to S3, one at a time.
# Put pre-signed URL in quotes.
curl -X PUT -T /path/to/test_file_1.csv \
-L "https://blah.s3.amazonaws.com/presigned_url_1"
# Put pre-signed URL in quotes.
curl -X PUT -T /path/to/test_file_2.csv \
-L "https://blah.s3.amazonaws.com/presigned_url_2"
Use python 3 and the requests
library
import requests
import json
url = 'https://indeed-atsdi.com/api/get_upload_url'
file_paths = ['/path/to/test_file_1.csv', '/path/to/test_file_2.csv']
API_KEY = 'XXXXXXX'
# File tuple [0] = path, [1] = basename.
file_infos = [(fp, ntpath.basename(fp)) for fp in file_paths]
headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'token': API_KEY
}
# This gets the presigned URLs
r = requests.post(url,
headers=headers,
data=json.dumps({'file_names': [fi[1] for fi in file_infos]}))
try:
r.raise_for_status()
except:
print("Error occurred.")
print (r.json())
# Upload file(s) to AWS.
s3_signed_urls = r.json()
for file_info in file_infos:
with open(file_info[0], 'rb') as data:
upload_result = requests.put(s3_signed_urls[file_info[1]], data=data)
try:
upload_result.raise_for_status()
except:
print("Issue uploading file to AWS.")
Use ruby and only standard packages
require 'net/http'
require 'net/https'
require 'uri'
require 'json'
Tuple = Struct.new(:_1, :_2)
api_url = URI.parse('https://indeed-atsdi.com/api/get_upload_url')
file_paths = ['/path/to/test_file_1.csv', '/path/to/test_file_2.csv']
api_key = 'XXXXXXX'
names = []
file_info = []
file_paths.each do |path|
file_info.push(Tuple.new(path, File.basename(path)))
names.push(File.basename(path))
end
header = {'Accept': 'application/json',
'Content-Type': 'application/json',
'token': api_key}
data = {file_names: names}
# Access indeed api
api_response = nil
Net::HTTP.start(api_url.host, :use_ssl => true) do |http|
api_response = http.send_request("POST", api_url.request_uri, data.to_json, header)
end
case api_response
when Net::HTTPSuccess
json = JSON.parse(api_response.body)
# Upload to S3.
file_info.each do |upload_file|
s3_url = URI.parse(json[upload_file._2])
file = File.open(upload_file._1, "rb")
file_data = file.read
file.close
s3_response = nil
Net::HTTP.start(s3_url.host, :use_ssl => true) do |http|
s3_response = http.send_request('PUT', s3_url.request_uri, file_data, {
# Content type has to be here, even if set to '', or else 403 error.
"content-type" => '',
})
end
case s3_response
when Net::HTTPSuccess
print 'Successfully uploaded ' + upload_file._1 + "\n"
else
print 'Error uploading file ' + upload_file._1 + "\n"
print s3_response.inspect + "\n"
end
end
else
print 'Bad Response from Indeed API.' + "\n"
print api_response.inspect + "\n"
end
Use PHP with standard libraries and curl PHP module.
<?php
class IndeeddispositionClient{
private static $api_key = 'XXXXXXXXX';
private static $api_url = 'https://indeed-atsdi.com/api/get_upload_url';
static function get_s3_url($filename) {
$url = self::$api_url;
$data = '{"file_names":["'.$filename.'"]}';
$headers = array(
'Content-Type: application/json',
'token: ' . self::$api_key,
'Accept: application/json'
);
$options = array(
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $data,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => 1
);
$curl = curl_init($url);
curl_setopt_array($curl, $options);
$res = curl_exec($curl);
curl_close($curl);
return $res;
}
static function upload_to_s3($file_path_string, $signed_url){
$fh = fopen($file_path_string, 'rb');
$options = array(
CURLOPT_VERBOSE => 1,
CURLOPT_POST => 1,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => $signed_url,
CURLOPT_INFILE => $fh,
CURLOPT_INFILESIZE => filesize($file_path_string),
CURLOPT_PUT => 1
);
$ch = curl_init();
curl_setopt_array($ch, $options);
$result = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
fclose($fh);
curl_close($ch);
return $result;
}
}
$file_paths = array("test_file_1.csv","test_file_2.csv");
foreach ($file_paths as $file_path){
if (!file_exists($file_path)) {
print 'Cannot find file '.$file_path."\n";
throw new Exception('File not found '.$file_path);
}
$file_name = basename($file_path);
print "Uploading ".$file_name ."\n";
print "... ".$file_name ."\n";
$s3_url = json_decode(IndeeddispositionClient::get_s3_url($file_name), true)[$file_name];
$result = IndeeddispositionClient::upload_to_s3($file_path, $s3_url);
print $result;
print "\nFinished with ".$file_name ."\n";
}
?>
SignatureDoesNotMatch
error when trying to upload a file to S3 using a pre-signed upload URL.
To receive assistance, please contact our integration support team at: [email protected]
While our integration documentation is publicly available as a reference to understand and plan your integration with Indeed, it is intended to be implemented only by ATS partners who have signed a Master Services Agreement with us.