Bulk Api
Bulk Api
names and marks. Other marks appearing herein may be trademarks of their respective owners.
CONTENTS
Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
Sample Client Application Using Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Set Up Your Client Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Walk Through the Sample Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
Map Data Fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
Bulk API End-of-Life Policy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
INDEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
CHAPTER 1 Introduction to Bulk API 2.0 and Bulk API
In this chapter ... Both Salesforce Bulk APIs are based on REST principles and are optimized for working with large sets of
data. Use them to insert, update, upsert, or delete many records asynchronously. You submit a request
• What’s the Difference and come back for the results later. Salesforce processes the request in the background.
Between Bulk API 2.0
and Bulk API? Any data operation that includes more than 2,000 records is a good candidate for Bulk API 2.0 to
successfully prepare, execute, and manage an asynchronous workflow that uses the Bulk framework.
Jobs with fewer than 2,000 records should involve “bulkified” synchronous calls in REST (for example,
Composite) or SOAP.
Using Bulk API 2.0 or Bulk API requires basic familiarity with software development, web services, and
the Salesforce user interface. Because both Bulk APIs are asynchronous, Salesforce doesn’t guarantee a
service level agreement.
1
Introduction to Bulk API 2.0 and Bulk API What’s the Difference Between Bulk API 2.0 and Bulk API?
What’s the Difference Between Bulk API 2.0 and Bulk API?
Although Bulk API 2.0's predecessor, “Bulk API”, is available, use Bulk API 2.0 instead of Bulk API if you want a more streamlined workflow.
Bulk API 2.0 provides a simple interface to load large amounts of data into your Salesforce org and to perform bulk queries on your org
data. Its design is more consistent and better integrated with other Salesforce APIs. Bulk API 2.0 also has the advantage of future innovation.
Bulk API 2.0 allows for:
• Less client-side code writing.
• Easy-to-monitor job status.
• Automatic retry of failed records.
• Support for parallel processing.
• Fewer calls are required to complete ingest or query workflows.
• Easier batch management.
Here's an example of the Bulk API 2.0 query workflow:
Bulk API's query workflow is more complex - requiring the creation of batches and iterating through the retrieval of result sets:
2
Introduction to Bulk API 2.0 and Bulk API What’s the Difference Between Bulk API 2.0 and Bulk API?
Bulk API 2.0's ingest workflow is the same for insert, update, delete, hard delete, and upsert operations. You:
1. Create a job
2. Upload job data
3. Set job state to UploadComplete
4. Get results
If the feature set and limits are a unique match to your project requirements, use Bulk API.
3
Introduction to Bulk API 2.0 and Bulk API What’s the Difference Between Bulk API 2.0 and Bulk API?
This table shows a basic feature set comparison between Bulk API 2.0 and Bulk API.
Authentication Supports all OAuth 2.0 flows supported by None. Requires a special X-SFDC-Session
other Salesforce REST APIs. header fetched with SOAP API's login()
call.
Ingest Data Format CSV CSV, XML, JSON, and binary attachment
processing
Large File Batching Simplifies uploading large amounts of data Large files must be batched manually, either
by breaking the data into batches and with custom code or by hand.
providing parallelism automatically. Upload
a CSV file with your record data and check
back when the results are ready. All results
are returned from one endpoint.
Query Job Optimization Automatically performs PK chunking. PK chunking is manually invoked and
configured.
Query Results Retrieval All in a single endpoint. Iterate through the retrieval of individual
result sets.
Daily Upload Limits Limits by total records uploaded per day. Limits by quantity of batches per day
Available to clients via REST API /limits
endpoint.
For a detailed comparison of Bulk API 2.0 and Bulk API limits, see Bulk API and Bulk API 2.0 Limits and Allocations.
SEE ALSO:
Bulk API 2.0 Older Documentation
4
CHAPTER 2 Bulk API 2.0
In this chapter ... Perform ingest and query operations with Salesforce Bulk API 2.0. The REST-based Bulk API 2.0 provides
a programmatic option to asynchronously insert, upsert, query, or delete large datasets in your Salesforce
• How Requests Are org. This API is enabled by default for Performance, Unlimited, Enterprise, and Developer Editions. The
Processed API Enabled permission must be enabled on the profile assigned to users accessing an org or data via
• Quick Start: Bulk API the API.
2.0
• Bulk API 2.0 Ingest
• Bulk API 2.0 Query
• Headers
• Limits
• Bulk API 2.0 Older
Documentation
• Bulk API 2.0
End-of-Life Policy
5
Bulk API 2.0 How Requests Are Processed
Job States
When you create job requests with Bulk API 2.0, Salesforce provides a job “state” to describe the progress or outcome of the job.
Learn how to check and interpret each status.
SEE ALSO:
Bulk API 2.0 Older Documentation
Limits
Set Up and Maintain Your Salesforce Organization: Manage Bulk Data Load Jobs
Job States
When you create job requests with Bulk API 2.0, Salesforce provides a job “state” to describe the progress or outcome of the job. Learn
how to check and interpret each status.
You can manually Check the status of the job, or you can view job state from within the Salesforce UI. From Setup, in the Quick Find box,
enter Bulk Data Load Jobs, and then select Bulk Data Load Jobs. The following table summarizes Bulk API 2.0 job states
during job creation and processing.
Creation UploadComplete (Ingest) All job data has been uploaded and the job is ready to be processed.
(Query) The job is ready to be processed.
Processing InProgress The job is being processed by Salesforce. Operations include automatic, optimized
batching or chunking of job data, and processing of job operations.
Outcome Aborted The job was canceled by the job creator, or by a user with the “Manage Data
Integrations” permission.
6
Bulk API 2.0 Using cURL
Using cURL
Get to know the formatting used with cURL to place calls to Salesforce orgs. This Quick Start uses cURL examples to issue Bulk API
2.0 calls, but you can use any tool or development environment that can make REST requests.
Step 1: Set Up a Salesforce Developer Edition Org
This Quick Start suggests using a Developer Edition org. Sign up for a Salesforce Developer Edition org before trying Bulk API 2.0
with this Quick Start.
Step 2: Authentication
The first action in an API-based integration is authenticating requests with your Salesforce org. Bulk API 2.0 and Bulk API use different
authentication methods.
Step 3: Bulk Insert
This Bulk API 2.0 example guides you through creating a job, uploading data for the job, notifying Salesforce servers that your
upload(s) are complete, checking the status of the processing job, and retrieving the results.
Step 4: Bulk Insert with a Multipart Request
This Bulk API 2.0 example guides you through creating a job, uploading data for the job, checking the status, and retrieving the
results. This example uses a single, multipart request to create the job and upload the data.
Step 5: Bulk Upsert
This Bulk API 2.0 example guides you through creating a job, uploading data for the job, notifying Salesforce servers that your
upload(s) are complete, checking the status, and retrieving the results. Some of the records exist (update), and some are new records
(insert).
Step 6: Query Jobs
This Bulk API 2.0 example shows you how to create a query job, monitor its progress, and get the job results.
Using cURL
Get to know the formatting used with cURL to place calls to Salesforce orgs. This Quick Start uses cURL examples to issue Bulk API 2.0
calls, but you can use any tool or development environment that can make REST requests.
Familiarize yourself with cURL enough to be able to understand the examples in this guide and translate them into the tool that you’re
using. You’ll be attaching files containing the body of the request and must properly format the access token. For more information
about cURL, see the documentation at curl.se.
Attach Request Bodies
Many examples include request bodies—JSON or XML files that contain data for the request. When using cURL, save these files to your
local system and attach them to the request using the —data-binary or -d option.
This example attaches the new-account.json file.
curl https://MyDomainName.my.salesforce.com/services/data/v61.0/sobjects/Account/ -H
'Authorization Bearer
00DE0X0A0M0PeLE!AQcAQH0dMHEXAMPLEzmpkb58urFRkgeBGsxL_QJWwYMfAbUeeG7c1EXAMPLEDUkWe6H34r1AAwOR8B8fLEz6nEXAMPLE'
-H "Content-Type: application/json" —d @new-account.json -X POST
7
Bulk API 2.0 Step 1: Set Up a Salesforce Developer Edition Org
For example, the access token string in this cURL command has the exclamation mark (!) escaped.
curl https://MyDomainName.my.salesforce.com/services/data/v61.0/ -H "Authorization: Bearer
00DE0X0A0M0PeLE\!AQcAQH0dMHEXAMPLEzmpkb58urFRkgeBGsxL_QJWwYMfAbUeeG7c1EXAMPLEDUkWe6H34r1AAwOR8B8fLEz6nEXAMPLE"
Or, you can enclose the access token within single quotes to not escape the exclamation mark.
curl https://MyDomainName.my.salesforce.com/services/data/v61.0/ -H 'Authorization: Bearer
00DE0X0A0M0PeLE!AQcAQH0dMHEXAMPLEzmpkb58urFRkgeBGsxL_QJWwYMfAbUeeG7c1EXAMPLEDUkWe6H34r1AAwOR8B8fLEz6nEXAMPLE'
Important: All quotes, whether single or double, must be straight quotes, not curly quotes.
Note: Developer Edition orgs have a data storage maximum of 5 MB. This limit doesn’t prevent you from working with these
examples.
Step 2: Authentication
The first action in an API-based integration is authenticating requests with your Salesforce org. Bulk API 2.0 and Bulk API use different
authentication methods.
Bulk API 2.0 is a REST-based API that supports all OAuth 2.0 flows supported by other Salesforce REST APIs. Bulk API 2.0 requires an access
token (also known as a “bearer token”) for authentication. This topic, and the remainder of this Quick Start, describe getting an access
token and using it to make Bulk API 2.0 requests with cURL.
In contrast, Bulk API uses a session ID obtained with an X-SFDC-Session header fetched with SOAP API’s login() call. For an example,
see Step 1: Log In Using the SOAP API on page 92.
Note: These examples use an access token. Any API call that requires a session ID doesn’t work with these instructions.
While it’s possible to create and authenticate against your own connected app, Salesforce CLI is used in these Quick Start examples for
convenience. Effectively, Salesforce CLI is a connected app with which you can authenticate and requires no work to configure.
The examples in this Quick Start use the cURL tool to send HTTP requests that access, create, and manipulate resources in Salesforce. If
you use a different tool to send requests, you can use the same elements from the cURL examples to send requests. Although these
instructions describe a scenario with a Developer org, they work in the same way with any type of Salesforce org. The cURL tool is
pre-installed on many Linux and macOS systems. Windows users can download a version at curl.se. When using HTTPS on Windows,
ensure that your system meets the cURL requirements for SSL.
8
Bulk API 2.0 Step 2: Authentication
5. At the command line, get the access token by viewing authentication information about your org.
sf org display --target-org <username>
For example:
sf org display --target-org [email protected]
KEY VALUE
───────────────
────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Access Token
00DE0X0A0M0PeLE!AQcAQH0dMHEXAMPLEzmpkb58urFRkgeBGsxL_QJWwYMfAbUeeG7c1EXAMPLEDUkWe6H34r1AAwOR8B8fLEz6nEXAMPLE
9
Bulk API 2.0 Step 3: Bulk Insert
In the command output, make note of the long Access Token string and the Instance Url string. You need both to make cURL requests.
Note: To get a new token after your access token expires, repeat this step of viewing your authentication information.
Opens the specified org (identified by username or alias) in your browser. Because you’ve successfully authenticated with this org
previously using the org login web Salesforce CLI command, it’s not required to provide your credentials again.
Display the Access Token for My Org
sf org display --target-org <username>
Output includes your access token, client ID, connected status, org ID, instance URL, username, and alias, if applicable.
Set an Alias for My Username
For convenience, create an alias for your username so that you don’t have to enter the entire Salesforce string. For example, instead of
[email protected]
10
Bulk API 2.0 Step 3: Bulk Insert
To do any Bulk API 2.0 task, such as inserting or updating records, you first create a Bulk API 2.0 job. The job specifies the type of object
that you’re loading, such as Account, and the operation that you’re performing, such as insert or delete. After you create the job, you
use the resulting job ID in subsequent Bulk API 2.0 requests to upload job data or abort (cancel) the job.
1. Copy this CSV formatted list of accounts into a file named bulkinsert.csv. You use this file to upload data after creating the
job.
Note: Save all files in this example in your terminal’s current working directory.
The first row of the CSV file lists the field names for the object that you’re working with. Each subsequent row corresponds to a record
that you want to insert.
Name,ShippingCity,NumberOfEmployees,AnnualRevenue,Website,Description
Lorem Ipsum,Milano,2676,912260031,https://ft.com/lacus/at.jsp,"Lorem ipsum dolor sit
amet"
Posuere
Inc,Bodø,141603,896852810,http://webs.com/in/faucibus/orci/luctus/et/ultrices/posuere.json,"consectetur
adipiscing elit"
Angeles Urban,Aykol,197724,257060529,http://odnoklassniki.ru/sapien.aspx,"sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua"
Madaline Neubert
Shoes,Xukou,190305,71664061,https://blogs.com/faucibus/orci/luctus/et/ultrices/posuere/cubilia.json,"Ut
enim ad minim veniam"
Times Online UK,Varadero,121802,58284123,http://timesonline.co.uk/eu/magna.html,"quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat"
The Washington
Post,Hengdaohezi,190944,164329406,http://washingtonpost.com/vestibulum/proin/eu/mi/nulla/ac/enim.png,"Duis
aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur"
Amazon,Quintães,80285,684173825,http://amazon.co.uk/potenti/cras/in/purus/eu.png,"Excepteur
sint occaecat cupidatat non proident"
2. Create a job.
a. Create a file named newinsertjob.json.
b. Copy this content into the file.
{
"object" : "Account",
"contentType" : "CSV",
"operation" : "insert",
"lineEnding" : "LF"
}
When you create a Bulk API 2.0 job, specify a line ending that matches the line ending used to create the CSV file using the
lineEnding request field. Bulk API 2.0 supports two line-ending formats: linefeed (LF), and carriage-return plus linefeed
(CRLF). The default line ending, if not specified, is LF. Different operating systems use different characters to mark the end of
a line.
Unix / Linux / OS X uses LF (line feed, '\n', 0x0A).
Windows / DOS uses CRLF (carriage return followed by line feed, '\r\n', 0x0D0A).
It’s also possible that the text editor used to create the CSV file is configured for a specific line-ending format that supersedes
the default operating system format.
11
Bulk API 2.0 Step 3: Bulk Insert
URI
/services/data/v61.0/jobs/ingest/
{ "id" : "7505fEXAMPLE4C2AAM",
"operation" : "insert",
"object" : "Account",
"createdById" : "0055fEXAMPLEtG4AAM",
"createdDate" : "2022-01-02T21:33:43.000+0000",
"systemModstamp" : "2022-01-02T21:33:43.000+0000",
"state" : "Open",
"concurrencyMode" : "Parallel",
"contentType" : "CSV",
"apiVersion" : 61.0,
"contentUrl" : "services/data/61.0/jobs/ingest/7505fEXAMPLE4C2AAM/batches",
"lineEnding" : "LF", "columnDelimiter" : "COMMA" }
You use the job id from this response in the next steps. You can also use the URI in the contentUrl field in the next step
when you upload your data.
3. Upload your CSV data using the URI in the contentUrl field of the response.
You can upload up to 150 MB per job (after base64 encoding).
The URI is similar to
/services/data/v61.0/jobs/ingest/jobId/batches/
/services/data/v61.0/jobs/ingest/jobId/
12
Bulk API 2.0 Step 3: Bulk Insert
/services/data/v61.0/jobs/ingest/jobId/
13
Bulk API 2.0 Step 4: Bulk Insert with a Multipart Request
/services/data/v61.0/jobs/ingest/jobId/successfulResults/
The response contains CSV formatted data, with each row containing a record ID (sf__Id) and information on whether that record
was successfully processed or not (sf__Created).
Example response body
"sf__Id","sf__Created",Name,ShippingCity,NumberOfEmployees,AnnualRevenue,Website,Description
"0018c00002FInboAAD","true","Lorem
Ipsum","Milano","2676","9.12260031E8","https://ft.com/lacus/at.jsp","Lorem ipsum dolor
sit amet"
"0018c00002FInbpAAD","true","Posuere
Inc","Bodø","141603","8.9685281E8","http://webs.com/in/faucibus/orci/luctus/et/ultrices/posuere.json","consectetur
adipiscing elit"
"0018c00002FInbqAAD","true","Angeles
Urban","Aykol","197724","2.57060529E8","http://odnoklassniki.ru/sapien.aspx","sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua"
"0018c00002FInbrAAD","true","Madaline Neubert
Shoes","Xukou","190305","7.1664061E7","https://blogs.com/faucibus/orci/luctus/et/ultrices/posuere/cubilia.json","Ut
enim ad minim veniam"
"0018c00002FInbsAAD","true","Times Online
UK","Varadero","121802","5.8284123E7","http://timesonline.co.uk/eu/magna.html","quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat"
"0018c00002FInbtAAD","true","The Washington
Post","Hengdaohezi","190944","1.64329406E8","http://washingtonpost.com/vestibulum/proin/eu/mi/nulla/ac/enim.png","Duis
aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur"
"0018c00002FInbuAAD","true","Amazon","Quintães","80285","6.84173825E8","http://amazon.co.uk/potenti/cras/in/purus/eu.png","Excepteur
sint occaecat cupidatat non proident"
To get details about records that encountered an error during processing, use a GET request using the failedResults resource.
To make sure that you’re looking at the complete result set, look at unprocessed records by using the unprocessedRecords
resource. See Get Job Unprocessed Record Results.
14
Bulk API 2.0 Step 4: Bulk Insert with a Multipart Request
Note: Save all files in this example in your terminal’s current working directory.
--BOUNDARY
Content-Type: application/json
Content-Disposition: form-data; name="job"
{
"object":"Contact",
"contentType":"CSV",
"operation": "insert",
"lineEnding" : "LF"
}
--BOUNDARY
Content-Type: text/csv
Content-Disposition: form-data; name="content"; filename="content"
FirstName,LastName,MailingCity
Astro,Nomical,San Francisco
Hootie,McOwl,San Francisco
Appy,Camper,San Francisco
Earnie,Badger,San Francisco
--BOUNDARY--
2. Create a job.
URI
/services/data/v61.0/jobs/ingest/
The response includes the job id, with a job state of UploadComplete. You use the job id in the next steps.
Example response body
{
"id" : "7303gEXAMPLE4X2QAN",
"operation" : "insert",
"object" : "Contact",
"createdById" : "0055fEXAMPLEtG4AAM",
"createdDate" : "2022-01-02T19:26:52.000+0000",
"systemModstamp" : "2022-01-02T19:26:52.000+0000",
"state" : "UploadComplete",
"concurrencyMode" : "Parallel",
"contentType" : "CSV",
"apiVersion" : 61.0,
"lineEnding" : "LF",
"columnDelimiter" : "COMMA"
}
15
Bulk API 2.0 Step 4: Bulk Insert with a Multipart Request
After you create a multipart job, the upload is completed for you automatically. You don’t need to manually set the job state to
UploadComplete for a multipart job.
/services/data/v61.0/jobs/ingest/jobId/
/services/data/v61.0/jobs/ingest/jobId/successfulResults/
16
Bulk API 2.0 Step 5: Bulk Upsert
To get details about records that encountered an error during processing, use a GET request with the failedResults resource.
To make sure that you’re looking at the complete result set, look at unprocessed records by using the unprocessedRecords
resource. See Get Job Unprocessed Record Results.
2. Create a CSV file containing the records that you want to upsert.
Note: Save all files in this example in your terminal’s current working directory.
The first row of the CSV file lists the field names for the object that you’re working with. Each subsequent row corresponds to a record
that you want to insert.
One column in the CSV file must correspond to the external ID field customExtIdField__c.
For information on preparing CSV files, such as delimiter options and valid date and time formats, see Bulk API 2.0 Ingest on page
22.
For this example, copy this information into a file named accountupsert.csv.
customExtIdField__c,name,NumberOfEmployees
123,GenePoint,800
234,"United Oil & Gas, UK",1467
345,"United Oil & Gas, Singapore",348
456,Edge Communications,10045
567,Burlington Textiles Corp of America,5876
678,Dickenson plc,67
789,Grand Hotels & Resorts Ltd,409
890,Express Logistics and Transport,243
901,University of Arizona,9506
1350,United Oil & Gas Corp.,5467
17
Bulk API 2.0 Step 5: Bulk Upsert
1579,sForce,40000
2690,University of The Terrific,1257
URI
/services/data/v61.0/jobs/ingest/
/services/data/v61.0/jobs/ingest/jobId/batches/
18
Bulk API 2.0 Step 5: Bulk Upsert
URI
/services/data/v61.0/jobs/ingest/jobId/
Example of setting state to UploadComplete
curl
https://MyDomainName.my.salesforce.com/services/data/v61.0/jobs/ingest/7476gEXAMPLE4X2ZWO/
-H 'Authorization: Bearer
00DE0X0A0M0PeLE!AQcAQH0dMHEXAMPLEzmpkb58urFRkgeBGsxL_QJWwYMfAbUeeG7c1EXAMPLEDUkWe6H34r1AAwOR8B8fLEz6nEXAMPLE'
-H "Content-Type: application/json" -H "X-PrettyPrint:1" -d @upload_complete.json -X
PATCH
/services/data/v61.0/jobs/ingest/jobId/successfulResults/
19
Bulk API 2.0 Step 6: Query Jobs
-H 'Authorization: Bearer
00DE0X0A0M0PeLE!AQcAQH0dMHEXAMPLEzmpkb58urFRkgeBGsxL_QJWwYMfAbUeeG7c1EXAMPLEDUkWe6H34r1AAwOR8B8fLEz6nEXAMPLE'
-H "Content-Type: application/json" -H "Accept: text/csv" -H "X-PrettyPrint:1" -X GET
The response contains CSV formatted data, with each row containing a record ID of successfully processed records.
Example response body
"sf__Id","sf__Created",customExtIdField__c,name,NumberOfEmployees
"0018c00002DJIpJAAX","true","123","GenePoint","800"
"0018c00002DJIpKAAX","true","234","United Oil & Gas, UK","1467"
"0018c00002DJIpLAAX","true","345","United Oil & Gas, Singapore","348"
"0018c00002DJIpMAAX","true","456","Edge Communications","10045"
"0018c00002DJIpNAAX","true","567","Burlington Textiles Corp of America","5876"
"0018c00002DJIpOAAX","true","678","Dickenson plc","67"
"0018c00002DJIpPAAX","true","789","Grand Hotels & Resorts Ltd","409"
"0018c00002DJIpQAAX","true","890","Express Logistics and Transport","243"
"0018c00002DJIpRAAX","true","901","University of Arizona","9506"
"0018c00002DJIpSAAX","true","1350","United Oil & Gas Corp.","5467"
"0018c00002DJIpTAAX","true","1579","sForce","40000"
"0018c00002DJIpUAAX","true","2690","University of The Terrific","1257"
To get details about records that encountered an error, use the failedResults resource. To make sure that you’re looking at
the complete result set, use the unprocessedRecords resource. See Get Job Unprocessed Record Results.
/services/data/v61.0/jobs/query
The response includes the job id and shows the job’s state as UploadComplete. (You use the job id to monitor the job or
get its results.)
Example response body
{
"id" : "7986gEXAMPLE4X2OPT",
"operation" : "query",
"object" : "Account",
"createdById" : "0055fEXAMPLEtG4AAM",
"createdDate" : "2022-01-02T17:38:59.000+0000",
"systemModstamp" : "2022-01-02T17:38:59.000+0000",
"state" : "UploadComplete",
"concurrencyMode" : "Parallel",
20
Bulk API 2.0 Step 6: Query Jobs
"contentType" : "CSV",
"apiVersion" : 61.0,
"lineEnding" : "LF",
"columnDelimiter" : "COMMA"
}
/services/data/v61.0/jobs/query/queryJobId
/services/data/v61.0/jobs/query/queryJobId/results
21
Bulk API 2.0 Bulk API 2.0 Ingest
The response shows the results of the SOQL query when you created the query job.
Example response body
"Id","Name"
"0015f00000BCvReAAL","Sample Account for Entitlements"
"0015f00000BFjNuAAL","University of The Terrific"
"0015f00000C6beUAAR","Edge Communications"
"0015f00000C6beVAAR","Burlington Textiles Corp of America"
"0015f00000C6beWAAR","Pyramid Construction Inc."
"0015f00000C6beXAAR","Dickenson plc"
"0015f00000C6beYAAR","Grand Hotels & Resorts Ltd"
"0015f00000C6beZAAR","United Oil & Gas Corp."
"0015f00000C6beaAAB","Express Logistics and Transport"
"0015f00000C6bebAAB","University of Arizona"
"0015f00000C6becAAB","United Oil & Gas, UK"
"0015f00000C6bedAAB","United Oil & Gas, Singapore"
"0015f00000C6beeAAB","GenePoint"
This example returns a small result set, and it’s easy to see the complete results. Queries that return larger results spread them across
a sequence of result sets. To see the other result sets, use the locator to fetch the next set of results. For more information, see Get
Results for a Query Job.
22
Bulk API 2.0 Understanding Bulk API 2.0 Ingest
23
Bulk API 2.0 Prepare Data to Ingest
24
Bulk API 2.0 Prepare Data to Ingest
SEE ALSO:
Bulk API 2.0 Older Documentation
Simple CSV
This example contains three Account records and specifies the Name, Description, and NumberOfEmployees fields for each record.
Name,Description,NumberOfEmployees
TestAccount1,Description of TestAccount1,30
TestAccount2,Another description,40
TestAccount3,Yet another description,50
A job that uses this CSV data might be defined with the following job properties.
{
"object" : "Account",
"contentType" : "CSV",
"operation" : "insert"
}
25
Bulk API 2.0 Prepare Data to Ingest
A job that uses this CSV data and specifies that carriage return + line feed is used as the line ending sequence would use the following
job properties.
{
"object" : "Contact",
"contentType" : "CSV",
"operation" : "insert",
"lineEnding" : "CRLF"
}
A job that uses this CSV data and specifies that semicolon is used as the column delimiter would use the following job properties.
{
"object" : "Contact",
"contentType" : "CSV",
"operation" : "insert",
"columnDelimiter" : "SEMICOLON"
}
A job that uses this CSV data might be defined with the following job properties.
{
"object" : "Contact",
"contentType" : "CSV",
26
Bulk API 2.0 Prepare Data to Ingest
"operation" : "insert"
}
A job that uses this CSV data might be an upsert job defined with the following properties.
{
"object" : "Contact",
"externalIdFieldName" : "ExternalId__c",
"contentType" : "CSV",
"operation" : "upsert"
}
You can also associate records using external IDs. For more information, see Upserting Records and Associating with an External ID.
SEE ALSO:
Bulk API 2.0 Older Documentation
dateTime
Use the yyyy-MM-ddTHH:mm:ss.SSS+/-HH:mm or yyyy-MM-ddTHH:mm:ss.SSSZ formats to specify dateTime
fields.
• yyyy is the four-digit year
• MM is the two-digit month (01-12)
• dd is the two-digit day (01-31)
• 'T' is a separator indicating that time-of-day follows
• HH is the two-digit hour (00-23)
• mm is the two-digit minute (00-59)
• ss is the two-digit seconds (00-59)
• SSS is the optional three-digit milliseconds (000-999)
• +/-HH:mm is the Zulu (UTC) time zone offset
• 'Z' is the reference UTC timezone
When a timezone is added to a UTC dateTime, the result is the date and time in that timezone. For example, 2002-10-10T12:00:00+05:00
is 2002-10-10T07:00:00Z and 2002-10-10T00:00:00+05:00 is 2002-10-09T19:00:00Z. See W3C XML Schema Part 2: DateTime Datatype.
27
Bulk API 2.0 Prepare Data to Ingest
date
Use the yyyy-MM-dd format to specify date fields.
SEE ALSO:
Bulk API 2.0 Older Documentation
FirstName,LastName,ReportsTo.Email
Tom,Jones,[email protected]
28
Bulk API 2.0 Create a Job
Important: Starting with version 57.0 of the API, for ObjectType use apiName, which should include namespace, if any,
and should include __c if the object is a custom object.
The following sample includes two reference fields:
1. The WhoId field is polymorphic and has a relationshipName of Who. It refers to a lead and the indexed Email field
uniquely identifies the parent record.
2. The OwnerId field is not polymorphic and has a relationshipName of Owner. It refers to a user and the indexed Id field
uniquely identifies the parent record.
Subject,Priority,Status,Lead:Who.Email,Owner.Id
Test Bulk API polymorphic reference field,Normal,Not
Started,[email protected],005D0000001AXYz
Warning: The ObjectType: portion of a field column header is only required for a polymorphic field. You get an error if you
omit this syntax for a polymorphic field. You also get an error if you include this syntax for a field that is not polymorphic.
SEE ALSO:
Bulk API 2.0 Older Documentation
Create a Job
Creates a job representing a bulk operation and its associated data that is sent to Salesforce for asynchronous processing. Provide job
data via an Upload Job Data request or as part of a multipart create job request.
URI
/services/data/vXX.X/jobs/ingest
Availability
This resource is available in API version 41.0 and later.
Formats
JSON
HTTP Method
POST
Authentication
Authorization: Bearer token
Parameters
None.
Headers
Optionally, use the Sforce-Call-Options header to specify a default namespace.
29
Bulk API 2.0 Create a Job
Request Body
columnDelimiter ColumnDelimiterEnum The column delimiter used for CSV job data. The default Optional
value is COMMA. Valid values are:
• BACKQUOTE—backquote character (`)
• CARET—caret character (^)
• COMMA—comma character (,) which is the default
delimiter
• PIPE—pipe character (|)
• SEMICOLON—semicolon character (;)
• TAB—tab character
contentType ContentType The content type for the job. The only valid value (and the Optional
default) is CSV.
externalIdFieldName string The external ID field in the object being updated. Only Required for
needed for upsert operations. Field values must also exist upsert
in CSV job data. operations
lineEnding LineEndingEnum The line ending used for CSV job data, marking the end of Optional
a data row. The default is LF. Valid values are:
• LF—linefeed character
• CRLF—carriage return character followed by a
linefeed character
object string The object type for the data being processed. Use only a Required
single object type per job.
operation OperationEnum The processing operation for the job. Valid values are: Required
• insert
• delete
• hardDelete
• update
• upsert
30
Bulk API 2.0 Create a Job
For multipart requests, the request body can also include CSV record data. See Usage Notes on page 32 for more details.
Response Body
assignmentRuleId id The ID of the assignment rule. This property is only shown if an assignment
rule is specified when the job is created.
columnDelimiter ColumnDelimiterEnum The column delimiter used for CSV job data. Values include:
• BACKQUOTE—backquote character (`)
• CARET—caret character (^)
• COMMA—comma character (,) which is the default delimiter
• PIPE—pipe character (|)
• SEMICOLON—semicolon character (;)
• TAB—tab character
concurrencyMode ConcurrencyModeEnum For future use. How the request was processed. Currently only parallel
mode is supported. (When other modes are added, the mode will be
chosen automatically by the API and will not be user configurable.)
contentType ContentType The format of the data being processed. Only CSV is supported.
contentUrl URL The URL to use for Upload Job Data on page 33 requests for this job. Only
valid if the job is in Open state.
createdDate dateTime The date and time in the UTC time zone when the job was created.
31
Bulk API 2.0 Create a Job
object string The object type for the data being processed.
state JobStateEnum The current state of processing for the job. Values include:
• Open—The job has been created, and data can be added to the job.
• UploadComplete—No new data can be added to this job. You
can’t edit or save this job, as Salesforce is processing it.
• Aborted—The job has been aborted. You can abort a job if you
created it or if you have the “Manage Data Integrations” permission.
• JobComplete—The job was processed by Salesforce.
• Failed—Some records in the job failed. Job data that was
successfully processed isn’t rolled back.
systemModstamp dateTime Date and time in the UTC time zone when the job finished.
Usage Notes
For small amounts of job data (100,000 characters or less), you can create a job and upload all the data for a job using a multipart
request. The following example request header and body uses a multipart format to contain both job information and job data.
Content-Type: multipart/form-data; boundary=BOUNDARY
--BOUNDARY
Content-Type: application/json
Content-Disposition: form-data; name="job"
{
"object":"Contact",
"contentType":"CSV",
"operation":"insert"
}
--BOUNDARY
Content-Type: text/csv
Content-Disposition: form-data; name="content"; filename="content"
32
Bulk API 2.0 Upload Job Data
SEE ALSO:
Bulk API 2.0 Older Documentation
SEE ALSO:
Bulk API 2.0 Older Documentation
Upload Complete
Notifies Salesforce servers that the upload of job data is complete and is ready for processing. You can’t add any more job data. This
request is required for every Bulk API 2.0 ingest job. If you don't make this request, processing of your data does not start.
33
Bulk API 2.0 Upload Complete
URI
/services/data/vXX.X/jobs/ingest/jobID
Availability
This resource is available in API version 41.0 and later.
Formats
JSON
HTTP Method
PATCH
Authentication
Authorization: Bearer token
Parameters
None.
Request Body
Response Body
assignmentRuleId id The ID of the assignment rule. This property is only shown if an assignment
rule is specified when the job is created.
columnDelimiter ColumnDelimiterEnum The column delimiter used for CSV job data. Values include:
• BACKQUOTE—backquote character (`)
• CARET—caret character (^)
• COMMA—comma character (,) which is the default delimiter
• PIPE—pipe character (|)
• SEMICOLON—semicolon character (;)
• TAB—tab character
concurrencyMode ConcurrencyModeEnum For future use. How the request was processed. Currently only parallel
mode is supported. (When other modes are added, the mode will be
chosen automatically by the API and will not be user configurable.)
contentType ContentType The format of the data being processed. Only CSV is supported.
contentUrl URL The URL to use for Upload Job Data on page 33 requests for this job. Only
valid if the job is in Open state.
34
Bulk API 2.0 Get Information About an Ingest Job
lineEnding LineEndingEnum The line ending used for CSV job data. Values include:
• LF—linefeed character
• CRLF—carriage return character followed by a linefeed character
object string The object type for the data being processed.
state JobStateEnum The current state of processing for the job. Values include:
• Open—The job has been created, and data can be added to the job.
• UploadComplete—No new data can be added to this job. You
can’t edit or save this job, as Salesforce is processing it.
• Aborted—The job has been aborted. You can abort a job if you
created it or if you have the “Manage Data Integrations” permission.
• JobComplete—The job was processed by Salesforce.
• Failed—Some records in the job failed. Job data that was
successfully processed isn’t rolled back.
systemModstamp dateTime Date and time in the UTC time zone when the job finished.
SEE ALSO:
Bulk API 2.0 Older Documentation
35
Bulk API 2.0 Get Information About an Ingest Job
URI
/services/data/vXX.X/jobs/ingest/jobID
Availability
This resource is available in API version 41.0 and later.
Formats
JSON
HTTP Method
GET
Authentication
Authorization: Bearer token
Request parameters
Request Body
None required.
Response Body
apiActiveProcessingTime long The number of milliseconds taken to actively process the job and
includes apexProcessingTime, but doesn't include the time
the job waited to be processed.
apiVersion string The API version that the job was created in.
columnDelimiter ColumnDelimiterEnum The column delimiter used for CSV job data. Values include:
• BACKQUOTE—backquote character (`)
• CARET—caret character (^)
• COMMA—comma character (,) which is the default delimiter
• PIPE—pipe character (|)
• SEMICOLON—semicolon character (;)
• TAB—tab character
concurrencyMode ConcurrencyModeEnum For future use. How the request was processed. Currently only parallel
mode is supported. (When other modes are added, the mode will be
chosen automatically by the API and will not be user configurable.)
36
Bulk API 2.0 Get Information About an Ingest Job
contentUrl URL The URL to use for Upload Job Data requests for this job. Only valid if
the job is in Open state.
createdDate dateTime The date and time in the UTC time zone when the job was created.
errorMessage string The error message shown for jobs with errors. For more details, see
Errors and Status Codes and Error Responses.
lineEnding LineEndingEnum The line ending used for CSV job data. Values include:
• LF—linefeed character
• CRLF—carriage return character followed by a linefeed character
numberRecordsFailed long The number of records that were not processed successfully in this
job.
This property is of type int in API version 46.0 and earlier.
object string The object type for the data being processed.
operation OperationEnum The processing operation for the job. Values include:
• insert
• delete
• hardDelete
• update
• upsert
retries int The number of times that Salesforce attempted to save the results of
an operation. The repeated attempts are due to a problem, such as a
lock contention.
state JobStateEnum The current state of processing for the job. Values include:
• Open: The job has been created, and job data can be uploaded
to the job.
37
Bulk API 2.0 Get Information About an Ingest Job
systemModstamp dateTime Date and time in the UTC time zone when the job finished.
Example
This example gets information about the job with ID 7506g00000DhRA2AAN:
curl --include --request GET \
--header "Authorization: Bearer token" \
"https://instance.salesforce.com/services/data/vXX.X/jobs/query/7506g00000DhRA2AAN
38
Bulk API 2.0 Get Job Successful Record Results
"lineEnding" : "LF",
"columnDelimiter" : "COMMA",
"retries" : 0,
"totalProcessingTime" : 0,
"apiActiveProcessingTime" : 0,
"apexProcessingTime" : 0
}
SEE ALSO:
Bulk API 2.0 Older Documentation
Fields from the various Field data for the row that was provided in the original job data upload request.
original CSV
request data
Usage Notes
• The order of records in the response is not guaranteed to match the ordering of records in the original job data.
39
Bulk API 2.0 Get Job Failed Record Results
• Results are not recorded for batches that exceed the daily batch allocation.
SEE ALSO:
Bulk API 2.0 Older Documentation
sf__Id string ID of the record that had an error during processing. Available in API version 53
and later.
Fields from the various Field data for the row that was provided in the original job data upload request.
original CSV
request data
Usage Notes
• The order of records in the response is not guaranteed to match the ordering of records in the original job data.
• Results are not recorded for batches that exceed the daily batch allocation.
SEE ALSO:
Bulk API 2.0 Older Documentation
40
Bulk API 2.0 Get Job Unprocessed Record Results
Usage Notes
• The order of records in the response is not guaranteed to match the ordering of records in the original job data.
• Results are not recorded for batches that exceed the daily batch allocation.
SEE ALSO:
Bulk API 2.0 Older Documentation
Delete a Job
Deletes a job. To be deleted, a job must have a state of UploadComplete, JobComplete, Aborted, or Failed.
URI
/services/data/vXX.X/jobs/ingest/jobID
41
Bulk API 2.0 Abort a Job
Availability
This resource is available in API version 41.0 and later.
Formats
JSON
HTTP Method
DELETE
Authentication
Authorization: Bearer token
Parameters
None.
Request Body
None required.
Response Body
None. Returns a status code of 204 (No Content), which indicates that the job was successfully deleted.
Usage Notes
When a job is deleted, job data stored by Salesforce is also deleted and job metadata information is removed. The job will no longer
display in the Bulk Data Load Jobs page in Salesforce.
SEE ALSO:
Bulk API 2.0 Older Documentation
Abort a Job
If you abort a job, Salesforce doesn’t process the job.
URI
/services/data/vXX.X/jobs/ingest/jobID
Availability
This resource is available in API version 41.0 and later.
Formats
JSON
HTTP Method
PATCH
Authentication
Authorization: Bearer token
Parameters
None.
Request Body
42
Bulk API 2.0 Abort a Job
Response Body
assignmentRuleId id The ID of the assignment rule. This property is only shown if an assignment
rule is specified when the job is created.
columnDelimiter ColumnDelimiterEnum The column delimiter used for CSV job data. Values include:
• BACKQUOTE—backquote character (`)
• CARET—caret character (^)
• COMMA—comma character (,) which is the default delimiter
• PIPE—pipe character (|)
• SEMICOLON—semicolon character (;)
• TAB—tab character
concurrencyMode ConcurrencyModeEnum For future use. How the request was processed. Currently only parallel
mode is supported. (When other modes are added, the mode will be
chosen automatically by the API and will not be user configurable.)
contentType ContentType The format of the data being processed. Only CSV is supported.
contentUrl URL The URL to use for Upload Job Data on page 33 requests for this job. Only
valid if the job is in Open state.
createdDate dateTime The date and time in the UTC time zone when the job was created.
lineEnding LineEndingEnum The line ending used for CSV job data. Values include:
• LF—linefeed character
• CRLF—carriage return character followed by a linefeed character
object string The object type for the data being processed.
43
Bulk API 2.0 Get Information About All Ingest Jobs
state JobStateEnum The current state of processing for the job. Values include:
• Open—The job has been created, and data can be added to the job.
• UploadComplete—No new data can be added to this job. You
can’t edit or save this job, as Salesforce is processing it.
• Aborted—The job has been aborted. You can abort a job if you
created it or if you have the “Manage Data Integrations” permission.
• JobComplete—The job was processed by Salesforce.
• Failed—Some records in the job failed. Job data that was
successfully processed isn’t rolled back.
systemModstamp dateTime Date and time in the UTC time zone when the job finished.
Parameter Description
isPkChunkingEnabled If set to true, filters jobs with PK chunking enabled.
queryLocator Use queryLocator with a locator value to get a specific set of job results. Get All Jobs
returns up to 1000 result rows per request, along with a nextRecordsUrl value that
contains the locator value used to get the next set of results.
44
Bulk API 2.0 Get Information About All Ingest Jobs
Request Body
None required.
Response Body
nextRecordsUrl URL A URL that contains a query locator used to get the next set of results in a
subsequent request if done isn’t true.
JobInfo
columnDelimiter ColumnDelimiterEnum The column delimiter used for CSV job data. Values include:
• BACKQUOTE—backquote character (`)
• CARET—caret character (^)
• COMMA—comma character (,) which is the default delimiter
• PIPE—pipe character (|)
• SEMICOLON—semicolon character (;)
• TAB—tab character
concurrencyMode ConcurrencyModeEnum For future use. How the request was processed. Currently only parallel
mode is supported. (When other modes are added, the mode will be
chosen automatically by the API and will not be user configurable.)
contentType ContentType The format of the data being processed. Only CSV is supported.
contentUrl URL The URL to use for Upload Job Data requests for this job. Only valid if
the job is in Open state.
createdById string The ID of the user who created the job. Create the batch with the same
user.
createdDate dateTime The date and time in the UTC time zone when the job was created.
45
Bulk API 2.0 Upsert Records
object string The object type for the data being processed.
state JobStateEnum The current state of processing for the job. Values include:
• Open—The job has been created, and data can be added to the
job.
• UploadComplete—No new data can be added to this job.
You can’t edit or save this job, as Salesforce is processing it.
• Aborted—The job has been aborted. You can abort a job if you
created it or if you have the “Manage Data Integrations” permission.
• JobComplete—The job was processed by Salesforce.
• Failed—Some records in the job failed. Job data that was
successfully processed isn’t rolled back.
systemModstamp dateTime Date and time in the UTC time zone when the job finished.
SEE ALSO:
Bulk API 2.0 Older Documentation
Upsert Records
Create records or update existing records (upsert) based on an ID, or the value of a specified external ID field.
• If the external ID isn’t matched, then a new record is created according to the request body.
• If the external ID is matched one time, then the record is updated according to the request body.
• If the external ID is matched multiple times, then a 300 error is reported, and the record isn’t created or updated.
The following sections show you how to work with the external ID resource to retrieve records by external ID and upsert records.
46
Bulk API 2.0 Upsert Records
Note: The created parameter is present in the response in API version 46.0 and later. It doesn't appear in earlier versions.
Error responses
Incorrect external ID field:
{
"message" : "The requested resource does not exist",
"errorCode" : "NOT_FOUND"
}
47
Bulk API 2.0 Upsert Records
In API version 45.0 and earlier, the HTTP status code is 204 (No Content) and there isn’t a response body.
Error responses
If the external ID value isn't unique, an HTTP status code 300 is returned, plus a list of the records that matched the query.
If the external ID field doesn't exist, an error message and code is returned:
{
"message" : "The requested resource does not exist",
"errorCode" : "NOT_FOUND"
}
curl https://MyDomainName.my.salesforce.com/services/data/v61.0/sobjects/Account/Id -H
"Authorization: Bearer token" -H "Content-Type: application/json" -d @newrecord.json
-X POST
Note: The created parameter is present in the response in API version 46.0 and later. It doesn't appear in earlier versions.
48
Bulk API 2.0 Use Compression for Bulk API 2.0 Ingest Responses
Bulk API 2.0 follows the HTTP 1.1 standards for response compression, as described in Using Compression. Most clients automatically
support compressed responses. Even though you request a compressed response, the REST framework sometimes doesn’t send back
the response in a compressed format. Visit https://developer.salesforce.com/page/Tools for more information on
particular clients.
2. Create a new ingest job with only the failed and unprocessed records.
• To get the failed records, use Get Job Failed Record Results on page 40.
• To get the unprocessed records, use Get Job Unprocessed Record Results on page 41.
49
Bulk API 2.0 Troubleshooting Ingest Timeouts
SEE ALSO:
Errors
Tip: Always test your data loads in a sandbox organization first. Processing times can be different in a production organization.
Be Aware of Operations that Increase Lock Contention with Bulk API 2.0
These operations are likely to cause lock contention:
• Creating users
• Updating ownership for records with private sharing
• Updating user roles
• Updating territory hierarchies
Organize Bulk API 2.0 Data to Minimize Lock Contention
For large data loads, sort main records based on their parent record to avoid having different child records (with the same parent) in
different jobs.
• Example: When an AccountTeamMember record is created or updated, the corresponding Account for this record is locked
during the transaction. If you upload different jobs that include AccountTeamMember records, and they all contain references
to the same account, they all try to lock the same account, and it's likely that you experience a lock timeout. When working with
AccountTeamMember records, organize your CSV data files by AccountId.
Note: Because your data model is unique to your organization, Salesforce can't predict exactly when you experience lock contention
problems.
Bulk API 2.0 Automatic Record Lock Handling (PILOT)
Based on a popular suggestion in the Salesforce Idea Exchange, we're now offering a pilot feature that automatically checks for Bulk API
2.0 locking errors and handles them to increase the likelihood of successful job completion.
If you’re interested in a pilot to help you automatically minimize lock contention, contact your account team and ask to be nominated for
the "Bulk API 2.0 Automatic Record Lock Handling Pilot".
Note: This feature is not generally available and is being piloted with certain Customers subject to additional terms and conditions.
It is not part of your purchased Services. This feature is subject to change, may be discontinued with no notice at any time in SFDC’s
sole discretion, and SFDC may never make this feature generally available. Make your purchase decisions only on the basis of
generally available products and features. This feature is made available on an AS IS basis and use of this feature is at your sole risk.
50
Bulk API 2.0 Errors
Errors
Operations that you perform with Bulk API 2.0 can trigger error codes. This list shows the most common error codes and the Bulk API
2.0 action that possibly triggered them.
Tip: For HTTP response codes, see Status Codes and Error Responses.
ClientInputError
The operation failed with an unknown client-side error.
For binary attachments, the request content is provided both as an input stream and an attachment.
ExceededQuota
The job or batch you tried to create exceeds the allowed number for the past 24-hour period.
FeatureNotEnabled
Bulk API 2.0 isn’t enabled for this organization.
InvalidBatch
The batch ID specified in a batch update or query is invalid.
This error code is returned for binary attachments when the zip content is malformed or these conditions occur:
• The request.txt file can't be found, can't be read, is a directory, or contains invalid content.
• The decompressed size of a binary attachment is too large.
• The size of the zip file is too large.
• The total decompressed size of all the binary attachments is too large.
For more information about binary attachment limits, see the “General Limits” section in Bulk API and Bulk API 2.0 Limits and
Allocations.
InvalidJob
The job ID specified in a query or update for a job, or a create, update, or query for batches is invalid.
The user attempted to create a job using a zip content type in API version 19.0 or earlier.
InvalidJobState
The job state specified in a job update operation is invalid.
InvalidOperation
The operation specified in a URI for a job is invalid. Check the spelling of “job” in the URI.
InvalidSessionId
The session ID specified is invalid.
InvalidUrl
The URI specified is invalid.
InvalidUser
Either the user sending a Bulk API 2.0 request doesn't have the correct permission, or the job or batch specified was created by
another user.
InvalidXML
XML contained in the request body is invalid.
51
Bulk API 2.0 Bulk API 2.0 Query
MethodNotAllowed
HTTP Method '<displays incorrect method>' not allowed. Allowed are <displays correct method(s)>.
NotFound
The requested resource does not exist. Check the job id, api version, and URI.
Timeout
The connection timed out. This error is thrown if Salesforce takes too long to process a batch. To resolve timeouts, see
• Troubleshooting Ingest Timeouts on page 49
• Troubleshooting Query Timeouts on page 74
TooManyLockFailure
Too many lock failures while processing the current batch. This error may be returned during processing of a batch. To resolve, see
General Guidelines for Data Loads on page 88.
Unknown
Exception with unknown cause occurred.
In addition, Bulk API 2.0 uses the same status codes and exception codes as SOAP API. For more information on these codes, see
“ExceptionCode” in the SOAP API Developer Guide.
52
Bulk API 2.0 Understanding Bulk API 2.0 Query
Availability
Query jobs in Bulk API 2.0 are available in API version 47.0 and later.
53
Bulk API 2.0 Create a Query Job
SOQL Considerations
Bulk API 2.0 doesn’t support SOQL queries that include any of these items:
• GROUP BY, LIMIT, ORDER BY, OFFSET, or TYPEOF clauses.
Don’t use ORDER BY or LIMIT, as they disable PKChunking for the query. With PKChunking disabled, the query takes longer to execute,
and potentially results in query timeouts. If ORDER BY or LIMIT is used, and you experience query time outs, then remove the ORDER
BY or LIMIT clause before any subsequent troubleshooting.
SEE ALSO:
Bulk API 2.0 Older Documentation
Syntax
URI
/services/data/vXX.X/jobs/query
Available since release
This resource is available in API version 47.0 and later.
Format
application/json
HTTP method
POST
Authentication
Authorization:Bearer token
Headers
Optionally, use the Sforce-Call-Options header to specify a default namespace.
Request body
The request body specifies the query to be performed.
{
"operation": "query",
"query": "SELECT Id FROM Account"
}
Note: Bulk API 2.0 doesn’t support SOQL queries that include any of these items:
• GROUP BY, LIMIT, ORDER BY, OFFSET, or TYPEOF clauses.
54
Bulk API 2.0 Create a Query Job
Don’t use ORDER BY or LIMIT, as they disable PKChunking for the query. With PKChunking disabled, the query takes longer
to execute, and potentially results in query timeouts. If ORDER BY or LIMIT is used, and you experience query time outs,
then remove the ORDER BY or LIMIT clause before any subsequent troubleshooting.
Request parameters
contentType The format to be used for the results. Currently the only supported Optional
value is CSV (comma-separated variables). Defaults to CSV.
Note:
columnDelimiter The column delimiter used for CSV job data. The default value is Optional
COMMA. Possible values are:
• BACKQUOTE—back quote character (`)
• CARET—caret character (^)
• COMMA—comma character (,)
• PIPE—pipe character (|)
• SEMICOLON—semicolon character (;)
• TAB—tab character
55
Bulk API 2.0 Create a Query Job
Response Body
{
"id" : "750R0000000zlh9IAA",
"operation" : "query",
"object" : "Account",
"createdById" : "005R0000000GiwjIAC",
"createdDate" : "2018-12-10T17:50:19.000+0000",
"systemModstamp" : "2018-12-10T17:50:19.000+0000",
"state" : "UploadComplete",
"concurrencyMode" : "Parallel",
"contentType" : "CSV",
"apiVersion" : 46.0,
"lineEnding" : "LF",
"columnDelimiter" : "COMMA"
}
Response Parameters
Parameter Description
id The unique ID for this job.
createdDate The UTC date and time when the job was created.
systemModstamp The UTC date and time when the API last updated the job
information.
state The current state of processing for the job. Possible values are:
• UploadComplete—The job is ready to be processed
and Salesforce has put the job in the queue.
• InProgress—Salesforce is processing the job.
• Aborted—The job has been aborted. See Abort a Query
Job.
• JobComplete—Salesforce has finished processing the
job.
• Failed—The job failed.
56
Bulk API 2.0 Create a Query Job
Parameter Description
concurrencyMode Reserved for future use. How the request is processed. Currently
only parallel mode is supported. (When other modes are added,
the API chooses the mode automatically. The mode isn’t user
configurable.)
contentType The format to be used for the results. Currently the only
supported value is CSV.
apiVersion The API version that the job was created in.
lineEnding The line ending used for CSV job data, marking the end of a data
row.
Example
This example creates a job that queries Accounts.
curl --include --request POST \
--header "Authorization: Bearer token" \
--header "Accept: application/json " \
--header "Content-Type: application/json" \
--data '{
"operation": "query",
"query": "SELECT Id, Name FROM Account"
}' \
https://instance.salesforce.com/services/data/vXX.X/jobs/query
SEE ALSO:
Bulk API 2.0 Older Documentation
57
Bulk API 2.0 Get Information About a Query Job
Syntax
URI
/services/data/vXX.X/jobs/query/queryJobId
Available since release
This resource is available in API version 47.0 and later.
Formats
JSON
HTTP methods
GET
Authentication
Authorization: Bearer token
Request parameters
Response Body
{
"id" : "750R0000000zlh9IAA",
"operation" : "query",
"object" : "Account",
"createdById" : "005R0000000GiwjIAC",
"createdDate" : "2018-12-10T17:50:19.000+0000",
"systemModstamp" : "2018-12-10T17:51:27.000+0000",
"state" : "JobComplete",
"concurrencyMode" : "Parallel",
"contentType" : "CSV",
"apiVersion" : 46.0,
"jobType" : "V2Query",
"lineEnding" : "LF",
"columnDelimiter" : "COMMA",
"numberRecordsProcessed" : 500,
"retries" : 0,
"totalProcessingTime" : 334,
"isPkChunkingSupported": true
}
58
Bulk API 2.0 Get Information About a Query Job
Response Parameters
createdDate dateTime The UTC date and time when the job was
created.
systemModstamp dateTime The UTC date and time when the API last
updated the job information.
59
Bulk API 2.0 Get Information About a Query Job
apiVersion string The API version that the job was created
in.
jobType JobTypeEnum The job’s type. For a query job, the type is
always V2Query.
lineEnding LineEndingEnum The line ending used for CSV job data,
marking the end of a data row. The default
is LF. Possible values are:
• LF—linefeed character
• CRLF—carriage return character
followed by a linefeed character
60
Bulk API 2.0 Get Results for a Query Job
Example
This example gets information about the job with ID 750R0000000zxikIAA:
curl --include --request GET \
--header "Authorization: Bearer token" \
"https://instance.salesforce.com/services/data/vXX.X/jobs/query/750R0000000zxikIAA
SEE ALSO:
Bulk API 2.0 Older Documentation
Tip: If encoding is enabled for Bulk API 2.0 Query job responses, there is a significant improvement in performance of query result
downloads. This not the total query time, but a reduction in the time to download the results. See Use Compression for Bulk API
2.0 Query Responses.
61
Bulk API 2.0 Get Results for a Query Job
Syntax
URI
/services/data/vXX.X/jobs/query/queryJobId/results
or
/services/data/vXX.X/jobs/query/queryJobId/results
?locator=locator
&maxRecords=maxRecords
Note: Use the same API version to get query results that you used to create the query. Otherwise, the call returns a 409 error.
locator A string that identifies a specific set of query results. Providing a value Optional
for this parameter returns only that set of results.
Omitting this parameter returns the first set of results.
You can find the locator string for the next set of results in the response
of each request. See Example and Rules and Guidelines.
As long as the associated job exists, the locator string for a set of results
does not change. You can use the locator to retrieve a set of results
multiple times.
maxRecords The maximum number of records to retrieve per set of results for the Optional
query. The request is still subject to the size limits.
If you are working with a very large number of query results, you may
experience a timeout before receiving all the data from Salesforce. To
prevent a timeout, specify the maximum number of records your client
is expecting to receive in the maxRecords parameter. This splits the
results into smaller sets with this value as the maximum size.
If you don’t provide a value for this parameter, the server uses a default
value based on the service.
62
Bulk API 2.0 Get Results for a Query Job
Response Body
If the request is successful, the status code is 200 (OK) and the request body contains the results of the job’s query. For example:
"Id","Name"
"005R0000000UyrWIAS","Jane Dunn"
"005R0000000GiwjIAC","George Wright"
"005R0000000GiwoIAC","Pat Wilson"
...
Note: In API version 50.0 and later, the order of the columns returned by the query is the same as the order you requested them.
In version 49.0 and earlier, the order of the columns is returned alphabetically.
Response Headers
Header Description
Sforce-NumberOfRecords The number of records in this set.
Sforce-Locator The locator for the next set of results (if there are any). Use this
value in other GET request to retrieve the next set of query
results.
This value is a pseudo random string (for example, MTAwMDA).
The length of this string varies depending on how many sets of
results there are.
If there are no more sets of query results, this value is the string
‘null’.
See Example and Rules and Guidelines.
Example
This example retrieves the results for the job with ID 750R0000000zxr8IAA. It also shows how to use the locator and
maxRecords query parameters. (In this example, we use them both, but they are independent. You don’t have to use them together.)
We start by sending an initial request to retrieve the first set of query results. We don’t use the locator parameter because we want
to get the first set of results.
curl --include --request GET \
--header "Authorization: Bearer token" \
--header "Accept: text/csv" \
https://instance.salesforce.com/services/data/vXX.X/jobs/query/750R0000000zxr8IAA/results
?maxRecords=50000
Note: The Accept header must match what was specified when the job was created. Currently, only text/csv is supported.
63
Bulk API 2.0 Get Results for a Query Job
"Id","Name"
"005R0000000UyrWIAS","Jane Dunn"
"005R0000000GiwjIAC","George Wright"
"005R0000000GiwoIAC","Pat Wilson"
...
The response includes MTAwMDA as a value for the Sforce-Locator header. This value is not ‘null’, which means that there are
more query results that we can retrieve.
To retrieve the next set of query results, we send another request, using the locator parameter and the locator string, MTAwMDA.
curl --include --request GET \
--header "Accept: text/csv" \
https://instance.salesforce.com/services/data/vXX.X/jobs/query/750R0000000zxr8IAA/results
?locator=MTAwMDA&maxRecords=50000
"Id","Name"
"005R0000000UyrWIAv","James Wu"
"005R0000000GiwjIxx","Samantha Jones"
"005R0000000GiwoIAB","Doug West"
...
Notice that the locator value has changed. This means that there is another set of query results that we can retrieve. We use the new
locator string, MjAwMDAw, in another request.
curl --include --request GET \
--header "Accept: text/csv" \
https://instance.salesforce.com/services/data/vXX.X/jobs/query/750R0000000zxr8IAA/results
?locator=MjAwMDAw&maxRecords=50000
We repeat this process until the value of the Sforce-Locator header is ‘null’, which indicates that there are no more results to
retrieve.
HTTP/1.1 200 OK
Sforce-Locator: null
Sforce-NumberOfRecords: 6155
...
"Id","Name"
...
64
Bulk API 2.0 Delete a Query Job
2. If there are no more results, the Sforce-Locator header’s value is the string ‘null’. Otherwise, set the locator query
parameter to that value to get the next set of results.
Note: For locator, use only the value from the Sforce-Locator header. Don’t try to guess what it is. How this
parameter is evaluated is subject to change.
3. Repeat this process until the Sforce-Locator header’s value is the string ‘null’. That set is the last set of results.
SEE ALSO:
Bulk API 2.0 Older Documentation
Note: You can only delete a job if its state is JobComplete, Aborted, or Failed.
Syntax
URI
/services/data/vXX.X/jobs/query/queryJobId
Available since release
This resource is available in API version 47.0 and later.
Formats
None
HTTP methods
DELETE
Authentication
Authorization: Bearer token
Request parameters
Response Body
If the method is successful, the status code is 204 (No Content) and there is no response body.
Response Body - For an Unsuccessful Request
If the request fails, the server returns a 400 (Bad Request) status, and the request body shows details of the error. For example:
HTTP/1.1 400 Bad Request
[{
"errorCode": "API_ERROR",
"message": "Error encountered when deleting the job because the job is not terminated"
}]
65
Bulk API 2.0 Abort a Query Job
Example
This example deletes the job with ID 750R0000000zxnaIAA.
curl --include --request DELETE \
--header "Authorization: Bearer token \
--header "Content-Type: " \
https://instance.salesforce.com/services/data/vXX.X/jobs/query/750R0000000zxnaIAA
SEE ALSO:
Bulk API 2.0 Older Documentation
Note:
• To abort a job, you must be the job’s creator or have the Manage Data Integrations permission.
• You can only abort jobs that are in the following states:
– UploadComplete
– InProgress
Syntax
URI
/services/data/vXX.X/jobs/query/queryJobId
Available since release
This resource is available in API version 47.0 and later.
Formats
JSON
HTTP methods
PATCH
Authentication
Authorization: Bearer token
Request body
The request body must be the following:
{
"state": "Aborted"
}
66
Bulk API 2.0 Abort a Query Job
Request parameters
Response Body
If the request is successful, the response is similar to that for Get Results for a Query Job but the state is Aborted. For example:
{
"id" : "750R000000146UvIAI",
"operation" : "query",
"object" : "Account",
"createdById" : "005R0000000GiwjIAC",
"createdDate" : "2018-12-18T16:15:31.000+0000",
"systemModstamp" : "2018-12-18T16:15:32.000+0000",
"state" : "Aborted",
"concurrencyMode" : "Parallel",
"contentType" : "CSV",
"apiVersion" : 46.0
}
Response Parameters
Parameter Description
id The unique ID for this job.
createdDate The UTC date and time when the job was created.
systemModstamp The UTC date and time when the API last updated the job
information.
state The current state of processing for the job. Possible values are:
• UploadComplete—The job is ready to be processed
and Salesforce has put the job in the queue.
• InProgress—Salesforce is processing the job.
67
Bulk API 2.0 Abort a Query Job
Parameter Description
concurrencyMode Reserved for future use. How the request is processed. Currently
only parallel mode is supported. (When other modes are added,
the API chooses the mode automatically. The mode isn’t user
configurable.)
contentType The format that is used for the results. Currently the only
supported value is CSV.
apiVersion The API version that the job was created in.
Example
This example aborts the job with ID 750R000000146UvIAI:
curl --request PATCH \
--header "Authorization: Bearer token" \
--header "Content-Type: application/json" \
--data '{
"state": "Aborted"
}' \
https://instance.salesforce.com/services/data/vXX.X/jobs/query/750R000000146UvIAI
68
Bulk API 2.0 Get Information About All Query Jobs
"apiVersion": 46.0
}
SEE ALSO:
Bulk API 2.0 Older Documentation
Syntax
URI
/services/data/vXX.X/jobs/query
/services/data/vXX.X/jobs/query/
?isPkChunkingEnabled=isPkChunkingEnabled
&jobType=jobType
&concurrencyMode=concurrencyMode
&queryLocator=queryLocator
jobType Gets information only about jobs matching the specified job type. Optional
Possible values are:
• Classic—Bulk API jobs. This includes both query jobs and
ingest jobs.
• V2Query—Bulk API 2.0 query jobs.
• V2Ingest—Bulk API 2.0 ingest (upload and upsert) jobs.
69
Bulk API 2.0 Get Information About All Query Jobs
queryLocator Gets information about jobs starting with that locator value. Optional
Note: Do not enter your own value here. Always use the value
from the nextRecordsUrl from the previous set.
See Example and Rules and Guidelines.
Response Body
The response contains a completion flag, an array of records, and a locator value to be used to obtain more records. For example:
{
"done" : false,
"records" : [
{
"id" : "750R0000000zhfdIAA",
"operation" : "query",
"object" : "Account",
"createdById" : "005R0000000GiwjIAC",
"createdDate" : "2018-12-07T19:58:09.000+0000",
"systemModstamp" : "2018-12-07T19:59:14.000+0000",
"state" : "JobComplete",
"concurrencyMode" : "Parallel",
"contentType" : "CSV",
"apiVersion" : 61.0,
"jobType" : "V2Query",
"lineEnding" : "LF",
"columnDelimiter" : "COMMA"
},
{
"id" : "750R0000000zhjzIAA",
"operation" : "query",
"object" : "Account",
"createdById" : "005R0000000GiwjIAC",
"createdDate" : "2018-12-07T20:52:28.000+0000",
"systemModstamp" : "2018-12-07T20:53:15.000+0000",
"state" : "JobComplete",
"concurrencyMode" : "Parallel",
"contentType" : "CSV",
"apiVersion" : 61.0,
"jobType" : "V2Query",
"lineEnding" : "LF",
"columnDelimiter" : "COMMA"
},
...
],
70
Bulk API 2.0 Get Information About All Query Jobs
"nextRecordsUrl" :
"/services/data/v61.0/jobs/ingest?queryLocator=01gR0000000opRTIAY-2000"
}
Response Parameters
Parameter Description
done This is true if this is the last (or only) set of results. It is false
if there are more records to fetch. See Example and Rules and
Guidelines.
nextRecordsUrl The URI to get the next set of records (if there are any).
This method returns up to 1,000 result rows per request. If there
are more than 1,000 records, use the nextRecordsUrl to
get the next set of records. See Example and Rules and Guidelines.
This parameter is null if there are no more records to fetch.
Record Objects
Parameter Description
id The unique ID for this job.
createdDate The UTC date and time when the job was created.
systemModstamp The UTC date and time when the API last updated the job
information.
state The current state of processing for the job. Possible values are:
• UploadComplete—The job is ready to be processed
and Salesforce has put the job in the queue.
• InProgress—Salesforce is processing the job.
71
Bulk API 2.0 Get Information About All Query Jobs
Parameter Description
concurrencyMode Reserved for future use. How the request is processed. Currently
only parallel mode is supported. (When other modes are added,
the API chooses the mode automatically. The mode isn’t user
configurable.)
contentType The format to be used for the results. Currently the only
supported value is CSV (comma-separated variables). Defaults
to CSV.
Note:
apiVersion The API version that the job was created in.
lineEnding The line ending used for CSV job data, marking the end of a data
row. The default is LF. Possible values are:
• LF—linefeed character
• CRLF—carriage return character followed by a linefeed
character
columnDelimiter The column delimiter used for CSV job data. The default value is
COMMA. Possible values are:
• BACKQUOTE—back quote character (`)
• CARET—caret character (^)
• COMMA—comma character (,)
• PIPE—pipe character (|)
• SEMICOLON—semicolon character (;)
• TAB—tab character
Example
This example shows how to use the nextRecordsUrl query parameter.
72
Bulk API 2.0 Use Compression for Bulk API 2.0 Query Responses
The first request doesn’t use nextRecordsUrl, because we don’t know what value to use yet.
curl --request GET \
--header "Authorization: Bearer token"
https://instance.salesforce.com/services/data/vXX.X/jobs/query
Because there are more records than can be returned in a single response, the value of done in the response isn’t true. We use the
value of nextRecordsUrl,
/services/data/vXX.X/jobs/ingest?queryLocator=01gRM000000NS1vYAG-1000, as the URI to get the next
set of records:
curl --request GET \
--header "Authorization: Bearer token"
https://instance.salesforce.com/services/data/vXX.X/jobs/query?queryLocator=01gRM000000NS1vYAG-1000
Repeat this process until done is true, indicating that there are no more results to fetch.
SEE ALSO:
Bulk API 2.0 Older Documentation
Tip: If encoding is enabled for Bulk API 2.0 Query job responses, there is a significant improvement in performance of query result
downloads. This not the total query time, but a reduction in the time to download the results.
Responses are compressed if the client makes a request using the Accept-Encoding header, with a value of gzip. Bulk API 2.0
compresses the response in gzip format and sends the response to the client with a Content-Encoding: gzip response header.
If a request is made using the Accept-Encoding header with a value other than gzip, the encoding type is ignored, and the
response isn’t compressed.
73
Bulk API 2.0 Troubleshooting Query Timeouts
As an example, if a Get Results for a Query Job request is made with the Accept-Encoding: gzip header, the response looks
something like:
HTTP/1.1 200 OK
Date: Tue, 09 Oct 2012 18:36:45 GMT
Content-Type: text/csv; charset=UTF-8
Content-Encoding: gzip
Transfer-Encoding: chunked
Bulk API 2.0 follows the HTTP 1.1 standards for response compression, as described in Using Compression. Most clients automatically
support compressed responses. Even though you request a compressed response, the REST framework sometimes doesn’t send back
the response in a compressed format. Visit https://developer.salesforce.com/page/Tools for more information on
particular clients.
SEE ALSO:
Salesforce Object Query Language (SOQL) Reference
Errors
Headers
These are custom HTTP request and response headers that are used for Bulk API 2.0.
SEE ALSO:
Bulk API 2.0 Older Documentation
74
Bulk API 2.0 Sforce Call Options Header
/services/data/vXX.X/query/?q=SELECT+Id+botID__c+FROM+Account
SEE ALSO:
Bulk API 2.0 Older Documentation
Warnings Header
Use the Warning header to return warnings, such as the use of a deprecated version of the API.
75
Bulk API 2.0 Content Type Header
Example
Warning: 299 - "This API is deprecated and will be removed by Summer '22. Please see
https://help.salesforce.com/articleView?id=000351312 for details."
SEE ALSO:
Bulk API 2.0 Older Documentation
Note that it’s possible that the text editor used to create the CSV file is configured for a specific line-ending format and might supersede
the default operating system format.
76
Bulk API 2.0 Limits
Limits
Learn about the importance of limits, and compare the limits and allocations of Bulk API 2.0 and Bulk API. For Bulk API 2.0, we simplified
limits, which are available to clients via the REST API /limits endpoint.
Considering Limits
Limits are in place to ensure optimal performance for all customers and to provide fair access to system resources. Each org is only able
to handle a certain number of API requests within a 24-hour period. Budget your overall API consumption to account for what each
integration does against the org.
Questions that might help to plan for limits:
• How many other integrations are making API requests into your org?
• How close does your org come to reaching its entitled request limit each day?
• How many API requests per day would be required in order to address your use cases and data volume?
• Of the APIs that could do the job you’re planning, what are their limits characteristics?
So consider both what your new implementation is attempting to do as well as what existing integrations are doing to make sure your
workloads won’t be interrupted.
Most limits for Bulk API 2.0, such as
• Batch allocations
• General limits
• Ingest limits
• Query limits
are described in Bulk API and Bulk API 2.0 Limits and Allocations. Additional limits specific to Bulk API 2.0 are called out in this topic.
Description Value
Maximum CPU time on the Salesforce servers for Bulk API and Bulk 60,000 milliseconds
API 2.0
SEE ALSO:
Bulk API 2.0 Older Documentation
77
Bulk API 2.0 Bulk API 2.0 Older Documentation
Document Location
Spring ’21 (API version 51.0) https://resources.docs.salesforce.com/230/latest/en-us/sfdc/pdf/api_bulk_v2.pdf
Versions 21.0 through 30.0 As of Summer ’22, these versions have been Salesforce Platform API Versions 21.0 through 30.0
deprecated and no longer supported by Retirement
Salesforce.
Starting Summer ’25, these versions will be
retired and unavailable.
Versions 7.0 through 20.0 As of Summer ’22, these versions are retired Salesforce Platform API Versions 7.0 through 20.0
and unavailable. Retirement
If you request any resource or use an operation from a retired API version, REST API returns the 410:GONE error code.
To identify requests made from old or unsupported API versions, use the API Total Usage event type.
78
CHAPTER 3 Bulk API
In this chapter ... Bulk API is the predecessor to the current Bulk API 2.0. Although Bulk API gives you more fine-grained
control over the specifics of jobs and batches, its work-flow is more complex than Bulk API 2.0. If the
• How Bulk API Works feature set and limits are a unique match to your project requirements, use Bulk API.
• Quick Start: Bulk API
• Bulk API Ingest
• Bulk API Query
• Headers
• Limits
• Bulk API Reference
• Sample Client
Application Using
Java
• Map Data Fields
• Bulk API End-of-Life
Policy
79
Bulk API How Bulk API Works
Note: Salesforce provides an additional API, Bulk API 2.0, which uses the REST API framework to provide similar capabilities to
Bulk API. Bulk API 2.0 simplifies the job creation and monitoring process. For more information on Bulk API 2.0, see the Bulk API
2.0 Developer Guide.
80
Bulk API Step One: Create a Job
81
Bulk API Step One: Create a Job
"object" : "Account",
"contentType" : "CSV"
}
In these samples, the contentType field indicates that the batches associated with the job are in CSV format. For alternative options,
such as XML or JSON, see JobInfo.
Warning: The operation value must match that shown in JobInfo. For example, you get an error if you use INSERT instead of
insert.
SEE ALSO:
Create a Job for Batches with Binary Attachments
Step Four: Get Job Details
Step Three: Close a Job
Step Five: Abort a Job
Add a Batch to a Job
Limits
About URIs
JobInfo
Quick Start: Bulk API 2.0
82
Bulk API Step Two: Monitor a Job
SEE ALSO:
Step One: Create a Job
Step Four: Get Job Details
Step Three: Close a Job
Step Five: Abort a Job
Add a Batch to a Job
Limits
Data Loader Guide
83
Bulk API Step Three: Close a Job
<numberBatchesFailed>0</numberBatchesFailed>
<numberBatchesTotal>1</numberBatchesTotal>
<numberRecordsProcessed>2</numberRecordsProcessed>
<numberRetries>0</numberRetries>
<apiVersion>36.0</apiVersion>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>3647</totalProcessingTime>
<apiActiveProcessingTime>2136</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</jobInfo>
SEE ALSO:
Step One: Create a Job
Step Two: Monitor a Job
Step Four: Get Job Details
Step Five: Abort a Job
Limits
About URIs
JobInfo
Quick Start: Bulk API 2.0
84
Bulk API Step Four: Get Job Details
85
Bulk API Step Five: Abort a Job
"numberRetries" : 0,
"object" : "Account",
"operation" : "insert",
"state" : "Open",
"systemModstamp" : "2015-12-15T20:45:25.000+0000",
"totalProcessingTime" : 0
}
SEE ALSO:
Step One: Create a Job
Step Two: Monitor a Job
Step Three: Close a Job
Step Five: Abort a Job
Add a Batch to a Job
Limits
About URIs
JobInfo
Quick Start: Bulk API 2.0
86
Bulk API Step Five: Abort a Job
<numberBatchesCompleted>1</numberBatchesCompleted>
<numberBatchesFailed>0</numberBatchesFailed>
<numberBatchesTotal>1</numberBatchesTotal>
<numberRecordsProcessed>2</numberRecordsProcessed>
<numberRetries>0</numberRetries>
<apiVersion>36.0</apiVersion>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>3647</totalProcessingTime>
<apiActiveProcessingTime>2136</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</jobInfo>
SEE ALSO:
Step Four: Get Job Details
Step One: Create a Job
Step Two: Monitor a Job
Step Three: Close a Job
Limits
About URIs
JobInfo
87
Bulk API Bulk API Ingest
88
Bulk API Plan Bulk Data Loads
Note: Because your data model is unique to your organization, Salesforce can't predict exactly when you might see lock
contention problems.
Minimize Number of Fields
Processing time is faster if there are fewer fields loaded for each record. Foreign key, lookup relationship, and roll-up summary fields
are more likely to increase processing time. It's not always possible to reduce the number of fields in your records, but if it is, loading
times improve.
89
Bulk API Install cURL
Note: For Bulk queries, the batch size isn’t applied to the query result set or the retrieved data size. If your bulk query takes
too long to process, filter your query statement to return less data.
For information on monitoring batch processing, see Monitor a Batch on page 114.
Minimize Number of Batches in the Asynchronous Queue
Salesforce uses a queue-based framework to handle asynchronous processes from such sources as future and batch Apex, and Bulk
API batches. This queue is used to balance request workload across organizations. If more than 2,000 unprocessed requests from a
single organization are in the queue, any more requests from the same organization will be delayed while the queue handles requests
from other organizations. Minimize the number of batches submitted at one time to ensure that your batches aren’t delayed in the
queue.
Bulk API follows the HTTP 1.1 standards for response compression. Most clients automatically support compressed responses. Visit
https://developer.salesforce.com/page/Tools for more information on particular clients.
Install cURL
The Bulk API uses HTTP GET and HTTP POST methods to send and receive CSV, XML, and JSON content, so it’s simple to build client
applications using the tool or the language of your choice. This quick start uses a command-line tool called cURL to simplify sending
and receiving HTTP requests and responses.
90
Bulk API Walkthrough Sending HTTP Requests with cURL
cURL is pre-installed on many Linux, Mac, and Windows systems. If cURL isn’t pre-installed on Windows, users can download a version
at curl.haxx.se/. When using HTTPS on Windows, ensure that your system meets the cURL requirements for SSL.
Escaping the Session ID or Using Single Quotes on Mac and Linux Systems
When running the cURL examples, you can get an error on Mac and Linux systems due to the presence of the exclamation mark
special character in the session ID argument. To avoid getting this error, use one of these solutions:
• Escape the exclamation mark (!) special character in the session ID by inserting a backslash before it (\!) when the session ID is
enclosed within double quotes. For example, the session ID string in this cURL command has the exclamation mark (!) escaped:
curl https://MyDomainName.my.salesforce.com/services/async/61.0/job
-H "X-SFDC-Session:
00D50000000IehZ\!AQcAQH0dMHZfz972Szmpkb58urFRkgeBGsxL_QJWwYMfAbUeeG7c1E6
LYUfiDUkWe6H34r1AAwOR8B8fLEz6n04NPGRrq0FM"
curl https://MyDomainName.my.salesforce.com/services/async/61.0/job
-H 'X-SFDC-Session: sessionID'
91
Bulk API Walkthrough Sending HTTP Requests with cURL
SEE ALSO:
About URIs
Data Loader Guide
SEE ALSO:
Set a Session Header
SOAP API Developer Guide
Warning: The operation value must match that shown here. For example, you get an error if you use INSERT instead of
insert.
Note: When running cURL examples, you can get an error on Mac and Linux systems due to the presence of the exclamation
mark special character in the session ID argument. To avoid getting this error, either escape the exclamation mark by inserting
a backslash before it (\!) or enclose the session ID within single quotes.
92
Bulk API Walkthrough Sending HTTP Requests with cURL
3. Note the value of the job ID returned in the <id> element. Use this ID in subsequent operations.
SEE ALSO:
Step One: Create a Job
The value for the Description field in the last row spans multiple lines, so it’s wrapped in double quotes.
93
Bulk API Walkthrough Sending HTTP Requests with cURL
Salesforce doesn’t parse the CSV content or otherwise validate the batch until later. The response only acknowledges that the batch
was received.
3. Note the value of the batch ID returned in the <id> element. You can use this batch ID later to check the status of the batch.
SEE ALSO:
Prepare CSV Files
Add a Batch to a Job
Limits
94
Bulk API Walkthrough Sending HTTP Requests with cURL
This cURL command updates the job resource state from Open to Closed.
SEE ALSO:
Step Three: Close a Job
If Salesforce can’t read the batch content or if the batch contains errors, such as invalid field names in the CSV header row, the batch
state is Failed. When the batch state is Completed, all records in the batch have been processed. However, individual records
could have failed. To see the status of individual records, retrieve the batch result.
Checking the status of each individual batch isn't necessary. You can check the status for all batches that are part of the job by running
this cURL command:
curl https://instance.salesforce.com/services/async/61.0/job/jobId/batch -H
"X-SFDC-Session: sessionId"
SEE ALSO:
Get Information for a Batch
Get Information for All Batches in a Job
Interpret Batch State
95
Bulk API Prepare Data Files
curl https://instance.salesforce.com/services/async/61.0/job/jobId/batch/batchId/result
-H "X-SFDC-Session: sessionId"
instance is the portion of the <serverUrl> element and sessionId is the <sessionId> element that you noted in the
login response. jobId is the job ID that was returned when you created the job. batchId is the batch ID that was returned when
you added a batch to the job.
Salesforce returns a response with data such as this:
"Id","Success","Created","Error"
"003x0000004ouM4AAI","true","true",""
"003x0000004ouM5AAI","true","true",""
The response body is a CSV file with a row for each row in the batch request. If a record was created, the ID is contained in the row. If a
record was updated, the value in the Created column is false. If a record failed, the Error column contains an error message.
SEE ALSO:
Get Batch Results
Handle Failed Records in Batches
Note: For best performance, Salesforce recommends the following order of preference for data files: CSV, JSON, XML.
For information about loading records containing binary attachments, see Load Binary Attachments on page 106.
For information about loading data from third-party sources, see Map Data Fields on page 169.
SEE ALSO:
Data Loader Guide
96
Bulk API Prepare Data Files
SEE ALSO:
Salesforce Help: Find Object Management Settings
dateTime
Use the yyyy-MM-ddTHH:mm:ss.SSS+/-HH:mm or yyyy-MM-ddTHH:mm:ss.SSSZ formats to specify dateTime
fields.
• yyyy is the four-digit year
• MM is the two-digit month (01-12)
• dd is the two-digit day (01-31)
• 'T' is a separator indicating that time-of-day follows
• HH is the two-digit hour (00-23)
• mm is the two-digit minute (00-59)
• ss is the two-digit seconds (00-59)
• SSS is the optional three-digit milliseconds (000-999)
• +/-HH:mm is the Zulu (UTC) time zone offset
• 'Z' is the reference UTC timezone
97
Bulk API Prepare Data Files
When a timezone is added to a UTC dateTime, the result is the date and time in that timezone. For example, 2002-10-10T12:00:00+05:00
is 2002-10-10T07:00:00Z and 2002-10-10T00:00:00+05:00 is 2002-10-09T19:00:00Z. See W3C XML Schema Part 2: DateTime Datatype.
date
Use the yyyy-MM-dd format to specify date fields.
Tip: To import data from CSV files that don’t meet these rules, map the data fields in the CSV file to Salesforce data fields. See Map
Data Fields on page 169.
SEE ALSO:
Data Loader Guide
98
Bulk API Prepare Data Files
FirstName,LastName,ReportsTo.Email
Tom,Jones,[email protected]
Important: Starting with version 57.0 of the API, for ObjectType use apiName, which should include namespace, if any,
and should include __c if the object is a custom object.
The following sample includes two reference fields:
99
Bulk API Prepare Data Files
1. The WhoId field is polymorphic and has a relationshipName of Who. It refers to a lead and the indexed Email field
uniquely identifies the parent record.
2. The OwnerId field is not polymorphic and has a relationshipName of Owner. It refers to a user and the indexed Id field
uniquely identifies the parent record.
Subject,Priority,Status,Lead:Who.Email,Owner.Id
Test Bulk API polymorphic reference field,Normal,Not
Started,[email protected],005D0000001AXYz
Warning: The ObjectType: portion of a field column header is only required for a polymorphic field. You get an error if you
omit this syntax for a polymorphic field. You also get an error if you include this syntax for a field that is not polymorphic.
100
Bulk API Prepare Data Files
The Description field for the last record includes a line break, which is why the field value is enclosed in double quotes.
SEE ALSO:
Sample XML File
Sample JSON File
Data Loader Guide
101
Bulk API Prepare Data Files
XML:
<RelationshipName>
<sObject>
<IndexedFieldName>[email protected]</IndexedFieldName>
</sObject>
</RelationshipName>
Use the describeSObjects() call in the API to get the relationshipName property value for a field. Use an indexed field
to uniquely identify the parent record for the relationship. A standard field is indexed if its idLookup property is set to true.
These samples include a contact record that includes the ReportsTo field, which is a reference to another contact. ReportsTo is
the relationshipName property value for the ReportsTo field. In this case, the parent object for the ReportsTo field is
also a contact, so we use the Email field to identify the parent record. The idLookup property value for the Email field is true.
To see if there is a idLookup property for a field, go to the Field Properties column in the field table for each standard object.
JSON:
[{
"FirstName" : "Ray",
"LastName" : "Riordan",
"ReportsTo" : { "Email" : "[email protected]" }
}]
XML:
<?xml version="1.0" encoding="UTF-8"?>
<sObjects xmlns="http://www.force.com/2009/06/asyncapi/dataload">
<sObject>
<FirstName>Ray</FirstName>
<LastName>Riordan</LastName>
<ReportsTo>
<sObject>
<Email>[email protected]</Email>
</sObject>
</ReportsTo>
</sObject>
</sObjects>
102
Bulk API Prepare Data Files
XML:
<?xml version="1.0" encoding="UTF-8"?>
<sObjects xmlns="http://www.force.com/2009/06/asyncapi/dataload">
<sObject>
<Name>CustomObject1</Name>
<Mother_Of_Child__r>
<sObject>
<External_ID__c>123456</External_ID__c>
</sObject>
</Mother_Of_Child__r>
</sObject>
</sObjects>
"RelationshipName" : {
"attributes" : {
"type" : "ObjectTypeName" },
"IndexedFieldName" : "[email protected]"
}
XML:
<RelationshipName>
<sObject>
<type>ObjectTypeName</type>
<IndexedFieldName>[email protected]</IndexedFieldName>
</sObject>
</RelationshipName>
103
Bulk API Prepare Data Files
2. The OwnerId field is not polymorphic and has a relationshipName of Owner. It refers to a user and the indexed Id field
uniquely identifies the parent record.
JSON:
[{
"Subject" : "Test Bulk API polymorphic reference field",
"Priority" : "Normal",
"Status" : "Not Started",
"Who" : {
"attributes" : {
"type" : "Lead" },
"Email" : "[email protected]" },
"Owner" : { "Id" : "005D0000001AXYz" }
}]
XML:
<?xml version="1.0" encoding="UTF-8"?>
<sObjects xmlns="http://www.force.com/2009/06/asyncapi/dataload">
<sObject>
<Subject>Test Bulk API polymorphic reference field</Subject>
<Priority>Normal</Priority>
<Status>Not Started</Status>
<Who>
<sObject>
<type>Lead</type>
<Email>[email protected]</Email>
</sObject>
</Who>
<Owner>
<sObject>
<Id>005D0000001AXYz</Id>
</sObject>
</Owner>
</sObject>
</sObjects>
Warning: The type element is required only for a polymorphic field. If you omit this element for a polymorphic field or include
it for a non-polymorphic field, you get an error.
104
Bulk API Prepare Data Files
</sObject>
</sObjects>
Each batch in a JSON file uses this format with each JSON object representing a record.
[
{
"field_name" : "field_value"
...
},
{
"field_name" : "field_value"
...
}
]
Note: You must include the type field for a polymorphic field and exclude it for non-polymorphic fields in any batch. If you
don’t the batch fails. A polymorphic field can refer to more than one type of object as a parent. For example, either a contact or a
lead can be the parent of a task. In other words, the WhoId field of a task can contain the ID of either a contact or a lead.
When generating records in XML or JSON files:
• Fields that aren’t defined in the file for a record are ignored when you update records. To set a field value to null in XML, set the
xsi:nil value for the field to true. For example, <description xsi:nil="true"/> sets the description field to
null. Setting xsi:nil to false has no effect. If you define a field value and set xsi:nil to false, the value still gets
assigned. To specify a null value in JSON, set the field value to null. For example, "description" : null.
• Fields with a double data type can include fractional values. Values can be stored in scientific notation if the number is large
enough (or, for negative numbers, small enough), as indicated by theW3C XML Schema Part 2: Datatypes Second Edition specification
SEE ALSO:
Sample XML File
Sample JSON File
105
Bulk API Load Binary Attachments
</sObject>
</sObjects>
SEE ALSO:
Sample CSV File
Sample JSON File
SEE ALSO:
Sample CSV File
Sample XML File
106
Bulk API Load Binary Attachments
Note: If you create a zip file on OS X by right-clicking a folder and choosing "Compress" - it won't work. The result is an extra folder
level inside the zip file. You can use zip to create it properly and unzip -l to check it.
The request.txt file is a manifest file for the attachments in the zip file and contains the data for each record that references a
binary file.
Note: The batch data file is named request.txt, whether you’re working with CSV, XML, or JSON data.
For the Attachment object, the notation for these fields is particularly important:
• The Name field is the file name of the binary attachment. The easiest way to get a unique name for each attachment in your batch
is to use the relative path from the base directory to the binary attachment. For example, attachment1.gif or
subdir/attachment2.doc.
• The Body is the relative path to the binary attachment, preceded with a # symbol. For example, #attachment1.gif or
#subdir/attachment2.doc.
• The ParentId field identifies the parent record, such as an account or a case, for the attachment.
The batch file can also include other optional Attachment fields, such as Description. For more information, see Attachment.
Name,ParentId,Body
attachment1.gif,Account Id,#attachment1.gif
subdir/attachment2.doc,Account Id,#subdir/attachment2.doc
107
Bulk API Load Binary Attachments
<ParentId>Account Id</ParentId>
<Body>#attachment1.gif</Body>
</sObject>
<sObject>
<Name>subdir/attachment2.doc</Name>
<ParentId>Account Id</ParentId>
<Body>#subdir/attachment2.doc</Body>
</sObject>
</sObjects>
Note: The batches for this job contain data in CSV format, so the contentType field is set to ZIP_CSV. For XML or JSON
batches, use ZIP_XML or ZIP_JSON, respectively.
108
Bulk API Load Binary Attachments
3. Note the value of the job ID returned in the <id> element. Use this ID in subsequent operations.
Note: The Content-type for the POST request is zip/csv. For XML or JSON batches, use zip/xml or zip/json instead.
109
Bulk API Request Basics
Salesforce doesn’t parse the CSV content or otherwise validate the batch until later. The response only acknowledges that the batch
was received.
4. Note the value of the batch ID returned in the <id> element. You can use this batch ID later to check the status of the batch.
For details on proceeding to close the associated job, check batch status, and retrieve batch results, see the Getting Started.
Request Basics
Here are some Bulk API request basics, including the format of URIs used to perform operations and details on how to authenticate
requests using a session header.
About URIs
You send HTTP requests to a URI to perform operations with Bulk API.
Set a Session Header
All HTTP requests must contain a valid API session ID obtained with the SOAP API login() call. The session ID is returned in the
SessionHeader.
About URIs
You send HTTP requests to a URI to perform operations with Bulk API.
The URI where you send HTTP requests has this format:
https://Web_Services_SOAP_endpoint_hostame/services/async/APIversion/Resource_address
Think of the part of the URI through the API version as a base URI that’s used for all operations. The part after the API version
(Resource_address) varies depending on the job or batch being processed. For example, if you're working with version 61.0 of
Bulk API in a production org, your base URI would be
https://MyDomainName.my.salesforce.com/services/async/61.0.
110
Bulk API Work with Batches
You can find the My Domain name and My Domain login URL for your org on the My Domain page in Setup. Or, to get the hostname
of your My Domain login URL in Apex, use the getMyDomainHostname() method of the System.DomainCreator class.
SEE ALSO:
Quick Start: Bulk API
Work with Batches
SEE ALSO:
Quick Start: Bulk API 2.0
Sample Client Application Using Java
Note: Salesforce provides an additional API, Bulk API 2.0, which uses the REST API framework to provide similar capabilities to
Bulk API. Bulk API 2.0 removes the need for creating and monitoring batches, and it lets you load record data for a job directly. For
more information on Bulk API 2.0, see the Bulk API 2.0 Developer Guide.
111
Bulk API Work with Batches
Note: The API version in the URI for all batch operations must match the API version for the associated job.
In this sample, the batch data is in XML format because the contentType field of the associated job was set to XML. For alternative
formats for batch data, such as CSV or JSON, see JobInfo on page 148.
112
Bulk API Work with Batches
In this sample, the batch data is in JSON format because the contentType field of the associated job was set to JSON.
Example JSON response body
{
"apexProcessingTime":0,
"apiActiveProcessingTime":0,
"createdDate":"2015-12-15T21:56:43.000+0000",
"id":"751D00000004YGZIA2",
"jobId":"750D00000004SkVIAU",
"numberRecordsFailed":0,
"numberRecordsProcessed":0,
"state":"Queued",
"systemModstamp":"2015-12-15T21:56:43.000+0000",
"totalProcessingTime":0
}
113
Bulk API Work with Batches
Note: You can add batch jobs using non-Bulk API-compliant CSV files. See Map Data Fields on page 169.
SEE ALSO:
Create a Batch with Binary Attachments
Get Information for a Batch
Monitor a Batch
Get Information for All Batches in a Job
Interpret Batch State
Get a Batch Request
Get Batch Results
Quick Start: Bulk API
Limits
About URIs
BatchInfo
Quick Start: Bulk API 2.0
Monitor a Batch
You can monitor a Bulk API batch in Salesforce.
To track the status of bulk data load jobs and their associated batches, from Setup, in the Quick Find box, enter Bulk Data
Load Jobs, then select Bulk Data Load Jobs. Click the Job ID to view the job detail page.
The job detail page includes a related list of all the batches for the job. The related list provides View Request and View Response links
for each batch. If the batch is a CSV file, the links return the request or response in CSV format. If the batch is an XML or JSON file, the
links return the request or response in XML or JSON format, respectively. These links are available for batches created in API version 19.0
and later. For Bulk V2 type jobs, batch information is unavailable.
SEE ALSO:
Get Information for a Batch
Add a Batch to a Job
Get Information for All Batches in a Job
Interpret Batch State
Get a Batch Request
Get Batch Results
Handle Failed Records in Batches
Quick Start: Bulk API
Limits
About URIs
BatchInfo
Quick Start: Bulk API 2.0
114
Bulk API Work with Batches
115
Bulk API Work with Batches
"totalProcessingTime" : 0
}
SEE ALSO:
Add a Batch to a Job
Monitor a Batch
Get Information for All Batches in a Job
Interpret Batch State
Get a Batch Request
Get Batch Results
Limits
BatchInfo
About URIs
Quick Start: Bulk API
Quick Start: Bulk API 2.0
116
Bulk API Work with Batches
<systemModstamp>2009-04-14T18:16:09.000Z</systemModstamp>
<numberRecordsProcessed>800</numberRecordsProcessed>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>5870</totalProcessingTime>
<apiActiveProcessingTime>0</apiActiveProcessingTime>
<apexProcessingTime>2166</apexProcessingTime>
</batchInfo>
</batchInfoList>
117
Bulk API Work with Batches
]
}
SEE ALSO:
Add a Batch to a Job
Monitor a Batch
Get Information for a Batch
Interpret Batch State
Get a Batch Request
Get Batch Results
Limits
BatchInfo
About URIs
Quick Start: Bulk API
Quick Start: Bulk API 2.0
118
Bulk API Work with Batches
After the original batch is changed to this state, you can monitor the subsequent batches and retrieve each batch’s results when it’s
completed.
SEE ALSO:
Add a Batch to a Job
Monitor a Batch
Get Information for All Batches in a Job
Get a Batch Request
Get Batch Results
Handle Failed Records in Batches
Limits
BatchInfo
About URIs
Quick Start: Bulk API
Quick Start: Bulk API 2.0
119
Bulk API Work with Batches
SEE ALSO:
Get Information for a Batch
Monitor a Batch
Get Information for All Batches in a Job
Interpret Batch State
Get Batch Results
Quick Start: Bulk API
Limits
About URIs
BatchInfo
Quick Start: Bulk API 2.0
120
Bulk API Work with Batches
<result>
<id>001D000000ISUr4IAH</id>
<success>true</success>
<created>true</created>
</result>
</results>
Note: The batch result indicates that the last record wasn’t processed successfully because the LastName field was missing.
The Error column includes error information. These error messages are exclusive to the Failed state of the job. You
must look at the Success field for each result row to ensure that all rows were processed successfully. For more information,
see Handle Failed Records in Batches on page 122.
SEE ALSO:
Add a Batch to a Job
Monitor a Batch
Get a Batch Request
Get Information for a Batch
Get Information for All Batches in a Job
Interpret Batch State
Limits
BatchInfo
About URIs
Quick Start: Bulk API
Quick Start: Bulk API 2.0
121
Bulk API Bulk API Query
After you examine each result record, you can manually fix each record in the error file and submit these records in a new batch. To
check that each record processed successfully, repeat the previous steps.
SEE ALSO:
Add a Batch to a Job
Errors
Limits
122
Bulk API How Bulk Queries Are Processed
123
Bulk API Use Bulk Query
SEE ALSO:
Use Bulk Query
PK Chunking
Walk Through a Bulk Query Sample
124
Bulk API Use Bulk Query
URI
/services/async/APIversion/job/jobid/batch
Bulk Query Request
POST baseURI/job/750x00000000014/batch
X-SFDC-Session: 4f1a00D30000000K7zB!ARUAQDqAHcM...
Content-Type: [either text/csv, application/xml, or application/json depending on job]
Bulk API query supports both query and queryAll operations. The queryAll operation returns records that have been deleted because
of a merge or delete. The queryAll operation also returns information about archived Task and Event records. For more information,
see queryAll() in the SOAP API Developer Guide.
Relationship queries traverse parent-to-child and child-to-parent relationships between objects to filter and return results. You can
use SOQL relationships in bulk queries. For more information about SOQL relationships, see Using Relationship Queries in the SOQL
and SOSL Reference.
Bulk API doesn’t support queries with any of the following:
• GROUP BY, OFFSET, or TYPEOF clauses
• Aggregate functions such as COUNT()
• Date functions in GROUP BY clauses (date functions in WHERE clauses are supported)
• Compound address fields or compound geolocations fields
125
Bulk API Use Bulk Query
Get Batch Information for All Batches in a Job HTTP Request (used when PK chunking is enabled)
GET baseURI/job/750x00000000014/batch
X-SFDC-Session: 4f1a00D30000000K7zB!ARUAQDqAHcM...
Get Batch Information for All Batches in a Job HTTP Response Body
<?xml version="1.0" encoding="UTF-8"?><batchInfoList
xmlns="http://www.force.com/2009/06/asyncapi/dataload">
<batchInfo>
<id>751D00000004YjwIAE</id>
<jobId>750D00000004T5OIAU</jobId>
<state>NotProcessed</state>
<createdDate>2011-03-10T00:59:47.000Z</createdDate>
<systemModstamp>2011-03-10T01:00:19.000Z</systemModstamp>
<numberRecordsProcessed>0</numberRecordsProcessed>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>0</totalProcessingTime>
<apiActiveProcessingTime>0</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</batchInfo>
<batchInfo>
<id>751D00000004Yk1IAE</id>
<jobId>750D00000004T5OIAU</jobId>
<state>Completed</state>
<createdDate>2011-03-10T00:59:47.000Z</createdDate>
<systemModstamp>2011-03-10T01:00:19.000Z</systemModstamp>
<numberRecordsProcessed>100000</numberRecordsProcessed>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>1000</totalProcessingTime>
<apiActiveProcessingTime>1000</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</batchInfo>
<batchInfo>
<id>751D00000004Yk2IAE</id>
<jobId>750D00000004T5OIAU</jobId>
<state>Completed</state>
<createdDate>2011-03-10T00:59:47.000Z</createdDate>
<systemModstamp>2011-03-10T01:00:19.000Z</systemModstamp>
<numberRecordsProcessed>100000</numberRecordsProcessed>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>1000</totalProcessingTime>
<apiActiveProcessingTime>1000</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</batchInfo>
<batchInfo>
<id>751D00000004Yk6IAE</id>
<jobId>750D00000004T5OIAU</jobId>
<state>Completed</state>
<createdDate>2011-03-10T00:59:47.000Z</createdDate>
<systemModstamp>2011-03-10T01:00:19.000Z</systemModstamp>
<numberRecordsProcessed>100000</numberRecordsProcessed>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>1000</totalProcessingTime>
<apiActiveProcessingTime>1000</apiActiveProcessingTime>
126
Bulk API Use Bulk Query
<apexProcessingTime>0</apexProcessingTime>
</batchInfo>
<batchInfo>
<id>751D00000004Yk7IAE</id>
<jobId>750D00000004T5OIAU</jobId>
<state>Completed</state>
<createdDate>2011-03-10T00:59:47.000Z</createdDate>
<systemModstamp>2011-03-10T01:00:19.000Z</systemModstamp>
<numberRecordsProcessed>50000</numberRecordsProcessed>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>500</totalProcessingTime>
<apiActiveProcessingTime>500</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</batchInfo>
</batchInfoList>
This is expected behavior and something to be aware of if you are accessing the full XML response data and not using WSC
to access the web service response. For more information, see Queries and the Partner WSDL in the SOAP API Developer Guide.
127
Bulk API Use Bulk Query
job.setOperation(OperationEnum.query);
job.setConcurrencyMode(ConcurrencyMode.Parallel);
job.setContentType(ContentType.CSV);
job = bulkConnection.createJob(job);
assert job.getId() != null;
job = bulkConnection.getJobStatus(job.getId());
128
Bulk API Use Bulk Query
String query =
"SELECT Name, Id, Description__c FROM Merchandise__c";
if (info.getState() == BatchStateEnum.Completed) {
QueryResultList list =
bulkConnection.getQueryResultList(job.getId(),
info.getId());
queryResults = list.getResult();
break;
} else if (info.getState() == BatchStateEnum.Failed) {
System.out.println("-------------- failed ----------"
+ info);
break;
} else {
System.out.println("-------------- waiting ----------"
+ info);
}
}
if (queryResults != null) {
for (String resultId : queryResults) {
bulkConnection.getQueryResultStream(job.getId(),
info.getId(), resultId);
}
}
} catch (AsyncApiException aae) {
aae.printStackTrace();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
SEE ALSO:
How Bulk Queries Are Processed
PK Chunking
Walk Through a Bulk Query Sample
129
Bulk API PK Chunking
PK Chunking
Use the primary key (PK) chunking request header to enable automatic PK chunking for a bulk query job. PK chunking splits bulk queries
on large tables into chunks based on the record IDs, or primary keys, of the queried records.
Each chunk is processed as a separate batch that counts toward your daily batch limit, and you must download each batch’s results
separately. PK chunking works only with queries that don’t include subqueries or conditions other than WHERE.
PK chunking works by adding record ID boundaries to the query with a WHERE clause, limiting the query results to a smaller chunk of
the total results. The remaining results are fetched with extra queries that contain successive boundaries. The number of records within
the ID boundaries of each chunk is referred to as the chunk size. The first query retrieves records between a specified starting ID and the
starting ID plus the chunk size. The next query retrieves the next chunk of records, and so on.
For example, let’s say you enable PK chunking for the following query on an Account table with 10,000,000 records.
SELECT Name FROM Account
Assuming a chunk size of 250,000 and a starting record ID of 001300000000000, the query is split into these 40 queries. Each query
is submitted as a separate batch.
SELECT Name FROM Account WHERE Id >= 001300000000000 AND Id < 00130000000132G
SELECT Name FROM Account WHERE Id >= 00130000000132G AND Id < 00130000000264W
SELECT Name FROM Account WHERE Id >= 00130000000264W AND Id < 00130000000396m
...
SELECT Name FROM Account WHERE Id >= 00130000000euQ4 AND Id < 00130000000fxSK
Each query executes on a chunk of 250,000 records specified by the base-62 ID boundaries.
PK chunking is designed for extracting data from entire tables, but you can also use it for filtered queries. Because records could be
filtered from each query’s results, the number of returned results for each chunk can be less than the chunk size. The IDs of soft-deleted
records are counted when the query is split into chunks, but the records are omitted from the results. Therefore, if soft-deleted records
fall within a given chunk’s ID boundaries, the number of returned results is less than the chunk size. In some scenarios, the net chunk
size can also be greater than what is specified.
The default chunk size is 100,000, and the maximum size is 250,000. The default starting ID is the first record in the table. However, you
can specify a different starting ID to restart a job that failed between chunked batches.
When a query is successfully chunked, the original batch’s status shows as NOT_PROCESSED. If the chunking fails, the original batch’s
status shows as FAILED, but any chunked batches that were successfully queued during the chunking attempt are processed as
normal. When the original batch’s status is changed to NOT_PROCESSED, monitor the subsequent batches. You can retrieve the
results from each subsequent batch after it’s completed. Then you can safely close the job.
Salesforce recommends that you enable PK chunking when querying tables with more than 10 million records or when a bulk query
consistently times out. However, the effectiveness of PK chunking depends on the specifics of the query and the queried data.
Supported Objects
PK chunking only works with the following objects:
• Account
• AccountContactRelation
• AccountTeamMember
• AiVisitSummary
• Asset
• AssignedResource
130
Bulk API PK Chunking
• Campaign
• CampaignMember
• CandidateAnswer
• Case
• CaseArticle
• CaseComment
• CaseRelatedIssue
• ChangeRequest
• ChangeRequestRelatedIssue
• ChangeRequestRelatedItem
• Claim
• ClaimParticipant
• Contact
• ContentDistribution
• ContentDocument
• ContentNote
• ContentVersion
• Contract
• ContractLineItem
• ConversationDefinitionEventLog
• ConversationEntry
• ConversationReason
• ConversationReasonExcerpt
• ConversationReasonGroup
• CustomerProperty
• EinsteinAnswerFeedback
• EmailMessage
• EngagementScore
• Entitlement
• Event
• EventRelation
• FeedItem
• Incident
• IncidentRelatedItem
• Individual
• InsurancePolicy
• InsurancePolicyAsset
• InsurancePolicyParticipant
• Lead
• LeadInsight
131
Bulk API PK Chunking
• LinkedArticle
• LiveChatTranscript
• LoginHistory
• LoyaltyAggrPointExprLedger
• LoyaltyLedger
• LoyaltyMemberCurrency
• LoyaltyMemberTier
• LoyaltyPartnerProduct
• LoyaltyProgramMbrPromotion
• LoyaltyProgramMember
• LoyaltyProgramPartner
• LoyaltyProgramPartnerLedger
• MlRetrainingFeedback
• Note
• ObjectTerritory2Association
• Opportunity
• OpportunityContactRole
• OpportunityHistory
• OpportunityLineItem
• OpportunitySplit
• OpportunityTeamMember
• Order
• OrderItem
• Pricebook2
• PricebookEntry
• Problem
• ProblemIncident
• ProblemRelatedItem
• Product2
• ProductConsumed
• ProductRequired
• QuickText
• Quote
• QuoteLineItem
• ReplyText
• ScoreIntelligence
• ServiceAppointment
• ServiceContract
• Task
• TaskRelation
132
Bulk API PK Chunking
• TermDocumentFrequency
• TimeSheetEntry
• TransactionJournal
• User
• UserRole
• VoiceCall
• VoiceCallRecording
• Voucher
• WebCart
• WorkloadUnit
• WorkOrder
• WorkOrderLineItem
• WorkPlan
• WorkPlanTemplate
Support includes custom objects.
Filtered Queries
PK chunking is designed for extracting data from entire tables, but you can also use it for filtered queries.
Because records could be filtered from each query’s results, the number of returned results for each chunk can be less than the chunk
size. Also, the IDs of soft-deleted records are counted when the query is split into chunks, but the records are omitted from the results.
Therefore, if soft-deleted records fall within a given chunk’s ID boundaries, the number of returned results is less than the chunk size.
Some query limitations apply that effectively disable PK chunking for the specified bulk query job:
• Filtering on any field with “id” in the field name (ID fields).
• Using an "ORDER BY" clause.
133
Bulk API Walk Through a Bulk Query Sample
• parent—Specifies the parent object when you’re enabling PK chunking for queries on sharing objects. The chunks are based
on the parent object’s records rather than the sharing object’s records. For example, when querying on AccountShare, specify
Account as the parent object. PK chunking is supported for sharing objects as long as the parent object is supported.
Similarly, for CaseHistory, specify Case as the parent object. For example:
Sforce-Enable-PKChunking: parent=Case
• startRow—Specifies the 15-character or 18-character record ID to be used as the lower boundary for the first chunk. Use this
parameter to specify a starting ID when restarting a job that failed between batches.
Example
Sforce-Enable-PKChunking: chunkSize=50000; startRow=00130000000xEftMGH
Create a Job
1. Create a file called create-job.xml containing this text.
<?xml version="1.0" encoding="UTF-8"?>
<jobInfo
xmlns="http://www.force.com/2009/06/asyncapi/dataload">
<operation>query</operation>
<object>Account</object>
<concurrencyMode>Parallel</concurrencyMode>
<contentType>CSV</contentType>
</jobInfo>
134
Bulk API Walk Through a Bulk Query Sample
<state>Open</state>
<concurrencyMode>Parallel</concurrencyMode>
<contentType>CSV</contentType>
<numberBatchesQueued>0</numberBatchesQueued>
<numberBatchesInProgress>0</numberBatchesInProgress>
<numberBatchesCompleted>0</numberBatchesCompleted>
<numberBatchesFailed>0</numberBatchesFailed>
<numberBatchesTotal>0</numberBatchesTotal>
<numberRecordsProcessed>0</numberRecordsProcessed>
<numberRetries>0</numberRetries>
<apiVersion>36.0</apiVersion>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>0</totalProcessingTime>
<apiActiveProcessingTime>0</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</jobInfo>
2. Using a command-line window, execute this cURL command to add a batch to the job:
curl -d @query.txt -H "X-SFDC-Session: sessionId" -H "Content-Type: text/csv;
charset=UTF-8" https://instance.salesforce.com/services/async/61.0/job/jobId/batch
jobId is the job ID returned in the response to the job creation.
Salesforce returns an XML response with data such as this.
<?xml version="1.0" encoding="UTF-8"?>
<batchInfo
xmlns="http://www.force.com/2009/06/asyncapi/dataload">
<id>751x000000009vwAAA</id>
<jobId>750x000000009tvAAA</jobId>
<state>Queued</state>
<createdDate>2016-01-10T00:59:47.000Z</createdDate>
<systemModstamp>2016-01-10T00:59:47.000Z</systemModstamp>
<numberRecordsProcessed>0</numberRecordsProcessed>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>0</totalProcessingTime>
<apiActiveProcessingTime>0</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</batchInfo>
Note: When you add a batch to a bulk query job, the Content-Type in the header for the request must be text/csv,
application/xml, or application/json, depending on the content type specified when the job was created.
The actual SOQL statement supplied for the batch is in plain text format.
135
Bulk API Walk Through a Bulk Query Sample
2. Using a command-line window, execute this cURL command to close the job.
curl -H "X-SFDC-Session: sessionId" -H "Content-Type: text/csv; charset=UTF-8" -d
@close-job.xml https://instance.salesforce.com/services/async/61.0/job/jobId
Salesforce returns an XML response with data such as this.
<?xml version="1.0" encoding="UTF-8"?>
<jobInfo
xmlns="http://www.force.com/2009/06/asyncapi/dataload">
<id>750x000000009tvAAA</id>
<operation>query</operation>
<object>Account</object>
<createdById>005x0000001WR0lAAG</createdById>
<createdDate>2016-01-10T00:53:19.000Z</createdDate>
<systemModstamp>2016-01-10T00:53:19.000Z</systemModstamp>
<state>Closed</state>
<concurrencyMode>Parallel</concurrencyMode>
<contentType>CSV</contentType>
<numberBatchesQueued>0</numberBatchesQueued>
<numberBatchesInProgress>0</numberBatchesInProgress>
<numberBatchesCompleted>1</numberBatchesCompleted>
<numberBatchesFailed>0</numberBatchesFailed>
<numberBatchesTotal>1</numberBatchesTotal>
<numberRecordsProcessed>10</numberRecordsProcessed>
<numberRetries>0</numberRetries>
<apiVersion>36.0</apiVersion>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>0</totalProcessingTime>
<apiActiveProcessingTime>0</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</jobInfo>
136
Bulk API Walk Through a Bulk Query Sample
<object>Account</object>
<createdById>005x0000001WR0lAAG</createdById>
<createdDate>2016-01-10T00:53:19.000Z</createdDate>
<systemModstamp>2016-01-10T00:53:19.000Z</systemModstamp>
<state>Open</state>
<concurrencyMode>Parallel</concurrencyMode>
<contentType>CSV</contentType>
<numberBatchesQueued>0</numberBatchesQueued>
<numberBatchesInProgress>0</numberBatchesInProgress>
<numberBatchesCompleted>1</numberBatchesCompleted>
<numberBatchesFailed>0</numberBatchesFailed>
<numberBatchesTotal>1</numberBatchesTotal>
<numberRecordsProcessed>10</numberRecordsProcessed>
<numberRetries>0</numberRetries>
<apiVersion>36.0</apiVersion>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>0</totalProcessingTime>
<apiActiveProcessingTime>0</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</jobInfo>
2. Using a command-line window, execute this cURL command to check the batch status.
curl -H "X-SFDC-Session: sessionId"
https://instance.salesforce.com/services/async/61.0/job/jobId/batch/batchId
batchId is the batch ID in the response to the batch creation.
Salesforce returns an XML response with data such as this.
<?xml version="1.0" encoding="UTF-8"?>
<batchInfo
xmlns="http://www.force.com/2009/06/asyncapi/dataload">
<id>751x000000009vwAAA</id>
<jobId>750x000000009tvAAA</jobId>
<state>Completed</state>
<createdDate>2016-01-10T00:59:47.000Z</createdDate>
<systemModstamp>2016-01-10T01:00:19.000Z</systemModstamp>
<numberRecordsProcessed>10</numberRecordsProcessed>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>0</totalProcessingTime>
<apiActiveProcessingTime>0</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</batchInfo>
137
Bulk API Walk Through a Bulk Query Sample Using PK Chunking
Note: If the batch required retries, there will be more than one <result> element in the output.
2. Using the command-line window, execute this cURL command to retrieve the results of the query.
curl -H "X-SFDC-Session: sessionId"
https://instance.salesforce.com/services/async/61.0/job/jobId/batch/batchId/result/resultId
resultId is the result ID in the response to the batch result list request.
Salesforce returns a CSV response with data such as this.
"Id","Name"
"001x000xxx4TU4JAAW","name161268--1296595660659"
"001x000xxx4TU4KAAW","name161269--1296595660659"
"001x000xxx4TU4LAAW","name161270--1296595660659"
"001x000xxx4TU4MAAW","name161271--1296595660659"
"001x000xxx4TU4NAAW","name161272--1296595660659"
"001x000xxx4TU4OAAW","name161273--1296595660659"
"001x000xxx4TU4PAAW","name161274--1296595660659"
"001x000xxx4TU4QAAW","name161275--1296595660659"
"001x000xxx4TU4RAAW","name161276--1296595660659"
"001x000xxx4TU4SAAW","name161277--1296595660659"
SEE ALSO:
How Bulk Queries Are Processed
Use Bulk Query
Walk Through a Bulk Query Sample Using PK Chunking
138
Bulk API Walk Through a Bulk Query Sample Using PK Chunking
<operation>query</operation>
<object>Account</object>
<concurrencyMode>Parallel</concurrencyMode>
<contentType>CSV</contentType>
</jobInfo>
2. Using a command-line window, execute this cURL command to create a job with PK chunking enabled.
curl -H "X-SFDC-Session: sessionId" -H "Content-Type: application/xml; charset=UTF-8"
-H "Sforce-Enable-PKChunking: true" -d @create-job.xml
https://instance.salesforce.com/services/async/61.0/job
instance is the portion of the <serverUrl> element, and sessionId is the <sessionId> element that you noted
in the login response.
Note: Salesforce recommends that you enable PK chunking when querying tables with more than 10 million records or when
a bulk query consistently times out. For the purposes of this example, if you’re querying significantly fewer records, set
chunkSize to a number smaller than the number of records you’re querying. For example,
Sforce-Enable-PKChunking: chunkSize=1000. This way, you get to see PK chunking in action, and the query
is split into multiple batches.
Salesforce returns an XML response with data such as this.
<?xml version="1.0" encoding="UTF-8"?>
<jobInfo
xmlns="http://www.force.com/2009/06/asyncapi/dataload">
<id>750x000000009tvAAA</id>
<operation>query</operation>
<object>Account</object>
<createdById>005x0000001WR0lAAG</createdById>
<createdDate>2016-01-10T00:53:19.000Z</createdDate>
<systemModstamp>2016-01-10T00:53:19.000Z</systemModstamp>
<state>Open</state>
<concurrencyMode>Parallel</concurrencyMode>
<contentType>CSV</contentType>
<numberBatchesQueued>0</numberBatchesQueued>
<numberBatchesInProgress>0</numberBatchesInProgress>
<numberBatchesCompleted>0</numberBatchesCompleted>
<numberBatchesFailed>0</numberBatchesFailed>
<numberBatchesTotal>0</numberBatchesTotal>
<numberRecordsProcessed>0</numberRecordsProcessed>
<numberRetries>0</numberRetries>
<apiVersion>36.0</apiVersion>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>0</totalProcessingTime>
<apiActiveProcessingTime>0</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</jobInfo>
139
Bulk API Walk Through a Bulk Query Sample Using PK Chunking
2. Using a command-line window, execute this cURL command to add a batch to the job.
curl -d @query.txt -H "X-SFDC-Session: sessionId" -H "Content-Type: text/csv;
charset=UTF-8" https://instance.salesforce.com/services/async/61.0/job/jobId/batch
jobId is the job ID returned in the response to the job creation.
Salesforce returns an XML response with data such as this.
<?xml version="1.0" encoding="UTF-8"?>
<batchInfo
xmlns="http://www.force.com/2009/06/asyncapi/dataload">
<id>751x000000009vwAAA</id>
<jobId>750x000000009tvAAA</jobId>
<state>Queued</state>
<createdDate>2016-01-10T00:59:47.000Z</createdDate>
<systemModstamp>2016-01-10T00:59:47.000Z</systemModstamp>
<numberRecordsProcessed>0</numberRecordsProcessed>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>0</totalProcessingTime>
<apiActiveProcessingTime>0</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</batchInfo>
Note: When you add a batch to a bulk query job, the Content-Type in the header for the request must be text/csv,
application/xml, or application/json, depending on the content type specified when the job was created.
The actual SOQL statement supplied for the batch is in plain text format.
140
Bulk API Walk Through a Bulk Query Sample Using PK Chunking
<apiVersion>36.0</apiVersion>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>3500</totalProcessingTime>
<apiActiveProcessingTime>3500</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</jobInfo>
Because PK chunking is enabled, extra batches are automatically created to process the entire query.
2. Using a command-line window, execute this cURL command to check the status of the original batch.
curl -H "X-SFDC-Session: sessionId"
https://instance.salesforce.com/services/async/61.0/job/jobId/batch/batchId
batchId is the batch ID in the response to the batch creation.
Salesforce returns an XML response with data such as this.
<?xml version="1.0" encoding="UTF-8"?>
<batchInfo
xmlns="http://www.force.com/2009/06/asyncapi/dataload">
<id>751x000000009vwAAA</id>
<jobId>750x000000009tvAAA</jobId>
<state>Not Processed</state>
<createdDate>2016-01-10T00:59:47.000Z</createdDate>
<systemModstamp>2016-01-10T01:00:19.000Z</systemModstamp>
<numberRecordsProcessed>0</numberRecordsProcessed>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>0</totalProcessingTime>
<apiActiveProcessingTime>0</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</batchInfo>
Because PK chunking is enabled, the original batch is given a state of Not Processed. The query is processed in the remaining
batches.
141
Bulk API Walk Through a Bulk Query Sample Using PK Chunking
<apiActiveProcessingTime>0</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</batchInfo>
<batchInfo>
<id>751D00000004Yk1IAE</id>
<jobId>750D00000004T5OIAU</jobId>
<state>Completed</state>
<createdDate>2016-01-10T00:59:47.000Z</createdDate>
<systemModstamp>2016-01-10T01:00:19.000Z</systemModstamp>
<numberRecordsProcessed>100000</numberRecordsProcessed>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>1000</totalProcessingTime>
<apiActiveProcessingTime>1000</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</batchInfo>
<batchInfo>
<id>751D00000004Yk2IAE</id>
<jobId>750D00000004T5OIAU</jobId>
<state>Completed</state>
<createdDate>2016-01-10T00:59:47.000Z</createdDate>
<systemModstamp>2016-01-10T01:00:19.000Z</systemModstamp>
<numberRecordsProcessed>100000</numberRecordsProcessed>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>1000</totalProcessingTime>
<apiActiveProcessingTime>1000</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</batchInfo>
<batchInfo>
<id>751D00000004Yk6IAE</id>
<jobId>750D00000004T5OIAU</jobId>
<state>Completed</state>
<createdDate>2016-01-10T00:59:47.000Z</createdDate>
<systemModstamp>2016-01-10T01:00:19.000Z</systemModstamp>
<numberRecordsProcessed>100000</numberRecordsProcessed>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>1000</totalProcessingTime>
<apiActiveProcessingTime>1000</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</batchInfo>
<batchInfo>
<id>751D00000004Yk7IAE</id>
<jobId>750D00000004T5OIAU</jobId>
<state>Completed</state>
<createdDate>2016-01-10T00:59:47.000Z</createdDate>
<systemModstamp>2016-01-10T01:00:19.000Z</systemModstamp>
<numberRecordsProcessed>50000</numberRecordsProcessed>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>500</totalProcessingTime>
<apiActiveProcessingTime>500</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</batchInfo>
</batchInfoList>
142
Bulk API Walk Through a Bulk Query Sample Using PK Chunking
Note: If the batch required retries, there will be more than one <result> element in the output.
2. Using the command-line window, execute this cURL command to retrieve the results of the query.
curl -H "X-SFDC-Session: sessionId"
https://instance.salesforce.com/services/async/61.0/job/jobId/batch/batchId/result/resultId
resultId is the result ID in the response to the batch result list request.
Salesforce returns a CSV response with data such as this.
"Id","Name"
"001x000xxx4TU4JAAW","name161268--1296595660659"
"001x000xxx4TU4KAAW","name161269--1296595660659"
"001x000xxx4TU4LAAW","name161270--1296595660659"
"001x000xxx4TU4MAAW","name161271--1296595660659"
"001x000xxx4TU4NAAW","name161272--1296595660659"
"001x000xxx4TU4OAAW","name161273--1296595660659"
"001x000xxx4TU4PAAW","name161274--1296595660659"
"001x000xxx4TU4QAAW","name161275--1296595660659"
"001x000xxx4TU4RAAW","name161276--1296595660659"
"001x000xxx4TU4SAAW","name161277--1296595660659"
...
2. Using a command-line window, execute this cURL command to close the job.
curl -H "X-SFDC-Session: sessionId" -H "Content-Type: text/csv; charset=UTF-8" -d
@close-job.xml https://instance.salesforce.com/services/async/61.0/job/jobId
Salesforce returns an XML response with data such as this.
<?xml version="1.0" encoding="UTF-8"?>
<jobInfo
143
Bulk API Headers
xmlns="http://www.force.com/2009/06/asyncapi/dataload">
<id>750x000000009tvAAA</id>
<operation>query</operation>
<object>Account</object>
<createdById>005x0000001WR0lAAG</createdById>
<createdDate>2016-01-10T00:53:19.000Z</createdDate>
<systemModstamp>2016-01-10T00:53:19.000Z</systemModstamp>
<state>Closed</state>
<concurrencyMode>Parallel</concurrencyMode>
<contentType>CSV</contentType>
<numberBatchesQueued>0</numberBatchesQueued>
<numberBatchesInProgress>0</numberBatchesInProgress>
<numberBatchesCompleted>4</numberBatchesCompleted>
<numberBatchesFailed>0</numberBatchesFailed>
<numberBatchesTotal>4</numberBatchesTotal>
<numberRecordsProcessed>350000</numberRecordsProcessed>
<numberRetries>0</numberRetries>
<apiVersion>36.0</apiVersion>
<numberRecordsFailed>0</numberRecordsFailed>
<totalProcessingTime>3500</totalProcessingTime>
<apiActiveProcessingTime>3500</apiActiveProcessingTime>
<apexProcessingTime>0</apexProcessingTime>
</jobInfo>
SEE ALSO:
How Bulk Queries Are Processed
Use Bulk Query
PK Chunking
Walk Through a Bulk Query Sample
Headers
These are the custom HTTP request and response headers that are used for Bulk API.
144
Bulk API Content Type Header
145
Bulk API Warning Header
Warning Header
This header is returned if there are warnings, such as the use of a deprecated version of the API.
Limits
Note the following limits specific to Bulk API.
146
Bulk API Limits
147
Bulk API Bulk API Reference
Schema
The Bulk API service is described by an XML Schema Document (XSD) file.
JobInfo
A job contains one or more batches of data for you to submit to Salesforce for processing. When a job is created, Salesforce sets the
job state to Open.
BatchInfo
A BatchInfo contains one batch of data for you to submit to Salesforce for processing.
Errors
Operations that you perform with Bulk API can trigger error codes. This list shows the most common error codes and the Bulk API
action that possibly triggered them.
Schema
The Bulk API service is described by an XML Schema Document (XSD) file.
You can download the schema file for an API version by using this URI:
Web_Services_SOAP_endpoint_hostname/services/async/APIversion/AsyncApi.xsd
For example, if you're working with version 61.0 of the Bulk API, the URI for a production org is in this format.
https://MyDomainName.my.salesforce.com/services/async/61.0/AsyncApi.xsd
You can find the My Domain name and My Domain login URL for your org on the My Domain page in Setup. Or, to get the hostname
of your My Domain login URL in Apex, use the getMyDomainHostname() method of the System.DomainCreator class.
SEE ALSO:
JobInfo
BatchInfo
Errors
JobInfo
A job contains one or more batches of data for you to submit to Salesforce for processing. When a job is created, Salesforce sets the job
state to Open.
148
Bulk API JobInfo
You can create a job, get information about a job, close a job, or abort a job using the JobInfo resource.
Fields
Name Type Request Description
apiVersion string Read only. Don’t The API version of the job set in the URI when the job
set for new job. was created. The earliest supported version is 17.0.
apexProcessingTime long Don’t specify for The number of milliseconds taken to process triggers
new job. and other processes related to the job data. This
number is the sum of the equivalent times in all
batches in the job. This doesn't include the time used
for processing asynchronous and batch Apex
operations. If there are no triggers, the value is 0. See
also apiActiveProcessingTime and
totalProcessingTime.
This field is available in API version 19.0 and later.
apiActiveProcessingTime long Don’t specify for The number of milliseconds taken to actively process
new job. the job. It includes apexProcessingTime, but
doesn't include the time the job waited in the queue
to be processed or the time required for serialization
and deserialization. This is the sum of the equivalent
times in all batches in the job. See also
apexProcessingTime and
totalProcessingTime.
This field is available in API version 19.0 and later.
assignmentRuleId string Can't update after The ID of a specific assignment rule to run for a case or
creation. a lead. The assignment rule can be active or inactive.
The ID can be retrieved by using the SOAP-based SOAP
API to query the AssignmentRule object.
concurrencyMode ConcurrencyModeEnum The concurrency mode for the job. The valid values are:
• Parallel: Process batches in Parallel
mode. Default value. Batches from the same job,
and from other jobs submitted with parallel mode,
are processed simultaneously. Parallel processing,
though, has the potential to cause lock contention
on records. When record locking is severe, the job
can fail. Any failed records must be resubmitted.
• Serial: Process batches in Serial mode. If
parallel mode results in too many failed records or
failed jobs, submit the job with Serial
concurrency mode. In this mode, batches from the
job and batches from other serial mode jobs are
149
Bulk API JobInfo
contentType ContentType The content type for the job. The valid values are:
• CSV—data in CSV format (default and only
supported content type for Bulk V2 type jobs)
• JSON—data in JSON format
• XML—data in XML format (default option for Bulk
V1 type jobs)
• ZIP_CSV—data in CSV format in a zip file
containing binary attachments
• ZIP_JSON—data in JSON format in a zip file
containing binary attachments
• ZIP_XML—data in XML format in a zip file
containing binary attachments
createdById string System field The ID of the user who created this job. All batches
must be created by this same user.
createdDate dateTime System field The date and time in the UTC time zone when the job
was created.
externalIdFieldName string Required with The name of the external ID field for an upsert().
upsert
numberBatchesCompleted int Don’t specify for The number of batches that have been completed for
new job. this job.
numberBatchesQueued int Don’t specify for The number of batches queued for this job.
new job.
numberBatchesFailed int Don’t specify for The number of batches that have failed for this job.
new job.
numberBatchesInProgress int Don’t specify for The number of batches that are in progress for this job.
new job.
numberBatchesTotal int Don’t specify for The number of total batches currently in the job. This
new job. value increases as more batches are added to the job.
When the job state is Closed or Failed, this
number represents the final total.
The job is complete when numberBatchesTotal
equals the sum of numberBatchesCompleted
and numberBatchesFailed.
150
Bulk API JobInfo
numberRecordsProcessed int Don’t specify for The number of records already processed. This number
new job. increases as more batches are processed.
object string Required The object type for the data being processed. All data
in a job must be of a single object type.
operation OperationEnum Required The processing operation for all the batches in the job.
The valid values are:
• delete
• hardDelete
• insert
• query
• queryAll
• update
• upsert
151
Bulk API BatchInfo
systemModstamp dateTime System field Date and time in the UTC time zone when the job
finished.
totalProcessingTime long Don’t specify for The number of milliseconds taken to process the job.
new job. This number is the sum of the total processing times
for all batches in the job. See also
apexProcessingTime and
apiActiveProcessingTime.
This field is available in API version 19.0 and later.
SEE ALSO:
Quick Start: Bulk API
Quick Start: Bulk API 2.0
SOAP API Developer Guide
BatchInfo
A BatchInfo contains one batch of data for you to submit to Salesforce for processing.
152
Bulk API BatchInfo
BatchInfo
Name Type Request Description
apexProcessingTime long System The number of milliseconds taken to process triggers and other
field processes related to the batch data. If there are no triggers, the value
is 0. This doesn't include the time used for processing asynchronous
and batch Apex operations. See also
apiActiveProcessingTime and
totalProcessingTime.
This field is available in API version 19.0 and later.
apiActiveProcessingTime long System The number of milliseconds taken to actively process the batch, and
field includes apexProcessingTime. This doesn't include the time
the batch waited in the queue to be processed or the time required
for serialization and deserialization. See also
totalProcessingTime.
This field is available in API version 19.0 and later.
createdDate dateTime System The date and time in the UTC time zone when the batch was created.
field This is not the time processing began, but the time the batch was
added to the job.
id string Required The ID of the batch. May be globally unique, but does not have to
be.
jobId string Required The unique, 18–character ID for the job associated with this batch.
numberRecordsFailed int System The number of records that were not processed successfully in this
field batch.
This field is available in API version 19.0 and later.
numberRecordsProcessed int System The number of records processed in this batch at the time the request
field was sent. This number increases as more batches are processed.
state BatchStateEnum System The current state of processing for the batch:
field • Queued: Processing of the batch hasn’t started yet. If the job
associated with this batch is aborted, the batch isn’t processed
and its state is set to NotProcessed.
• InProgress: The batch is being processed. If the job
associated with the batch is aborted, the batch is still processed
to completion. You must close the job associated with the batch
so that the batch can finish processing.
• Completed: The batch has been processed completely, and
the result resource is available. The result resource indicates if
some records failed. A batch can be completed even if some or
all the records failed. If a subset of records failed, the successful
records aren’t rolled back.
153
Bulk API BatchInfo
stateMessage string System When the state value is Failed, this field contains the reasons
field for failure. If there are multiple failures, the message may be truncated.
If so, fix the known errors and re-submit the batch. Even if the batch
failed, some records could have completed successfully.
systemModstamp dateTime System The date and time in the UTC time zone that processing ended. This
field is only valid when the state is Completed.
totalProcessingTime long System The number of milliseconds taken to process the job. This is the sum
field of the total processing times for all batches in the job. See also
apexProcessingTime and
apiActiveProcessingTime.
This field is available in API version 19.0 and later.
HTTP BatchInfoList
Name Type Description
batchInfo BatchInfo One BatchInfo resource for each batch in the associated job. For the structure
of BatchInfo, see Get Information for a Batch .
SEE ALSO:
Work with Batches
Interpret Batch State
Quick Start: Bulk API 2.0
SOAP API Developer Guide
154
Bulk API Errors
Errors
Operations that you perform with Bulk API can trigger error codes. This list shows the most common error codes and the Bulk API action
that possibly triggered them.
Tip: For HTTP response codes, see Status Codes and Error Responses.
ClientInputError
The operation failed with an unknown client-side error.
For binary attachments, the request content is provided both as an input stream and an attachment.
ExceededQuota
The job or batch you tried to create exceeds the allowed number for the past 24-hour period.
FeatureNotEnabled
Bulk API isn’t enabled for this organization.
InvalidBatch
The batch ID specified in a batch update or query is invalid.
This error code is returned for binary attachments when the zip content is malformed or these conditions occur:
• The request.txt file can't be found, can't be read, is a directory, or contains invalid content.
• The decompressed size of a binary attachment is too large.
• The size of the zip file is too large.
• The total decompressed size of all the binary attachments is too large.
For more information about binary attachment limits, see "General Limits" in Bulk API and Bulk API 2.0 Limits and Allocations.
InvalidJob
The job ID specified in a query or update for a job, or a create, update, or query for batches is invalid.
The user attempted to create a job using a zip content type in API version 19.0 or earlier.
InvalidJobState
The job state specified in a job update operation is invalid.
InvalidOperation
The operation specified in a URI for a job is invalid. Check the spelling of “job” in the URI.
InvalidSessionId
The session ID specified is invalid.
InvalidUrl
The URI specified is invalid.
InvalidUser
Either the user sending a Bulk API request doesn't have the correct permission, or the job or batch specified was created by another
user.
InvalidXML
XML contained in the request body is invalid.
155
Bulk API Sample Client Application Using Java
Timeout
The connection timed out. This error is thrown if Salesforce takes too long to process a batch. For more information on timeout
limits, see "Limits Specific to Ingest Jobs" in Bulk API and Bulk API 2.0 Limits and Allocations. If you get a timeout error when processing
a batch, split your batch into smaller batches, and try again.
TooManyLockFailure
Too many lock failures while processing the current batch. This error may be returned during processing of a batch. To resolve,
analyze the batches for lock conflicts. See "General Limits" in Bulk API and Bulk API 2.0 Limits and Allocations.
Unknown
Exception with unknown cause occurred.
In addition, Bulk API uses the same status codes and exception codes as SOAP API. For more information on these codes, see
“ExceptionCode” in the SOAP API Developer Guide.
SEE ALSO:
Handle Failed Records in Batches
156
Bulk API Walk Through the Sample Code
For example, if force-wsc-XX.X.X-uber.jar is installed in C:\salesforce\wsc, and the partner WSDL is saved to
C:\salesforce\wsdl\partner:
force-wsc-XX.X.X-uber.jar and the generated partner.jar are the only libraries needed in the classpath for the code examples
in the following sections.
import java.io.*;
import java.util.*;
import com.sforce.async.*;
import com.sforce.soap.partner.PartnerConnection;
import com.sforce.ws.ConnectionException;
import com.sforce.ws.ConnectorConfig;
157
Bulk API Walk Through the Sample Code
/**
* Creates a Bulk API job and uploads batches for a CSV file.
*/
public void runSample(String sobjectType, String userName,
String password, String sampleFileName)
throws AsyncApiException, ConnectionException, IOException {
BulkConnection connection = getBulkConnection(userName, password);
JobInfo job = createJob(sobjectType, connection);
List<BatchInfo> batchInfoList = createBatchesFromCSVFile(connection, job,
sampleFileName);
closeJob(connection, job.getId());
awaitCompletion(connection, job, batchInfoList);
checkResults(connection, job, batchInfoList);
}
/**
* Create the BulkConnection used to call Bulk API operations.
*/
private BulkConnection getBulkConnection(String userName, String password)
throws ConnectionException, AsyncApiException {
ConnectorConfig partnerConfig = new ConnectorConfig();
partnerConfig.setUsername(userName);
partnerConfig.setPassword(password);
partnerConfig.setAuthEndpoint("https://login.salesforce.com/services/Soap/u/61.0");
158
Bulk API Walk Through the Sample Code
config.setRestEndpoint(restEndpoint);
// This should only be false when doing debugging.
config.setCompression(true);
// Set this to true to see HTTP requests and responses on stdout
config.setTraceMessage(false);
BulkConnection connection = new BulkConnection(config);
return connection;
}
This BulkConnection instance is the base for using the Bulk API. The instance can be reused for the rest of the application lifespan.
Create a Job
After creating the connection, create a job. Data is always processed in the context of a job. The job specifies the details about the data
being processed: which operation is being executed (insert, update, upsert, or delete) and the object type. This code creates a new insert
job on the Account object.
/**
* Create a new job using the Bulk API.
*
* @param sobjectType
* The object type being loaded, such as "Account"
* @param connection
* BulkConnection used to create the new job.
* @return The JobInfo for the new job.
* @throws AsyncApiException
*/
private JobInfo createJob(String sobjectType, BulkConnection connection)
throws AsyncApiException {
JobInfo job = new JobInfo();
job.setObject(sobjectType);
job.setOperation(OperationEnum.insert);
job.setContentType(ContentType.CSV);
job = connection.createJob(job);
System.out.println(job);
return job;
}
When a job is created, it’s in the Open state. In this state, new batches can be added to the job. When a job is Closed, batches can
no longer be added.
/**
159
Bulk API Walk Through the Sample Code
160
Bulk API Walk Through the Sample Code
} finally {
tmpFile.delete();
}
return batchInfos;
}
/**
* Create a batch by uploading the contents of the file.
* This closes the output stream.
*
* @param tmpOut
* The output stream used to write the CSV data for a single batch.
* @param tmpFile
* The file associated with the above stream.
* @param batchInfos
* The batch info for the newly created batch is added to this list.
* @param connection
* The BulkConnection used to create the new batch.
* @param jobInfo
* The JobInfo associated with the new batch.
*/
private void createBatch(FileOutputStream tmpOut, File tmpFile,
List<BatchInfo> batchInfos, BulkConnection connection, JobInfo jobInfo)
throws IOException, AsyncApiException {
tmpOut.flush();
tmpOut.close();
FileInputStream tmpInputStream = new FileInputStream(tmpFile);
try {
BatchInfo batchInfo =
connection.createBatchFromStream(jobInfo, tmpInputStream);
System.out.println(batchInfo);
batchInfos.add(batchInfo);
} finally {
tmpInputStream.close();
}
}
When the server receives a batch, it’s immediately queued for processing. Errors in formatting aren’t reported when sending the batch.
These errors are reported in the result data when the batch is processed.
Tip: To import binary attachments, use the following methods. Specify the CSV, XML, or JSON content for the batch in the
batchContent parameter, or include request.txt in the attached files and pass null to the batchContent
parameter. These methods are contained within the com.async.BulkConnection class:
• createBatchFromDir()
• createBatchWithFileAttachments()
• createBatchWithInputStreamAttachments()
• createBatchFromZipStream()
161
Bulk API Walk Through the Sample Code
/**
* Wait for a job to complete by polling the Bulk API.
*
* @param connection
* BulkConnection used to check results.
* @param job
* The job awaiting completion.
* @param batchInfoList
* List of batches for this job.
* @throws AsyncApiException
*/
private void awaitCompletion(BulkConnection connection, JobInfo job,
List<BatchInfo> batchInfoList)
throws AsyncApiException {
long sleepTime = 0L;
Set<String> incomplete = new HashSet<String>();
for (BatchInfo bi : batchInfoList) {
incomplete.add(bi.getId());
}
while (!incomplete.isEmpty()) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {}
System.out.println("Awaiting results..." + incomplete.size());
sleepTime = 10000L;
BatchInfo[] statusList =
connection.getBatchInfoList(job.getId()).getBatchInfo();
for (BatchInfo b : statusList) {
if (b.getState() == BatchStateEnum.Completed
|| b.getState() == BatchStateEnum.Failed) {
if (incomplete.remove(b.getId())) {
System.out.println("BATCH STATUS:\n" + b);
}
}
}
162
Bulk API Walk Through the Sample Code
}
}
A batch is done when it's either failed or completed. This code loops infinitely until all the batches for the job have either failed or
completed.
/**
* Gets the results of the operation and checks for errors.
*/
private void checkResults(BulkConnection connection, JobInfo job,
List<BatchInfo> batchInfoList)
throws AsyncApiException, IOException {
// batchInfoList was populated when batches were created and submitted
for (BatchInfo b : batchInfoList) {
CSVReader rdr =
new CSVReader(connection.getBatchResultStream(job.getId(), b.getId()));
List<String> resultHeader = rdr.nextRecord();
int resultCols = resultHeader.size();
List<String> row;
while ((row = rdr.nextRecord()) != null) {
Map<String, String> resultInfo = new HashMap<String, String>();
for (int i = 0; i < resultCols; i++) {
resultInfo.put(resultHeader.get(i), row.get(i));
}
boolean success = Boolean.valueOf(resultInfo.get("Success"));
boolean created = Boolean.valueOf(resultInfo.get("Created"));
String id = resultInfo.get("Id");
String error = resultInfo.get("Error");
if (success && created) {
System.out.println("Created row with id " + id);
} else if (!success) {
System.out.println("Failed with error: " + error);
}
}
}
}
This code retrieves the results for each record and reports whether the operation succeeded or failed. If an error occurred for a record,
the code prints out the error.
163
Bulk API Walk Through the Sample Code
import java.io.*;
import java.util.*;
import com.sforce.async.*;
import com.sforce.soap.partner.PartnerConnection;
import com.sforce.ws.ConnectionException;
import com.sforce.ws.ConnectorConfig;
/**
* Creates a Bulk API job and uploads batches for a CSV file.
*/
public void runSample(String sobjectType, String userName,
String password, String sampleFileName)
throws AsyncApiException, ConnectionException, IOException {
BulkConnection connection = getBulkConnection(userName, password);
JobInfo job = createJob(sobjectType, connection);
List<BatchInfo> batchInfoList = createBatchesFromCSVFile(connection, job,
sampleFileName);
closeJob(connection, job.getId());
awaitCompletion(connection, job, batchInfoList);
checkResults(connection, job, batchInfoList);
}
/**
* Gets the results of the operation and checks for errors.
*/
private void checkResults(BulkConnection connection, JobInfo job,
List<BatchInfo> batchInfoList)
throws AsyncApiException, IOException {
// batchInfoList was populated when batches were created and submitted
for (BatchInfo b : batchInfoList) {
CSVReader rdr =
new CSVReader(connection.getBatchResultStream(job.getId(), b.getId()));
List<String> resultHeader = rdr.nextRecord();
int resultCols = resultHeader.size();
164
Bulk API Walk Through the Sample Code
List<String> row;
while ((row = rdr.nextRecord()) != null) {
Map<String, String> resultInfo = new HashMap<String, String>();
for (int i = 0; i < resultCols; i++) {
resultInfo.put(resultHeader.get(i), row.get(i));
}
boolean success = Boolean.valueOf(resultInfo.get("Success"));
boolean created = Boolean.valueOf(resultInfo.get("Created"));
String id = resultInfo.get("Id");
String error = resultInfo.get("Error");
if (success && created) {
System.out.println("Created row with id " + id);
} else if (!success) {
System.out.println("Failed with error: " + error);
}
}
}
}
/**
* Wait for a job to complete by polling the Bulk API.
*
* @param connection
* BulkConnection used to check results.
* @param job
* The job awaiting completion.
* @param batchInfoList
* List of batches for this job.
* @throws AsyncApiException
*/
private void awaitCompletion(BulkConnection connection, JobInfo job,
List<BatchInfo> batchInfoList)
throws AsyncApiException {
long sleepTime = 0L;
Set<String> incomplete = new HashSet<String>();
for (BatchInfo bi : batchInfoList) {
incomplete.add(bi.getId());
}
while (!incomplete.isEmpty()) {
try {
Thread.sleep(sleepTime);
165
Bulk API Walk Through the Sample Code
} catch (InterruptedException e) {}
System.out.println("Awaiting results..." + incomplete.size());
sleepTime = 10000L;
BatchInfo[] statusList =
connection.getBatchInfoList(job.getId()).getBatchInfo();
for (BatchInfo b : statusList) {
if (b.getState() == BatchStateEnum.Completed
|| b.getState() == BatchStateEnum.Failed) {
if (incomplete.remove(b.getId())) {
System.out.println("BATCH STATUS:\n" + b);
}
}
}
}
}
/**
* Create a new job using the Bulk API.
*
* @param sobjectType
* The object type being loaded, such as "Account"
* @param connection
* BulkConnection used to create the new job.
* @return The JobInfo for the new job.
* @throws AsyncApiException
*/
private JobInfo createJob(String sobjectType, BulkConnection connection)
throws AsyncApiException {
JobInfo job = new JobInfo();
job.setObject(sobjectType);
job.setOperation(OperationEnum.insert);
job.setContentType(ContentType.CSV);
job = connection.createJob(job);
System.out.println(job);
return job;
}
/**
* Create the BulkConnection used to call Bulk API operations.
*/
private BulkConnection getBulkConnection(String userName, String password)
throws ConnectionException, AsyncApiException {
ConnectorConfig partnerConfig = new ConnectorConfig();
partnerConfig.setUsername(userName);
partnerConfig.setPassword(password);
partnerConfig.setAuthEndpoint("https://login.salesforce.com/services/Soap/u/61.0");
166
Bulk API Walk Through the Sample Code
/**
* Create and upload batches using a CSV file.
* The file into the appropriate size batch files.
*
* @param connection
* Connection to use for creating batches
* @param jobInfo
* Job associated with new batches
* @param csvFileName
* The source file for batch data
*/
private List<BatchInfo> createBatchesFromCSVFile(BulkConnection connection,
JobInfo jobInfo, String csvFileName)
throws IOException, AsyncApiException {
List<BatchInfo> batchInfos = new ArrayList<BatchInfo>();
BufferedReader rdr = new BufferedReader(
new InputStreamReader(new FileInputStream(csvFileName))
);
// read the CSV header row
byte[] headerBytes = (rdr.readLine() + "\n").getBytes("UTF-8");
int headerBytesLength = headerBytes.length;
File tmpFile = File.createTempFile("bulkAPIInsert", ".csv");
167
Bulk API Walk Through the Sample Code
/**
* Create a batch by uploading the contents of the file.
* This closes the output stream.
*
* @param tmpOut
* The output stream used to write the CSV data for a single batch.
* @param tmpFile
* The file associated with the above stream.
* @param batchInfos
* The batch info for the newly created batch is added to this list.
* @param connection
* The BulkConnection used to create the new batch.
* @param jobInfo
* The JobInfo associated with the new batch.
*/
private void createBatch(FileOutputStream tmpOut, File tmpFile,
List<BatchInfo> batchInfos, BulkConnection connection, JobInfo jobInfo)
throws IOException, AsyncApiException {
tmpOut.flush();
tmpOut.close();
FileInputStream tmpInputStream = new FileInputStream(tmpFile);
try {
BatchInfo batchInfo =
connection.createBatchFromStream(jobInfo, tmpInputStream);
168
Bulk API Map Data Fields
System.out.println(batchInfo);
batchInfos.add(batchInfo);
} finally {
tmpInputStream.close();
}
}
Considerations
• Transformation specs must be CSV files. XML and JSON files aren’t supported.
• Transformation specs must have a file size less than 8192 characters.
• Transformation specs (spec.csv files) must use UTF-8 encoding. CSV import files don’t need to use UTF-8 encoding. (You can specify
the encoding in the Content-Type header.)
• Transformation specs aren’t persistent; their scopes are limited to the current job.
Field Description
Salesforce Field The Salesforce field you want to map to.
Csv Header The field in your import file you want to map.
169
Bulk API Map Data Fields
Field Description
Value A default value.
Bulk API uses this value in two instances:
• When there’s no value present in the import file for the field
specified in the Csv Header field
• When there’s no value defined for the Csv Header field in the
spec.csv file
This field is optional.
Hint Tells Bulk API how to interpret data in the import file.
Bulk API can use this value to do two things:
• Interpret Java format strings for date and time fields
• Define what is true using regular expressions for boolean fields
This field is optional.
170
Bulk API Bulk API End-of-Life Policy
https://MyDomainName.my.salesforce.com/services/async/APIversion/job/jobid/spec
You can find the My Domain name and My Domain login URL for your org on the My Domain page in Setup.
Versions 21.0 through 30.0 As of Summer ’22, these versions have been Salesforce Platform API Versions 21.0 through 30.0
deprecated and no longer supported by Retirement
Salesforce.
Starting Summer ’25, these versions will be
retired and unavailable.
Versions 7.0 through 20.0 As of Summer ’22, these versions are retired Salesforce Platform API Versions 7.0 through 20.0
and unavailable. Retirement
If you request any resource or use an operation from a retired API version, REST API returns the 410:GONE error code.
If you request any resource or use an operation from a retired API version, SOAP API returns 500:UNSUPPORTED_API_VERSION error
code.
To identify requests made from old or unsupported API versions, use the API Total Usage event type.
171
INDEX
172