> ## Documentation Index
> Fetch the complete documentation index at: https://docs.omnicommerce.sg/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Product

> Queue a single-product create workflow for the authenticated organization. Product enrichment is disabled by default; set `workflow.enrich` to `true` to enable it.

### Request behavior

- `product` contains developer-supplied fields. Unknown fields are preserved as enrichment context.
- SKU is the unique product upsert identifier.
- Externally hosted HTTP(S) images are copied to managed R2 storage.
- `targetMarketplaces` and `targetCountries` are optional; enrichment can run without publishing targets.

### Asynchronous result

The API returns a job ID. Poll `GET /api/v1/jobs/{jobId}` for completion. Product creation, image ingestion, enrichment, and taxonomy assignment run in the same product workflow job. ACO generation runs separately when enabled; poll `result.geoJobId` for its completion.



## OpenAPI

````yaml /openapi.json post /api/v1/products
openapi: 3.1.0
info:
  title: OmniCommerce API
  version: 1.0.0
  license:
    name: Proprietary
    url: https://omnicommerce.sg/terms
  description: >-
    OmniCommerce API surface for agents and developer integrations. Includes
    public endpoints (merchant discovery, product search, compare, catalog, ACO
    retrieval) and authenticated endpoints (product management via API key
    Bearer tokens).
servers:
  - url: https://omnicommerce.sg
    description: Production
  - url: http://localhost:3000
    description: Local development
security: []
tags:
  - name: agentic-checkout
    description: Merchant-fulfilled agentic checkout
    x-group: Agentic Checkout
  - name: aops
    description: Agent operating procedures
    x-group: AOPs
  - name: commerce
    description: Root commerce discovery
    x-group: Commerce
  - name: developer-platform
    description: Authenticated developer platform APIs
    x-group: Developer Platform
  - name: looks
    description: AI-styled product looks
    x-group: Looks
  - name: oauth
    description: OAuth token endpoints
    x-group: OAuth
  - name: orders
    description: Workspace and agentic orders
    x-group: Orders
  - name: organizations
    description: Organization management
    x-group: Organizations
  - name: price-books
    description: Marketplace list-price markup rules
    x-group: Price Books
  - name: products
    description: Product CRUD, bulk import, and publish
    x-group: Products
  - name: promotions
    description: Central promotions and marketplace sync
    x-group: Promotions
  - name: public-agent
    description: Public agent discovery and catalog APIs
    x-group: Public Agent
  - name: returns
    description: returns
    x-group: Returns
  - name: settlements
    description: settlements
    x-group: Settlements
  - name: ucp
    description: Universal Commerce Protocol
    x-group: UCP
paths:
  /api/v1/products:
    post:
      tags:
        - products
      summary: Create Product
      description: >-
        Queue a single-product create workflow for the authenticated
        organization. Product enrichment is disabled by default; set
        `workflow.enrich` to `true` to enable it.


        ### Request behavior


        - `product` contains developer-supplied fields. Unknown fields are
        preserved as enrichment context.

        - SKU is the unique product upsert identifier.

        - Externally hosted HTTP(S) images are copied to managed R2 storage.

        - `targetMarketplaces` and `targetCountries` are optional; enrichment
        can run without publishing targets.


        ### Asynchronous result


        The API returns a job ID. Poll `GET /api/v1/jobs/{jobId}` for
        completion. Product creation, image ingestion, enrichment, and taxonomy
        assignment run in the same product workflow job. ACO generation runs
        separately when enabled; poll `result.geoJobId` for its completion.
      operationId: post_v1_products
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - product
              properties:
                product:
                  type: object
                  description: >-
                    Single product payload. `sku` and `title` are required for
                    create/upsert. Known fields are normalized; arbitrary extra
                    fields are preserved and passed to enrichment.
                  required:
                    - sku
                    - title
                  additionalProperties: true
                  properties:
                    id:
                      type: string
                      description: Optional external/source product ID.
                    sku:
                      type: string
                      description: Unique SKU used as the product upsert identifier.
                      maxLength: 200
                    title:
                      type: string
                      maxLength: 400
                    name:
                      type: string
                      description: Alias accepted for `title`.
                      maxLength: 400
                    brand:
                      type: string
                      maxLength: 160
                    description:
                      type: string
                      description: >-
                        Original product description or source evidence for
                        enrichment.
                    price:
                      oneOf:
                        - type: number
                        - type: string
                      description: Product selling price.
                    costPrice:
                      oneOf:
                        - type: number
                        - type: string
                      description: >-
                        Unit cost basis for COGS. Persisted as top-level
                        `product_data.costPrice`.
                    inventory:
                      oneOf:
                        - type: integer
                          minimum: 0
                        - type: string
                        - type: object
                          properties:
                            quantity:
                              type: integer
                              minimum: 0
                      description: >-
                        Inventory quantity. Objects with `quantity` are
                        accepted.
                    weight:
                      oneOf:
                        - type: number
                        - type: string
                      description: >-
                        Product weight in grams. No `weightUnit` field is
                        required.
                    dimensions:
                      oneOf:
                        - type: object
                          properties:
                            length:
                              type: number
                              minimum: 0
                            width:
                              type: number
                              minimum: 0
                            height:
                              type: number
                              minimum: 0
                        - type: string
                      description: >-
                        Product dimensions. Strings such as `Length 17cm x
                        Height 11cm x Width 9cm` are parsed when possible.
                    images:
                      type: array
                      items:
                        type: string
                        format: uri
                        maxLength: 2048
                        pattern: ^[Hh][Tt][Tt][Pp][Ss]?://
                      description: >-
                        Array of HTTP(S) image URL strings only. Image objects
                        and delimited strings are not accepted. Each entry is a
                        complete URL, including commas in paths or query
                        strings. Images follow array order. Images are mirrored
                        to R2 before storage. At least one URL is required
                        unless automatic image sourcing is enabled; data
                        URI/base64 images are not supported.
                    category:
                      type: string
                    categoryName:
                      type: string
                    category_name:
                      type: string
                    product_type:
                      type: string
                      description: Alias/source hint used for category name when present.
                    marketplaces:
                      type: object
                      additionalProperties: true
                      description: >-
                        Select connected stores with
                        `product.marketplaces.<platform>.storeId` and set each
                        store's `country`. This request supports one store and
                        country per marketplace.


                        Get store IDs from `GET /api/v1/marketplaces/connected`
                        ([List Connected
                        Marketplaces](/api-reference/developer-platform/list-connected-marketplaces)).
                        Copy `storeId` from the matching entry in
                        `connectedMarketplaces`; use a store connected to the
                        authenticated organization.


                        Use an ISO 3166-1 alpha-2 country code, such as `sg` or
                        `my`. Codes are trimmed and normalized to lowercase.
                        Country names such as `Singapore`, custom values, and
                        `global` are rejected with HTTP 400. Country is not
                        inferred from storeId.


                        When top-level `targetMarketplaces` and
                        `targetCountries` are omitted, targets are inferred from
                        these entries. A marketplace's `country` takes
                        precedence over the first top-level target country for
                        its saved assignment.


                        To enrich and assign categories, brands, and attributes
                        without human approval, set both `workflow.enrich` and
                        `workflow.autoAssignMarketplaceTaxonomy` to `true`; both
                        default to `false`. This saves the product in Omni;
                        publishing is a separate action.


                        Example value for `product.marketplaces`:


                        ```json

                        {
                          "shopee": {
                            "enabled": true,
                            "country": "sg",
                            "storeId": "YOUR_SHOPEE_STORE_ID"
                          },
                          "lazada": {
                            "enabled": true,
                            "country": "sg",
                            "storeId": "YOUR_LAZADA_STORE_ID"
                          }
                        }

                        ```
                      properties:
                        shopee:
                          type: object
                          additionalProperties: true
                          properties:
                            enabled:
                              type: boolean
                              description: >-
                                Enable this marketplace on the product. On
                                create, when top-level targetMarketplaces is
                                omitted, entries with enabled set to true or
                                omitted become targets.
                            country:
                              $ref: '#/components/schemas/ProductCountryCode'
                            storeId:
                              type: string
                              maxLength: 255
                              description: >-
                                Connected store ID. Copy
                                connectedMarketplaces[].storeId from GET
                                /api/v1/marketplaces/connected for this
                                marketplace and country.
                        lazada:
                          type: object
                          additionalProperties: true
                          properties:
                            enabled:
                              type: boolean
                              description: >-
                                Enable this marketplace on the product. On
                                create, when top-level targetMarketplaces is
                                omitted, entries with enabled set to true or
                                omitted become targets.
                            country:
                              $ref: '#/components/schemas/ProductCountryCode'
                            storeId:
                              type: string
                              maxLength: 255
                              description: >-
                                Connected store ID. Copy
                                connectedMarketplaces[].storeId from GET
                                /api/v1/marketplaces/connected for this
                                marketplace and country.
                        tiktok:
                          type: object
                          additionalProperties: true
                          properties:
                            enabled:
                              type: boolean
                              description: >-
                                Enable this marketplace on the product. On
                                create, when top-level targetMarketplaces is
                                omitted, entries with enabled set to true or
                                omitted become targets.
                            country:
                              $ref: '#/components/schemas/ProductCountryCode'
                            storeId:
                              type: string
                              maxLength: 255
                              description: >-
                                Connected store ID. Copy
                                connectedMarketplaces[].storeId from GET
                                /api/v1/marketplaces/connected for this
                                marketplace and country.
                        shopify:
                          type: object
                          additionalProperties: true
                          properties:
                            enabled:
                              type: boolean
                              description: >-
                                Enable this marketplace on the product. On
                                create, when top-level targetMarketplaces is
                                omitted, entries with enabled set to true or
                                omitted become targets.
                            country:
                              $ref: '#/components/schemas/ProductCountryCode'
                            storeId:
                              type: string
                              maxLength: 255
                              description: >-
                                Connected store ID. Copy
                                connectedMarketplaces[].storeId from GET
                                /api/v1/marketplaces/connected for this
                                marketplace and country.
                        zalora:
                          type: object
                          additionalProperties: true
                          properties:
                            enabled:
                              type: boolean
                              description: >-
                                Enable this marketplace on the product. On
                                create, when top-level targetMarketplaces is
                                omitted, entries with enabled set to true or
                                omitted become targets.
                            country:
                              $ref: '#/components/schemas/ProductCountryCode'
                            storeId:
                              type: string
                              maxLength: 255
                              description: >-
                                Connected store ID. Copy
                                connectedMarketplaces[].storeId from GET
                                /api/v1/marketplaces/connected for this
                                marketplace and country.
                        amazon:
                          type: object
                          additionalProperties: true
                          properties:
                            enabled:
                              type: boolean
                              description: >-
                                Enable this marketplace on the product. On
                                create, when top-level targetMarketplaces is
                                omitted, entries with enabled set to true or
                                omitted become targets.
                            country:
                              $ref: '#/components/schemas/ProductCountryCode'
                            storeId:
                              type: string
                              maxLength: 255
                              description: >-
                                Connected store ID. Copy
                                connectedMarketplaces[].storeId from GET
                                /api/v1/marketplaces/connected for this
                                marketplace and country.
                variants:
                  type: array
                  description: >-
                    Optional variant rows to create under the root product.
                    Arbitrary variant fields are accepted; `variationAttributes`
                    or `attributes` are normalized when present.
                  items:
                    type: object
                    additionalProperties: true
                    properties:
                      sku:
                        type: string
                      price:
                        oneOf:
                          - type: number
                          - type: string
                      inventory:
                        oneOf:
                          - type: integer
                          - type: string
                      variationAttributes:
                        type: object
                        additionalProperties:
                          type: string
                      attributes:
                        type: object
                        additionalProperties: true
                variationSchema:
                  type: object
                  description: >-
                    Optional variation schema, e.g. `{ "color": ["BLUE",
                    "BLACK"] }`.
                  additionalProperties:
                    type: array
                    items:
                      type: string
                targetMarketplaces:
                  type: array
                  description: >-
                    Optional marketplace targets. Product creation/enrichment
                    works when omitted.
                  items:
                    type: string
                    enum:
                      - shopee
                      - lazada
                      - tiktok
                      - shopify
                      - zalora
                      - amazon
                targetCountries:
                  type: array
                  description: >-
                    Optional country codes for marketplace and ACO workflows.
                    Uses the same country enum as
                    product.marketplaces.<platform>.country. Codes are
                    normalized to lowercase; country names and custom values are
                    rejected.
                  items:
                    $ref: '#/components/schemas/ProductCountryCode'
                model:
                  type: string
                  description: Optional enrichment model override.
                additionalInstructions:
                  type: string
                  maxLength: 4000
                  description: >-
                    Optional instructions applied to LLM enrichment and image
                    handling. For example, exclude images tagged as size charts,
                    maps, or cluttered supplier feed shots.
                workflow:
                  type: object
                  description: Optional workflow switches.
                  properties:
                    enrich:
                      type: boolean
                      default: false
                      description: >-
                        Enable AI product enrichment. Defaults to false when
                        omitted, including when the workflow object is omitted.
                    aco:
                      type: boolean
                      default: true
                      description: >-
                        Defaults to true. Queues a separate asynchronous ACO
                        generation job after the product is written, or reuses
                        an active ACO job. Poll the returned `result.geoJobId`
                        for ACO completion. Set to false to run product
                        creation, enrichment, and taxonomy assignment without
                        starting an ACO job.
                    publish:
                      type: boolean
                      default: false
                    syncBack:
                      type: boolean
                      default: false
                      description: >-
                        Reserved for future source-store sync-back. Accepted for
                        forward compatibility, but currently does not trigger a
                        source update.
                    sourceImagesAutomatically:
                      type: boolean
                      default: false
                      description: >-
                        When true, permits products without submitted image URLs
                        and lets enrichment use the Source Product Images tool
                        to find official brand-site gallery photos. Requires
                        `workflow.enrich: true` to source images.
                    enableRichDescription:
                      type: boolean
                      default: false
                      description: >-
                        When true, asks enrichment to produce slot-based Rich
                        Content Descriptions (Markdown With Images). Description
                        image URLs are converted to slot:// placeholders and
                        must be distinct from product gallery image URLs.
                    skipBackgroundRemoval:
                      type: boolean
                      default: false
                      description: >-
                        When true, skips automatic background removal during
                        image ingestion.
                    enableMannequinRemoval:
                      type: boolean
                      default: false
                      description: >-
                        When true, queues separate ghost mannequin removal jobs
                        for eligible product images after ingestion. Their IDs
                        are returned in
                        `result.imageProcessing.ghostMannequinQueuedJobIds`.
                    autoAssignMarketplaceTaxonomy:
                      type: boolean
                      default: false
                      description: >-
                        Defaults to false. Set to true together with
                        `workflow.enrich: true` and marketplace/country targets
                        to automatically resolve and save marketplace
                        categories, brands, and attributes without human
                        approval. Existing assigned taxonomy is preserved.
                        Low-confidence matches and missing required attributes
                        are reported in the job result warnings; publishing
                        remains a separate step.
                    excludedImageTags:
                      oneOf:
                        - type: string
                        - type: array
                          maxItems: 50
                          items:
                            type: string
                            maxLength: 120
                      description: >-
                        Optional comma-separated string or string array of
                        normalized image tags to exclude from the saved product
                        gallery after image tagging.
                    customImageTags:
                      type: array
                      maxItems: 20
                      items:
                        type: object
                        required:
                          - name
                          - description
                        additionalProperties: false
                        properties:
                          name:
                            type: string
                            maxLength: 120
                            description: >-
                              Seller-defined tag name. Normalized to snake_case
                              before tagging.
                          description:
                            type: string
                            maxLength: 280
                            description: >-
                              Natural-language instruction describing what the
                              vision model should look for before adding this
                              tag.
                      description: >-
                        Seller-defined image tags evaluated by the same image
                        tagging step as built-in tags. Use `excludedImageTags`
                        separately when matching tagged images should be removed
                        from the saved gallery.
            example:
              product:
                id: cml55mqcq06vwo20ialgr54ry
                sku: TZVBGTB82269
                sku_tpp: TZVBGTB82269
                sku_ori: '63074830'
                title: Navy Blue Leather Tote and Crossbody Bag
                brand: ZADIG & VOLTAIRE
                status: ACTIVE
                price: '600'
                compare_at_price: '720'
                cost_per_item: '425.4'
                description: >-
                  Gender: Women Brand: ZADIG & VOLTAIRE Product Name: Zadig &
                  Voltaire Navy Blue Leather Tote and Crossbody Bag Condition: A
                  Color: navy blue Material: lamb leather Origin: Tunisia
                  Includes: dust bag
                images:
                  - https://api.example.com/images/1.jpg
                  - https://api.example.com/images/2.jpg
                category: BAGS
                category_name: SHOULDER BAGS
                color: BLUE
                condition: GOOD
                gender: WOMEN
                material: LEATHER
                inventory: '1'
                dimensions: Length 17cm x Height 11cm x Width 9cm
                weight: 450
                product_type: SHOULDER BAGS
                marketplaces:
                  shopee:
                    enabled: true
                    country: sg
                    storeId: YOUR_SHOPEE_STORE_ID
                  lazada:
                    enabled: true
                    country: sg
                    storeId: YOUR_LAZADA_STORE_ID
              variants:
                - sku: TZVBGTB82269-BLUE
                  price: '600'
                  variationAttributes:
                    color: BLUE
              additionalInstructions: >-
                Exclude images that are size charts, maps, or cluttered supplier
                feed shots.
              targetMarketplaces:
                - shopee
                - lazada
              targetCountries:
                - sg
              workflow:
                enrich: false
                aco: true
                sourceImagesAutomatically: false
                enableRichDescription: false
                skipBackgroundRemoval: false
                enableMannequinRemoval: true
                autoAssignMarketplaceTaxonomy: false
                customImageTags:
                  - name: model_holding_bag
                    description: person is holding or wearing the bag
                excludedImageTags:
                  - phone
                  - logo
                  - size_reference
      responses:
        '202':
          description: Product create/enrich workflow accepted
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  apiVersion:
                    type: string
                    default: developer_v1
                  operationId:
                    type: string
                  status:
                    type: string
                  jobId:
                    type: string
                  warnings:
                    type: array
                    items:
                      type: string
                  recommendations:
                    type: array
                    items:
                      type: string
                  links:
                    type: object
                    additionalProperties:
                      type: string
                  data:
                    type: object
                    properties:
                      normalizedInput:
                        type: object
                      issues:
                        type: array
                        items:
                          type: object
                      targetMarketplaces:
                        type: array
                        items:
                          type: string
                      targetCountries:
                        type: array
                        items:
                          type: string
        '400':
          description: Bad Request - Invalid product data
        '401':
          description: Unauthorized - Invalid or missing Bearer token
        '403':
          description: Forbidden - Token not authorized for this organization
        '500':
          description: Internal Server Error
      security:
        - bearerAuth: []
components:
  schemas:
    ProductCountryCode:
      type: string
      enum:
        - ad
        - ae
        - af
        - ag
        - ai
        - al
        - am
        - ao
        - aq
        - ar
        - as
        - at
        - au
        - aw
        - ax
        - az
        - ba
        - bb
        - bd
        - be
        - bf
        - bg
        - bh
        - bi
        - bj
        - bl
        - bm
        - bn
        - bo
        - bq
        - br
        - bs
        - bt
        - bv
        - bw
        - by
        - bz
        - ca
        - cc
        - cd
        - cf
        - cg
        - ch
        - ci
        - ck
        - cl
        - cm
        - cn
        - co
        - cr
        - cu
        - cv
        - cw
        - cx
        - cy
        - cz
        - de
        - dj
        - dk
        - dm
        - do
        - dz
        - ec
        - ee
        - eg
        - eh
        - er
        - es
        - et
        - fi
        - fj
        - fk
        - fm
        - fo
        - fr
        - ga
        - gb
        - gd
        - ge
        - gf
        - gg
        - gh
        - gi
        - gl
        - gm
        - gn
        - gp
        - gq
        - gr
        - gs
        - gt
        - gu
        - gw
        - gy
        - hk
        - hm
        - hn
        - hr
        - ht
        - hu
        - id
        - ie
        - il
        - im
        - in
        - io
        - iq
        - ir
        - is
        - it
        - je
        - jm
        - jo
        - jp
        - ke
        - kg
        - kh
        - ki
        - km
        - kn
        - kp
        - kr
        - kw
        - ky
        - kz
        - la
        - lb
        - lc
        - li
        - lk
        - lr
        - ls
        - lt
        - lu
        - lv
        - ly
        - ma
        - mc
        - md
        - me
        - mf
        - mg
        - mh
        - mk
        - ml
        - mm
        - mn
        - mo
        - mp
        - mq
        - mr
        - ms
        - mt
        - mu
        - mv
        - mw
        - mx
        - my
        - mz
        - na
        - nc
        - ne
        - nf
        - ng
        - ni
        - nl
        - 'no'
        - np
        - nr
        - nu
        - nz
        - om
        - pa
        - pe
        - pf
        - pg
        - ph
        - pk
        - pl
        - pm
        - pn
        - pr
        - ps
        - pt
        - pw
        - py
        - qa
        - re
        - ro
        - rs
        - ru
        - rw
        - sa
        - sb
        - sc
        - sd
        - se
        - sg
        - sh
        - si
        - sj
        - sk
        - sl
        - sm
        - sn
        - so
        - sr
        - ss
        - st
        - sv
        - sx
        - sy
        - sz
        - tc
        - td
        - tf
        - tg
        - th
        - tj
        - tk
        - tl
        - tm
        - tn
        - to
        - tr
        - tt
        - tv
        - tw
        - tz
        - ua
        - ug
        - um
        - us
        - uy
        - uz
        - va
        - vc
        - ve
        - vg
        - vi
        - vn
        - vu
        - wf
        - ws
        - ye
        - yt
        - za
        - zm
        - zw
      description: >-
        ISO 3166-1 alpha-2 country code, for example sg or my. Codes are trimmed
        and normalized to lowercase. Country names, custom values, and global
        are rejected. Select the country for the connected store explicitly.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API Key
      description: >-
        Bearer API key for server-to-server access. Session auth is also
        supported in first-party UI flows.

````