Upload and Retrieve a Provisioned Catalogue

This guide is for an account where Youzu has already created one empty catalogue and selected its categories, attributes, and moderation ruleset. You receive an API key; you do not need a catalogue ID.

The workflow has three API operations:

  1. Submit product data with the API key.
  2. Create a single-use product:read token with the API key.
  3. Use a fresh token for each page of GET /api/v1/product until every submitted product has reached a terminal processing and moderation state.

Keep the API key on your server. Do not put it in browser code, a mobile application, source control, or a product-data file.

Before You Start

Set the production API base URL and your API key in the environment used by your server-side integration:

export YOUZU_API_BASE="https://platform.youzu.ai"
export YOUZU_CLIENT_KEY="YOUR_CLIENT_KEY"

Prepare each input record according to the Product Data Requirements. Keep a copy of every submitted SKU; you will use those SKUs to determine when the batch is ready.

1. Submit Product Data

Both supported ingestion methods use the same catalogue-free endpoint:

POST /api/v1/admin/catalogue/ingest
x-client-key: YOUR_CLIENT_KEY
Content-Type: application/json

The Product Data Requirements are the canonical input-field contract for both methods. Neither method accepts a client or catalogue ID from the customer.

A 200 response means Youzu accepted the asynchronous ingestion request. It does not mean that image processing, AI enrichment, deduplication, or moderation has finished. Use the product list in the next steps as the source of truth for progress and results.

2. Create a Product Read Token

Create a token immediately before each product-list request using the authentication flow:

POST /api/v1/token
x-client-key: YOUR_CLIENT_KEY
Content-Type: application/json

{
  "actionResource": "product",
  "actionType": "read"
}

The API derives the provisioned catalogue from the key. The returned token is valid for five minutes and single-use: pagination, polling, and retries each require another token.

3. Retrieve Every Product Page

Use the token once to request the first page:

curl "$YOUZU_API_BASE/api/v1/product?page=1&limit=100" \
  -H "Authorization: Bearer YOUR_TOKEN"

The product-list response contains full product records in data and pagination state in meta. Fetch pages 1 through meta.totalPages, creating a fresh token before every page. Do this again on each polling pass so that products added or merged during processing are not missed.

Each product record includes the original product data plus the currently available AI enrichment, variants, nested offers, processing details, and current moderation result. The list returns current state, not a historical snapshot of the ingestion request.

Decide When the Submitted Data Is Ready

Evaluate only the SKUs from the batch you submitted:

  • Reconcile each submitted SKU against variants[].offers[].sku. Do not rely only on the top-level product.sku, which represents one offer.
  • Deduplication can merge multiple submitted SKUs into variants and offers under one product. For that reason, meta.totalItems can be lower than the number of submitted SKUs.
  • processStatus is terminal when it is completed or failed. The values pending and processing are not terminal.
  • moderation.status is terminal when it is approved, flagged, error, or skipped. A missing or null moderation result, pending, and processing are not terminal.

The submitted batch is ready when every submitted SKU is present and its containing product has both terminal states. Treat failed, flagged, and error as completed states that require attention; do not wait for them to become successful automatically.

Export the Current Product Records

The following dependency-free Node.js script retrieves all current pages and writes one complete product JSON object per line. It creates a new token for every page as required:

const baseUrl = process.env.YOUZU_API_BASE ?? 'https://platform.youzu.ai'
const clientKey = process.env.YOUZU_CLIENT_KEY

if (!clientKey) throw new Error('YOUZU_CLIENT_KEY is required')

async function createReadToken() {
  const response = await fetch(`${baseUrl}/api/v1/token`, {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
      'x-client-key': clientKey
    },
    body: JSON.stringify({
      actionResource: 'product',
      actionType: 'read'
    })
  })
  if (!response.ok) throw new Error(`Token request failed: ${response.status}`)
  return (await response.json()).token
}

let page = 1
let totalPages = 1

do {
  const token = await createReadToken()
  const response = await fetch(
    `${baseUrl}/api/v1/product?page=${page}&limit=100`,
    { headers: { authorization: `Bearer ${token}` } }
  )
  if (!response.ok) throw new Error(`Product page ${page} failed: ${response.status}`)

  const body = await response.json()
  for (const product of body.data) process.stdout.write(`${JSON.stringify(product)}\n`)

  totalPages = body.meta.totalPages
  page += 1
} while (page <= totalPages)

Save it as export-products.mjs, then run:

node export-products.mjs > products.ndjson

Repeat the export whenever you need a new view of the current enriched and moderated catalogue.

Relevant Errors

  • 400 from catalogue ingestion means the submitted product data or ingestion source is invalid.
  • 401 means the API key or bearer token is missing, invalid, expired, outside the required scope, or already consumed.
  • 404 from token creation or catalogue ingestion means no enabled catalogue is provisioned for the key.
  • 409 means the key currently resolves to more than one enabled catalogue and Youzu must correct the account provisioning.
  • 413 means the JSON request or upstream ingestion payload is too large.
  • 429 means product ingestion is temporarily rate limited; retry the ingestion request later.
  • 502 means the product or ingestion service was unavailable or returned an invalid response. Create a fresh token before retrying a product-list request.