---
schema_version: "1"
id: 1f8521b673b0d9cd825484b9497b067c63a09cee228452776a8fcbad84845b9e
title: Inventory IMPEX Best Practices
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/commerce-cloud/commerce-api/guides/inventory-impex-best-practices.md
canonical_url: https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/inventory-impex-best-practices.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: feef93423a6ffc47b6371fa969a71f1da4f0abe9ae3e5381bd07f93bb9f71837
products:
  - Composable Storefront
  - Salesforce APIs
---
# Inventory IMPEX Best Practices

Use Inventory Impex APIs to manage imports and exports of inventory availability for Omnichannel Inventory (OCI). This document is meant to assist you in following some best practices while implementing your use of the OCI service, as well as provide some information about the service itself.

## Inventory Import

- ALWAYS use the high performant import process. The legacy import process should no longer be used and will be deprecated. The _new_ method has much higher performance and is the method of choice for performing imports. For more information regarding the high-performance changes, refer to "Import File Layout - High Performance" in the Inventory Impex documentation.

- Don’t perform an import of inventory data while location graph changes are in progress. Doing so can cause inventory inconsistencies between the group and the locations that it contains. If you’re running scheduled imports, make sure that they aren’t running during location graph changes, or are paused until those changes are complete. This makes sure that you have an accurate picture of inventory in the system across the locations and groups.

- For updating small batches of data, we recommend using the `batchInventoryUpdate` API call, rather than performing a full import. There’s a limitation of 100 SKUs per batch, however, this is faster than loading the data via file.

- If using the `batchInventoryUpdate` API call, and you find that you’re updating more than 1000 SKUs via multiple calls to the API, this is the time to switch back over and use the inventory file import process.

- For best performance, use _delta_ data imports for updating things that have changed rather than full data imports. Full data imports are more time intensive and shouldn’t be used unless necessary.

- Be _very careful_ in the scheduling of your data imports. Make sure that you’re allowing ample time between full data imports. Multiple customers have had difficult situations arise because they’ve scheduled their imports too closely together (some as close as one minute). Recovery from misusing the service in this way is difficult and can create problems for your go-live and implementation plans.

- When processing large amounts of import data, split your data into multiple files and submit them separately. However, there are rate and concurrency limits within the OCI service and infrastructure. For this reason, it’s best to group inventory imports into fewer files rather than large numbers of smaller files.

## Considerations Regarding The Import File

- Separate the top-level entries in your import file with line feeds, not with commas. Each entry in the file must be on a single line.
- The mode is always assumed to be `UPDATE`.
- Each inventory record entry request has a unique _idempotence_ recordId. Best practice in this case is to use a UUID. The record ID protects against the import of duplicate data.
- Each inventory record imported requires an `effectiveDate` entry.
- Each inventory Future record imported requires a nonzero quantity and `expectedDate`.
- The system only creates or updates entries that are included in the data. It doesn’t delete entries that aren't included. However, if an included entry has an empty value, it will be ignored and reported as an error.
- To avoid overselling during the initial implementation period, we recommend defining safety stock levels.

## Import Process - Best Practice

When performing an import for item availability records, the following endpoints should be used in this order:

1.  Initiate the import with a call to the imports _POST_ URI.
    `https://{shortCode}.api.commercecloud.salesforce.com/inventory/impex/v1/organizations/{organizationId}/availability-records/imports`

    Use the availability-records imports _POST_ endpoint to initiate a load of the inventory availability data into Omnichannel Inventory. The details of the data being imported are included in the body of the _POST_ request.

2.  Use the uploadLink from the response body of step 1 to upload the data stream/file to OCI using a _POST_ call.
    `https://{shortCode}.api.commercecloud.salesforce.com/inventory/impex/v1/organizations/{organizationId}/availability-records/imports/uploadlink/{uploadLinkId}`

    The resulting response body from the initiate call contains a link to submit the actual import data stream/file. If the file being uploaded into the system is larger than 100 MB, the file _must_ be compressed with gzip.

3.  After the file has been uploaded into OCI, use a _GET_ call to the importStatusLink that was provided in the response body to the initiate call of step 1, to check on the status of the processing of your import data.
    `https://{shortCode}.api.commercecloud.salesforce.com/inventory/impex/v1/organizations/{organizationId}/availability-records/imports/{importId}/status`

    After the file has been successfully uploaded to the OCI system, the status of the import can be checked by making calls to the availability-records imports status endpoint. When using this endpoint in conjunction with the importId used in the file upload, check if the import process has completed yet.

4.  After the status field in the response body returned from step 3 is _COMPLETED_, the import of the availability record data into OCI is complete. The status response includes a _fullResults href_ field that has a URI for retrieving the details about the completed import process. This information is retrieved with a _GET_ call to the provided URI.
    `https://{shortCode}.api.commercecloud.salesforce.com/inventory/impex/v1/organizations/{organizationId}/availability-records/imports/{importId}/file-content`

    After the file has been successfully processed by OCI, the response body includes a status of _COMPLETED_. Other metrics regarding the import are also included, and can be found in the documentation for the _status_ call.

    Also included in the _COMPLETED_ status is the _fullResults href_. Using this URI, retrieve the detailed results of the completed import process.

Following these steps in this order, with the endpoints indicated, successfully imports availability records into OCI.

## Location Inventory Import File Layout

This is the preferred import file layout:

**note:** The `mode` is assumed to be `UPDATE` since it's currently the only one supported.

`{"recordId":"0a87539d-f3dd-47bc-91c7-9c752e39dbe0","onHand":10,"sku":"sku1","effectiveDate":"2020-04-08T14:05:22.790896-07:00","futures":[{"quantity":1,"expectedDate":"2020-04-18T14:05:22.781-07:00"}],"safetyStockCount":0,"locationId":"wickenburg"}`

`{"recordId":"3127e2ad-748b-459a-917c-78bef741602c","onHand":10,"sku":"sku1","effectiveDate":"2020-04-08T14:05:22.790896-07:00","futures":[{"quantity":1,"expectedDate":"2020-04-18T14:05:22.781-07:00"}],"safetyStockCount":0,"locationId":"prescott"}`

`{"recordId":"b709e7a8-7d4f-4458-be0c-a88f1e594f1d","onHand":10,"sku":"sku2","effectiveDate":"2020-04-08T14:05:22.790896-07:00","futures":[{"quantity":1,"expectedDate":"2020-04-18T14:05:22.781-07:00"}],"safetyStockCount":0,"locationId":"wickenburg"}`

`{"recordId":"b34c99ea-e659-40f7-bcb4-2a3fdc4a80b0","onHand":10,"sku":"sku2","effectiveDate":"2020-04-08T14:05:22.790896-07:00","futures":[{"quantity":1,"expectedDate":"2020-04-18T14:05:22.781-07:00"}],"safetyStockCount":0,"locationId":"prescott"}`

`{"recordId":"4bf7b40b-c965-485c-afa0-cc56a8ea70eb","onHand":10,"sku":"sku3","effectiveDate":"2020-04-08T14:05:22.790896-07:00","futures":[{"quantity":1,"expectedDate":"2020-04-18T14:05:22.781-07:00"}],"safetyStockCount":0,"locationId":"wickenburg"}`

`{"recordId":"539d41b7-5f05-4908-831b-3dd0461794fc","onHand":10,"sku":"sku3","effectiveDate":"2020-04-08T14:05:22.790896-07:00","futures":[{"quantity":1,"expectedDate":"2020-04-18T14:05:22.781-07:00"}],"safetyStockCount":0,"locationId":"prescott"}`

There are no other requirements for indicating that you’re using the High-Performance Layout. The system reads the file and automatically determines how to process it.

For information regarding the field contents, see the Import Field Definitions section below.

### Import Field Definitions

Location Header:

| Field      | Description                                                                    | Required Field |
| ---------- | ------------------------------------------------------------------------------ | -------------- |
| `location` | The physical location where inventory is housed.                               | `TRUE`         |
| `mode`     | The type of system operation to perform. Currently, only `UPDATE` is supported | `TRUE`         |

Location Inventory:

| Field              | Description                                                                                                                                                                                                        | Required Field                                                 |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------- |
| `recordId`         | Unique identifier of inventory record.                                                                                                                                                                             | `TRUE`                                                         |
| `sku`              | Unique item identifier.                                                                                                                                                                                            | `TRUE`                                                         |
| `onHand`           | The current quantity on hand.                                                                                                                                                                                      | `FALSE`                                                        |
| `effectiveDate`    | The effective date of the `onHand` (ISO format).                                                                                                                                                                   | `FALSE`, see the additional description below for more detail. |
| `futures`          | A collection of future quantity information for the item. (See Future Quantity, below.) Note: the Inventory Availability API references `futures` in a collection called, `futureStock`. These are the same thing. | `FALSE`, If specified see the required fields below.           |
| `safetyStockCount` | The safety stock count.                                                                                                                                                                                            | `FALSE`                                                        |

Future Quantity:

| Field          | Description                                                                             | Required Field |
| -------------- | --------------------------------------------------------------------------------------- | -------------- |
| `quantity`     | The quantity that will be arriving in the future. **The value must be greater than 0.** | `TRUE`         |
| `expectedDate` | The date the future quantity is expected to arrive (ISO format).                        | `TRUE`         |

Availability Effective Date:

The `effectiveDate` field represents the time the `onHand` value was accurate at the physical location. It’s used in conjunction with the reservation fulfillment field, `fulfillmentTime` to keep `onHand` in sync with the physical location. For example, if `effectiveDate` is specified on a location record, the system will optionally decrement the value of `onHand` when a Reservation Fulfillment is made. See the [Inventory Reservation API](https://developer.salesforce.com/docs/commerce/commerce-api/references?meta=inventory-reservation-service:Summary) for more information on how Reservation Fulfillments work.

Example:

Import happens for SKU: `abc` at location: `123`, and the value of `onHand` accounts for a Reservation Fulfillment that hasn't yet processed in OCI.

**note:** The JSON is shown formatted here, however in the actual import file it _must_ all be on a single line.

```json
   {
    "recordId":"a26fe1fd-c413-4b74-8570-1ec185ca7192",
    "onHand":10,
    "sku":"abc",
    "effectiveDate":"2021-03-09T00:00:00.000000-07:00"
   }
```

Reservation Fulfillment Request happens after the import for SKU: `abc` at location: `123`

```{
    "records": [
      {
        "id": "82251928-8863-488e-840b-2aebd10b57ba",
        "location": "123",
        "sku": "abc",
        "fulfillmentTime":"2021-03-08T00:00:00.000000-07:00"
        "quantity": 1
      }
    ]
  }
```

The system compares the values of `effectiveDate` and `fulfillmentTime`. Since `fulfillmentTime` is _less_ than `effectiveDate` it does _not_ decrement the value of `onHand`. If the reservation fulfillment happened first, `onHand` would be decremented (assuming the previous value of `effectiveDate` was less than `fulfillmentTime`). Then when the system performed the inventory import, the value of `onHand` would replace the previous value.

### Location Inventory Import Result File Layout

The result file starts with a status line record.

`{"status": "COMPLETED_WITHOUT_ERRORS"}`

| Result Status                     | Description                          |
| --------------------------------- | ------------------------------------ |
| `COMPLETED_WITHOUT_ERRORS`        | Import completed without any errors. |
| `COMPLETED_WITH_PARTIAL_FAILURES` | Some records failed to load.         |
| `FAILED`                          | Failed to load any records.          |

Each line following the status line represents an error record.

`{"recordId": "2a3e769c-c981-4d96-ba6a-e0b821a5bbbb","locationId":"location1","sku": "sku1", "message": "Unknown"}`

| Field        | Description                                                | Required Field |
| ------------ | ---------------------------------------------------------- | -------------- |
| `recordId`   | Unique identifier of inventory record sent in import file. | `TRUE`         |
| `locationId` | Location identifier.                                       | `TRUE`         |
| `sku`        | Unique item identifier of an item.                         | `TRUE`         |
| `message`    | Message containing details for failure.                    | `TRUE`         |

## Flash Sale and High Volume Transactions

All endpoints have a theoretical limit of approximately 50 requests per second for the same sku/locationGroup combination. For this reason, things like flash sales struggle to perform optimally. When making large numbers of requests for an individual SKU/locationGroup, where possible, it’s recommended that you combine or batch your requests into one for availability, reservation, transfer, fulfill, and so on. That aids in keeping performance optimized across your implementation.

## External Reference Identifier

Currently, there are a number of places where a consumer can submit an `ExternalRefId` with their request. This is to allow the consumer to submit user-generated data along with their request as a link to other external systems data. For example, if I'm pulling data from an order that has an order ID, I can submit that order ID with my reservation request as the `externalRefId`. Then, if there’s a problem with the reservation, there’s an easy way to connect it with the order in the external system that generated the error or problem. This is NOT to be confused with `externalRefId` used in Salesforce Core, or any other services. The usage is exclusive to OCI and isn’t used anywhere else.

## Correlation ID

To facilitate tracking of operations in OCI, customers must populate a header named `correlation-id`, which is used by the CDN to send the request to OCI. This header helps trace requests as they move throughout our service.

Some services use a header named `x-correlation-id`. If this header is used with OCI, it’s overwritten by the CDN with a new value and the initial purpose of the header is defeated. Use the `correlation-id` instead for a consistent result.
