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: Use the same URL for all environments. Your API key determines the environment:

  • pk_test_* / sk_test_* → Routes to Staging
  • pk_live_* / sk_live_* → Routes to Production
import { create23BlocksClient } from '@23blocks/sdk';

const client = create23BlocksClient({
urls: { products: 'https://products.api.us.23blocks.com' },
apiKey: 'your-api-key', // Use pk_test_* for staging, pk_live_* for production
});

// 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

Search Products

GET /v1/products/search

Query Parameters:

ParameterTypeDescription
qstringSearch query
filtersobjectFacet filters
sortstringSort order
pageintegerPage number
per_pageintegerResults per page

Example:

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

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