Skip to main content
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>
page
integer
default:"0"
Zero-based page index.
pageSize
integer
default:"100"
Items per page. Clamped to the range 1–500; values outside it are coerced into range.
modifiedSince
string
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"]
}
FieldTypeRole
id, sku, externalId, gtinidentityMatch submissions back to this product
name, slug, descriptionenrichablePropose new values
attributeTemplateIdnumberThe template this product is bound to
attributesenrichableCurrent structured attributes
brand, categories, imagesread-onlyContext to feed your model
filesenrichableAssociated document references
See the full field reference on the Get products page. Next, turn these into proposals — Submitting proposals.