# Web Image Downloader Scraper (`automation-lab/web-image-downloader`) Actor

Download images in bulk from direct URLs or public web pages and export original files with source URLs, MIME types, byte sizes, dimensions, alt text, filenames, and SHA-256 hashes.

- **URL**: https://apify.com/automation-lab/web-image-downloader.md
- **Developed by:** [Automation Lab](https://apify.com/automation-lab) (community)
- **Categories:** Developer tools, Automation, SEO tools
- **Features:** Limited permissions
- **Stats:** 46 total users, 9 monthly users, 99.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.41 / 1,000 item extracteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Web Image Downloader Scraper

Download original image files in bulk from direct image URLs or anonymously reachable public web pages.
This **web image downloader** saves every accepted image to Apify storage and returns structured metadata for asset inventories, migrations, audits, and scheduled comparisons.

Supply one URL or a batch of URLs.
The Actor distinguishes image responses from HTML pages automatically.
For pages, it discovers standard `<img>`, `srcset`, lazy-load, `<picture>`, Open Graph, and Twitter image references.
For direct images, it saves the response without HTML parsing.

### What does Web Image Downloader do?

Web Image Downloader turns public web images into reusable files plus clean dataset records.
For each unique downloaded file it provides:

- the original input and source-page URL;
- the discovered and final redirected image URL;
- the original image bytes in the run's key-value store;
- filename, MIME type, extension, and byte size;
- width and height when the format exposes dimensions;
- page alt text when present;
- a SHA-256 content hash for exact duplicate checks;
- a timestamp and authenticated Apify file API link.

It downloads the original HTTP response bytes.
It does not resize, recompress, convert, or watermark images.

### Who is it for?

**Content migration teams** can collect image assets before moving a public site to a new CMS.

**SEO and accessibility specialists** can compare image files, dimensions, and available alt text from supplied pages.

**Developers and data engineers** can feed stable file URLs and hashes into ETL, computer-vision, deduplication, or archival workflows.

**Brand and ecommerce operators** can build a bounded inventory of anonymously accessible image assets from pages they are authorized to process.

**Researchers** can schedule the same public pages and compare SHA-256 hashes between runs to identify changed files.

### Why use this instead of a browser extension?

A browser extension is useful for a one-off manual download on one computer.
This Actor is designed for repeatable cloud automation:

- process many supplied URLs in one run;
- save files and metadata together;
- call the workflow through an API;
- schedule recurring runs;
- connect results to webhooks, datasets, and other Actors;
- enforce a predictable global image limit;
- retain source provenance for every dataset record.

It is a cloud workflow, not a web image downloader extension, Chrome extension, Android app, or APK.
No software is installed in a browser or mobile device.

### Supported input routes

#### Direct image URLs

Pass a public HTTP or HTTPS URL whose successful response has an `image/*` MIME type.
JPEG, PNG, GIF, and WebP files with missing or generic binary MIME headers are also recognized by their byte signatures; explicit HTML and other non-image types are not reclassified.
The Actor follows up to five public redirects, validates the final response, and saves its bytes.

```json
{
  "startUrls": [
    { "url": "https://upload.wikimedia.org/wikipedia/commons/6/6a/JavaScript-logo.png" }
  ],
  "maxImages": 1
}
```

#### Public page URLs

Pass an anonymously reachable server-rendered HTML page.
The Actor resolves relative image paths against the final page URL and prefers the largest advertised `srcset` candidate.

```json
{
  "startUrls": [
    { "url": "https://en.wikipedia.org/wiki/Web_scraping" }
  ],
  "maxImages": 5,
  "maxImagesPerPage": 10
}
```

You can mix direct image and page URLs in the same run.
The global `maxImages` limit applies to both routes.

### Image sources discovered on a page

The HTML parser recognizes these public, server-rendered references:

| HTML source | Behavior |
| --- | --- |
| `<img src>` | Downloads the resolved source URL. |
| `<img srcset>` | Selects the candidate with the largest width or density descriptor. |
| Lazy-load attributes | Reads `data-src`, `data-lazy-src`, `data-original`, and `data-srcset`. |
| `<picture><source>` | Reads image source sets exposed in HTML. |
| Open Graph | Reads `og:image` and `og:image:url`. |
| Twitter cards | Reads `twitter:image`. |
| `link[rel=image_src]` | Reads a declared page image. |
| Inline CSS | Reads HTTP(S) `url(...)` references from element `style` attributes. |
| Server-rendered `<style>` blocks | Reads quoted or unquoted HTTP(S) `url(...)` references embedded in the page HTML. |

Linked stylesheets, canvas pixels, dynamically rendered JavaScript state, authenticated pages, and browser-only network responses are not discovered.
CSS `data:`, `blob:`, fragment-only, and non-HTTP(S) references are ignored. A discovered URL must still return `image/*` or a recognized image signature with missing/generic binary MIME metadata to be saved.
Use direct image URLs when you already know the assets and need exact control.

### Getting started

1. Open the Actor in Apify Console.
2. Add at least one direct image URL or public page URL under **Image or page URLs**.
3. Choose a conservative **Maximum images** value for the first run.
4. Keep the default file-size and timeout limits unless the source requires a bounded increase.
5. Click **Start**.
6. Open **Downloaded image metadata** to inspect dataset rows.
7. Open **Downloaded image files** to browse the original binary files.
8. Save the input as an Apify Task if you want a schedule or webhook integration.

The prefilled input uses a direct PNG and a public Wikipedia page so a new user can verify both routes.

### Input parameters

| Field | Type | Default | Description |
| --- | --- | ---: | --- |
| `startUrls` | array | required | One to 1,000 public HTTP(S) direct image or HTML page URLs. |
| `maxImages` | integer | `100` | Global maximum number of unique image files saved, from 1 to 5,000. |
| `maxImagesPerPage` | integer | `20` | Maximum candidates accepted from one page, from 1 to 1,000. |
| `maxFileSizeBytes` | integer | `20971520` | Maximum accepted response size; default 20 MiB and maximum 100 MiB. |
| `requestTimeoutSecs` | integer | `30` | Per-request timeout before a bounded retry, from 5 to 120 seconds. |

Malformed URLs, credential-bearing URLs, non-HTTP protocols, localhost targets, and private network addresses are rejected.
These restrictions protect the run from accidental access to internal services.

### Output dataset

Each successfully saved image creates one record in the default dataset.
Nullable fields remain `null` when the source does not provide them or the image format does not expose them.

| Field | Meaning |
| --- | --- |
| `sourceUrl` | Original direct image or page URL from the input. |
| `pageUrl` | Final page URL where the image was discovered; `null` for direct input. |
| `imageUrl` | Resolved image candidate before image redirects. |
| `resolvedUrl` | Final image response URL after redirects. |
| `fileName` | Sanitized response or URL filename. |
| `storageKey` | Key of the original file in the run's key-value store. |
| `fileUrl` | Apify API URL for the stored file; authentication may be required. |
| `mimeType` | HTTP image MIME type, or a recognized JPEG/PNG/GIF/WebP type inferred from bytes when the header is missing/generic binary. |
| `extension` | Normalized extension inferred from a known MIME type. |
| `byteSize` | Exact downloaded byte count. |
| `width`, `height` | Detected pixel dimensions when available. |
| `altText` | Trimmed HTML alt text, or `null`. |
| `sha256` | SHA-256 hash of the original bytes. |
| `downloadedAt` | ISO 8601 save timestamp. |

A real direct-PNG result has this shape:

```json
{
  "sourceUrl": "https://httpbin.org/image/png",
  "pageUrl": null,
  "imageUrl": "https://httpbin.org/image/png",
  "resolvedUrl": "https://httpbin.org/image/png",
  "fileName": "png.png",
  "storageKey": "image-541a1ef5373be3dc-png.png",
  "fileUrl": "https://api.apify.com/v2/key-value-stores/STORE_ID/records/image-541a1ef5373be3dc-png.png",
  "mimeType": "image/png",
  "extension": "png",
  "byteSize": 8090,
  "width": 100,
  "height": 100,
  "altText": null,
  "sha256": "541a1ef5373be3dc49fc542fd9a65177b664aec01c8d8608f99e6ec95577d8c1",
  "downloadedAt": "2026-01-15T12:00:00.000Z"
}
```

The file remains in the default key-value store according to your Apify storage retention settings.

### Exact duplicate handling

The Actor avoids charging or creating multiple records for the same discovered URL in one run.
It also hashes downloaded bytes and skips a later response whose SHA-256 hash matches an already saved file.

URL deduplication prevents repeated requests when a page declares the same source in multiple tags.
Hash deduplication catches identical bytes delivered through different URLs.
The first accepted source retains the dataset provenance.

### How much does it cost to download web images?

Pricing uses one `start` event per run and one `item` event per successfully saved image record.
Failed, rejected, and duplicate images do not emit an `item` charge.
Apify platform usage is billed according to the pricing shown in Console.

Current source pricing is:

| Event | FREE | BRONZE | SILVER | GOLD | PLATINUM | DIAMOND |
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
| Run start | $0.001 one time | $0.001 | $0.001 | $0.001 | $0.001 | $0.001 |
| Downloaded image | $0.0007912 | $0.000688 | $0.00053664 | $0.0004128 | $0.0002752 | $0.00019264 |

At BRONZE rates, one downloaded image costs about **$0.001688** including the run start, 10 images cost about **$0.00788**, and 100 images cost about **$0.0698**.
The exact charge depends on the number of successfully saved unique images and your Apify tier.

### Scheduled image monitoring workflow

To detect changes on public pages:

1. Create a Task with the pages and a fixed `maxImages` value.
2. Schedule it daily, weekly, or monthly in Apify Console.
3. Export each run's dataset to your warehouse or automation tool.
4. Match records by `resolvedUrl` or another source key.
5. Compare `sha256`, `byteSize`, `width`, and `height` with the prior run.
6. Trigger your own alert when a hash appears, disappears, or changes.

The Actor supplies the repeatable snapshots and content hashes.
It does not retain cross-run state or send change alerts by itself.

### CMS migration and asset audit workflow

For a bounded public-site migration:

1. Supply the page URLs included in the migration scope.
2. Set `maxImagesPerPage` high enough for the expected page template.
3. Review `sourceUrl`, `pageUrl`, and `resolvedUrl` for provenance.
4. Download the files from the run's key-value store.
5. Use `sha256` to collapse identical assets before upload.
6. Use dimensions and byte sizes to find oversized or unexpectedly small files.
7. Review nullable `altText` separately; missing alt text is not inferred or generated.

This workflow inventories supplied pages only.
The Actor does not crawl internal links or discover an entire domain automatically.

### API usage with cURL

Start a run and wait for completion:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~web-image-downloader/runs?token=$APIFY_TOKEN&waitForFinish=300" \
  -H "Content-Type: application/json" \
  -d '{
    "startUrls": [{"url": "https://en.wikipedia.org/wiki/Web_scraping"}],
    "maxImages": 5
  }'
```

Fetch dataset items using the `defaultDatasetId` returned by the run:

```bash
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?clean=true&format=json&token=$APIFY_TOKEN"
```

### API usage with JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/web-image-downloader').call({
    startUrls: [
        { url: 'https://en.wikipedia.org/wiki/Web_scraping' },
    ],
    maxImages: 5,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map(({ fileName, fileUrl, sha256 }) => ({ fileName, fileUrl, sha256 })));
```

The image files are stored in `run.defaultKeyValueStoreId`.
Dataset `fileUrl` values point to individual records in that store.

### API usage with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/web-image-downloader').call(run_input={
    'startUrls': [
        {'url': 'https://en.wikipedia.org/wiki/Web_scraping'},
    ],
    'maxImages': 5,
})

for item in client.dataset(run['defaultDatasetId']).iterate_items():
    print(item['fileName'], item['mimeType'], item['sha256'])
```

Use the key-value store client with `run['defaultKeyValueStoreId']` when you need the binary response directly.

### Use with Apify MCP

Add this Actor to Claude Code through the Apify MCP server:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/web-image-downloader"
```

#### Claude Desktop, Cursor, and VS Code setup

Claude Desktop, Cursor, and VS Code can use this equivalent MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/web-image-downloader"
    }
  }
}
```

Example prompts:

- "Download up to five images from this public page and list file names, dimensions, and alt text."
- "Save this direct image URL and return its SHA-256 hash and Apify file link."
- "Run the web image archive Task and compare its dataset hashes with the previous run."

### Reliability and request behavior

Requests have a configurable timeout and up to three attempts for transient network, HTTP 429, and server-side 5xx failures.
Permanent client responses such as 400 and 404 are not retried.
When a host rejects the direct request with HTTP 403, HTTP 429 or a connection error, the Actor makes one attempt through an Apify datacenter proxy. It stops using this fallback in a run after five consecutive fallback failures.
Redirects are bounded and every next target is checked before the request.
Requests explicitly accept any response type instead of preferring HTML viewer pages. Page-discovered images keep their page referer; supplied URLs use the current target's origin as referer without its path or query. This supports public image endpoints and common hotlink checks without credentials or browser sessions.

Downloads run sequentially.
This intentionally favors predictable memory use and respectful source traffic over maximum request speed.
The Actor has no residential proxy or browser fallback. The datacenter fallback adds no charge: you pay per saved image as usual.

A failed image does not stop independent URLs from being processed.
If every supplied URL fails, or candidates are found but none can be downloaded, the run fails with a non-zero status.
A valid HTML page containing no supported image references succeeds with zero records.

### Limits and unsupported pages

The Actor is designed for anonymously reachable public HTTP(S) resources.
It does not support:

- login, cookies, credentials, or private sessions;
- CAPTCHA solving or bypassing access controls;
- localhost, intranet, cloud metadata, or private IP targets;
- JavaScript-rendered images absent from initial HTML;
- image discovery inside linked stylesheets (inline CSS and server-rendered `<style>` blocks are supported);
- `data:`, `blob:`, FTP, or local file URLs;
- automatic site crawling, sitemap expansion, or search queries;
- image conversion, OCR, classification, or alt-text generation;
- ZIP aggregation of all files into one memory-heavy archive.

Some sites block automated downloads or reject hotlinks even with the source page as referer.
Supply authorized direct URLs or choose a source that permits anonymous access.

### Diagnostic privacy

Failed operations send sanitized diagnostic input, exceptions, and Actor/build/run IDs to our private GlitchTip service for repair. Secret fields and URL queries are removed, and reports are retained for 30 days. Reporting is bounded to the first exhausted source failure and image failure per run, plus a terminal exception when the run fails. Successful downloads and result charging are unchanged.

### Responsible use and legality

Only download images that you are authorized to access and use.
Public availability does not automatically grant copyright, trademark, privacy, or redistribution rights.

Review the source website's terms, robots guidance where applicable, licenses, and applicable law.
Respect usage restrictions and use bounded limits.
Do not use the Actor to bypass authentication, technical controls, or paywalls.

You are responsible for retention, sharing, and downstream use of downloaded files.
Delete Apify storage when it is no longer needed.

### Troubleshooting

#### Why did a page return zero images?

The page may contain no supported server-rendered references.
Inspect the original HTML rather than only the rendered browser view.
The Actor reads image tags, social metadata, inline CSS, and server-rendered `<style>` blocks. Images inserted by JavaScript, referenced only by linked stylesheets, drawn on canvas, or fetched through authenticated requests remain outside its scope.

#### Why did an image URL fail?

Check the run log for HTTP status, timeout, DNS, private-network, content-type, or file-size errors.
Open the URL in an anonymous session and verify it responds with `image/*` (or JPEG/PNG/GIF/WebP bytes with missing/generic binary MIME) rather than HTML or a challenge page.
Increase limits only when the source and file size are known.

#### Why is `width` or `height` null?

The downloaded MIME type may be valid while its encoding is not supported by the dimension parser, or the source may omit intrinsic dimensions.
The original bytes, MIME type, byte size, and hash are still available.

#### Why does `fileUrl` require authentication?

Run storage is private by default.
Use your Apify token, the Console output link, or the Apify client for the run's key-value store.
Do not append tokens to datasets or commit them to source control.

### Related Automation Lab Actors

- [Instagram Scraper](https://apify.com/automation-lab/instagram-scraper) discovers public-profile posts and returns main and carousel image URLs. Flatten a selected record's `displayUrl` or `images` values into this Actor's `startUrls` to store the original files with hashes and metadata for an authorized competitor creative audit, UGC image archive, or brand-monitoring image set. This is an API or orchestration workflow, not direct dataset-ID ingestion; automatic Actor-to-Actor handoff, ZIP creation, S3 upload, and image conversion are not supported.
- [Link Extractor](https://apify.com/automation-lab/link-extractor) extracts page links when the buyer needs URL discovery rather than image-file storage.
- [Webpage Text Extractor](https://apify.com/automation-lab/webpage-text-extractor) extracts readable page text for content pipelines.
- [HTML to PDF Converter](https://apify.com/automation-lab/html-to-pdf-converter) preserves a page as a rendered document instead of separate original image files.

Combine related Actors through Tasks, schedules, webhooks, or API orchestration only when each one matches the required data type.

### FAQ

#### Does this download every image from an entire website?

No.
It processes only the direct image and page URLs supplied in `startUrls`.
It does not crawl links to other pages.

#### Can I mix direct images and pages?

Yes.
Both routes share the same `maxImages`, deduplication, storage, output, and pricing behavior.

#### Are duplicate images charged twice?

Not within one run when they have the same discovered URL or exact SHA-256 content hash.
The first successfully saved copy creates the dataset record and `item` event.

#### Does it preserve the original image quality?

Yes, for a successful response.
The Actor stores the received image bytes without conversion or recompression.
For `srcset`, it selects the largest advertised candidate rather than downloading every variant.

#### Can I schedule recurring downloads?

Yes.
Save a working input as an Apify Task, attach a schedule, and compare dataset hashes downstream.
The Actor itself does not send change alerts.

#### Can it scrape protected or logged-in pages?

No.
The supported product scope is anonymous public pages and direct image URLs.
There is no credential, session, browser, or proxy input. Images that a datacenter proxy cannot reach either, such as Cloudflare-challenged hosts, stay unsupported.

#### Where are the files?

Original image bytes are in the run's default key-value store under keys beginning with `image-`.
The default dataset contains one metadata row and a `fileUrl` for each saved file.

# Changelog

This Actor's version history is a separate document: https://apify.com/automation-lab/web-image-downloader/changelog.md

# Actor input Schema

## `startUrls` (type: `array`):

Direct HTTP(S) image URLs and/or anonymously reachable public web-page URLs. Private-network, authenticated, data:, and file: URLs are rejected.

## `maxImages` (type: `integer`):

Maximum number of unique image files to save across all supplied URLs.

## `maxImagesPerPage` (type: `integer`):

Maximum number of image candidates accepted from each HTML page before global deduplication.

## `maxFileSizeBytes` (type: `integer`):

Reject an individual response larger than this many bytes. The default is 20 MiB.

## `requestTimeoutSecs` (type: `integer`):

Maximum duration of each page or image request before a bounded retry.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://httpbin.org/image/png"
    },
    {
      "url": "https://en.wikipedia.org/wiki/Web_scraping"
    }
  ],
  "maxImages": 10,
  "maxImagesPerPage": 20,
  "maxFileSizeBytes": 20971520,
  "requestTimeoutSecs": 30
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing one typed record per successfully downloaded image.

## `files` (type: `string`):

Key-value store containing the original downloaded image bytes.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        {
            "url": "https://httpbin.org/image/png"
        },
        {
            "url": "https://en.wikipedia.org/wiki/Web_scraping"
        }
    ],
    "maxImages": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/web-image-downloader").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "startUrls": [
        { "url": "https://httpbin.org/image/png" },
        { "url": "https://en.wikipedia.org/wiki/Web_scraping" },
    ],
    "maxImages": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/web-image-downloader").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    {
      "url": "https://httpbin.org/image/png"
    },
    {
      "url": "https://en.wikipedia.org/wiki/Web_scraping"
    }
  ],
  "maxImages": 10
}' |
apify call automation-lab/web-image-downloader --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/web-image-downloader"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/rm7i5EfQ1ZtxDlioE/builds/qVCqYgNV9hqY3hkdd/openapi.json
