{
  "openapi": "3.0.1",
  "info": {
    "title": "Bulk Image & File Downloader: URLs, Pages or CSV to ZIP",
    "description": "$2 per 1,000 files; failed downloads are free. Download all images and files (PDFs, docs, media) from web pages, URL lists, CSV files, Google Sheets (e.g. Shopify Image Src), Shopify stores (all product images), Google Drive folders or Apify datasets into one ZIP, named by SKU. Retries.",
    "version": "0.0",
    "x-build-id": "5FYtm1fNW0obVag5L"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/chris_elder~bulk-file-downloader/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-chris_elder-bulk-file-downloader",
        "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/chris_elder~bulk-file-downloader/runs": {
      "post": {
        "operationId": "runs-sync-chris_elder-bulk-file-downloader",
        "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/chris_elder~bulk-file-downloader/run-sync": {
      "post": {
        "operationId": "run-sync-chris_elder-bulk-file-downloader",
        "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",
        "properties": {
          "urls": {
            "title": "File URLs",
            "type": "array",
            "description": "List of http(s) URLs to download. Each item is a URL string or {\"url\": \"...\", \"fileName\": \"optional.ext\", \"key\": \"optional-kv-key\"}. Provide this and/or a dataset ID below (at least one is needed). Only download files you have the right to use."
          },
          "pageUrls": {
            "title": "Web pages: download every image on them (optional)",
            "type": "array",
            "description": "Web page URLs (product pages, galleries, articles). Every image on each page is downloaded: <img> src, the largest srcset size, lazy-load data-src, <picture> sources and og:image. Turn on \"Crawl the whole website\" below to also follow the site's own links and take the images from every page found. Pages that can't be fetched are skipped and not charged. Static HTML only: images injected by JavaScript after load are not seen. Turn on \"Images only\" to skip non-image responses.",
            "items": {
              "type": "string"
            }
          },
          "maxImagesPerPage": {
            "title": "Max images per page",
            "minimum": 1,
            "maximum": 2000,
            "type": "integer",
            "description": "Cap on image URLs taken from each page in pageUrls.",
            "default": 200
          },
          "crawlWebsite": {
            "title": "Crawl the whole website (follow links from the pages above)",
            "type": "boolean",
            "description": "When on, each URL in \"Web pages\" is a start page: the Actor follows links to other pages on the same website (breadth first, same domain only, robots.txt respected) and downloads every image it finds, de-duplicated across pages. Visiting pages is free; you pay only for saved files. Use \"Max pages to crawl\" and \"Max files\" to cap the run.",
            "default": false
          },
          "maxCrawlPages": {
            "title": "Max pages to crawl",
            "minimum": 1,
            "maximum": 500,
            "type": "integer",
            "description": "Website crawl only: stop after visiting this many pages in total (start pages included).",
            "default": 20
          },
          "crawlUrlFilter": {
            "title": "Only follow links containing (optional)",
            "type": "string",
            "description": "Website crawl only: follow only links whose URL contains this text, e.g. /products/ or /gallery/. Start pages are always visited."
          },
          "shopifyStoreUrls": {
            "title": "Shopify stores, collections or products: download product images (optional)",
            "type": "array",
            "description": "Shopify store homepages (e.g. yourstore.com), /collections/<name> pages or /products/<name> pages. All product images are read from the store's public products feed at full resolution, in product order, with handle, title, SKU, position and alt text in the dataset. Up to 10,000 products per store. Listing products is free; you pay only per image saved. Use it for your own store (backup, migration, marketplace feeds) or a supplier that allows reuse of its images.",
            "items": {
              "type": "string"
            }
          },
          "shopifyFileNames": {
            "title": "Shopify file names",
            "enum": [
              "handle",
              "sku",
              "original"
            ],
            "type": "string",
            "description": "How to name Shopify images: product handle plus position (classic-tee-1.jpg), variant SKU plus position (TEE-BLK-M-1.jpg, falls back to the handle), or the original CDN file name.",
            "default": "handle"
          },
          "shopifyMainImageOnly": {
            "title": "Shopify: main image only",
            "type": "boolean",
            "description": "Save only the first (featured) image of each product.",
            "default": false
          },
          "wooStoreUrls": {
            "title": "WooCommerce stores, categories or products: download product images (optional)",
            "type": "array",
            "description": "WooCommerce store homepages (e.g. yourstore.com, or a sub-folder install like example.com/shop-site), /product-category/<name> pages or /product/<name> pages. All product images are read from the store's public WooCommerce Store API (the same product feed the shop's own blocks use) at full size, in gallery order, with slug, title, SKU, position, alt text and categories in the dataset. No WordPress login, API key or plugin. Up to 10,000 products per store. Stores whose robots.txt disallows the API are skipped. Listing products is free; you pay only per image saved. Use it for your own store (backup, migration, marketplace feeds) or a supplier that allows reuse of its images.",
            "items": {
              "type": "string"
            }
          },
          "wooFileNames": {
            "title": "WooCommerce file names",
            "enum": [
              "slug",
              "sku",
              "original"
            ],
            "type": "string",
            "description": "How to name WooCommerce images: product slug plus position (blue-hoodie-1.jpg), SKU plus position (HD-BLU-1.jpg, falls back to the slug), or the original uploaded file name.",
            "default": "slug"
          },
          "wooMainImageOnly": {
            "title": "WooCommerce: main image only",
            "type": "boolean",
            "description": "Save only the first (featured) image of each product.",
            "default": false
          },
          "driveFolderUrls": {
            "title": "Google Drive folders: download every file (optional)",
            "type": "array",
            "description": "Public Google Drive folder links (shared as \"Anyone with the link can view\"), e.g. https://drive.google.com/drive/folders/<id>, or bare folder IDs. Every file is downloaded with its Drive name, subfolders included (subfolder names become a file-name prefix), and Google Docs, Sheets and Slides are exported as PDF, XLSX and PDF. Listing folders is free; you pay only per file saved. No Google login or API key. Folder links pasted into the URL list, a CSV or a dataset are listed the same way.",
            "items": {
              "type": "string"
            }
          },
          "driveRecursive": {
            "title": "Google Drive: include subfolders",
            "type": "boolean",
            "description": "Also download files in subfolders (up to 500 folders per run).",
            "default": true
          },
          "dropboxFolderUrls": {
            "title": "Dropbox shared folders: download every file (optional)",
            "type": "array",
            "description": "Dropbox shared folder links that anyone with the link can view, e.g. https://www.dropbox.com/scl/fo/<id>/<key>?rlkey=...&dl=0 (older dropbox.com/sh/ links work too). Dropbox serves the folder as one ZIP; it is unpacked and every file is saved on its own with its Dropbox name (subfolder names become a file-name prefix). Fetching the folder is free; you pay only per file saved. No Dropbox login or app. The largest folder a run can read is about 1.6x the run's memory. Folder links pasted into the URL list, a CSV or a dataset are handled the same way.",
            "items": {
              "type": "string"
            }
          },
          "csvUrl": {
            "title": "CSV or Google Sheets link (optional)",
            "type": "string",
            "description": "Link to a CSV/TSV file or a Google Sheet shared as \"Anyone with the link can view\" (e.g. a Shopify product export with an \"Image Src\" column). The link column is detected automatically, or set \"URL field\" below to the column name. Cells holding several links (comma/space separated) are all downloaded. \"Filename field\" can name a column such as Handle or SKU. Google Drive and Dropbox share links are converted to direct downloads."
          },
          "datasetId": {
            "title": "Apify dataset ID (optional)",
            "type": "string",
            "description": "Download URLs from an Apify dataset instead of (or as well as) the list above, e.g. a scraper run's output (use the run's defaultDatasetId). Paste a dataset ID or name. Read-only access to this one dataset is requested. Rows without a URL are skipped and never charged. The 2 sample URLs above are ignored automatically when a dataset is given."
          },
          "urlField": {
            "title": "URL field in dataset",
            "type": "string",
            "description": "Field on each dataset item that holds the file URL. Dots reach nested fields (e.g. \"file.url\"). The field may also hold a list of URLs (e.g. \"images\"); each one is downloaded.",
            "default": "url"
          },
          "fileNameField": {
            "title": "Filename field in dataset (optional)",
            "type": "string",
            "description": "Optional field on each dataset row used as the saved file name (e.g. \"sku\" → sku.jpg). Dots reach nested fields. When the URL field holds a list, \"-1\", \"-2\"… is appended. Ignored for the urls list (use {url, fileName} objects there)."
          },
          "maxFiles": {
            "title": "Max files",
            "minimum": 1,
            "maximum": 5000,
            "type": "integer",
            "description": "Hard cap on downloads this run.",
            "default": 100
          },
          "maxFileBytes": {
            "title": "Max file size (bytes)",
            "minimum": 1024,
            "maximum": 52428800,
            "type": "integer",
            "description": "Skip (free) files larger than this. Default 10 MB.",
            "default": 10485760
          },
          "createZip": {
            "title": "Create ZIP archive",
            "type": "boolean",
            "description": "When true, also write OUTPUT.zip to the Key-Value store with all successful files.",
            "default": true
          },
          "zipKey": {
            "title": "ZIP key name",
            "type": "string",
            "description": "Key for the ZIP record in the default Key-Value store.",
            "default": "OUTPUT.zip"
          },
          "dedupe": {
            "title": "Deduplicate URLs",
            "type": "boolean",
            "description": "Skip duplicate URLs (after normalisation).",
            "default": true
          },
          "maxConcurrency": {
            "title": "Max concurrency",
            "minimum": 1,
            "maximum": 20,
            "type": "integer",
            "description": "Max concurrency",
            "default": 5
          },
          "requestDelayMs": {
            "title": "Per-host delay (ms)",
            "minimum": 0,
            "maximum": 10000,
            "type": "integer",
            "description": "Per-host delay (ms)",
            "default": 100
          },
          "timeoutSecs": {
            "title": "Timeout per file (seconds)",
            "minimum": 5,
            "maximum": 300,
            "type": "integer",
            "description": "Timeout per file (seconds)",
            "default": 60
          },
          "onlyImages": {
            "title": "Images only",
            "type": "boolean",
            "description": "When true, only keep responses that are images (Content-Type image/* or image magic bytes). Non-images are listed as skipped and never charged. Use this for bulk image downloader workflows.",
            "default": false
          },
          "referer": {
            "title": "Referer header (optional)",
            "type": "string",
            "description": "Optional Referer header sent with each download. Useful for product-image CDNs that block hotlinking without a store page referer (e.g. https://www.example.com/)."
          },
          "userAgent": {
            "title": "User-Agent (optional)",
            "type": "string",
            "description": "Optional User-Agent. Leave blank to use the Actor default. Some image hosts require a browser-like UA."
          },
          "maxRetries": {
            "title": "Retries on transient errors",
            "minimum": 0,
            "maximum": 5,
            "type": "integer",
            "description": "Retry each URL this many times on timeouts, network errors, HTTP 429 and 5xx. Permanent errors (404, SSRF, not-an-image) are not retried. Default 2.",
            "default": 2
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}