Skip to main content

Products Block

Products Block

Product catalog and inventory management API

The Products Block provides complete e-commerce product management. Create product catalogs, manage inventory, handle variants, organize into categories, and deliver product data to any frontend.

Features

  • Product Catalog - Rich product data with unlimited attributes
  • Inventory Management - Real-time stock tracking with alerts
  • Product Variants - Size, color, and custom variant support
  • Categories & Collections - Hierarchical organization
  • Dynamic Pricing - Multi-currency and tiered pricing
  • Product Search - Full-text search with filtering

Quick Start

npm install @23blocks/sdk

API Endpoint

ServiceURL
Productshttps://products.api.us.23blocks.com

Environment Routing: One URL, one environment. All shared-platform API keys are live keys:

  • pk_live_* / sk_live_* → your production tenant. Need a separate staging environment? It is available as a paid add-on on deployments in your own cloud account — see 23blocks in a Box.
import { create23BlocksClient } from '@23blocks/sdk';

const client = create23BlocksClient({
urls: { products: 'https://products.api.us.23blocks.com' },
apiKey: 'your-api-key', // Your live API key (pk_live_*)
});

// Create a product
const product = await client.products.create({
name: 'Premium Wireless Headphones',
sku: 'WH-PRO-2024',
price: { amount: 29900, currency: 'USD' },
inventory: { quantity: 100, track_stock: true }
});

// List products with filters
const products = await client.products.list({
category: 'electronics',
in_stock: true,
sort: '-created_at'
});

Authentication

All API requests require authentication headers:

curl -X GET "https://api.23blocks.com/v1/products" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "X-App-Id: YOUR_APP_ID" \
-H "Content-Type: application/json"

Products

Create Product

Create a new product in your catalog.

POST /v1/products

Request Body:

{
"data": {
"type": "products",
"attributes": {
"name": "Premium Wireless Headphones",
"sku": "WH-PRO-2024",
"description": "High-fidelity audio with active noise cancellation and 30-hour battery life.",
"short_description": "Premium wireless headphones with ANC",
"status": "active",
"type": "physical",
"price": {
"amount": 29900,
"currency": "USD",
"compare_at": 34900
},
"cost": {
"amount": 12000,
"currency": "USD"
},
"inventory": {
"quantity": 247,
"track_stock": true,
"allow_backorder": false,
"low_stock_threshold": 25
},
"weight": {
"value": 250,
"unit": "g"
},
"dimensions": {
"length": 20,
"width": 18,
"height": 8,
"unit": "cm"
},
"attributes": {
"brand": "AudioPro",
"battery_life": "30 hours",
"connectivity": "Bluetooth 5.3",
"driver_size": "40mm"
},
"seo": {
"title": "Premium Wireless Headphones | AudioPro",
"description": "Experience studio-quality sound with our premium wireless headphones.",
"slug": "premium-wireless-headphones"
},
"metadata": {
"warehouse_location": "A1-23"
}
},
"relationships": {
"categories": {
"data": [
{ "type": "categories", "id": "cat_electronics" },
{ "type": "categories", "id": "cat_audio" }
]
}
}
}
}

Response:

{
"data": {
"type": "products",
"id": "prod_abc123",
"attributes": {
"name": "Premium Wireless Headphones",
"sku": "WH-PRO-2024",
"description": "High-fidelity audio with active noise cancellation...",
"status": "active",
"type": "physical",
"price": {
"amount": 29900,
"currency": "USD",
"compare_at": 34900,
"formatted": "$299.00",
"compare_at_formatted": "$349.00"
},
"inventory": {
"quantity": 247,
"available": 247,
"reserved": 0,
"in_stock": true,
"track_stock": true,
"low_stock": false
},
"created_at": "2026-01-02T10:30:00Z",
"updated_at": "2026-01-02T10:30:00Z"
}
}
}

List Products

Retrieve a paginated list of products with filtering and sorting.

GET /v1/products

Query Parameters:

ParameterTypeDescription
page[number]integerPage number (default: 1)
page[size]integerItems per page (default: 20, max: 100)
filter[status]stringFilter by status: active, draft, archived
filter[category]stringFilter by category ID or slug
filter[in_stock]booleanFilter by stock availability
filter[type]stringFilter by type: physical, digital, service
filter[price_min]integerMinimum price in cents
filter[price_max]integerMaximum price in cents
filter[created_after]datetimeProducts created after date
searchstringFull-text search query
sortstringSort field: name, price, created_at, -created_at
includestringInclude related resources: variants, categories, images

Example:

GET /v1/products?filter[category]=electronics&filter[in_stock]=true&sort=-created_at&include=variants,images

Get Product

Retrieve a single product by ID or SKU.

GET /v1/products/:id
GET /v1/products/sku/:sku

Query Parameters:

ParameterTypeDescription
includestringInclude: variants, categories, images, related

Update Product

Update an existing product.

PATCH /v1/products/:id

Request Body:

{
"data": {
"type": "products",
"id": "prod_abc123",
"attributes": {
"price": {
"amount": 27900,
"compare_at": 29900
},
"status": "active"
}
}
}

Delete Product

Delete a product (soft delete by default).

DELETE /v1/products/:id

Query Parameters:

ParameterTypeDescription
permanentbooleanPermanently delete (default: false)

Product Variants

Variants represent different versions of a product (size, color, material).

Create Variant

POST /v1/products/:product_id/variants

Request Body:

{
"data": {
"type": "variants",
"attributes": {
"name": "Black",
"sku": "WH-PRO-2024-BLK",
"options": {
"color": "black"
},
"price_modifier": {
"type": "fixed",
"amount": 0
},
"inventory": {
"quantity": 120,
"track_stock": true
},
"weight": {
"value": 250,
"unit": "g"
},
"position": 1
}
}
}

Response:

{
"data": {
"type": "variants",
"id": "var_xyz789",
"attributes": {
"name": "Black",
"sku": "WH-PRO-2024-BLK",
"options": {
"color": "black"
},
"price": {
"amount": 29900,
"currency": "USD",
"formatted": "$299.00"
},
"inventory": {
"quantity": 120,
"in_stock": true
},
"position": 1,
"created_at": "2026-01-02T10:35:00Z"
}
}
}

List Variants

GET /v1/products/:product_id/variants

Update Variant

PATCH /v1/products/:product_id/variants/:variant_id

Delete Variant

DELETE /v1/products/:product_id/variants/:variant_id

Variant Options

Define available options for variants:

PUT /v1/products/:product_id/options

Request Body:

{
"data": {
"options": [
{
"name": "Color",
"values": ["Black", "White", "Navy Blue"]
},
{
"name": "Size",
"values": ["S", "M", "L", "XL"]
}
]
}
}

Categories

Organize products into hierarchical categories.

Create Category

POST /v1/categories

Request Body:

{
"data": {
"type": "categories",
"attributes": {
"name": "Electronics",
"slug": "electronics",
"description": "Electronic devices and accessories",
"parent_id": null,
"position": 1,
"seo": {
"title": "Electronics - Shop the Latest Tech",
"description": "Browse our selection of electronics and gadgets."
},
"metadata": {
"icon": "electronics-icon"
}
}
}
}

List Categories

GET /v1/categories

Query Parameters:

ParameterTypeDescription
filter[parent_id]stringFilter by parent (null for root)
includestringInclude: children, products, product_count
treebooleanReturn full category tree

Get Category

GET /v1/categories/:id
GET /v1/categories/slug/:slug

Update Category

PATCH /v1/categories/:id

Delete Category

DELETE /v1/categories/:id

Assign Products to Category

POST /v1/categories/:id/products

Request Body:

{
"data": {
"product_ids": ["prod_abc123", "prod_def456"]
}
}

Collections

Curated product groupings for merchandising.

Create Collection

POST /v1/collections

Request Body:

{
"data": {
"type": "collections",
"attributes": {
"name": "Summer Sale 2026",
"slug": "summer-sale-2026",
"description": "Hot deals for summer",
"type": "manual",
"status": "active",
"start_date": "2026-06-01T00:00:00Z",
"end_date": "2026-08-31T23:59:59Z",
"rules": null,
"seo": {
"title": "Summer Sale - Up to 50% Off",
"description": "Shop our biggest summer sale with discounts up to 50%."
}
}
}
}

Automated Collections

Create collections with automatic product matching:

{
"data": {
"type": "collections",
"attributes": {
"name": "New Arrivals",
"type": "automated",
"rules": {
"match": "all",
"conditions": [
{
"field": "created_at",
"operator": "greater_than",
"value": "30_days_ago"
},
{
"field": "status",
"operator": "equals",
"value": "active"
}
]
}
}
}
}

List Collections

GET /v1/collections

Get Collection Products

GET /v1/collections/:id/products

Add Products to Collection

POST /v1/collections/:id/products

Remove Products from Collection

DELETE /v1/collections/:id/products/:product_id

Inventory

Get Inventory Levels

GET /v1/products/:id/inventory

Response:

{
"data": {
"type": "inventory",
"id": "inv_abc123",
"attributes": {
"product_id": "prod_abc123",
"total_quantity": 247,
"available": 235,
"reserved": 12,
"committed": 0,
"in_stock": true,
"low_stock": false,
"locations": [
{
"location_id": "loc_warehouse1",
"name": "Main Warehouse",
"quantity": 200,
"available": 188
},
{
"location_id": "loc_store1",
"name": "Downtown Store",
"quantity": 47,
"available": 47
}
],
"updated_at": "2026-01-02T10:30:00Z"
}
}
}

Adjust Inventory

POST /v1/products/:id/inventory/adjust

Request Body:

{
"data": {
"adjustments": [
{
"location_id": "loc_warehouse1",
"quantity": 50,
"reason": "restock",
"reference": "PO-2026-001"
}
]
}
}

Set Inventory

Set absolute inventory levels:

PUT /v1/products/:id/inventory

Request Body:

{
"data": {
"locations": [
{
"location_id": "loc_warehouse1",
"quantity": 250
}
]
}
}

Reserve Inventory

Reserve stock for pending orders:

POST /v1/products/:id/inventory/reserve

Request Body:

{
"data": {
"quantity": 2,
"order_id": "ord_abc123",
"expires_at": "2026-01-02T11:30:00Z"
}
}

Response:

{
"data": {
"type": "reservation",
"id": "res_xyz789",
"attributes": {
"product_id": "prod_abc123",
"quantity": 2,
"order_id": "ord_abc123",
"status": "active",
"expires_at": "2026-01-02T11:30:00Z"
}
}
}

Release Reservation

DELETE /v1/inventory/reservations/:reservation_id

Inventory Locations

Manage warehouse and store locations:

POST /v1/inventory/locations
{
"data": {
"type": "locations",
"attributes": {
"name": "Main Warehouse",
"code": "WH-001",
"type": "warehouse",
"address": {
"line1": "123 Industrial Way",
"city": "Austin",
"state": "TX",
"postal_code": "78701",
"country": "US"
},
"is_default": true
}
}
}

Pricing

Price Tiers

Set up volume-based pricing:

PUT /v1/products/:id/price-tiers

Request Body:

{
"data": {
"tiers": [
{
"min_quantity": 1,
"max_quantity": 9,
"price": { "amount": 29900, "currency": "USD" }
},
{
"min_quantity": 10,
"max_quantity": 49,
"price": { "amount": 27900, "currency": "USD" }
},
{
"min_quantity": 50,
"max_quantity": null,
"price": { "amount": 24900, "currency": "USD" }
}
]
}
}

Customer-Specific Pricing

Set prices for specific customers or groups:

PUT /v1/products/:id/customer-prices

Request Body:

{
"data": {
"prices": [
{
"customer_group_id": "grp_wholesale",
"price": { "amount": 19900, "currency": "USD" }
},
{
"customer_id": "cust_vip123",
"price": { "amount": 22900, "currency": "USD" }
}
]
}
}

Multi-Currency Prices

PUT /v1/products/:id/prices

Request Body:

{
"data": {
"prices": [
{ "amount": 29900, "currency": "USD" },
{ "amount": 27900, "currency": "EUR" },
{ "amount": 3990000, "currency": "JPY" }
]
}
}

Scheduled Pricing

Schedule price changes:

POST /v1/products/:id/scheduled-prices

Request Body:

{
"data": {
"type": "scheduled_price",
"attributes": {
"price": { "amount": 24900, "currency": "USD" },
"compare_at": { "amount": 29900, "currency": "USD" },
"starts_at": "2026-06-01T00:00:00Z",
"ends_at": "2026-06-30T23:59:59Z",
"name": "June Sale"
}
}
}

Product Images

Upload Image

POST /v1/products/:id/images

Request Body (multipart/form-data):

file: [binary image data]
alt_text: "Premium Wireless Headphones - Black"
position: 1
is_primary: true

Response:

{
"data": {
"type": "images",
"id": "img_abc123",
"attributes": {
"url": "https://cdn.23blocks.com/products/prod_abc123/img_abc123.jpg",
"alt_text": "Premium Wireless Headphones - Black",
"position": 1,
"is_primary": true,
"width": 1200,
"height": 1200,
"thumbnails": {
"small": "https://cdn.23blocks.com/products/prod_abc123/img_abc123_100x100.jpg",
"medium": "https://cdn.23blocks.com/products/prod_abc123/img_abc123_400x400.jpg",
"large": "https://cdn.23blocks.com/products/prod_abc123/img_abc123_800x800.jpg"
}
}
}
}

List Images

GET /v1/products/:id/images

Reorder Images

PUT /v1/products/:id/images/reorder

Request Body:

{
"data": {
"image_ids": ["img_xyz789", "img_abc123", "img_def456"]
}
}

Delete Image

DELETE /v1/products/:id/images/:image_id

Object Detection for Multi-Product Images

NEW: Automatically detect multiple products in shelf photos and batch create product listings.

POST /v1/products/:id/files/:file_id/process

Request Body:

{
"processing_mode": "object_detection"
}

Response:

{
"data": {
"type": "product_file_processing",
"id": "proc_abc123",
"attributes": {
"file_id": "file_xyz789",
"objects_detected": 5,
"detection_metadata": [
{
"class": "product",
"confidence": 0.95,
"bbox": {
"x": 120,
"y": 45,
"width": 180,
"height": 240
},
"suggested_crop": "https://cdn.23blocks.com/crops/crop_001.jpg"
},
{
"class": "product",
"confidence": 0.92,
"bbox": {
"x": 320,
"y": 50,
"width": 175,
"height": 235
},
"suggested_crop": "https://cdn.23blocks.com/crops/crop_002.jpg"
}
// ... 3 more detected products
],
"processing_status": "completed",
"processed_at": "2026-06-19T10:30:00Z"
}
}
}

Use Cases:

  • Shelf Photo Upload - User uploads photo containing 5 products → system detects all 5
  • Bulk Product Creation - Create 5 individual product listings from one shelf photo
  • Visual Search Improvement - Search per-product instead of per-scene
  • Automated Cropping - Get pre-cropped product images from detection bounding boxes

Example Workflow:

// 1. Upload shelf photo
const file = await client.products.uploadFile(productId, shelfPhoto);

// 2. Process with object detection
const detection = await client.products.processFile(productId, file.id, {
processing_mode: 'object_detection'
});

// 3. Show preview to user
console.log(`Detected ${detection.objects_detected} products`);
detection.detection_metadata.forEach((obj, i) => {
console.log(`Product ${i+1}: ${obj.confidence * 100}% confidence`);
console.log(`Crop preview: ${obj.suggested_crop}`);
});

// 4. Bulk create products from detections
for (const detected of detection.detection_metadata) {
await client.products.create({
name: `Product from Shelf ${i+1}`,
image_url: detected.suggested_crop
});
}

UI Components Needed:

  • Detection preview with bounding box overlays
  • "Create X products" bulk action button
  • Individual product selection interface
  • Cropped image previews

Search Products

GET /v1/products/search

Query Parameters:

ParameterTypeDescription
qstringSearch query
filtersobjectFacet filters
sortstringSort order
pageintegerPage number
per_pageintegerResults per page
use_object_detectionbooleanNEW: Enable object detection for multi-object images (default: true)

Example - Text Search:

GET /v1/products/search?q=wireless+headphones&filters[category]=electronics&filters[price][min]=10000&filters[price][max]=50000&sort=relevance

Example - Visual Search with Object Detection (Multi-Object Image):

POST /v1/products/search
Content-Type: multipart/form-data

image: [binary image data - shelf photo with 5 wine bottles]
use_object_detection: true # Default behavior

Multi-Object Search Response:

{
"data": [
{
"type": "products",
"id": "prod_wine_123",
"attributes": {
"name": "Château Margaux 2015",
"similarity_score": 0.94,
"detection_metadata": {
"object_index": 0,
"total_objects": 5,
"class": "wine_bottle",
"confidence": 0.96,
"bbox": { "x": 120, "y": 45, "width": 180, "height": 240 }
}
}
},
{
"type": "products",
"id": "prod_wine_456",
"attributes": {
"name": "Penfolds Grange 2016",
"similarity_score": 0.91,
"detection_metadata": {
"object_index": 1,
"total_objects": 5,
"class": "wine_bottle",
"confidence": 0.94,
"bbox": { "x": 320, "y": 50, "width": 175, "height": 235 }
}
}
}
// ... matches for remaining 3 detected bottles
],
"meta": {
"total": 15,
"objects_detected": 5,
"average_detection_time": "1.8s",
"page": 1,
"per_page": 20
}
}

Behavior:

  • 0-1 objects detected: Standard single-image search (automatic fallback)
  • 2+ objects detected: Multi-object search with grouped results
  • Performance: ~500ms overhead for detection, 1.5-2.5s total for multi-object
  • Disable detection: Set use_object_detection=false to skip detection entirely

Text Search Response:

{
"data": [...],
"meta": {
"total": 45,
"page": 1,
"per_page": 20,
"facets": {
"category": [
{ "value": "electronics", "count": 32 },
{ "value": "audio", "count": 28 }
],
"brand": [
{ "value": "AudioPro", "count": 15 },
{ "value": "SoundMax", "count": 12 }
],
"price_range": [
{ "min": 10000, "max": 20000, "count": 12 },
{ "min": 20000, "max": 30000, "count": 18 },
{ "min": 30000, "max": 50000, "count": 15 }
]
},
"suggestions": ["wireless earbuds", "bluetooth headphones"]
}
}

Search Suggestions

GET /v1/products/search/suggest?q=wire

Response:

{
"data": {
"suggestions": [
"wireless headphones",
"wireless earbuds",
"wireless speakers"
],
"products": [
{
"id": "prod_abc123",
"name": "Premium Wireless Headphones",
"image": "https://cdn.23blocks.com/..."
}
]
}
}

PUT /v1/products/:id/related

Request Body:

{
"data": {
"cross_sells": ["prod_def456", "prod_ghi789"],
"up_sells": ["prod_jkl012"],
"accessories": ["prod_mno345", "prod_pqr678"]
}
}
GET /v1/products/:id/related

Query Parameters:

ParameterTypeDescription
typestringType: cross_sells, up_sells, accessories
limitintegerMaximum products to return

Product Bundles

Create Bundle

POST /v1/products

Request Body:

{
"data": {
"type": "products",
"attributes": {
"name": "Complete Audio Setup",
"sku": "BUNDLE-AUDIO-001",
"type": "bundle",
"price": {
"amount": 49900,
"currency": "USD"
},
"bundle_items": [
{
"product_id": "prod_headphones",
"quantity": 1,
"required": true
},
{
"product_id": "prod_case",
"quantity": 1,
"required": true
},
{
"product_id": "prod_cable",
"quantity": 2,
"required": false
}
],
"bundle_pricing": "fixed"
}
}
}

Webhooks

Subscribe to product events:

Available Events

EventDescription
product.createdNew product created
product.updatedProduct updated
product.deletedProduct deleted
product.publishedProduct status changed to active
inventory.low_stockInventory below threshold
inventory.out_of_stockInventory depleted
inventory.adjustedInventory level changed
variant.createdNew variant created
variant.updatedVariant updated
category.updatedCategory modified

Webhook Payload

{
"event": "inventory.low_stock",
"timestamp": "2026-01-02T10:30:00Z",
"data": {
"product_id": "prod_abc123",
"sku": "WH-PRO-2024",
"name": "Premium Wireless Headphones",
"current_quantity": 20,
"threshold": 25,
"location_id": "loc_warehouse1"
}
}

SDK Examples

JavaScript/TypeScript

import { create23BlocksClient } from '@23blocks/sdk';

const client = create23BlocksClient({
urls: { products: 'https://products.api.us.23blocks.com' },
appId: 'your-app-id',
apiKey: 'your-api-key',
});

// Create product with variants
const product = await client.products.create({
name: 'Cotton T-Shirt',
sku: 'TSHIRT-001',
price: { amount: 2500, currency: 'USD' },
options: [
{ name: 'Size', values: ['S', 'M', 'L', 'XL'] },
{ name: 'Color', values: ['White', 'Black', 'Navy'] }
]
});

// Generate variants from options
await client.products.generateVariants(product.id);

// Search products with facets
const results = await client.products.search({
query: 't-shirt',
filters: {
category: 'clothing',
size: ['M', 'L'],
price: { min: 1000, max: 5000 }
},
sort: 'price_asc'
});

// Check inventory across locations
const inventory = await client.inventory.get(product.id, {
include_locations: true
});

// Reserve inventory for cart
const reservation = await client.inventory.reserve({
product_id: product.id,
quantity: 2,
cart_id: 'cart_abc123',
expires_in: 900 // 15 minutes
});

React Example

import { useProducts, useProduct } from '@23blocks/react';

function ProductGrid() {
const { products, loading, facets, loadMore } = useProducts({
category: 'electronics',
in_stock: true,
per_page: 20
});

if (loading) return <Spinner />;

return (
<div>
<Facets data={facets} />
<div className="grid grid-cols-4 gap-4">
{products.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
<button onClick={loadMore}>Load More</button>
</div>
);
}

function ProductDetail({ id }: { id: string }) {
const { product, variants, selectVariant, selectedVariant } = useProduct(id);

return (
<div>
<h1>{product.name}</h1>
<Price amount={selectedVariant?.price || product.price} />
<VariantSelector
variants={variants}
selected={selectedVariant}
onSelect={selectVariant}
/>
<InventoryStatus stock={selectedVariant?.inventory || product.inventory} />
</div>
);
}

Error Codes

CodeDescription
PRODUCT_NOT_FOUNDProduct does not exist
SKU_ALREADY_EXISTSSKU is already in use
INVALID_PRICEPrice format is invalid
INSUFFICIENT_INVENTORYNot enough stock available
INVENTORY_RESERVEDStock is reserved for other orders
VARIANT_NOT_FOUNDVariant does not exist
CATEGORY_NOT_FOUNDCategory does not exist
INVALID_OPTION_VALUESVariant options don't match product options
BUNDLE_INVALIDBundle configuration is invalid
IMAGE_UPLOAD_FAILEDFailed to upload product image

Rate Limits

EndpointLimit
GET /products1000/minute
GET /products/:id2000/minute
POST /products100/minute
PATCH /products/:id200/minute
GET /products/search500/minute
POST /inventory/adjust500/minute
POST /inventory/reserve1000/minute

Best Practices

  1. SKU Management - Use consistent SKU formats across variants
  2. Inventory Sync - Set up webhooks for real-time stock updates
  3. Image Optimization - Use provided thumbnail URLs for performance
  4. Search Indexing - Include relevant attributes for better search results
  5. Category Structure - Keep category depth to 3-4 levels maximum
  6. Price Precision - Always use cents/smallest currency unit
  7. Reservation Expiry - Set appropriate expiration for cart reservations

Use This Block with AI Agents

This block ships an official Claude Code plugin from the public 23blocks marketplace (19 plugins, 205 skills). Your agent gets full working knowledge of this API — endpoints, identity registration, and conventions.

# one-time: add the 23blocks marketplace
claude plugin marketplace add https://github.com/23blocks-OS/ai-agents

# install this block's plugin
claude plugin install products-block

Configure BLOCKS_API_URL, BLOCKS_API_KEY, and BLOCKS_AUTH_TOKEN. Register identity first: each block is autonomous — register the user with this block's identity endpoint before private calls (only user_unique_id is required; email/phone are optional notification-routing fields).

Full reference: AI Agents & Claude Code Plugins · github.com/23blocks-OS/ai-agents