{
  "openapi": "3.0.1",
  "info": {
    "title": "Shopify Products Data Scraper – Full Catalog, Shopify CSV",
    "description": "Every product from any Shopify store or collection: prices, variants, SKUs, barcodes, stock counts, availability, images, tags. Filter by price, sale, brand, type or stock. Overlapping collections deduped: one row, one charge per product. Watch a store: drops, restocks, new, delisted. No browser.",
    "version": "0.1",
    "x-build-id": "koyEYbpmeefswjqaL"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/fetchsmith~shopify-products-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-fetchsmith-shopify-products-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/fetchsmith~shopify-products-scraper/runs": {
      "post": {
        "operationId": "runs-sync-fetchsmith-shopify-products-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/fetchsmith~shopify-products-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-fetchsmith-shopify-products-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "required": [
          "storeUrls"
        ],
        "properties": {
          "storeUrls": {
            "title": "Store URLs",
            "type": "array",
            "description": "Shopify store homepages, collection URLs or product URLs, e.g. https://www.allbirds.com or https://www.allbirds.com/collections/mens.",
            "default": [
              "https://www.allbirds.com"
            ],
            "items": {
              "type": "string"
            }
          },
          "searchQuery": {
            "title": "Search query",
            "type": "string",
            "description": "Only return products whose title, vendor, product type or tags contain every word in this query (case-insensitive, Unicode-normalized so accented words like \"café\" match regardless of composed/decomposed input form). Applied client-side after fetching each store's catalog — Shopify's public feed has no server-side search, so this still walks the full store (same request cost as without it) but needs no collection URL guessing. Ignored for direct product URLs."
          },
          "vendors": {
            "title": "Vendors (any of)",
            "type": "array",
            "description": "Only return products whose vendor/brand contains one of these (case-insensitive, OR logic — e.g. [\"Allbirds\",\"Rothy's\"] matches either). Combines with every other filter using AND; only the entries within this list are OR'd together. Zero extra requests (vendor is already on every row). Ignored for direct product URLs.",
            "items": {
              "type": "string"
            }
          },
          "productTypes": {
            "title": "Product types (any of)",
            "type": "array",
            "description": "Only return products whose product type contains one of these (case-insensitive, OR logic), e.g. [\"Shoes\",\"Sandals\"]. Combines with every other filter using AND; only the entries within this list are OR'd together. Zero extra requests. Ignored for direct product URLs.",
            "items": {
              "type": "string"
            }
          },
          "maxProductsPerStore": {
            "title": "Max products per store",
            "minimum": 1,
            "maximum": 100000,
            "type": "integer",
            "description": "Stop after this many products for each store URL. In watch mode (\"Watch label\" set) this caps how many products are SCANNED per store instead — unchanged products aren't returned, so the diff has to walk the feed; raise it above your store's catalog size or changes further down the feed are missed.",
            "default": 500
          },
          "includeDescription": {
            "title": "Include description",
            "type": "boolean",
            "description": "Include the product description as plain text.",
            "default": true
          },
          "includeVariants": {
            "title": "Include variants",
            "type": "boolean",
            "description": "Include the full variants array (SKU, price, options, availability).",
            "default": true
          },
          "onlyAvailable": {
            "title": "Only available products",
            "type": "boolean",
            "description": "Skip products where no variant is available.",
            "default": false
          },
          "minPrice": {
            "title": "Min price",
            "minimum": 0,
            "type": "integer",
            "description": "Only return products a shopper could buy at or above this price, i.e. whose highest variant price is >= this value. Combined with \"maxPrice\" this is a price window, and a product matches when its own variant price range overlaps that window (a $40-$120 hoodie matches minPrice 100 because its $120 variant qualifies). In the store's own currency (see the `currency` output field) - no FX conversion. Filtered-out products are never charged. Apify's input schema has no decimal number type, so the Console editor takes whole units; API/JSON callers may pass decimals (e.g. 19.99) and they are honoured exactly."
          },
          "maxPrice": {
            "title": "Max price",
            "minimum": 0,
            "type": "integer",
            "description": "Only return products a shopper could buy at or below this price, i.e. whose lowest variant price is <= this value. See \"Min price\" for how a product's variant price range is matched against the window. In the store's own currency - no FX conversion. Filtered-out products are never charged. Apify's input schema has no decimal number type, so the Console editor takes whole units; API/JSON callers may pass decimals (e.g. 19.99) and they are honoured exactly."
          },
          "onSaleOnly": {
            "title": "On sale only",
            "type": "boolean",
            "description": "Only return products currently discounted, i.e. where a compare-at price is set above the current price (the same condition as the `isOnSale` output field). Products a store never set a compare-at price on are excluded. Filtered-out products are never charged.",
            "default": false
          },
          "minDiscountPercent": {
            "title": "Min discount %",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "Only return products discounted by at least this percentage, i.e. whose `discountPercent` output field is >= this value (computed from the cheapest variant's own compare-at price). Products with no discount at all (`discountPercent: null`) are excluded, not treated as 0%. Stricter than \"On sale only\", which accepts any discount. Filtered-out products are never charged."
          },
          "maxResults": {
            "title": "Max results (total)",
            "minimum": 1,
            "maximum": 200000,
            "type": "integer",
            "description": "Overall cap on the number of products across all stores.",
            "default": 5000
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Route storefront requests through Apify Proxy. Recommended: some stores rate-limit or geo-gate products.json by IP, and residential/country-specific proxies also return that country's prices and currency. Leave as-is to use automatic Apify Proxy; runs on accounts without proxy access fall back to a direct connection.",
            "default": {
              "useApifyProxy": true
            }
          },
          "detailLevel": {
            "title": "Detail level",
            "enum": [
              "basic",
              "full"
            ],
            "type": "string",
            "description": "\"Basic\" (default) uses only the store's bulk products.json feed — one request per page of products. \"Full\" additionally fetches each product's live page and its per-product .js route to read barcodes, inventory counts (inventoryQuantity / totalInventory), quantity rules (min/max/case-pack), subscription plans, SEO title/description and the star-rating summary — none of which the bulk feed carries. The two extra requests run in parallel and are charged as a single event per product. How much stock/subscription data exists is a per-store setting; unpublished values come back as null.",
            "default": "basic"
          },
          "watchLabel": {
            "title": "Watch label (change alerts)",
            "type": "string",
            "description": "Set a name (e.g. \"my-competitor-prices\") to turn this run into a catalog watch. The FIRST run under a given label + filter set records each product's price, availability and sale status and returns NOTHING (0 products charged). Every run after that returns ONLY products that are new, changed price, started or ended a sale, went out of stock, came back in stock or were removed from the catalog (delisted) — so you can schedule this Actor daily and pay only for what actually moved, instead of re-buying the whole catalog. Each returned row carries watchChange / watchChanges / previousPriceMin / previousAvailable / priceChange alongside the normal product fields. Adding a store URL to an existing label baselines just that store; changing a filter (onlyAvailable / searchQuery / vendors / productTypes / minPrice / maxPrice / onSaleOnly / minDiscountPercent) starts a fresh baseline. Leave empty for a normal one-off scrape."
          },
          "watchEvents": {
            "title": "Watch events to report",
            "type": "array",
            "description": "Optional. Only report these kinds of change in watch mode — e.g. pick \"Price drop\" alone to build a discount tracker and never pay for anything else. Leave empty for all eight. \"Went on sale\"/\"Sale ended\" fire only when a compare-at price is added or removed with the current price unchanged — a price change that also flips the sale flag is already reported as \"priceDrop\"/\"priceIncrease\" (check the row's own `isOnSale` field for the sale state in that case). \"Delisted\" is only reported for a store whose whole feed this run walked end to end (see \"Max products per store\"). Ignored when \"Watch label\" is empty.",
            "items": {
              "type": "string",
              "enum": [
                "new",
                "priceDrop",
                "priceIncrease",
                "wentOnSale",
                "saleEnded",
                "backInStock",
                "outOfStock",
                "delisted"
              ],
              "enumTitles": [
                "New product",
                "Price drop",
                "Price increase",
                "Went on sale (compare-at price newly added, current price unchanged)",
                "Sale ended (compare-at price removed, current price unchanged)",
                "Back in stock",
                "Out of stock",
                "Delisted (removed from the catalog)"
              ]
            },
            "default": []
          },
          "webhookUrl": {
            "title": "Webhook URL (notify on completion)",
            "type": "string",
            "description": "Optional. An http(s) URL to POST a small JSON summary to when the run finishes — products pushed, the per-change-type counts if a watch label is set, and the run's dataset ID so you can fetch the results. A convenience for callers who want a completion ping without configuring an Apify platform webhook per Task. Best-effort: a failed or slow webhook is logged as a warning and never fails the run or affects charging. Leave empty to skip."
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}