# AI Dataset Cleaner & Schema Normalizer (`komelf/ai-dataset-cleaner-schema-normalizer`) Actor

Clean, normalize, deduplicate and validate Apify datasets or JSON. Infer schemas, fix inconsistent fields, flatten nested data and prepare reliable datasets for AI agents, RAG, CRM, analytics, APIs and databases.

- **URL**: https://apify.com/komelf/ai-dataset-cleaner-schema-normalizer.md
- **Developed by:** [Flavian COMBES](https://apify.com/komelf) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.99 / 1,000 cleaned records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Turn messy scraper output into reliable, schema-consistent data.

**AI Dataset Cleaner & Schema Normalizer** cleans whitespace and nulls, normalizes field names and types, removes duplicates, flattens JSON and infers a schema — directly from an Apify dataset or JSON input.

The normalization layer between scraped data and downstream AI/automation systems. Deterministic, with **no LLM**. Your source dataset stays **read-only**; results go to a **new clean dataset** in this run.

### The problem it solves

Scraper output mixes field names, numeric strings, null placeholders, nesting and repeated rows. This dataset cleaner applies reproducible rules to make AI agent data, RAG datasets, CRM imports and analytics easier to use. Normalization consistency is not proof of semantic correctness.

### Before → after

Before:

```json
{"Company Name":" Acme Corp ","Email":" SALES@ACME.COM ","Employees":"25"}
```

After Smart clean:

```json
{"company_name":"Acme Corp","email":"SALES@acme.com","employees":25}
```

Email local-part case is preserved by default. Normalized dedupe compares strings without changing the first output row's values.

### Try it in 30 seconds

1. Keep **Source: Inline** and **Preset: Smart clean**.
2. Run the provided three-row example.
3. Open **Cleaned records**: two rows remain, employees become numbers and `N/A` becomes null.
4. Inspect **Cleaning report**, **Inferred schema** and **Diagnostics**.

No private dataset is needed for the default run. For an existing Apify dataset, switch Source to Dataset and select it using the READ-only picker. Published Tasks may instead expose the plain-text `source_dataset` field; it accepts the same dataset identifier without changing source permissions.

### What it does

- Recursive whitespace and configurable null-placeholder cleaning.
- Preserve, snake\_case or camelCase names; rename, include and exclude rules.
- Collision-safe nested-object flattening without row expansion.
- Conservative scalar types and email/URL/phone normalization.
- Exact, normalized, composite-key and bounded optional fuzzy deduplication.
- Population JSON Schema inference, supplied-schema validation and reports.
- Streaming source pagination and publication with structural limits.

It does not scrape, crawl, call LLMs, fetch record URLs, infer missing facts or execute user code.

### Common use cases

Use this JSON cleaner for scraped data cleaning before chaining Actors, JSON normalization before APIs/databases, CRM data cleaning for leads and contacts, structured data for analytics, and AI-ready data for ChatGPT, AI agents or a RAG pipeline. It prepares records, not embeddings or a vector index.

### Example input

```json
{
  "source_mode": "inline",
  "preset": "smart_clean",
  "inline_records": [
    {"Company Name":" Acme Corp ","Email":" SALES@ACME.COM ","Employees":"25","Website":"https://acme.com/"},
    {"Company Name":"Acme Corp","Email":"sales@acme.com","Employees":"25","Website":"https://acme.com"},
    {"Company Name":" Beta SAS ","Email":"N/A","Employees":"12","Website":" https://beta.example.com "}
  ]
}
```

Dataset input:

```json
{"source_mode":"dataset","source_dataset_id":"YOUR_DATASET_ID","preset":"smart_clean","max_records":10000}
```

Published Task equivalent:

```json
{"source_mode":"dataset","source_dataset":"YOUR_DATASET_ID","preset":"smart_clean","max_records":10000}
```

### Example output

The default example produces two direct records:

```json
[
  {"company_name":"Acme Corp","email":"SALES@acme.com","employees":25,"website":"https://acme.com"},
  {"company_name":"Beta SAS","email":null,"employees":12,"website":"https://beta.example.com"}
]
```

### Inputs

The first section contains Source, Source dataset, Inline records, Maximum records (default 1,000) and Cleaning preset. Named presets fully control the advanced cleaning settings so Apify Console defaults cannot silently change their behavior. Choose **Custom** when you want the Advanced options to be authoritative. Unknown input options fail validation.

| Options | Behavior |
| --- | --- |
| `field_name_style`, `rename_map` | Recursive naming and original-key renames; collision suffixes preserve values. |
| `flatten`, `flatten_separator`, `flatten_depth` | Flatten objects, default `_` and depth 8; retain arrays and empty objects. |
| `trim_strings`, `normalize_nulls`, `null_placeholders`, `remove_null_fields` | Smart placeholders: empty, N/A, NA, null, none, -, unknown. Missing fields are not invented. Zero/false remain values. |
| `infer_types` | Conservative integers/decimals/booleans and ISO dates. Leading zeros, precision-risk IDs and ambiguous dates remain strings. |
| `normalize_email`, `lowercase_email_local`, `normalize_url`, `normalize_phone` | Conservative formatting. Full email lowercase is opt in; invalid/ambiguous values remain with diagnostics. |
| `include_fields`, `exclude_fields` | Final top-level names after flattening; exclusion wins. |
| `dedupe_mode`, `dedupe_keys` | none, exact, normalized, key or fuzzy; keys can be composite. |
| `fuzzy_field`, `fuzzy_threshold`, `fuzzy_max_candidates` | One string field, default similarity .92, ≤10,000 candidates; fuzzy off by default. |
| `infer_schema`, `required_threshold`, `provided_schema`, `schema_invalid_behavior` | Population inference (presence default .95); supplied validation defaults to retain + report. |
| `include_cleaning_metadata` | Default false; append collision-protected source index and consistency score. |

See [.actor/input\_schema.json](.actor/input_schema.json) for field descriptions and [ARCHITECTURE.md](ARCHITECTURE.md) for exact transformation order and conversion rules. Binary decimal floats are approximate; disable inference when exact decimal precision matters.

### Output

The default dataset contains direct cleaned objects with dynamic user fields, without a `cleaned_record` wrapper. Use Apify JSON/CSV/Excel exports, Dataset API, downstream Actors or agent workflows. Arrays remain arrays; no separate exporter is needed.

| Default key-value store key | Contents |
| --- | --- |
| `CLEANING_REPORT` | Counts, configuration summary, billing confirmations, field statistics, warnings and status. |
| `INFERRED_SCHEMA` | Draft 2020-12 JSON Schema, or an explicit unconstrained artifact if inference is disabled/incomplete. |
| `DIAGNOSTICS` | Reason totals and up to 100 source-index samples; no record bodies. |

### Schema inference

This schema normalizer observes all processed structurally valid retained cleaned rows, including duplicates before dedupe and excluding metadata. It tracks missing versus null, mixed types, arrays and nested objects. Integer and float observations converge to number. Properties are sorted.

Default required threshold .95 means presence in at least 95% of observed object occurrences. Some observed rows can therefore fail that requirement. Set 1 for population-wide presence. Inference describes processed records, not future rows or semantic truth.

An optional **supplied** JSON Schema validates each cleaned row. Retain + report minimizes data loss; `schema_invalid_behavior: "reject"` excludes invalid rows from output and billing. V1 supports a bounded draft 2020-12 subset: common types/properties/items/required/enum/const/range/length constraints. References, regex, combinators and conditional/unevaluated constraints are rejected. Formats are annotations. No second pass validates against the inferred schema.

### Deduplication

**Exact** deduplicate-dataset mode hashes canonical cleaned JSON independently of key order. **Normalized** additionally casefolds/NFKC-normalizes strings and collapses whitespace for fingerprints only. **Key** compares selected final fields; missing/null/empty components keep rows distinct. First occurrence wins; last retention is not supported.

**Fuzzy** requires one selected string field. It uses two-character prefix blocks, ≤100 representatives/block, values ≤256 characters and ≤10,000 candidates. Known larger sources skip fuzzy with a warning and continue exact dedupe. It misses cross-prefix matches and can match incorrectly; review it for your use case. Removed duplicates are neither published nor charged as cleaned records.

### Cleaning presets

| Preset | Use |
| --- | --- |
| Smart clean | Trim/nulls/snake\_case/flatten/conservative types/contact formatting/normalized dedupe/schema. |
| Minimal | Trim and schema inference; preserve names/scalar strings/placeholders/nesting and retain duplicates. |
| Strict normalization | Smart clean plus null object-field removal and lowercase email local parts. |
| Custom | Advanced controls are authoritative; the form starts from Smart clean defaults and you can change them. |

Strict does not mean semantically correct. Full email lowercase may not suit every mailbox.

### Global report

Counts distinguish seen, cleaned, output, skipped, schema-rejected and duplicate rows. Reports include collision/rename/trim/null/contact/type counts, presence/null/type observations, transformations, fuzzy comparisons, runtime and confirmed custom events. Normal reconciliation is `seen = output + skipped + rejected + duplicates`; failures can add unpublished/uncertain rows.

Optional `record_consistency_score` metadata measures consistency, not truthfulness: 100 minus up to 10 points for top-level null fraction, 30 for supplied-schema invalidity and up to 10 for warnings. Metadata is off by default and excluded from inference.

### Pricing / billing contract

One custom **`record-cleaned`** event is requested after each confirmed cleaned-record publication. No events for removed duplicates, structural skips, failed writes or schema rejections. Budget checks happen before more work; the Actor stops when exhausted. The platform configures pricing; code contains no commercial price constant.

Candidate launch price: **$0.99 / 1,000 successfully cleaned records**, pending Cloud benchmarks — **not a configured Store price**. Do not enable nonzero synthetic dataset-item pricing alongside the custom event: the code refuses it. Optional platform-managed `apify-actor-start` pricing may be configured later; source code never manually emits it.

Publication and billing are separate operations. Network/process failures can leave a published row with an unconfirmed charge; execution stops for output/ledger review. `billable_result_count` counts confirmed published eligible rows; `platform_charged_event_count` counts confirmed custom charges. They differ in unmonetized runs or failures. No real customer billing was used locally.

### API / MCP / automation usage

Pass the same JSON to the Actor API, Console tasks or available Apify MCP integrations. Chain an upstream run's `defaultDatasetId` into `source_dataset_id`; use this run's `defaultDatasetId` downstream. Read reports/schema through `defaultKeyValueStoreId`.

Example after deployment, using the SDK's API client:

```python
import asyncio
import os
from apify_client import ApifyClientAsync

async def run():
    client = ApifyClientAsync(os.environ["APIFY_TOKEN"])
    result = await client.actor("YOUR_ACCOUNT/ai-dataset-cleaner-schema-normalizer").call(
        run_input={"source_mode": "dataset", "source_dataset_id": "SOURCE_ID", "max_records": 10000}
    )
    page = await client.dataset(result.default_dataset_id).list_items(limit=100, clean=False)
    return page.items

asyncio.run(run())
```

This repository task does not publish the Actor. Replace placeholders after creating it. Ten future task templates: [docs/PUBLISHED\_TASKS.md](docs/PUBLISHED_TASKS.md).

### Limits

| Limit | V1 ceiling |
| --- | --- |
| Rows | 1,000 inline; 100,000 dataset; default max\_records 1,000 |
| Source page | 500 rows |
| Nesting / flatten depth | 10 / 8 |
| Object fields / key length | 500 / 256 characters |
| String / array / total nodes | 100,000 characters / 1,000 elements / 10,000 value nodes per record |
| Serialized record | 1,000,000 UTF-8 bytes before and after cleaning |
| Rule lists/maps | 100 entries per option |
| Inference nodes / transformation paths | 20,000 each |
| Diagnostic samples | 100; aggregate counters continue |
| Fuzzy | 10,000 candidates, 256-character field, 100 representatives/block |

Unsafe records are skipped, never truncated or billed as successful. Inference exhaustion continues cleaning with an explicit warning and no partial constraints. Extreme pages can need substantial memory; benchmark your payloads. Start a fresh run after interruption. V1 does not resume and refuses preserved nonempty output storage.

### Privacy and security

Source READ-only permissions are declared for LIMITED\_PERMISSIONS; Cloud verification remains required. No external record-value API, URL fetching, browser, proxy, telemetry, user code, eval/exec or input-driven shell commands. Logs/diagnostics omit record bodies. Reports include field names/source IDs. Retention follows Apify; see [SECURITY.md](SECURITY.md).

### Technical notes

Python 3.12: `pip install -e '.[dev]'`. Checks: `pytest -q`, `ruff check .`, `ruff format --check .`, `python -m compileall -q my_actor scripts tests`, `python scripts/validate_schemas.py --official`, `python scripts/smoke.py`, `python scripts/sdk_smoke.py`.

Local execution: use fresh storage and `python -m my_actor`. Missing input runs the deterministic example. SDK smoke uses isolated temporary storage and simulated PPE with zero synthetic pricing. Docker uses Python 3.12 slim without browser/model downloads. Cloud and Docker evidence: [VALIDATION.md](VALIDATION.md), [BENCHMARK\_PLAN.md](BENCHMARK_PLAN.md), [REVIEW.md](REVIEW.md).

### FAQ

**AI-powered cleaning?** No. “AI” describes downstream use; the engine uses deterministic rules without an LLM.

**Does it change source data?** No. Source is read-only and cleaned records go to run output.

**Guaranteed phone/email/URL validity?** No. Formatting is conservative, ambiguities remain and no lookups occur.

**Does `00123` become 123?** No. Leading zeros and precision-risk integer strings remain strings.

**Can it fill missing fields or verify facts?** No. It measures structural consistency, not truthfulness or semantic data quality.

**CSV/Excel?** Use Apify exports; arrays remain arrays.

**Resume interrupted runs?** No. Review output/billing, then start fresh; do not retry into existing output.

**Established Cloud performance?** No. Local benchmarks do not establish Cloud runtime, memory or cost. Complete validation before release/pricing.

# Actor input Schema

## `source_mode` (type: `string`):

Inline is ready to try. Dataset mode reads an existing Apify dataset without modifying it.

## `source_dataset_id` (type: `string`):

Used only in dataset mode. Select a dataset you can read; READ permission only.

## `source_dataset` (type: `string`):

Plain-text alternative for Published Tasks. Use the source dataset ID or name; ignored when the picker field is filled with the same value.

## `inline_records` (type: `array`):

An array of JSON objects for tests and small workflows, up to 1,000 records.

## `max_records` (type: `integer`):

Maximum source rows to examine, including duplicates and rejected rows. Hard ceiling 100,000.

## `preset` (type: `string`):

Named presets control all advanced cleaning options. Choose Custom to edit advanced options.

## `trim_strings` (type: `boolean`):

Trim surrounding whitespace recursively, including strings inside arrays.

## `normalize_nulls` (type: `boolean`):

Convert configured placeholder strings to null; zero and false remain values.

## `null_placeholders` (type: `array`):

Case-insensitive exact matches after optional trimming. Does not infer missing keys.

## `remove_null_fields` (type: `boolean`):

Remove explicit null object fields recursively. Null array elements remain in place.

## `field_name_style` (type: `string`):

Normalize keys recursively. Collisions receive deterministic suffixes without overwriting values.

## `rename_map` (type: `object`):

Exact original key to new key mapping, applied recursively before field naming.

## `include_fields` (type: `array`):

Keep only these final top-level names after flattening. Empty list keeps every field.

## `exclude_fields` (type: `array`):

Remove these final top-level names; exclusion takes priority over inclusion.

## `flatten` (type: `boolean`):

Flatten nested nonempty objects. Arrays remain arrays and empty objects are preserved.

## `flatten_separator` (type: `string`):

Join nested field names with 1–4 characters. Collision suffixes use underscore.

## `flatten_depth` (type: `integer`):

Maximum object edges flattened (1–8). Deeper objects remain nested.

## `infer_types` (type: `boolean`):

Conservative integers, decimals, booleans and ISO date recognition. Preserve leading zeros, large IDs and ambiguous dates.

## `normalize_email` (type: `boolean`):

Preserve local-part case and lowercase domain. Invalid values remain present.

## `lowercase_email_local` (type: `boolean`):

Also lowercase email local parts; opt in only when appropriate for your data.

## `normalize_url` (type: `boolean`):

Normalize HTTP(S) scheme, host and default port; preserve query/fragment and never fetch URLs.

## `normalize_phone` (type: `boolean`):

Remove separators only from phone-like fields with 7–15 digits; never infer a country.

## `dedupe_mode` (type: `string`):

First occurrence wins. Normalized comparisons casefold strings without changing output. Fuzzy is opt in and bounded.

## `dedupe_keys` (type: `array`):

Composite final top-level field names. Missing, null or empty key components keep the record distinct.

## `fuzzy_field` (type: `string`):

One final top-level string field, required for fuzzy mode. Values over 256 characters are skipped.

## `fuzzy_threshold` (type: `number`):

Similarity from >0 to 1, within two-character prefix blocks. Can cause false matches.

## `fuzzy_max_candidates` (type: `integer`):

Maximum 10,000 candidates. Oversized known datasets skip fuzzy matching; exact dedupe continues.

## `infer_schema` (type: `boolean`):

Infer JSON Schema over all retained cleaned rows before dedupe. Metadata is excluded.

## `required_threshold` (type: `number`):

Presence fraction needed to mark fields required, using the full observed population.

## `provided_schema` (type: `object`):

Optional draft 2020-12 schema. References, regex and combinators are rejected for bounded offline validation. Formats are annotations.

## `schema_invalid_behavior` (type: `string`):

Retain and report minimizes data loss. Reject removes invalid rows from output and billing.

## `include_cleaning_metadata` (type: `boolean`):

Append source index and consistency score. Collision suffixes preserve user fields.

## Actor input object example

```json
{
  "source_mode": "inline",
  "inline_records": [
    {
      "Company Name": " Acme Corp ",
      "Email": " SALES@ACME.COM ",
      "Employees": "25",
      "Website": "https://acme.com/"
    },
    {
      "Company Name": "Acme Corp",
      "Email": "sales@acme.com",
      "Employees": "25",
      "Website": "https://acme.com"
    },
    {
      "Company Name": " Beta SAS ",
      "Email": "N/A",
      "Employees": "12",
      "Website": " https://beta.example.com "
    }
  ],
  "max_records": 1000,
  "preset": "smart_clean",
  "trim_strings": true,
  "normalize_nulls": true,
  "null_placeholders": [
    "",
    "n/a",
    "na",
    "null",
    "none",
    "-",
    "unknown"
  ],
  "remove_null_fields": false,
  "field_name_style": "snake_case",
  "rename_map": {},
  "include_fields": [],
  "exclude_fields": [],
  "flatten": true,
  "flatten_separator": "_",
  "flatten_depth": 8,
  "infer_types": true,
  "normalize_email": true,
  "lowercase_email_local": false,
  "normalize_url": true,
  "normalize_phone": true,
  "dedupe_mode": "normalized",
  "dedupe_keys": [],
  "fuzzy_field": "",
  "fuzzy_threshold": 0.92,
  "fuzzy_max_candidates": 10000,
  "infer_schema": true,
  "required_threshold": 0.95,
  "provided_schema": {},
  "schema_invalid_behavior": "retain",
  "include_cleaning_metadata": false
}
```

# Actor output Schema

## `records` (type: `string`):

No description

## `cleaning_report` (type: `string`):

No description

## `inferred_schema` (type: `string`):

No description

## `diagnostics` (type: `string`):

No description

# 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 = {
    "inline_records": [
        {
            "Company Name": " Acme Corp ",
            "Email": " SALES@ACME.COM ",
            "Employees": "25",
            "Website": "https://acme.com/"
        },
        {
            "Company Name": "Acme Corp",
            "Email": "sales@acme.com",
            "Employees": "25",
            "Website": "https://acme.com"
        },
        {
            "Company Name": " Beta SAS ",
            "Email": "N/A",
            "Employees": "12",
            "Website": " https://beta.example.com "
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("komelf/ai-dataset-cleaner-schema-normalizer").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 = { "inline_records": [
        {
            "Company Name": " Acme Corp ",
            "Email": " SALES@ACME.COM ",
            "Employees": "25",
            "Website": "https://acme.com/",
        },
        {
            "Company Name": "Acme Corp",
            "Email": "sales@acme.com",
            "Employees": "25",
            "Website": "https://acme.com",
        },
        {
            "Company Name": " Beta SAS ",
            "Email": "N/A",
            "Employees": "12",
            "Website": " https://beta.example.com ",
        },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("komelf/ai-dataset-cleaner-schema-normalizer").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 '{
  "inline_records": [
    {
      "Company Name": " Acme Corp ",
      "Email": " SALES@ACME.COM ",
      "Employees": "25",
      "Website": "https://acme.com/"
    },
    {
      "Company Name": "Acme Corp",
      "Email": "sales@acme.com",
      "Employees": "25",
      "Website": "https://acme.com"
    },
    {
      "Company Name": " Beta SAS ",
      "Email": "N/A",
      "Employees": "12",
      "Website": " https://beta.example.com "
    }
  ]
}' |
apify call komelf/ai-dataset-cleaner-schema-normalizer --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,komelf/ai-dataset-cleaner-schema-normalizer"
        }
    }
}
```

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/YyXuEDejnvR1enCmV/builds/DniBqnlmevtSrdqvk/openapi.json
