Job, Bulk API 2.0
A Job in Bulk API 2.0 is the unit of work Salesforce uses to insert, update, upsert, delete, or query large volumes of records asynchronously. A client creates the job with a small JSON request, up…
Definition
A Job in Bulk API 2.0 is the unit of work Salesforce uses to insert, update, upsert, delete, or query large volumes of records asynchronously. A client creates the job with a small JSON request, uploads the record data as a CSV, then marks the upload complete. Salesforce queues the work, splits it into batches on its own, processes the rows in parallel, and writes the outcome to result files the client downloads later. The whole exchange happens over REST, and the client never blocks waiting for the data to load.
Bulk API 2.0 is the practical choice for any load above roughly 2,000 records, and the only sensible one for multi-million-row migrations or nightly syncs. It removed the manual batch management that the original Bulk API required, so a caller no longer creates or tracks individual batches. A single ingest job can take up to 150 MB of CSV data per upload, and an org can process up to 150 million records across all jobs in a rolling 24-hour window. The Job resource reports its own state, record counters, and the URLs of the success and failure files.
How a Bulk API 2.0 job moves data into Salesforce
The ingest job lifecycle
An ingest job moves through a fixed set of states, and the client drives the early transitions. It starts in Open the moment you create it, which means the job exists and is ready to accept data. After you PUT the CSV, you PATCH the state to UploadComplete to tell Salesforce that no more data is coming. Salesforce then queues the job and moves it to InProgress while it processes the rows. When every record has been attempted, the state becomes JobComplete. Two terminal states signal trouble: Failed means a job-level problem stopped processing before the records were handled, and Aborted means you cancelled the job yourself, after which any uploaded data is discarded. JobComplete does not mean every row succeeded, only that processing finished. You still read the counters and the result files to learn how many rows passed. A client polls the job info endpoint every few seconds, and once it sees JobComplete or Failed it stops polling and downloads the results. Treating JobComplete as success without checking NumberRecordsFailed is the most common integration mistake.
Why 2.0 replaced manual batching
The original Bulk API, now called Bulk API 1.0, made the caller responsible for chopping data into batches, submitting each one, and tracking every batch state. That gave fine control but added real work and a lot of failure surface. Bulk API 2.0 took that job away. You upload one CSV stream and Salesforce decides how to split it into internal batches, how many to run at once, and how to retry transient failures. The trade is less control for far less code. Bulk API 2.0 also standardized on CSV input, simplified the error model, and exposes a cleaner REST lifecycle. Salesforce recommends 2.0 for new integrations and keeps 1.0 available mainly for older clients and a few edge cases such as very specific batch-level handling. One practical note: the two APIs count against limits differently, so a team migrating from 1.0 should re-check throughput assumptions rather than assume the numbers carry over. For most loads the simpler 2.0 model wins on both effort and reliability.
Creating and feeding the job
Creating a job is a small POST to the ingest jobs endpoint with a JSON body. The two required properties are object, the API name of the target sObject such as Account or Contact, and operation, one of insert, update, upsert, delete, or hardDelete. For upsert you must also send externalIdFieldName, naming the External ID field Salesforce uses to decide whether each row is a new record or an update to an existing one. Optional properties set the CSV shape, including columnDelimiter (comma by default) and lineEnding. The response returns a job id and a contentUrl. You then PUT the CSV bytes to that URL. Column headers in the CSV must match the field API names on the object exactly, and relationship fields can reference a parent by its External ID. Data can be uploaded in a single request up to 150 MB. When the data is in place, you PATCH the job state to UploadComplete, and from that point the job belongs to Salesforce.
Query jobs for large extracts
Bulk API 2.0 is not only for loading data in. Query jobs run a SOQL statement asynchronously and write the full result set to downloadable files. You create a query job by posting the SOQL to the query jobs endpoint, then poll until the job reaches JobComplete and pull the results, paging through with the result locator when the set is large. This path matters because synchronous query APIs and Apex both cap result sizes, and a normal SOQL query in Apex stops at 50,000 rows. A Bulk query job has no such row ceiling, so it is the right tool for exporting an entire object, feeding a data warehouse, or backing up records. Query jobs share the same job model as ingest jobs, with the same state names and the same polling pattern, which keeps client code consistent. The two operation modes are query, which respects PK chunking automatically, and queryAll, which also returns deleted and archived rows that a standard query would skip.
Throughput, parallelism, and limits
Once a job is InProgress, Salesforce processes the internal batches in parallel rather than one row at a time. Real throughput depends on far more than the API. Triggers, validation rules, flows, roll-up summaries, and sharing recalculations all run per row and can slow a load by an order of magnitude. A bare insert into a simple object can move hundreds of records per second, while the same volume into an object loaded with automation runs much slower. The headline allocation is 150 million records processed across all Bulk API 2.0 jobs in a rolling 24-hour period, counted per org. Each upload is limited to 150 MB of CSV. Because the window rolls rather than resetting at midnight, a burst of large jobs can borrow against the next day, so high-volume teams pace their loads. When a single job runs long, Salesforce can split very large datasets so partial results become available, but the client should still design for the job taking minutes, not milliseconds.
Partial success and result files
Every row in a Bulk API 2.0 job succeeds or fails on its own. After JobComplete the job exposes three downloadable result sets: successful records, failed records, and unprocessed records (rows the job never reached, common after a timeout). The successful file echoes each input row with the new record id. The failed file echoes each input row plus an error column that names the field, the rule, and a diagnostic message. This row-level reporting is what makes large loads survivable, because you reprocess only the failures instead of rerunning the whole file. Typical failures are a validation rule firing, a required field left blank, a lookup pointing at a record that does not exist, or a trigger throwing an exception. A well-built integration parses the failed file, routes each error to a remediation queue or a retry job, and never silently drops a row. Always keep a correlation value, such as an external id or a source row number, in the input so you can match a result line back to its origin.
Permissions and security
A Bulk API 2.0 job runs as the authenticated user, so it cannot do anything that user could not do through the UI. Field-level security applies: a field the running user cannot edit is ignored on write, which can silently leave data unset if you assume otherwise. Object permissions, record sharing, and validation rules all still apply per row. The hardDelete operation, which bypasses the Recycle Bin and permanently removes records, requires the Bulk API Hard Delete user permission and is off by default because it is irreversible. To use the API at all, the user needs the API Enabled permission. Because a single job can touch millions of records, it is worth scoping the integration user carefully, granting only the objects and fields the load needs. A common production safeguard is to disable noncritical automation during a large migration, then run a separate pass to recalculate, which both speeds the load and avoids partial-automation side effects on half-loaded data.
How to load data with a Bulk API 2.0 ingest job
Loading data with Bulk API 2.0 means creating an ingest job, uploading a CSV, and closing the job so Salesforce processes it. Here is the end-to-end shape of the call sequence using the REST resources.
- Create the job
Send a POST to /services/data/vXX.X/jobs/ingest with a JSON body containing object and operation (and externalIdFieldName for upsert). The response returns the job id and a contentUrl.
- Upload the CSV
Send a PUT to the contentUrl with your CSV in the body. Header names must match the field API names on the object exactly. Keep each upload at or under 150 MB.
- Close the job
Send a PATCH to the job with state set to UploadComplete. This tells Salesforce no more data is coming and queues the job for processing. Use Aborted instead to cancel and discard the upload.
- Poll and collect results
Poll the job info endpoint until state is JobComplete or Failed. Then download the successfulResults, failedResults, and unprocessedrecords files and reconcile them against your input.
The API name of the target sObject, such as Account or Contact. Must be a single object per job.
One of insert, update, upsert, delete, or hardDelete. Defines what the job does to each row.
Required only for upsert. Names the External ID field Salesforce uses to match incoming rows to existing records.
- JobComplete does not mean every row loaded. Always read NumberRecordsFailed and the failed-results file before declaring success.
- CSV column headers must match field API names exactly, including the __c suffix on custom fields, or the rows fail.
- The 150 million record allocation is a rolling 24-hour limit per org, not a per-job limit, and it covers every Bulk API 2.0 job together.
- hardDelete needs the Bulk API Hard Delete permission and skips the Recycle Bin, so deleted records cannot be recovered.
Trust & references
Cross-checked against the following references.
- Bulk API 2.0 IngestSalesforce
- Create a Job (Bulk API 2.0)Salesforce
Straight from the source - Salesforce's reference material on Job, Bulk API 2.0.
- Get Information About an Ingest JobSalesforce
- Bulk API 2.0 LimitsSalesforce
Hands-on resources to go deeper on Job, Bulk API 2.0.
About the Author
Dipojjal Chakrabarti is a B2C Solution Architect with 29 Salesforce certifications and over 13 years in the Salesforce ecosystem. He runs salesforcedictionary.com to help admins, developers, architects, and cert/interview candidates sharpen their fundamentals. More about Dipojjal.
Test your knowledge
Q1. What is a Bulk API 2.0 Job?
Q2. What states do Bulk API 2.0 Jobs transition through?
Q3. Why use Bulk API 2.0 over 1.0?
Discussion
Loading discussion…