Skip to main content
Use Bulk API 2.0 when your client imports or exports CSV. Connect to the environment with an actor that can access the relevant objects and fields. The paths below use {version} for a supported Bulk API version and {jobId} for the ID returned at job creation. Send requests through your authenticated client at the app URL. Keep the same actor and API version throughout each job.

Create an ingest job

Discover the target object’s fields before preparing the CSV. For a fictitious account fixture, create an insert job:
Save the returned job ID. The new ingest job is Open. Upload CSV to the job’s batches resource:
Finish the upload by changing the state:
Read GET /services/data/v{version}/jobs/ingest/{jobId} until the job reaches a terminal state, such as JobComplete, Failed, or Aborted. Keep completion polling in your integration even if a small replica job finishes before your first status request.

Check each row’s result

Read the job’s numberRecordsProcessed and numberRecordsFailed. Fetch the result resources under the ingest job:
  • /successfulResults contains successful rows and their Salesforce IDs.
  • /failedResults contains rejected rows and their errors.
  • /unprocessedrecords contains rows that were not processed.
A completed job can contain row failures. Assert the row outcomes your test expects, then query or retrieve the stored records. A successful CSV upload only confirms receipt of the file. For updates or deletes, include record IDs in the CSV. For upserts, set operation to upsert and provide externalIdFieldName when creating the job. Use a field that describe marks externalId or idLookup. Any other field fails job creation with INVALIDJOB. The replica also implements hardDelete. Use it only when permanent removal is part of your test.

Export a query as CSV

Create a query job with an explicit field list:
Use queryAll as the operation when the export must include deleted records. Save the returned job ID and read its status at /jobs/query/{jobId} under the same version. After JobComplete, request /jobs/query/{jobId}/results. Parse the CSV by its header names. If the Sforce-Locator response header contains a continuation value rather than null, request the same results endpoint with that value in the locator query parameter. Repeat until the header is null. Set maxRecords on every results request. The replica’s default page is 50,000 rows, and State Machines refuses an app response larger than 4 MiB with response_too_large. Keep the job’s API version when retrieving pages. Below API version 50.0 the CSV columns are in alphabetical order. From 50.0 they follow the SELECT order. A results request at a version on the other side of that boundary returns CONFLICT. From API version 58.0, GET /jobs/query/{jobId}/resultPages lists the result pages.

Adjust a query for Bulk

Bulk query jobs reject grouping, aggregate functions, OFFSET, TYPEOF, and parent-to-child subqueries. They also reject compound address and location fields. Select supported scalar component fields instead. Prefer explicit field names. FIELDS(ALL) and FIELDS(CUSTOM) are unsupported. FIELDS(STANDARD) expands the actor-visible standard fields, but the expanded selection still fails if it includes a compound field. Use REST queries when your test needs a supported query form that Bulk does not accept. Keep Bulk-specific failure assertions for clients that must report an invalid job correctly.