There are two ways to read products for enrichment: a paginated export of the whole catalog
(ideal for bulk and incremental syncs) and a targeted SKU lookup (ideal for re-enriching a
known set). Both require the catalog:read scope and both return the same product shape.
Paginated export
GET /api/enrichment/products?page=0&pageSize=100&modifiedSince=<optional>
Items per page. Clamped to the range 1–500; values outside it are coerced into range.
Optional. Return only products updated after this moment. Accepts epoch milliseconds, an
ISO-8601 instant (2026-06-01T00:00:00Z), or a local date-time (2026-06-01T00:00:00).
Use it to run incremental syncs instead of re-reading the whole catalog.
# First page of 250, only products changed since June 1
curl "https://api.verzla.com/api/enrichment/products?page=0&pageSize=250&modifiedSince=2026-06-01T00:00:00Z" \
-H "X-Api-Client-Key: sk_live_your_key_here"
Paginating through the whole catalog
async function* allProducts(modifiedSince?: string) {
let page = 0;
while (true) {
const qs = new URLSearchParams({ page: String(page), pageSize: "500" });
if (modifiedSince) qs.set("modifiedSince", modifiedSince);
const res = await enrichmentFetch(`/products?${qs}`);
const body = await res.json();
yield* body.items;
if (page >= body.totalPages - 1) break;
page++;
}
}
for await (const product of allProducts()) {
// enrich(product)
}
Only active products are returned. Results are sorted by ascending id, so the ordering is
stable across pages even while the catalog changes.
Fetch by SKU
When you already know which products to enrich, look them up directly. Send the SKUs in the request
body:
GET /api/enrichment/products/skus
Content-Type: application/json
{
"skus": ["ABC-123", "ABC-124", "XYZ-900"]
}
curl https://api.verzla.com/api/enrichment/products/skus \
-H "X-Api-Client-Key: sk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "skus": ["ABC-123", "ABC-124", "XYZ-900"] }'
This endpoint accepts at most 50 SKUs per call and rejects an empty list with
400 Bad Request. Batch larger sets into chunks of 50.
Unknown SKUs are simply absent from the response — there is no per-SKU “not found” entry, so compare
the returned SKUs against what you requested.
The product shape
Both endpoints return products in the same EnrichmentProductDto shape:
{
"id": 90210,
"sku": "ABC-123",
"externalId": "erp-55021",
"gtin": "5012345678900",
"name": "Cordless Impact Driver",
"slug": "cordless-impact-driver",
"description": "An 18V brushless impact driver...",
"attributeTemplateId": 41,
"attributes": [
{
"attribute": "Voltage",
"detail": "18",
"option": {
"optionId": 880,
"unit": "V",
"priority": 1,
"dataType": "NUMBER",
"showOnWebsite": true
}
}
],
"brand": {
"id": 12,
"name": "Acme Tools",
"website": "https://acme.example",
"slug": "acme-tools"
},
"categories": ["Power Tools", "Drivers"],
"images": ["https://cdn.verzla.com/p/abc-123/1.jpg"],
"files": ["https://cdn.verzla.com/p/abc-123/manual.pdf"]
}
| Field | Type | Role |
|---|
id, sku, externalId, gtin | identity | Match submissions back to this product |
name, slug, description | enrichable | Propose new values |
attributeTemplateId | number | The template this product is bound to |
attributes | enrichable | Current structured attributes |
brand, categories, images | read-only | Context to feed your model |
files | enrichable | Associated document references |
See the full field reference on the Get products page. Next, turn
these into proposals — Submitting proposals.