Product Management

Product endpoints let a customer integration list and inspect the products in one catalogue, including variants, offers, images, enrichment progress, and moderation state. An integration can also record whether an offer's vendor accepted Youzu's enhanced variant data.

Authenticate a product request

Product routes use the single-use bearer tokens described in Authentication. Use product:read for list, detail, and near-space requests, and product:update to record a vendor's enhancement decision. Generate a fresh token for every request. For the catalogue-free workflow, omit the catalogue ID when creating the token and never send client or catalogue IDs as product query parameters.

See Upload Product Data and Track Processing for pagination and processing readiness, and Check Moderation Results for moderation fields and completion.

Product routes

Method Path Purpose
GET /api/v1/product List and filter products
GET /api/v1/product/{id} Retrieve one product by ID
PUT /api/v1/product/offers/{offerId} Record whether the offer's vendor accepted enhanced variant data
POST /api/v1/product/search/near-space Find products in the same visual space or category
POST /api/v1/product/user-products/{productId} Save a product for the token-scoped user
DELETE /api/v1/product/user-products/{productId} Remove a product saved by the token-scoped user

List and filter products

curl "https://platform.youzu.ai/api/v1/product?page=1&limit=20&process_status=completed&in_stock=true&sort=updated_at&order=desc" \
  -H "Authorization: Bearer YOUR_TOKEN"

Query parameters use snake_case:

Parameter Description
page Page number, minimum 1; defaults to 1
limit Page size from 1 to 100; defaults to 10
search Search product names and SKUs; maximum 500 characters
category_id One category ID or comma-separated category IDs
brand_id Filter by a brand ID already returned in a product record
is_published Filter by whether a live offer is published
in_stock Filter by whether a live offer is in stock
process_status pending, processing, completed, partial, or failed
moderation_status Result status such as approved, pending, or flagged, or violation severity high, medium, or low
custom_properties URL-encoded, non-array JSON object matched against supplier properties
price_min, price_max Non-negative inclusive offer-price range; when both are present, price_min must not exceed price_max
currency Case-insensitive three-letter currency used by price filtering and sorting; normalized to uppercase and defaults to EUR
sort created_at, updated_at, or price
order asc or desc

List responses include customer-facing product records and pagination metadata:

{
  "success": true,
  "data": [
    {
      "id": "b60d9e58-2607-4ad5-a069-8ce77b8ad41d",
      "name": {"en": "Ergonomic Office Chair"},
      "price": {"USD": 299.99},
      "inStock": true,
      "isPublished": true,
      "url": "https://shop.example/products/chair-001",
      "externalRef": "CLIENT:CATALOGUE:550e8400-e29b-41d4-a716-446655440000:PRODUCT:CHAIR-001",
      "sku": "CHAIR-001",
      "versionHash": "8f2b9f1e6dd54a03",
      "images": [],
      "variants": [],
      "offers": [],
      "processStatus": "processing",
      "processing": {
        "completedStages": 3,
        "totalStages": 5,
        "currentStage": "indexing",
        "stages": [
          {"key": "ingest", "done": true},
          {"key": "images", "done": true},
          {"key": "enrichment", "done": true},
          {"key": "indexing", "done": false},
          {"key": "dedup", "done": false}
        ]
      },
      "moderation": null
    }
  ],
  "meta": {
    "currentPage": 1,
    "pageSize": 20,
    "totalPages": 4,
    "totalItems": 72
  }
}

Response bodies use camelCase. Depending on the source data and processing state, a product can also include its description, discounted price, brand, categories, identifiers, dimensions, weight, colour, custom properties, variant axes, AI-extracted and translated attributes, public image metadata, timestamps, and nullable current moderation result.

Each entry in variants can include variantValues, a dynamic map of configuration axes to values, for example {"color":"black","capacity":"256gb"}. Newly inferred keys and string values are lowercased, and keys normally use lower_snake_case. Treat the map as extensible and preserve unknown keys rather than relying on a fixed list of axes.

Understand variants and offers

A variant contains Youzu's consolidated, enhanced name, description, and attributes. Its offers represent the vendor-specific records that contributed to that variant. One variant can therefore contain offers from multiple vendors.

Every offer includes a UUID vendorId. Vendor-supplied values remain available on the offer as originalName, originalDescription, and read-only originalAttributes, so an integration can show them alongside the enhanced variant values.

vendorAcceptedEnhancement records the vendor's decision about the enhanced variant data:

  • null: no decision has been recorded.
  • true: the vendor accepted the enhanced data.
  • false: the vendor explicitly declined the enhanced data.

This field is metadata only. Changing it does not apply, regenerate, or overwrite any product, variant, or offer data.

Record vendor acceptance

Use the offer ID returned inside a variant and a fresh product:update token. The request body accepts only the required vendorAcceptedEnhancement boolean:

curl -X PUT "https://platform.youzu.ai/api/v1/product/offers/5bf718f6-75c1-4145-b88b-2a0949226d68" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"vendorAcceptedEnhancement":true}'

The response contains the updated offer:

{
  "success": true,
  "data": {
    "id": "5bf718f6-75c1-4145-b88b-2a0949226d68",
    "variantId": "9820d390-3207-4015-888c-58d546b8b40f",
    "vendorId": "bd0a6fe7-9288-4654-8770-fb3e9f670231",
    "originalName": {"en": "Office chair black"},
    "originalDescription": {"en": "Adjustable office chair"},
    "originalAttributes": {"colour": "black"},
    "vendorAcceptedEnhancement": true,
    "price": {"USD": 299.99},
    "inStock": true,
    "isPublished": true,
    "sku": "CHAIR-001-BLACK",
    "url": "https://shop.example/products/chair-001-black",
    "externalRef": "VENDOR-CHAIR-001-BLACK",
    "versionHash": "3f41982425e33cf1"
  }
}

Send false to record an explicit decline. The undecided null state is returned only before a decision; it cannot be submitted to clear or reset one. The token determines the tenant and catalogue, and the request cannot change the offer's vendor, original values, or enhanced variant data.

Search by visual space

POST /api/v1/product/search/near-space finds products in the same visual space or category as one query image. Generate a single-use product:read token and provide exactly one of these inputs:

  • file: a decodable JPEG, PNG, or WebP multipart upload no larger than 10 MiB.
  • image_url: a public HTTP or HTTPS URL without embedded credentials. Every redirect must remain on public network addresses, and the downloaded image must be a decodable JPEG, PNG, or WebP no larger than 10 MiB.
  • detectionId: the UUID returned for an object by /api/v1/object-detection; Youzu safely retrieves the cached source image and crops its validated bounding box.

For an image URL:

curl -X POST "https://platform.youzu.ai/api/v1/product/search/near-space?matchLevel=similar" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "image_url": "https://images.example.com/rooms/office.webp",
    "limit": 20
  }'

For a direct upload, send file and optional limit fields as multipart/form-data. For a cached detection, send detectionId and optional limit in JSON. limit defaults to 20 and accepts 1 through 100; the optional matchLevel query parameter is exact, similar, or broad.

The response uses the same { success, data, meta } product-list envelope shown above. A 400 indicates an invalid input or unsafe URL, 404 means a cached detection is no longer available, 413 indicates an image over 10 MiB, and 502 indicates that the remote image or product service was unavailable.

Save products for a user

Saved-product routes use the user carried by the bearer token. Supply a stable userReference when creating each token so the saved list belongs to the intended customer. Generate a separate single-use token for every operation:

  • Use product:create for POST /api/v1/product/user-products/{productId}. The product must exist in the token-scoped catalogue. Its optional JSON body can include generation_id to associate the saved item with a non-deleted Youzu generation owned by the same token-scoped user. Success returns 201 and {"message":"Product saved successfully"}.
  • Use product:delete for DELETE /api/v1/product/user-products/{productId}. Catalogue scope is stored with the saved item, so removal remains available even if the upstream product was later deleted. Success returns 204 with no response body.

The productId is a product identifier from a catalogue-scoped product response. Never reuse the read token that returned the product for a save or delete request.

Understand processing state

processStatus is the product-level summary: pending and processing are nonterminal; completed, partial, and failed are terminal. partial means some selected work failed while usable product output remains.

The processing object is authoritative for stage-level progress. It returns only stages in the catalogue's compiled, selected pipeline graph. Records use the stable keys ingest, image_acquisition, image_indexing, semantic_text_indexing, ai_processing, identity_enrichment, dedup_indexing, and deduplication, and every record includes status, required, and attemptCount. A returned stage can be skipped when runtime processing determines that no work is needed.

processing.errors contains customer-safe { code, stage, retryable } entries. Internal provider text and traces are omitted. See Upload Product Data and Track Processing for the complete status and stage table.

Moderation runs separately and appears in moderation; it is not a product-processing stage. Each applicable stageResults entry is nonterminal at pending or processing and terminal at approved, flagged, error, or skipped. The aggregate moderation.status is a summary, so inspect stage results to determine completion.

The API returns real pipeline state. It does not fabricate stock counts, generic product status, AI feature lists, or an always-completed processing value.

Handle errors

Customer-facing product routes preserve supported upstream 4xx statuses with safe messages. Upstream server and transport failures return 502 without exposing the upstream response body. A 401 generally means the token is missing, expired, outside the required product scope, or has already been consumed.