Managing SKUs
Learn how to manage SKUs and understand how their configuration affects downstream processes
Depending on how you send product data in create checkout or create checkout-session requests, SKUs can contain compliance and/or basic product data.
How you define SKUs influences numerous downstream processes. This includes whether a product is classified as physical or digital and who acts as its fulfillment coordinator.
Once defined, you have the option to either create or upsert a SKU. After that, a SKU can then be updated or deleted. We also provide you the ability to retrieve a SKU by its unique identifier or search for SKUs using optional filters.

How SKUs are classified as physical or digital

Defining a SKU

The following are some of a SKU's key definable attributes:
For comprehensive specifications, refer to the SKUs API reference page.

Unique identifier

A SKU's unique identifier is represented by id.
When creating SKUs, if you don't specify id, Digital River generates a value for you.
A product's identifier in your system should ideally match the SKU's id in our system. This ensures that synchronization is possible and that SKUs work properly during checkouts and checkout-sessions. As a result, it's best practice to (1) specify your own SKU id and (2) ensure it matches your product's universally unique identifier.
Some characters however are not allowed. If you submit a POST/skus and id contains one or more whitespaces, a 400 Bad Request is returned.
400 Bad Request
1
{
2
"type": "bad_request",
3
"errors": [
4
{
5
"code": "invalid_parameter",
6
"parameter": "id",
7
"message": "'UGG BB PUR 06' is not a valid SKU ID."
8
}
9
]
10
}
Copied!
In the same request type, an id that contains certain special characters (such as /, [ , ] , { , } , < , >, and ^) results in a 500 Internal Server Error. Therefore, we recommend restricting a SKU's id to the following character set:
  • Numbers from 0 to 9
  • Upper case letters from A to Z
  • Lower case letters from a to z
  • Hyphens: -
  • Underscores: _

Country of origin

A SKU's countryOfOrigin is a two-letter Alpha-2 country code as described in the ISO 3166 international standard. It represents the country where a product was manufactured.
Invalid country codes return a 400 Bad Request:
1
{
2
"type": "bad_request",
3
"errors": [
4
{
5
"code": "invalid_parameter",
6
"parameter": "countryOfOrigin",
7
"message": "'KP' is not a valid Country of Origin."
8
}
9
]
10
}
Copied!

ECCN

A SKU's eccn represents its Export Control Classification Number (ECCN). This value determines whether:
  • A product requires a U.S. export/re-export license
  • A product contains any other license requirements/restrictions
  • A product has an end use which is prohibited by applicable export control laws
Digital River's legal documentation lists ECCNs pre-approved for use in the Digital River APIs. In the table's description field, you may find additional requirements and restrictions that further limit the use of the ECCN.
Digital River can only resell products with these listed ECCNs. If you have a product with an ECCN that you'd like to be considered for addition to the list, please contact [email protected]

Harmonized system code

A SKU's hsCode represents a Harmonized System code. By setting this parameter, you're flagging a physical product as eligible for cross-border shipping. When configuring the landed cost feature, setting a SKU's hsCode is one of the available options for sending HS code.
The format of the code is ####.##.####, where # represents a numeric digit between 0 and 9. The first six digits are mandatory. Any code longer than six digits but less than ten digits is optional and based on the country's preference. The period is not included in the character count.
Digital River only validates that the format of the Harmonized System code you provide is correct. We don't determine whether the code accurately classifies your product.
For example, the full ten-digit code for Jasmine rice in the United States is 1006.20.4025. If that's the value you specify, we don't check to make sure your product fits into that category.
Incorrectly formatted hsCode values return a 400 Bad Request:
JSON
1
{
2
"type": "bad_request",
3
"errors": [
4
{
5
"code": "invalid_parameter",
6
"parameter": "hsCode",
7
"message": "'1234.56.YW' is not a valid HS code."
8
}
9
]
10
}
Copied!

SKU group identifier

The skuGroupId uniquely identifies the SKU group associated with the SKU. For more information, refer to the Grouping SKUs page.

Manufacturer id and part number

A SKU contains manufacturerId and partNumber fields. They are only applicable to physical products.
A SKU's manufacturerId signifies the unique identifier of a part/product's manufacturer.
A manufacturer part number (MPN) is a unique code issued by manufacturers to identify a part/product. This is represented by a SKU's partNumber.
MPNs are meant to be static identifiers of a part/product, universal to all distributors, wholesalers, and resellers. They allow customers to accurately identify exact parts and protect themselves from counterfeits.
If two parts/products originate from two different manufacturers, then each must have its own MPN. These identifiers are especially relevant for automotive and consumer electronics, due to the numerous parts in these complex products.

Managed fulfillments

Managed fulfillment requirements

In Digital River coordinated fulfillments that use the orchestrated model, all the checkout's physical SKUs must meet the following requirements:
SKU attribute
Requirement
Sample error
managedFulfillment
The specified value must be DRGlobalFulfillment.
400 Bad Request
{ "type": "bad_request",
"errors": [ {
"code": "invalid_parameter", "parameter":"managedFulfillment", "message": "'DRGlobalFulfillment^&%^' is not a valid item type." }
] }
taxCode
The specified value must be associated with a physical product.
400 Bad Request
{ "type": "bad_request",
"errors": [ {
"code": "invalid_parameter", "parameter": "taxCode",
"message": "'4512.100' is not a valid parameter." }
] }
partNumber
The value must be specified.
400 Bad Request
{ "type": "bad_request",
"errors": [ {
"code": "invalid_parameter", "parameter": "partNumber", "message": "'null' is not a valid parameter." }
] }
manufacturerId
If you specify this value, then the partNumber must be valid. In other words, the combination of manufacturerId and partNumber must be correct.
409 Conflict
{ "type": "conflict",
"errors": [ {
"code": "invalid_parameter", "parameter": "manufacturerId", "message": "Invalid manufacturer ID. The manufacturer ID and manufacturer part # combination could not be found." }
] }

Creating and updating SKU-Inventory Item pairs

When you create or upsert a SKU that meets our managed fulfillment requirements, Digital River synchronously creates an associated inventory item. These SKU-inventory item pairs have shared attributes with identical values.
POST/skus
SKU
GET/inventory-items/{id}
Inventory Item
1
curl --location --request POST 'https://api.digitalriver.com/skus' \
2
--header 'Authorization: Bearer <API_key>' \
3
--header 'Content-Type: application/json' \
4
...
5
--data-raw '{
6
"id": "sku_demo_1617140947939",
7
"eccn": "EAR99",
8
"countryOfOrigin": "DE",
9
"taxCode": "4323.310_A",
10
"partNumber": "DEMOPARTNUMBER2",
11
"name": "name_demo_1617140947939",
12
"weight": 8.88,
13
"weightUnit": "oz",
14
"metadata": {
15
"application": "iOS-LLL"
16
},
17
"managedFulfillment": "DRGlobalFulfillment"
18
}'
Copied!
1
{
2
"id": "sku_demo_1617146803587",
3
"createdTime": "2021-03-30T23:26:43Z",
4
"name": "name_demo_1617146803587",
5
"eccn": "EAR99",
6
"partNumber": "DEMOPARTNUMBER2",
7
"taxCode": "4323.310_A",
8
"countryOfOrigin": "DE",
9
"metadata": {
10
"application": "iOS-LLL"
11
},
12
"weight": 8.88,
13
"weightUnit": "oz",
14
"fulfill": false,
15
"allowOversell": true,
16
"liveMode": false,
17
"managedFulfillment": "DRGlobalFulfillment",
18
"physical": true
19
}
Copied!
1
curl --location --request GET 'https://api.digitalriver.com/inventory-items/sku_demo_1617146803587' \
2
--header 'Authorization: Bearer <API_key>' \
3
...
4
--data-raw ''
Copied!
1
{
2
"id": "sku_demo_1617146803587",
3
"manufacturerId": "20013",
4
"partNumber": "DEMOPARTNUMBER2",
5
"allowOversell": true,
6
"createdTime": "2021-03-30T23:26:43Z",
7
"eccn": "EAR99",
8
"countryOfOrigin": "DE",
9
"liveMode": false
10
}
Copied!
Since the SKU's id and the inventory item's id are the same, you can use this value to describe items in checkouts, check inventory levels, request shipping quotes and make reservations.
Every subsequent modification of a managedFulfillment SKU (assuming the update SKU request satisfies our managed fulfillment requirements) synchronously updates the paired inventory item.
POST/skus/{id}
SKU
GET/inventory-items/{id}
Inventory Item
1
curl --location --request POST 'https://api.digitalriver.com/skus/sku_demo2_1617153759250' \
2
--header 'Authorization: Bearer <API_key>' \
3
--header 'Content-Type: application/json' \
4
--data-raw '{
5
"countryOfOrigin": "US"
6
}'
Copied!
1
{
2
"id": "sku_demo2_1617153759250",
3
"createdTime": "2021-03-31T01:22:39Z",
4
"name": "name_demo2_1617153759250",
5
"eccn": "EAR99",
6
"partNumber": "DEMOPARTNUMBER2",
7
"updatedTime": "2021-03-31T01:23:04Z",
8
"taxCode": "4323.310_A",
9
"countryOfOrigin": "US",
10
"metadata": {
11
"application": "iOS-LLL"
12
},
13
"weight": 8.88,
14
"weightUnit": "oz",
15
"fulfill": false,
16
"allowOversell": true,
17
"liveMode": false,
18
"managedFulfillment": "DRGlobalFulfillment",
19
"physical": true
20
}
Copied!
1
curl --location --request GET 'https://api.digitalriver.com/inventory-items/sku_demo2_1617153759250' \
2
--header 'Authorization: Bearer <API_key>' \
3
...
4
--data-raw ''
Copied!
1
{
2
"id": "sku_demo2_1617153759250",
3
"manufacturerId": "20013",
4
"partNumber": "DEMOPARTNUMBER2",
5
"allowOversell": true,
6
"createdTime": "2021-03-31T01:22:43Z",
7
"updatedTime": "2021-03-31T01:23:04Z",
8
"eccn": "EAR99",
9
"countryOfOrigin": "US",
10
"liveMode": false
11
}
Copied!
So, if you have an existing SKU, and you want to make Digital River its fulfillment coordinator, you can set managedFulfillment to DRGlobalFulfillment and then send this value (along with any other values that must be added or modified to satisfy our managed fulfillment requirements) in an update SKU request.
Once Digital River internally creates an inventory item, do not directly update or delete it through the Inventory Items API. These operations modify and delete the inventory item but do not affect its paired SKU.
When you want to remove Digital River as a product's fulfillment coordinator, set managedFulfillment to null in an update SKU request. This deletes the inventory item paired with the SKU. If you then attempt to retrieve the inventory item, you receive a 404 Not Found.
POST/skus/{id}
SKU
GET/inventory-items/{id}
Inventory Item
1
curl --location --request POST 'https://api.digitalriver.com/skus/sku_demo_1617153057380' \
2
--header 'Authorization: Bearer <API_key>' \
3
--header 'Content-Type: application/json' \
4
...
5
--data-raw '{
6
"managedFulfillment": null
7
}'
Copied!
1
{
2
"id": "sku_demo_1617153057380",
3
"createdTime": "2021-03-31T01:10:57Z",
4
"name": "name_demo_1617153057380",
5
"eccn": "EAR99",
6
"partNumber": "DEMOPARTNUMBER2",
7
"updatedTime": "2021-03-31T01:19:14Z",
8
"taxCode": "4323.310_A",
9
"countryOfOrigin": "DE",
10
"metadata": {
11
"application": "iOS-LLL"
12
},
13
"weight": 8.88,
14
"weightUnit": "oz",
15
"fulfill": false,
16
"allowOversell": true,
17
"liveMode": false,
18
"physical": true
19
}
Copied!
1
curl --location --request GET 'https://api.digitalriver.com/inventory-items/sku_demo_1617153057380' \
2
--header 'Authorization: Bearer <API_key>' \
3
...
4
--data-raw ''
Copied!
1
{
2
"type": "not_found",
3
"errors": [
4
{
5
"code": "not_found",
6
"parameter": "id",
7
"message": "InventoryItem 'sku_demo_1617153057380' not found."
8
}
9
]
10
}
Copied!

Deleting SKU-Inventory Item pairs

A delete SKU request deletes both the SKU and the inventory item it's paired with.

Name and description

A SKU's name is required but description is optional.
In Drop-in Checkout, name is displayed in the order summary section of the checkout modal window.

Image and url

A SKU's image can hold a URL that provides the address of a resource that contains the product's image. This image should be similar to the image(s) you display to customers while they are reviewing and selecting products.
In Drop-in Checkout, image is displayed in the order summary section of the checkout modal window.
A SKU's url should hold a URL that provides the address of a resource that contains the product's description.
In the Global logistics solution, depending on your logistics partner's setup, both image and url are often transferred to the customs documentation. This allows customs officials to obtain information about the product during the pre-clearance phase of an importation.
Both image and url are required when customers are using ApplePay or GooglePay as their primary payment source.

Weight and weight unit

For physical SKUs, you can provide the product’s weight measured by a weightUnit. The enumerated weightUnit values are oz, lb, g, and kg. If you provide a weight but not a weightUnit, then the value defaults to oz.
In some countries, such as Switzerland, custom officials use a product's weight when calculating import duties. As a result, without this data, we're unable to calculate landed costs.
If you send a create or update checkout request that contains a shipTo.address.country from one of these nations, and any SKU referenced in the checkout's items[] array is missing weight, then the following 400 Bad Request is thrown:
400 Bad Request
1
{
2
"type": "bad_request",
3
"errors": [
4
{
5
"code": "missing_parameter",
6
"message": "The weight is missing.",
7
"parameter": "weight"
8
}
9
]
10
}
Copied!
So, if your site intends on selling physical products across international borders, we recommend that you define both weight and weightUnit for all of your catalog's physical SKUs.

Allow oversell

In version 2021-12-13 and later, you can no longer set a SKU's allowOversell attribute.
In Digital River coordinated fulfillments, you may decide to build your integration such that customers can reserve out of stock items or pre-order items not yet in stock. To do this, you can use the SKU's allowOversell flag.
If you set the flag to true, customers can reserve the item even when inventory is not available. When set to false, customers won't be able to place a hold on an item when its inventory levels are not sufficient.

Tax code

SKU's must contain a taxCode. This value determines whether a product gets classified as physical or digital and ensures that the correct tax is applied to the product. You can modify a SKU's taxCode in either an upsert or update SKU request.

Supported tax codes

The following table lists the tax codes currently supported by Digital River and whether they're associated with physical or digital products.
If you'd like to use a tax code not listed here, contact your account representative.
If a SKU's taxCode is in the table's physical grouping, then it's physical attribute is true . Conversely, if a SKU's taxCode is in the digital grouping, then physical is false.
Group
Type
Tax Code
Associated with physical or digital products?
Downloadable Goods (Non-Software)
Digital Image
4512.100
Digital
Downloadable Goods (Non-Software)
Virtual Goods
55111509.12
Digital
Downloadable Goods (Non-Software)
Music
55111512.100
Digital
Downloadable Goods (Non-Software)
Electronic Newspapers (Includes Subscriptions)
55111507.120
Digital
Downloadable Goods (Non-Software)
Electronic Magazines (Includes Subscriptions)
55111506.120
Digital
Downloadable Goods (Non-Software)
Educational / Vocational Texts
55111513.120
Digital
Downloadable Goods (Non-Software)
eBooks
55111502.120
Digital
Food, Beverage & Household
Non-Prescription Vitamins
51191905
Physical
Food, Beverage & Household
Non-Prescription Drugs
5124
Physical
Food, Beverage & Household
Miscellaneous Supplies
47
Physical
Food, Beverage & Household
Food - General
50
Physical
Physical Goods
Automatic Blood Pressure Monitors
531316.150
Physical
Physical Goods
Energy Star - Stove
52141545.100
Physical
Physical Goods
Energy Star - Dehumidifier
4010.200
Physical
Physical Goods
Energy Star - Air Conditioner
4010.100
Physical
Physical Goods
Energy Star - Ceiling Fan
40101609.100
Physical
Physical Goods
Energy Star - Light Bulbs
39101629.100
Physical
Physical Goods
Energy Star - Freezer
52141506.100
Physical
Physical Goods
Energy Star - Refrigerator
52141501.100
Physical
Physical Goods
Energy Star - Washer
52141601.100
Physical

SKUs API operations

You can use the SKUs API to create and update, upsert, retrieve, search for, and delete SKUs.

Creating and updating a SKU

Creating and updating SKUs are nearly identical processes. The main difference is that in a create SKU request you're allowed to specify the unique identifier, but in an update SKU request you must pass in its unique identifier as a path parameter.
Additionally, when creating a SKU, you're required to specify the export control classification number, tax code, a product name, and country of origin.
The following POST/skus request creates a physical SKU because the taxCode parameter references physical software:
cURL
1
curl --location --request POST 'https://api.digitalriver.com/skus' \
2
--header 'Authorization: Bearer <API_key>' \
3
--header 'Content-Type: text/plain' \
4
--data-raw '{
5
"id": "3170de75-68f8-4d54-9176-211f0e680136",
6
"eccn": "EAR99",
7
"countryOfOrigin": "US",
8
"taxCode": "4323.310_A",
9
"partNumber": "100-440-0.750-3434-A",
10
"name": "Test Product"
11
}'
Copied!
A 201 Created response returns a SKU object:
SKU
1
{
2
"id": "3170de75-68f8-4d54-9176-211f0e680136",
3
"createdTime": "2021-04-05T16:23:38Z",
4
"name": "Test Product",
5
"eccn": "EAR99",
6
"partNumber": "100-440-0.750-3434-A",
7
"taxCode": "4323.310_A",
8
"countryOfOrigin": "US",
9
"fulfill": false,
10
"allowOversell": true,
11
"liveMode": false,
12
"physical": true
13
}
Copied!

Upserting a SKU

The upsert request uses a PUT method to either create or update a SKU object. If the specified SKU doesn't exist, the operation creates one. Otherwise, if the SKU already exists, then the data specified in the request's body updates the SKU's corresponding attributes. The upsert operation is basically a create and update request rolled into one.
Since the SKU might not exist when you make the PUT request, the same parameters as a create request are required.

Upsert request

Let's say your Tax department informs you that an existing software product now falls into a new tax category. As a result, you need to update the taxCode value of the SKU. The following example shows how to do this using an upsert request.
When submitting the request, you need to pass in the SKU identifier as a path parameter. You also need to provide the eccn, taxCode, name, and countryOfOrigin.
cURL
1
curl https://api.digitalriver.com/skus/sku_5823595932 \
2
-u <API_key>: \
3
-d eccn="EAR99" \
4
-d taxCode="81112106" \
5
-d name="Wiser Word Editor" \
6
-d countryOfOrigin="US"
Copied!

Upsert response

If your request is successful, you'll receive either a 200 OK or a 201 Created response, depending on whether the SKU already exists or was created by the request.
A 200 OK response indicates the SKU was created prior to the request and is now updated. In the following example, note that the createdTime is earlier than the updatedTime.
SKU
1
{
2
"createdTime": "2020-01-11T20:48:03Z",
3
"id": "sku_5823595932",
4
"eccn": "EAR99",
5
"taxCode": "81112106",
6
"name": "Wiser Word Editor",
7
"description": "Wiser Word Editor",
8
"image": "https://imageurl.com",
9
"url": "https://producturl.com",
10
"countryOfOrigin": "US",
11
"physical": false,
12
"liveMode": false,
13
"metadata": {
14
"coupon": "iOS"
15
},
16
"updatedTime": "2020-04-14T18:28:09Z"
17
}
Copied!
A 201 Created response indicates that the SKU did not exist at the time of the request but has now been created. In the following example, the createdTime is identical to the updatedTime.
SKU
1
{
2
"createdTime": "2020-04-14T18:28:09Z",
3
"id": "sku_5823595932",
4
"eccn": "EAR99",
5
"taxCode": "81112106",
6
"name": "Wiser Word Editor",
7
"countryOfOrigin": "US",
8
"physical": false,
9
"updatedTime": "2020-04-14T18:28:09Z"
10
}
Copied!

Deleting a SKU

To delete a SKU, pass its unique identifier as a path parameter in a DELETE/skus/{id} request. This also deletes any Fee objects associated with the SKU.