---
schema_version: "1"
id: 90995040609b04d5c117e4d6696bc9e9efb4b95af42dff74186b2e6769578c8f
title: "Step 5: Bulk Upsert"
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/platform/api-asynch/guides/api-bulk-v2/example/walkthrough-upsert.md
canonical_url: https://developer.salesforce.com/docs/platform/api-asynch/guide/walkthrough-upsert.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: 04fb22a2cee91f6d475216257277ab4f54b688b48ee9bb9ac32b582341b97c5f
products:
  - Bulk API 2.0 and Bulk API Developer Guide
  - Platform Developer Content
---

# 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).

1.  Confirm that your object is using an external ID field.

    Upserting records requires an external ID field on the object involved in the job. Bulk API 2.0 uses the external ID field to determine whether a record is used to update an existing record or create a record.

    This example assumes that the external ID field `customExtIdField__c` has been added to the `Account` object.

    To add this custom field in your org with Object Manager, use these properties.

    - Data Type—**text**
    - Field Label—**customExtIdField**
    - Select **External ID**
      For more information, see [Custom Fields](https://help.salesforce.com/s/articleView?id=platform.adding_fields.htm&type=5) in _Salesforce Help_.

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](https://developer.salesforce.com/docs/platform/api-asynch/bulk-api-2-0-ingest.md).

    For this example, copy this information into a file named `accountupsert.csv`.

    ```nolang
    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
    1579,sForce,40000
    2690,University of The Terrific,1257
    ```

3.  Create a job that includes the external ID field.

    Copy this information into a file named `newupsertjob.json`.

    ```nolang
    {
        "object" : "Account",
        "externalIdFieldName" : "customExtIdField__c",
        "contentType" : "CSV",
        "operation" : "upsert",
        "lineEnding" : "LF"
    }
    ```

    **URI**

    ```nolang
    /services/data/v68.0/jobs/ingest/
    ```

    **Example for creating a bulk upsert job**

    ```nolang
    curl https://MyDomainName.my.salesforce.com/services/data/v68.0/jobs/ingest/ -H 'Authorization: Bearer 00DE0X0A0M0PeLE!AQcAQH0dMHEXAMPLEzmpkb58urFRkgeBGsxL_QJWwYMfAbUeeG7c1EXAMPLEDUkWe6H34r1AAwOR8B8fLEz6nEXAMPLE' -H "Content-Type: application/json" -H "X-PrettyPrint:1" -d @newupsertjob.json -X POST
    ```

    **Example response body**

    The response includes the job ID, with a job state of Open. Use the job ID and the URL in the contentUrl field in the next step when you upload your data.

    ```nolang
    {
      "id" : "7476gEXAMPLE4X2ZWO",
      "operation" : "upsert",
      "object" : "Account",
      "createdById" : "0055fEXAMPLEtG4AAM",
      "createdDate" : "2022-01-02T21:57:03.000+0000",
      "systemModstamp" : "2022-01-02T21:57:03.000+0000",
      "state" : "Open",
      "externalIdFieldName" : "customExtIdField__c",
      "concurrencyMode" : "Parallel",
      "contentType" : "CSV",
      "apiVersion" : 68.0,
      "contentUrl" : "services/data/68.0/jobs/ingest/7476gEXAMPLE4X2ZWO/batches",
      "lineEnding" : "LF",
      "columnDelimiter" : "COMMA"
    }
    ```

4.  Upload the CSV data file that you created.

    **URI**

    For convenience, use the URI in the `contentUrl` field of the response from step 1. The URI is similar to:

    ```nolang
    /services/data/v68.0/jobs/ingest/jobId/batches/
    ```

    **Example for uploading data**

    ```nolang
    curl /services/data/v68.0/jobs/ingest/7476gEXAMPLE4X2ZWO/batches/ -H 'Authorization: Bearer ' -H "Content-Type: text/csv" --data-binary @accountupsert.csv -X PUT
    ```

    **Example response body**

    No response body is returned.

5.  Set `state` to `UploadComplete`.

    After you’re done submitting data, notify Salesforce servers that the upload of job data is complete and is ready for processing.

    Create a JSON file named upload_complete.json with the contents:

    ```nolang
    {"state":"UploadComplete"}
    ```

    **URI**

    /services/data/v68.0/jobs/ingest/jobId/

    **Example of setting `state` to `UploadComplete`**

    ```nolang
    curl https://MyDomainName.my.salesforce.com/services/data/v68.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
    ```

    **Example response body**

    ```nolang
    {
      "id" : "7476gEXAMPLE4X2ZWO",
      "operation" : "upsert",
      "object" : "Account",
      "createdById" : "",
      "createdDate" : "2022-01-02T21:28:22.000+0000",
      "systemModstamp" : "T21:28:22.000+0000",
      "state" : "UploadComplete",
      "externalIdFieldName" : "customExtIdField__c",
      "concurrencyMode" : "Parallel",
      "contentType" : "CSV",
      "apiVersion" : 68.0
    }

    ```

6.  Get successful results.

    After a job is in the `JobComplete` or `Failed` state, you can get details about which job data records were successfully processed.

    **URI**

    ```nolang
    /services/data/v68.0/jobs/ingest/jobId/successfulResults/
    ```

    **Example of getting successful results**

    ```nolang
    curl /services/data/v68.0/jobs/ingest//successfulResults/ -H 'Authorization: Bearer ' -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**

    ```nolang
    "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](https://developer.salesforce.com/docs/platform/api-asynch/reference/get-job-unprocessed-results.md).
