Back

    Buyamia Directory API

    v1.1.0

    Products

    Product responses embed product_variants and product_pricing_tiers. The pricing-tier key is an alias over the pricing_tiers table — the JSON field name partners consume is and stays product_pricing_tiers.

    GET
    /v1/products

    List products with variants, pricing tiers and a nested `businesses` summary. Filters: `business_id`, `category_id`, `status`, `visibility` (internal scope only), `limit`, `offset`.

    products.read
    Example response (truncated)json
    {
      "data": [
        {
          "id": "7ab2…",
          "name": "Ergonomic office chair",
          "slug": "ergonomic-office-chair",
          "status": "active",
          "visibility": "public",
          "base_price": 1450000,
          "currency": "IDR",
          "business_id": "c3a1…",
          "businesses": { "id": "c3a1…", "name": "Bali Teak Works", "slug": "bali-teak-works" },
          "product_variants": [],
          "product_pricing_tiers": [
            { "id": "aa11…", "min_quantity": 50, "price": 1320000, "currency": "IDR" }
          ]
        }
      ],
      "total": 1842,
      "limit": 20,
      "offset": 0
    }

    Without products.internal.read, results are filtered to status = active AND visibility = public, and ?visibility= / ?status= cannot widen that.

    GET
    /v1/products/:id

    Single product with variants, pricing tiers and business summary. 404 when it is not active + public and the key lacks `products.internal.read`.

    products.read
    POST
    /v1/products

    Create a product. Slug is generated from the name. Fires `product.created`.

    products.write
    Request bodyjson
    {
      "business_id": "c3a1…",
      "name": "Ergonomic office chair",
      "description": "Mesh back, adjustable lumbar.",
      "category_id": "8f2b…",
      "base_price": 1450000,
      "currency": "IDR",
      "unit_of_measure": "piece",
      "status": "active",
      "visibility": "public"
    }

    Always send currency alongside base_price. If omitted the record is stored as IDR, which silently mis-prices non-IDR catalogs.

    PUT
    /v1/products/:id

    Partial update. Fires `product.updated` with the changed field names.

    products.write
    GET
    /v1/products/:id/price-history

    Historical price points for a product, newest first. Applies the same visibility guard as the product detail route: a non-public product returns 404 unless the key has `products.internal.read`.

    products.read
    Current as of API 1.1.0 — released 7 September 2026