1. Items
  2. Items

Items

Items

Before you create items, you'll want to set up locations and layouts in your dashboard so that you'll be able to add inventory levels for the item.

Your inventory for items is tracked in a property called levels, which will give you information about the location and optionally the layout the item is in.

Create Item

POST
`/v1/items`

The only property you need to create an item is name, by which this item will be searchable. However, we recommend adding a few more properties:

name string (required)
The name of the item
sku or gtin string
One of these is most likely on the barcode of your items so it's best to include this so that barcode scanners play nicely.
upc string
The universal product code of the item
description string
A description of the item
color string
The color of the item
size string
The size of the item (e.g., "small", "large")
vendor string
The name of the vendor or supplier for this item
origin_country string
The ISO country code of the country that manufactured this item
value number
The value of the item in cents
length number
The length of the item in inches
width number
The width of the item in inches
height number
The height of the item in inches
weight number
The weight of the item in pounds (lbs)
packaged_length float
If you're planning to do fulfillments, this property will be required, so it is easier to add it on the item
packaged_width float
If you're planning to do fulfillments, this property will be required, so it is easier to add it on the item
packaged_height float
If you're planning to do fulfillments, this property will be required, so it is easier to add it on the item
packaged_weight float
If you're planning to do fulfillments, this property will be required, so it is easier to add it on the item
harmonized_code string
The harmonized system code for the item, required for international shipping
metadata object
Key-value pairs of custom metadata for the item
attributes string[]
A list of attribute strings (e.g., alcohol, marijuana, pharma, dry_ice, lithium)
external_id string
An external identifier for linking with third-party systems
external_type string
A type label for the external system linked via external_id
is_asset boolean
Whether this item should be tracked as an asset
ship_ready boolean
Whether this item is ready to ship directly
tariff_codes array
Array of country-specific tariff codes. Each entry contains country and code. The item must have a harmonized_code set
base_uom string
The base unit of measure for this item (e.g., "unit", "kg", "lb")

Example

js
        const item = {
  name: "My item name",
  sku: "123345",
  gtin: "987654", //can have both, why not?
  upc: "45678"
  packaged_length: 5, //inches
  packaged_width: 6,
  packaged_height: 7,
  packaged_weight: 8, //lbs
};

fetch("https://api.packagex.io/v1/items", {
  method: "POST",
  headers: {
    "PX-API-KEY": process.env.PX_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(data),
});

      

Update Item

POST
`/v1/items/:item`

You can update an item by using its ID. All properties available at create time (name, sku, gtin, description, dimensions, metadata, is_asset, etc.) can also be updated via this endpoint.

When updating inventory, you increment and decrement quantities by passing in positive and negative integers.

You can reset a value by passing the integer inside of an array as shown in the example below. It's not recommended to reset values, since incrementing and decrementing will get you the same result, but this is an escape hatch if you need it and thus the ergonomics of an array prevent accidental usage of an otherwise potentially dangerous feature.

Lastly, you can optionally provide a layout value to be more specific about the item's exact whereabouts in that location. If the item already has a layout associated with it, it will keep adding to that layout unless you explicitly tell it not to. The best rule of thumb is either use layouts for everything, or don't use them at all.

Example

js
        const update = {
  name: "Updated Name",
  levels: [
    {
      location_id: "loc_8GiCVuqZqBJi43v2WebaME",
      available_qty: 30,
    },
    {
      location_id: "loc_dKa43ncARLdGENQPUq2CoX",
      available_qty: -50,
    },
    {
      location_id: "loc_v4BPffa3m2zJdhCLE8SL4C",
      layout_id: "lay_27ee779f2c9747228e1b62929522bb83",
      available_qty: [100], // Value is being reset to 100
    },
  ],
};

const response = await fetch(`https://api.packagex.io/v1/items/${item.id}`, {
  method: "POST",
  headers: {
    "PX-API-KEY": process.env.PX_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(body),
}).then((res) => res.json());

const item = response.data;

      

Retrieve Item

GET
`/v1/items/:item`

Get a single item using its id.

js
        const response = await fetch("https://api.packagex.io/v1/items/item_czhgjrk5JaVvyATPDbyURp", {
  method: "GET",
  headers: {
    "PX-API-KEY": process.env.PX_API_KEY,
    "Content-Type": "application/json",
  },
}).then((res) => res.json());

const item = response.data;

      

Location Based Retrieval

GET
`/v1/items/:item`

Get a single item with inventory from a given location only. For example, to see the inventory levels of an item with id item_czhgjrk5JaVvyATPDbyURp at the location loc_hj7gjrk5JaVvyATPDbyURp

js
        const response = await fetch("https://api.packagex.io/v1/items/item_czhgjrk5JaVvyATPDbyURp/locations/loc_hj7gjrk5JaVvyATPDbyURp", {
  method: "GET",
  headers: {
    "PX-API-KEY": process.env.PX_API_KEY,
    "Content-Type": "application/json",
  },
}).then((res) => res.json());

const item = response.data;

      

Delete Item

DELETE
`/v1/items/:item`

You can delete an item by using its ID, SKU, GTIN, or UPC. Deleted items are soft-deleted — they are marked as deleted but can be restored later. Any assets linked to the item will be archived automatically.

Deleted items will no longer appear in list or retrieve responses. Shipments, manifests, or fulfillments that are completed will not be impacted.

Confirmation required for items with assets: If the item has active (non-archived) assets, you must confirm the deletion by passing the item's name in confirm_name or its sku in confirm_sku in the request body. Without this, the API will return a 400 error indicating how many active assets exist.

Example

js
        // Simple delete (no active assets)
const response = await fetch(`https://api.packagex.io/v1/items/${item.id}`, {
  method: "DELETE",
  headers: {
    "PX-API-KEY": process.env.PX_API_KEY,
    "Content-Type": "application/json",
  },
}).then((res) => res.json());

// response.data = { success: true }
// response.message = "Item was deleted"

      

Delete with Confirmation

js
        // Delete an item that has active assets — confirm by name or SKU
const response = await fetch(`https://api.packagex.io/v1/items/${item.id}`, {
  method: "DELETE",
  headers: {
    "PX-API-KEY": process.env.PX_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    confirm_name: "Widget A", // or confirm_sku: "SKU-123"
  }),
}).then((res) => res.json());

      

Restore Item

POST
`/v1/items/:item/restore`

You can restore a previously deleted item by using its ID, SKU, GTIN, or UPC. The item will be returned to its original state. Any assets that were archived during deletion will be unarchived.

Restoration will fail if an active item already exists with the same SKU, GTIN, or UPC.

Note: If you create a new item with the same SKU, GTIN, or UPC as a previously deleted item, the deleted item will be automatically restored and updated with the new data instead of creating a duplicate.

Example

js
        const response = await fetch(`https://api.packagex.io/v1/items/${item.id}/restore`, {
  method: "POST",
  headers: {
    "PX-API-KEY": process.env.PX_API_KEY,
    "Content-Type": "application/json",
  },
}).then((res) => res.json());

const item = response.data; // the restored item object

      


Inventory Levels

Inventory levels track the quantity of an item at a specific location and optionally a layout within that location.

List Inventory Levels

GET
`/v1/items/:item/levels`

List all inventory levels for a given item. Requires the items:read scope.

Path Parameters

item string (required)
The ID of the item

Response Fields

Each level object in the data array contains:

id string
The inventory level ID
location_id string
The location this level belongs to
layout_id string
The layout within the location (if applicable)
layout_code string
The code of the layout
layout_name string
The name of the layout
location_name string
The name of the location
available_qty number
Quantity available for use
defective_qty number
Quantity marked as defective
manifested_qty number
Quantity currently on a manifest
reserved_qty number
Quantity reserved for orders
stored_qty number
Quantity in storage
operational_qty number
Quantity in operational use
processing_qty number
Quantity being processed
decommissioned_qty number
Quantity that has been decommissioned

Example

js
        const response = await fetch(`https://api.packagex.io/v1/items/${item.id}/levels`, {
  method: "GET",
  headers: {
    "PX-API-KEY": process.env.PX_API_KEY,
    "Content-Type": "application/json",
  },
}).then((res) => res.json());

const levels = response.data;

      

Retrieve Inventory Level

GET
`/v1/items/:item/levels/:level`

Retrieve a specific inventory level by its ID. Requires the items:read scope.

Path Parameters

item string (required)
The ID of the item
level string (required)
The ID of the inventory level

Example

js
        const response = await fetch(
  `https://api.packagex.io/v1/items/${item.id}/levels/${level.id}`,
  {
    method: "GET",
    headers: {
      "PX-API-KEY": process.env.PX_API_KEY,
      "Content-Type": "application/json",
    },
  }
).then((res) => res.json());

const level = response.data;

      

Create Inventory Levels

POST
`/v1/items/:item/levels`

Create or update inventory levels for an item. The request body must be an array of level objects. Quantities are incremented or decremented by passing positive or negative integers. To reset a quantity to an exact value, pass the integer inside an array (e.g., [100]). Requires the items:write scope. Returns 201 on success.

Path Parameters

item string (required)
The ID of the item

Body Parameters (array of objects)

location_id string (required if no id)
The location to create or update the level at
id string
The ID of an existing level to update
layout_id string
The layout within the location. If omitted, the default layout for the location is used
available_qty or verified_qty number
Increment/decrement available quantity, or pass as [value] to reset
defective_qty number
Increment/decrement defective quantity, or pass as [value] to reset
manifested_qty number
Increment/decrement manifested quantity, or pass as [value] to reset
reserved_qty number
Increment/decrement reserved quantity, or pass as [value] to reset

Example

js
        const levels = [
  {
    location_id: "loc_8GiCVuqZqBJi43v2WebaME",
    available_qty: 30,
  },
  {
    location_id: "loc_dKa43ncARLdGENQPUq2CoX",
    layout_id: "lay_27ee779f2c9747228e1b62929522bb83",
    available_qty: -10,
  },
  {
    location_id: "loc_v4BPffa3m2zJdhCLE8SL4C",
    available_qty: [100], // Reset to exactly 100
  },
];

const response = await fetch(`https://api.packagex.io/v1/items/${item.id}/levels`, {
  method: "POST",
  headers: {
    "PX-API-KEY": process.env.PX_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(levels),
}).then((res) => res.json());

const updated_levels = response.data;

      

Update Inventory Level

POST
`/v1/items/:item/levels/:level`

Update a specific inventory level. The level ID from the URL is injected into the request body. This endpoint uses the same controller as the create endpoint, so all the same quantity fields and reset-via-array behavior apply. Requires the items:write scope.

Path Parameters

item string (required)
The ID of the item
level string (required)
The ID of the inventory level

Body Parameters

location_id string
The location for this level
layout_id string
The layout within the location
available_qty or verified_qty number
Increment/decrement available quantity, or pass as [value] to reset
defective_qty number
Increment/decrement defective quantity, or pass as [value] to reset
manifested_qty number
Increment/decrement manifested quantity, or pass as [value] to reset
reserved_qty number
Increment/decrement reserved quantity, or pass as [value] to reset

Example

js
        const update = {
  available_qty: 15,
  defective_qty: -2,
};

const response = await fetch(
  `https://api.packagex.io/v1/items/${item.id}/levels/${level.id}`,
  {
    method: "POST",
    headers: {
      "PX-API-KEY": process.env.PX_API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(update),
  }
).then((res) => res.json());

const updated_levels = response.data;

      

Delete Inventory Level

DELETE
`/v1/items/:item/levels/:level`

Delete an inventory level. The level can only be deleted if all its quantities (available_qty, defective_qty, reserved_qty, manifested_qty) are zero. If any quantity is greater than zero, the request will fail with a 400 error. Requires the items:write scope.

Path Parameters

item string (required)
The ID of the item
level string (required)
The ID of the inventory level

Example

js
        const response = await fetch(
  `https://api.packagex.io/v1/items/${item.id}/levels/${level.id}`,
  {
    method: "DELETE",
    headers: {
      "PX-API-KEY": process.env.PX_API_KEY,
      "Content-Type": "application/json",
    },
  }
).then((res) => res.json());

// response.message = "Item level deleted"

      


Images

Manage images for an item. Images can be provided as URLs or base64-encoded strings.

Add/Manage Item Images

POST
`/v1/items/:item/images`

Add, remove, or set images for an item. Requires the items:write scope. You can pass images in several formats:

  • Array of URLs/base64 strings -- adds the images to the item
  • Object with add, remove, set arrays -- granular control over images

The images, image_urls, and image_url fields are all accepted (in that priority order).

Path Parameters

item string (required)
The ID of the item

Body Parameters

images array or object
An array of image URLs/base64 strings, or an object with add, remove, and/or set arrays for granular control
image_urls array
Alternative to images -- an array of image URLs or base64 strings to add
image_url string
Alternative to images -- a single image URL or base64 string to add

Example: Add images

js
        const body = {
  images: [
    "https://example.com/image1.jpg",
    "https://example.com/image2.jpg",
  ],
};

const response = await fetch(`https://api.packagex.io/v1/items/${item.id}/images`, {
  method: "POST",
  headers: {
    "PX-API-KEY": process.env.PX_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(body),
}).then((res) => res.json());

const updated_item = response.data;

      

Example: Add and remove images

js
        const body = {
  images: {
    add: ["https://example.com/new-image.jpg"],
    remove: ["https://example.com/old-image.jpg"],
  },
};

const response = await fetch(`https://api.packagex.io/v1/items/${item.id}/images`, {
  method: "POST",
  headers: {
    "PX-API-KEY": process.env.PX_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(body),
}).then((res) => res.json());

const updated_item = response.data;

      

Delete Item Image

DELETE
`/v1/items/:item/images/:image`

Delete a specific image from an item by its image ID. This internally calls the item update controller with the image marked for removal. Requires the items:write scope.

Path Parameters

item string (required)
The ID of the item
image string (required)
The ID of the image to remove

Example

js
        const response = await fetch(
  `https://api.packagex.io/v1/items/${item.id}/images/${image.id}`,
  {
    method: "DELETE",
    headers: {
      "PX-API-KEY": process.env.PX_API_KEY,
      "Content-Type": "application/json",
    },
  }
).then((res) => res.json());

const updated_item = response.data;

      


Transactional Units

Transactional units define alternative units of measure for an item beyond its base unit. For example, an item measured in "pieces" might also have a "box" unit with a conversion factor of 12 (1 box = 12 pieces). Each item can have up to 50 transactional units. The base unit is created automatically and cannot be modified or deleted via these endpoints.

List Transactional Units

GET
`/v1/items/:item/transactional-units`

List all transactional units for an item, including the base unit. Requires the items:read scope. Supports pagination.

Path Parameters

item string (required)
The ID of the item

Query Parameters

page number
The page number for pagination
limit number
The number of results per page

Response Fields

Each transactional unit object in the data array contains:

id string
The transactional unit ID (prefixed with itu_)
name string
The name of the unit (e.g., "Box", "Pallet")
conversion_factor number
How many base units equal one of this unit
created_at datetime
When the unit was created
updated_at datetime
When the unit was last updated
created_by_details object
The user who created the unit (id and name)
updated_by_details object
The user who last updated the unit (id and name)

Example

js
        const response = await fetch(
  `https://api.packagex.io/v1/items/${item.id}/transactional-units`,
  {
    method: "GET",
    headers: {
      "PX-API-KEY": process.env.PX_API_KEY,
      "Content-Type": "application/json",
    },
  }
).then((res) => res.json());

const units = response.data;
// response.pagination contains total, page, limit

      

Write Transactional Units

POST
`/v1/items/:item/transactional-units`

Create or update transactional units for an item. Units are matched by id first, then by name (case-insensitive). If a match is found, the unit is updated; otherwise, a new unit is created. Requires the items:write scope.

Constraints:

  • Unit names must be unique within the payload
  • Cannot modify or target the base transactional unit
  • Cannot use a name that conflicts with the base unit name
  • Maximum of 50 total transactional units per item

Path Parameters

item string (required)
The ID of the item

Body Parameters

transactional_units array (required)
An array of 1 to 50 unit objects
transactional_units[].id string
The ID of an existing unit to update. If omitted, matches by name or creates a new unit
transactional_units[].name string (required)
The name of the unit (1-100 characters, trimmed)
transactional_units[].conversion_factor number (required)
A positive number up to 999999.9999 representing how many base units equal one of this unit

Example

js
        const body = {
  transactional_units: [
    { name: "Box", conversion_factor: 12 },
    { name: "Pallet", conversion_factor: 144 },
  ],
};

const response = await fetch(
  `https://api.packagex.io/v1/items/${item.id}/transactional-units`,
  {
    method: "POST",
    headers: {
      "PX-API-KEY": process.env.PX_API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(body),
  }
).then((res) => res.json());

const units = response.data;
// response.message = "Transactional units updated"

      

Delete Transactional Unit

DELETE
`/v1/items/:item/transactional-units/:unit`

Delete a specific transactional unit. The base transactional unit cannot be deleted. Requires the items:write scope.

Path Parameters

item string (required)
The ID of the item
unit string (required)
The ID of the transactional unit to delete

Example

js
        const response = await fetch(
  `https://api.packagex.io/v1/items/${item.id}/transactional-units/${unit.id}`,
  {
    method: "DELETE",
    headers: {
      "PX-API-KEY": process.env.PX_API_KEY,
      "Content-Type": "application/json",
    },
  }
).then((res) => res.json());

// response.message = "Transactional unit deleted"

      


Assets

Assets are individual, trackable instances of an item. Each asset gets a unique serial number and can be tracked at a specific location and layout. Assets require the item to have is_asset set to true.

Create Asset

POST
`/v1/items/:item/assets`

Create a new asset under an item. The item_id is automatically set from the URL path. Requires the assets:write scope.

If no serial_number or sequence_id is provided, a serial number is generated automatically. If a sequence_id is provided, the serial number is derived from that sequence.

Path Parameters

item string (required)
The ID of the item

Body Parameters

location_id string (required)
The location where the asset will be stored
layout_id string
The layout within the location
serial_number string
A custom serial number. If omitted, one is auto-generated
sequence_id string
A sequence to derive the serial number from
status string
The initial status of the asset (defaults to in_storage)
contact_id or assignee string
The contact or assignee for the asset
manufacturer_number string
The manufacturer's part or model number
value number
The current value of the asset
initial_value number
The original purchase value
currency string
The currency for value fields
category string
The asset category
sub_category string
The asset sub-category
barcode string
Defaults to the serial number
vendor string
The vendor or supplier
origin_country string
The country of origin
warranty_expires_at datetime
When the warranty expires
is_warranty_valid boolean
Whether the warranty is currently valid
maintenance_schedule string
The maintenance schedule (e.g., monthly, quarterly)
next_maintenance_at datetime
When the next maintenance is due
maintenance_status string
The current maintenance status
purchased_at datetime
When the asset was purchased
disposed_at datetime
The disposal date (if applicable)
disposal_reason_code string
The reason code for disposal
disposal_comment string
Additional comments about disposal

Example

js
        const body = {
  location_id: "loc_8GiCVuqZqBJi43v2WebaME",
  serial_number: "AST-2024-001",
  status: "in_storage",
  value: 1500,
  currency: "USD",
  category: "Electronics",
  vendor: "Acme Corp",
};

const response = await fetch(`https://api.packagex.io/v1/items/${item.id}/assets`, {
  method: "POST",
  headers: {
    "PX-API-KEY": process.env.PX_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(body),
}).then((res) => res.json());

const asset = response.data;

      

Update Asset

POST
`/v1/items/:item/assets/:asset`

Update an existing asset under an item. The item_id is set from the URL path. Requires the assets:write scope. All body parameters from the create endpoint are also accepted here for updating.

Path Parameters

item string (required)
The ID of the item
asset string (required)
The ID of the asset to update

Example

js
        const update = {
  status: "in_use",
  value: 1200,
  maintenance_status: "due",
  next_maintenance_at: "2025-06-01T00:00:00Z",
};

const response = await fetch(
  `https://api.packagex.io/v1/items/${item.id}/assets/${asset.id}`,
  {
    method: "POST",
    headers: {
      "PX-API-KEY": process.env.PX_API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(update),
  }
).then((res) => res.json());

const updated_asset = response.data;