Skip to content
v0.3

read.bulk.products

List published products in a store; filter by category (ltree), SKU option, price range and facetable custom fields; sort; opt-in facets. projection selects a NAMED shape of the result (absent = the whole document; see the projections on the reference page). ⚠️ THE DEFAULT SHAPE IS THE WHOLE DOCUMENT and it is heavy — about 13 KB per product, so even limit=10 answers with 70–100 K characters. If you are an agent, or anything else that pays for what it reads, pass projection=feed: same published set, same page, roughly a fifth of the bytes. Served on the BULK face: the same published answer as the public read, charged to the caller’s own bulk budget instead of the shopper’s, and never to be reached by a browser.

  • Surface: GET /v1/read/bulk/products
  • Auth: ★ Bulk read (machine) — a TENANT credential is REQUIRED (no credential is unauthorized), and store must be a store of THAT tenant (another tenant’s is forbidden). The ANSWER is the public read’s, byte for byte: this store’s published assortment, no drafts, no actor. What the credential buys is the BUDGET — this face has its own RateLimit-* bucket, so walking a whole catalogue here takes nothing from the ceiling a shopper’s browser shares.
{
"additionalProperties": {
"type": "string"
},
"properties": {
"category": {
"pattern": "^[A-Za-z0-9_]+(\\.[A-Za-z0-9_]+)*$",
"type": "string"
},
"collection": {
"minLength": 1,
"type": "string"
},
"limit": {
"default": 300,
"maximum": 300,
"minimum": 1,
"type": "integer"
},
"page": {
"default": 1,
"maximum": 9007199254740991,
"minimum": 1,
"type": "integer"
},
"projection": {
"description": "Named projection of the result. Declared: full, feed. Absent = full.",
"type": "string"
},
"status": {
"enum": [
"draft",
"active",
"archived"
],
"type": "string"
},
"store": {
"minLength": 1,
"type": "string"
}
},
"required": [
"store"
],
"type": "object"
}

Open (unknown) — this capability does not declare an output schema.

Pass projection=<name>. An absent projection means full — an existing caller is unaffected. A name that is not declared here is refused (unknown_projection), never served as the default.

The whole product document, exactly as this read has always served it. This is what an absent projection means, so an existing caller is unaffected. ⚠️ It is BIG — about 13 KB per product, of which roughly three quarters is skus, so a single page of 10 is on the order of 70–100 K characters. A caller that renders a shelf wants it; a caller with a context window (an agent) almost never does, and should ask for feed.

Same shape as the result above.

The product reduced to what a shopping channel puts in a listing: identity, title, description, handle, brand, category path, the primary image, and per sku its code, price (with the promotional and compare-at prices), status, name, GTIN and its own image. It is the same published set and the same page as full — about a fifth of the bytes — for a caller that walks the whole catalog to EMIT a document (a product feed, a marketplace export). Everything a listing never prints is gone: options, rich content, sku metadata and option values.

{
"additionalProperties": false,
"properties": {
"brand_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"categories": {
"items": {
"additionalProperties": false,
"properties": {
"category_id": {
"type": "string"
},
"is_primary": {
"type": "boolean"
},
"path": {
"type": "string"
}
},
"required": [
"category_id",
"path",
"is_primary"
],
"type": "object"
},
"type": "array"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"handle": {
"type": "string"
},
"media": {
"items": {
"additionalProperties": false,
"properties": {
"kind": {
"type": "string"
},
"url": {
"type": "string"
}
},
"required": [
"kind"
],
"type": "object"
},
"type": "array"
},
"metadata": {},
"product_id": {
"type": "string"
},
"skus": {
"items": {
"additionalProperties": false,
"properties": {
"amount": {
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"code": {
"type": "string"
},
"compare_at_amount": {
"anyOf": [
{
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
{
"type": "null"
}
]
},
"currency": {
"type": "string"
},
"ean": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"id": {
"type": "string"
},
"media": {
"items": {
"additionalProperties": false,
"properties": {
"kind": {
"type": "string"
},
"url": {
"type": "string"
}
},
"required": [
"kind"
],
"type": "object"
},
"type": "array"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"promotional_price": {
"additionalProperties": false,
"properties": {
"promotional_amount": {
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
},
"unit_amount": {
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"type": "integer"
}
},
"required": [
"unit_amount",
"promotional_amount"
],
"type": "object"
},
"status": {
"type": "string"
}
},
"required": [
"id",
"code",
"amount",
"currency",
"status",
"name",
"ean",
"compare_at_amount",
"media"
],
"type": "object"
},
"type": "array"
},
"status": {
"type": "string"
},
"title": {
"type": "string"
}
},
"required": [
"product_id",
"title",
"description",
"handle",
"status",
"metadata",
"brand_id",
"categories",
"media",
"skus"
],
"type": "object"
}

invalid_params (400) · not_found (404) · unauthorized (401) · forbidden (403) · unknown_projection (400)