Legacy Custom Objects Jobs

The Jobs API lets you define and run asynchronous batch operation jobs on legacy object records and legacy relationship records. For example, you can define and run a single job that creates many object records.

For more information, see Jobs in the Legacy custom objects developer guide.

See also Rate limits in the introduction.

JSON format

Jobs are represented as JSON objects with the following properties:

NameTypeRead-onlyMandatoryDescription
completed_atstringtruefalseWhen the job was completed
created_atstringtruefalseCreation date-time for this job
idstringtruefalseThe ID of the Job
job_statusstringtruefalseThe job status. See Job statuses. Allowed values are "queued", "processing", "failed", "completed", or "aborted".
resultsarrayfalsefalseThe results that were affected by this Job
updated_atstringtruefalseLast update date-time for this job

Job statuses

A job can have one of the following statuses:

StatusDescription
queuedProcessing the job hasn't started yet
processingThe job is being processed
completedThe job has been processed completely and the record is available. The result indicates if some records have failed. A job can be completed even if some or all the records have failed
failedThe job failed to process the full request due to an unexpected error, such as the request is compressed with an unsupported format, or an internal server error. Even if the job failed, some records could have been completed successfully
abortedThe job won't be processed. This status is assigned when a job is aborted while the job is queued

You might also receive an "404 Not Found" HTTP response. Jobs and their related ids expire after a day.

Example

{  "completed_at": "2017-11-03T16:00:16Z",  "created_at": "2017-11-03T16:00:06Z",  "id": "8b72559ae838-c9a0-11e7-abc4-cec278b6b50a6e6",  "job_status": "completed",  "results": [    {      "data": {        "id": "73c698be-cb64-4678-ba73-29683d2c32er"      },      "success": true    },    {      "errors": [        {          "code": "UnprocessableEntity",          "detail": "External Id is already in use for the Resource Type key: product",          "status": "422",          "title": "Unprocessable Entity"        }      ],      "success": false    }  ],  "updated_at": "2017-11-03T16:00:16Z"}

List Jobs

  • GET /api/sunshine/jobs

Returns all current jobs or a list filtered by status. See Job statuses.

Jobs expire after one day, after which they can no longer be accessed.

You can use a parameter named status to filter the results. Example:

GET /api/sunshine/jobs?status=queued

The allowed parameter values are queued, processing, failed, completed, or aborted.

Allowed for

  • Agents

Parameters

NameTypeInRequiredDescription
statusstringQueryfalseThe status to filter the jobs. Allowed values are "queued", "processing", "failed", "completed", or "aborted".

Code Samples

curl
curl https://{subdomain}.zendesk.com/api/sunshine/jobs \  -v -u {email_address}/token:{api_token}
Go
import (	"fmt"	"io"	"net/http")
func main() {	url := "https://support.zendesk.com/api/sunshine/jobs?status="	method := "GET"	req, err := http.NewRequest(method, url, nil)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Content-Type", "application/json")
	client := &http.Client {}	res, err := client.Do(req)	if err != nil {		fmt.Println(err)		return	}	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)	if err != nil {		fmt.Println(err)		return	}	fmt.Println(string(body))}
Java
import com.squareup.okhttp.*;OkHttpClient client = new OkHttpClient();HttpUrl.Builder urlBuilder = HttpUrl.parse("https://support.zendesk.com/api/sunshine/jobs")		.newBuilder()		.addQueryParameter("status", "");
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("GET", null)		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');
var config = {  method: 'GET',  url: 'https://support.zendesk.com/api/sunshine/jobs',  headers: {	'Content-Type': 'application/json',  },  params: {    'status': '',  },};
axios(config).then(function (response) {  console.log(JSON.stringify(response.data));}).catch(function (error) {  console.log(error);});
Python
import requests
url = "https://support.zendesk.com/api/sunshine/jobs?status="headers = {	"Content-Type": "application/json",}
response = requests.request(	"GET",	url,	headers=headers)
print(response.text)
Ruby
require "net/http"uri = URI("https://support.zendesk.com/api/sunshine/jobs")uri.query = URI.encode_www_form("status": "")request = Net::HTTP::Get.new(uri, "Content-Type": "application/json")response = Net::HTTP.start uri.hostname, uri.port, use_ssl: true do |http|	http.request(request)end

Example response(s)

200 OK
// Status 200 OK
{  "data": [    {      "completed_at": "2017-11-03T16:04:06Z",      "created_at": "2017-11-03T16:00:06Z",      "id": "559ae838-c9a0-11e7-abc4-cec278b6b50a",      "job_status": "completed",      "updated_at": "2017-11-03T16:04:06Z"    },    {      "completed_at": null,      "created_at": "2017-11-03T16:02:06Z",      "id": "886ae838-c9a0-11e7-abc4-cec278b6b50a",      "job_status": "processing",      "updated_at": "2017-11-03T16:04:06Z"    }  ]}

Show Job

  • GET /api/sunshine/jobs/{custom_object_job_id}

Returns the status of the specified job. See Job statuses.

Jobs expire after one day, after which they can no longer be accessed.

Allowed for

  • Agents

Parameters

NameTypeInRequiredDescription
custom_object_job_idstringPathtrueThe ID of the legacy custom object job

Code Samples

curl
curl https://{subdomain}.zendesk.com/api/sunshine/jobs/{id} \  -v -u {email_address}/token:{api_token}
Go
import (	"fmt"	"io"	"net/http")
func main() {	url := "https://support.zendesk.com/api/sunshine/jobs/8b72559ae838-c9a0-11e7-abc4-cec278b6b50a6e6"	method := "GET"	req, err := http.NewRequest(method, url, nil)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Content-Type", "application/json")
	client := &http.Client {}	res, err := client.Do(req)	if err != nil {		fmt.Println(err)		return	}	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)	if err != nil {		fmt.Println(err)		return	}	fmt.Println(string(body))}
Java
import com.squareup.okhttp.*;OkHttpClient client = new OkHttpClient();HttpUrl.Builder urlBuilder = HttpUrl.parse("https://support.zendesk.com/api/sunshine/jobs/8b72559ae838-c9a0-11e7-abc4-cec278b6b50a6e6")		.newBuilder();
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("GET", null)		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');
var config = {  method: 'GET',  url: 'https://support.zendesk.com/api/sunshine/jobs/8b72559ae838-c9a0-11e7-abc4-cec278b6b50a6e6',  headers: {	'Content-Type': 'application/json',  },};
axios(config).then(function (response) {  console.log(JSON.stringify(response.data));}).catch(function (error) {  console.log(error);});
Python
import requests
url = "https://support.zendesk.com/api/sunshine/jobs/8b72559ae838-c9a0-11e7-abc4-cec278b6b50a6e6"headers = {	"Content-Type": "application/json",}
response = requests.request(	"GET",	url,	headers=headers)
print(response.text)
Ruby
require "net/http"uri = URI("https://support.zendesk.com/api/sunshine/jobs/8b72559ae838-c9a0-11e7-abc4-cec278b6b50a6e6")request = Net::HTTP::Get.new(uri, "Content-Type": "application/json")response = Net::HTTP.start uri.hostname, uri.port, use_ssl: true do |http|	http.request(request)end

Example response(s)

200 OK
// Status 200 OK
{  "data": {    "completed_at": "2017-11-03T16:00:16Z",    "created_at": "2017-11-03T16:00:06Z",    "id": "8b72559ae838-c9a0-11e7-abc4-cec278b6b50a6e6",    "job_status": "completed",    "results": [      {        "data": {          "id": "73c698be-cb64-4678-ba73-29683d2c32er"        },        "success": true      },      {        "errors": [          {            "code": "UnprocessableEntity",            "detail": "External Id is already in use for the Resource Type key: product",            "status": "422",            "title": "Unprocessable Entity"          }        ],        "success": false      }    ],    "updated_at": "2017-11-03T16:00:16Z"  }}

Create Job

  • POST /api/sunshine/jobs

Creates a job with supported type and action.

The API doesn't wait for the job to finish before sending a response. The response gives you a job id that you can use to poll the API for the status of the job. See Show Job and Job statuses.

The maximum number of concurrent jobs that can be processed for an account is 1000.

When creating a Job, you may use the following properties:

NameTypeRequiredComment
typestringyesOne of "resources" or "relationships". Resources refer to legacy object records. Relationships refer to relationship records
actionstringyesOne of the following depending on job type: "post", "delete", "update", "external_id_delete", "external_id_set". See action property
dataarrayyesAn array of legacy object or relationship records or ids to process. See data property

action property

The action you can specify depends on the job type.

A job of type "resources" (legacy object records) supports the following actions:

  • "post"
  • "delete"
  • "update"
  • "external_id_delete"
  • "external_id_set"

A job of type "relationships" (legacy relationship records) supports the following action:

  • "post"
  • "delete"

data property

The data property in the request body specifies an array of JSON objects to batch process. The format of the JSON objects you can specify depends on the job.

Jobs to post object records or relationship records

When a job's type is "resources" or "relationships" and its action is "post", the data property supports legacy object records or relationship records. The format of each legacy object is the same as the data object for the equivalent single-operation endpoints for legacy object records or legacy relationship records.

Example:

{  "type": "resources",  "action": "post",  "data": [    {      "type": "product",      "external_id": "3",      "attributes": {        "id": "3",        "name": "Strawberry Chewing Gum"      }    },    {      "type": "product",      "external_id": "4",      "attributes": {        "id": "4",        "name": "Coffee Chewing Gum"      }    }  ]}

Jobs to update legacy object records

When a job's type is "resources" and its action is "update", the data property supports JSON objects with the following properties:

NameTypeDescription
idstringThe id of the legacy object record to update
attributesobjectA legacy object containing the properties to update

For each legacy object, the id value is used to locate the legacy object record in the database and the attributes value is used to patch the existing value.

Example:

{  "type": "resources",  "action": "update",  "data": [    {      "id": "576a0d0d-fb3f-11e9-80f8-65590b274410",      "attributes": {        "name": "Strawberry Chewing Gum v2"      }    },    {      "id": "576a5b2e-fb3f-11e9-80f8-f1af99ee4b4c",      "attributes": {        "name": "Coffee Chewing Gum (decaf)"      }    }  ]}

Jobs to set legacy object records using external id

When a job's type is "resources" and its action is "external_id_set", the data property supports JSON objects with the following properties:

NameTypeDescription
typestringThe legacy object type of the legacy object record
external_idstringThe external_id of the legacy object record to set
attributesobjectA legacy object containing the properties to set

For each legacy object, the external_id and resource type values are used to locate the legacy object record in the database. If the resource exists, the attributes value is used to patch the existing value. If the resource does not exist, a new resource of the given resource type is created with the external_id and attributes.

Example:

{  "type": "resources",  "action": "external_id_set",  "data": [    {      "type": "product",      "external_id": "4",      "attributes": {        "name": "Coffee Chewing Gum (decaf)"      }    },    {      "type": "product",      "external_id": "5",      "attributes": {        "name": "Blueberry Chewing Gum"      }    }  ]}

Jobs to delete legacy object records or relationship records

When a job's type is "resources" or "relationships" and its action is "delete", the data property supports a list of ids of the legacy object or relationship records to be deleted.

Examples:

{  "type": "resources",  "action": "delete",  "data": [    "576a0d0d-fb3f-11e9-80f8-65590b274410",    "576a5b2e-fb3f-11e9-80f8-f1af99ee4b4c",    "69d0b3e2-ec4e-11e9-ad75-4b6f5c0467f5"  ]}
{  "type": "relationships",  "action": "delete",  "data": [    "576a0d0d-fb3f-11e9-80f8-65590b274410",    "576a5b2e-fb3f-11e9-80f8-f1af99ee4b4c",    "69d0b3e2-ec4e-11e9-ad75-4b6f5c0467f5"  ]}

Jobs to delete legacy object records using external id

When a job's type is "resources" and its action is "delete", the data property supports a list of object type and external_id of the legacy object records to be deleted.

Examples:

{  "type": "resources",  "action": "external_id_delete",  "data": [    {      "type": "product",      "external_id": "4"    },    {      "type": "product",      "external_id": "5"    }  ]}

Code Samples

curl
curl https://{subdomain}.zendesk.com/api/sunshine/jobs \  -d '{"type": "resources", "action": "post", "data": [{...}, {...}, ...]}' \  -H "Content-Type: application/json" -X POST \  -v -u {email_address}/token:{api_token}
Go
import (	"fmt"	"io"	"net/http")
func main() {	url := "https://support.zendesk.com/api/sunshine/jobs"	method := "POST"	req, err := http.NewRequest(method, url, nil)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Content-Type", "application/json")
	client := &http.Client {}	res, err := client.Do(req)	if err != nil {		fmt.Println(err)		return	}	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)	if err != nil {		fmt.Println(err)		return	}	fmt.Println(string(body))}
Java
import com.squareup.okhttp.*;OkHttpClient client = new OkHttpClient();HttpUrl.Builder urlBuilder = HttpUrl.parse("https://support.zendesk.com/api/sunshine/jobs")		.newBuilder();RequestBody body = RequestBody.create(MediaType.parse("application/json"),		"""""");
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("POST", body)		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');
var config = {  method: 'POST',  url: 'https://support.zendesk.com/api/sunshine/jobs',  headers: {	'Content-Type': 'application/json',  },};
axios(config).then(function (response) {  console.log(JSON.stringify(response.data));}).catch(function (error) {  console.log(error);});
Python
import requests
url = "https://support.zendesk.com/api/sunshine/jobs"headers = {	"Content-Type": "application/json",}
response = requests.request(	"POST",	url,	headers=headers)
print(response.text)
Ruby
require "net/http"uri = URI("https://support.zendesk.com/api/sunshine/jobs")request = Net::HTTP::Post.new(uri, "Content-Type": "application/json")response = Net::HTTP.start uri.hostname, uri.port, use_ssl: true do |http|	http.request(request)end

Example response(s)

201 Created
// Status 201 Created
{  "data": {    "completed_at": null,    "created_at": "2017-11-03T16:00:06Z",    "id": "8b72559ae838-c9a0-11e7-abc4-cec278b6b50a6e6",    "job_status": "queued",    "results": [],    "updated_at": "2017-11-03T16:00:06Z"  }}