Quick Start
Set up your Product Catalog
Define your master product data with names, images, categories, and identifiers
Configure Store Inventory
Track per-store availability, pricing, and aisle locations for efficient picking
Product Catalog
Your product catalog serves as the master data source for all items across your stores. It defines the core product information that drives inventory management, order processing, and picking operations.
Key fields
- Required fields:
name,imageUrls[],categories[],weight,dimensions{depth,height,width},identifiers[{type,value}]. - Optional fields:
externalIdentifier,sku,description,attributes[](e.g.,WEIGHTED), anddetails(sizeSpecification,packSizeSpecification,weightedItemInfo).
Rate Limits
- 10 requests per second per organization
- 1,000 products per request
API Endpoints
- Create/Update Products:
POST /v1/products- Bulk create or update products - List Products:
GET /v1/products- Retrieve products with pagination
Product Catalog Examples
Ready-to-use sample payloads for common product types
Store Inventory
Store inventory tracks the real-time availability, pricing, and location of products within each of your store locations. This data powers accurate order fulfillment by ensuring pickers know exactly what’s available and where to find it.
Key fields
- Required field:
available(boolean). - Common fields:
externalProductId,externalStoreLocationId,quantity,valueCents,currency,location{aisle,bay,shelf}.
Weighted Items
For variable-weight products (produce, deli items, etc.):- Set the product attribute to
WEIGHTEDin your product catalog - Use
details.weightedItemInfo.valueCentsPerMeasurementUnitfor per-unit pricing (e.g., price per pound)
Rate Limits
- 10 requests per second per organization
- 10,000 inventory items per request
API Endpoints
- Create/Update Inventory:
POST /v1/inventory- Bulk inventory updates - Get Inventory:
GET /v1/inventory- Query inventory with filters:externalStoreLocationId: Filter by store locationexternalProductId: Filter by product- Pagination:
pageIndex,numResultsPerPage
Pick and Pack Orders
Orders with Pick and Pack enabled leverage your product catalog and store inventory to enable precise item-level fulfillment. The system tracks exactly what was requested, what was picked, and any substitutions made during the process.To enable Pick and Pack functionality, include
pick_and_pack in the order.requirements array when creating orders. See the complete list in Order Requirements.Order Lifecycle
- Order Creation: Customer places order with specific items with substitution preferences
- Picking: 3rd party courier picks items, handling substitutions as needed
- Status Updates: Real-time updates on picking progress
- Delivery: Order handed off to delivery provider once picking is complete
Sub-item fields
item.subItems[].sku: optional SKU for the specific sub-item being picked.item.subItems[].substitution: object describing substitution preferences and chosen replacements.preference: e.g.,refundorsubstitute.source: who made the decision (e.g., merchant, customer).substituteItems[]: list of{ sku, quantity, weight }representing the chosen replacements.
Status
items_pick_complete: emitted when item picking for the order has finished and it is ready for handoff to delivery. Track this status via your order retrieval endpoints and/or subscribe to status change events in Webhooks.
Picked items
Each delivery carries apicked_items array describing what the picker actually put in the bag. The REST response always emits the same fields per item; values are nullable, but fields are never omitted.
| Field | Type | Notes |
|---|---|---|
id | string | null | Order line ID this pick fulfills. null when the SKU wasn’t a pre-existing line (substitution). |
sku | string | SKU of what was actually picked. |
name | string | Display name of the picked item. |
status | string | Fulfillment status (e.g. no_substitution, pre_selected, override). Opaque pass-through from the upstream provider. |
quantity | int | Units picked. |
requested_quantity | int | null | Units originally requested. |
weight | number | null | Net weight in kilograms for random-weight goods. |
price_cents | int | Line price in cents (already reflects weight × unit price for weighted items). |
requested_id | string | ID of the original order line. |
requested_sku | string | Originally requested SKU. Equals sku on straight picks. |
scanned_barcode | string | null | Raw scan at pick time. null for loose produce; 8/12/13 digits for EAN/UPC; ≥24 for GS1 in-store labels (GTIN + weight + price + use-by). |
scans | array | null | Per-scan detail for multi-scan items (e.g. a variable-weight item scanned multiple times). Each entry has its own parsed barcodes[] payload. |
sku != requested_sku (or equivalently, id == null).
Example — straight pick, packaged item
Example — straight pick, weighted item (single scan)
weight is populated; scanned_barcode is a GS1 in-store label encoding GTIN + weight + price. scans is null because the item was captured in a single scan.
Example — substitution
Example — loose produce (no scan)
Items sold “each” have no physical barcode. Identify bysku.
Example — weighted item with multiple scans
Variable-weight items picked across multiple physical units produce onescans[] entry per scan, each with a parsed GS1 payload. For richer parsed output, read scans[].barcodes[] instead of re-parsing scanned_barcode yourself.