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.