# Data Ops: Convert, Clean, Validate, Compare Files (`apizilla/data-ops-api`) Actor

Convert CSV, Excel, JSON, XML, PDF and Office files. Clean CSV data, validate rows with rules or JSON Schema, compare two files by key columns, and make PDF or DOCX documents from templates. Works in bulk.

- **URL**: https://apify.com/apizilla/data-ops-api.md
- **Developed by:** [APIzilla](https://apify.com/apizilla) (community)
- **Categories:** Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 file converteds

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

## Data Ops API: Convert, Clean, Validate, Compare Files

Data Ops API is one tool for everyday file work. It runs fully on Apify. You do not need a server.

It can:

- **Convert** files: CSV, TSV, Excel (XLSX, XLS), ODS, JSON, JSON Lines, XML, HTML tables and Parquet. It also turns Word, Excel and PowerPoint files into PDF. It can read text and tables from PDF files (BETA).
- **Clean** CSV and Excel data: remove duplicates, trim spaces, fix broken characters, and make dates, phone numbers and emails look the same.
- **Validate** rows with simple rules or a JSON Schema. You get a clear report that says which row and which column has a problem.
- **Compare** two files by key columns, like `id` or `sku`. You get an Excel report. New rows are green, removed rows are red, changed cells are yellow.
- **Generate documents** from a template and your data. Use an HTML, DOCX or XLSX template. Make one PDF or DOCX per row, or one document for all rows.

Every operation works in bulk. Send many files or many rows in one run.

### How to use it

1. Pick an **Operation**.
2. Add your input. You can use one or more of these:
   - **File links**: public links to your files.
   - **Inline files**: small files pasted into the input.
   - **Records**: rows as a JSON list.
   - **Key-value store** and **keys**: files you saved in Apify.
   - **Dataset**: an Apify dataset, used as a table.
3. Set the options for your operation.
4. Click **Start**.

### What you get

- One result row per file (or per document). Each row has a status, a message, a download link and any errors.
- All output files are saved in the run's key-value store. The **Download** link in each row opens the file.
- A `SUMMARY` record with the totals.

If a file fails, the other files still run. You are never charged for a failed file.

### Examples

#### Convert a CSV file to Excel

```json
{
  "operation": "convert",
  "fileUrls": ["https://example.com/customers.csv"],
  "targetFormat": "xlsx"
}
```

The delimiter (comma, semicolon, tab or pipe) and the text encoding are found for you.

#### Turn Word files into PDF

```json
{
  "operation": "convert",
  "fileUrls": ["https://example.com/letter.docx", "https://example.com/report.pptx"],
  "targetFormat": "pdf"
}
```

#### Clean a CSV file

```json
{
  "operation": "clean",
  "fileUrls": ["https://example.com/leads.csv"],
  "removeDuplicates": "exact",
  "emailColumns": ["email"],
  "phoneColumns": ["phone"],
  "phoneRegion": "US",
  "dateColumns": ["signup date"],
  "dateFormat": "YYYY-MM-DD",
  "headerStyle": "snake_case"
}
```

#### Validate rows

```json
{
  "operation": "validate",
  "fileUrls": ["https://example.com/orders.csv"],
  "requiredColumns": ["id", "email"],
  "rules": [
    { "column": "id", "required": true, "type": "integer", "unique": true },
    { "column": "email", "required": true, "type": "email" },
    { "column": "country", "allowedValues": ["US", "GB", "DE"] },
    { "column": "amount", "type": "number", "min": 0 }
  ]
}
```

Rule fields: `column`, `required`, `type` (string, integer, number, boolean, date, email, url, phone), `pattern`, `min`, `max`, `minLength`, `maxLength`, `allowedValues`, `unique`, `dateFormat`, `phoneRegion`, `caseSensitive`.

You can also use `jsonSchema` instead of rules, or together with them.

The report says things like: `Row 6, column "email": "abc" is not a valid email address.` Row 1 is the header, so the first data row is row 2.

#### Compare two files

```json
{
  "operation": "compare",
  "fileUrls": ["https://example.com/stock-monday.csv", "https://example.com/stock-tuesday.csv"],
  "keyColumns": ["sku"]
}
```

The first file is the old one. The second file is the new one. For many comparisons, add files in pairs: 1st with 2nd, 3rd with 4th, and so on.

#### Make one PDF invoice per row

```json
{
  "operation": "generate-document",
  "templateHtml": "<h1>Invoice {{ id }}</h1><p>Customer: {{ name }}</p><p>Total: {{ total }} EUR</p>",
  "records": [
    { "id": 1, "name": "Anna", "total": 120 },
    { "id": 2, "name": "Ben", "total": 80 }
  ],
  "documentFormat": "pdf",
  "fileNameTemplate": "invoice-{{ id }}"
}
```

For a DOCX template, write `{{ name }}` in the Word file and give it with `templateUrl`. For an XLSX template, write `{{ name }}` in a cell. If a column name has spaces, use `{{ row['Full Name'] }}`.

### Supported conversions

| From | To |
|---|---|
| CSV, TSV, XLSX, XLS, ODS, JSON, JSON Lines, XML, HTML table, Parquet, records, dataset | CSV, TSV, XLSX, JSON, JSON Lines, XML, HTML, Parquet, PDF |
| DOCX, DOC, ODT, RTF | PDF, DOCX, ODT, RTF |
| PPTX, PPT, ODP | PDF, PPTX, ODP |
| XLSX, XLS, ODS | also PDF (page layout from the file) and ODS |
| HTML page | PDF |
| PDF (BETA) | TXT (text), or CSV, XLSX, JSON, HTML (tables) |

### Safety

- Only public `http` and `https` links are downloaded. Links to private or local networks are blocked.
- Files bigger than **Max file size** are skipped. Packed files (like XLSX and DOCX) are checked before they are opened, so files that unpack to a huge size are rejected.
- XML is read in a safe way that blocks known XML attacks.
- Macros in Office files are never run. Macro parts are removed before conversion.
- Templates run in a sandbox. In HTML templates, images and styles load only from public links.
- Text that starts with `=` is saved as text in Excel files, not as a formula.

### Limits

- PDF reading is BETA. Scanned PDFs (images of text) are not supported. Tables without lines need `pdfTableMode: "text"`, and the result may need a check.
- Office to PDF uses LibreOffice. The look can differ a little from Microsoft Office, mostly when a font is missing.
- XLSX templates fill `{{ placeholders }}` in cells. Loops over rows are not supported in XLSX templates. Images and charts in XLSX templates may be lost.
- Excel files can hold at most 1,048,575 rows. Use CSV for bigger tables.
- In compare reports, old values are shown as cell notes for the first 20,000 changed cells. All changes are still in the JSON report.
- The default memory is 1 GB. For files with more than 100,000 rows, or for many Office files, use 2 to 4 GB.

### Cost

You pay only for what you use. You are never charged for a file that fails.

| What you pay for | Price |
|---|---|
| Run start (per GB of memory) | $0.00005 |
| One data file converted (CSV, Excel, JSON, XML and more) | $0.004 |
| One Office or HTML file turned into PDF or another document format | $0.015 |
| One PDF page read (text or tables, BETA) | $0.005 |
| 1,000 rows cleaned | $0.75 |
| 1,000 rows validated | $0.75 |
| One validation report | $0.01 |
| One comparison of two files | $0.01 |
| 1,000 rows compared | $0.05 |
| One document made from a template (up to 10 pages) | $0.006 |
| Each page after page 10 of a made document | $0.0005 |

When a DOCX or XLSX template is turned into a PDF, you pay for the document ($0.006) and for the PDF step ($0.015).

Examples:

- Convert 100 CSV files to Excel: about $0.40.
- Clean a file with 10,000 rows: about $7.50.
- Make 100 PDF invoices from an HTML template: about $0.60.

You can set a maximum cost per run. The run stops when it reaches that limit.

### Use it from code

You can start this Actor with the Apify API, the Apify client for JavaScript or Python, or from Make, Zapier, n8n and AI agents (MCP). The results are in the default dataset. The files are in the default key-value store.

# Actor input Schema

## `operation` (type: `string`):

What to do with your files or records. Every operation works in bulk.

## `fileUrls` (type: `array`):

Public links (http or https) to your files. Add one link per line. For compare, files are used in pairs: 1st with 2nd, 3rd with 4th.

## `inlineFiles` (type: `array`):

Small files pasted into the input. Each item: {"name": "data.csv", "content": "..."}. For binary files add "encoding": "base64".

## `records` (type: `array`):

Rows as a JSON list of objects. Example: \[{"id": 1, "name": "Anna"}]. Used as one table.

## `keyValueStoreId` (type: `string`):

ID or name of a key-value store that holds your files. Leave empty to use this run's default store.

## `keyValueStoreKeys` (type: `array`):

Keys of the files in the key-value store above. One key per line.

## `datasetId` (type: `string`):

ID or name of an Apify dataset to use as a table.

## `secondDatasetId` (type: `string`):

A second dataset. Useful for compare: the first dataset is the old data, this one is the new data.

## `inputDelimiter` (type: `string`):

Leave on auto. The delimiter and the text encoding are found for you.

## `sheetName` (type: `string`):

For Excel or ODS input. Leave empty to read the first sheet.

## `targetFormat` (type: `string`):

The output format for convert. Tables: csv, tsv, xlsx, json, jsonl, xml, html, parquet, pdf. Office files: pdf, docx, odt, rtf, pptx, odp, ods. PDF input (BETA): txt for text, or csv, xlsx, json, html for tables.

## `outputDelimiter` (type: `string`):

Delimiter for CSV output.

## `inferTypes` (type: `boolean`):

For JSON, Excel and Parquet output made from text files: turn "42" into 42 and "true" into true. Values with leading zeros, like zip codes, stay text.

## `excelFriendlyCsv` (type: `boolean`):

Add a BOM mark so Excel opens UTF-8 CSV files with the right characters.

## `maxPdfPages` (type: `integer`):

Read at most this many pages of each PDF.

## `pdfTableMode` (type: `string`):

How to find tables in PDF files. Use text for tables that have no lines. Text mode can split normal text into columns, so check the result.

## `trimWhitespace` (type: `boolean`):

Remove spaces at the start and end of each value.

## `collapseSpaces` (type: `boolean`):

Turn many spaces and odd space characters into one normal space.

## `fixEncoding` (type: `boolean`):

Repair text like "cafÃ©" to "café" and remove invisible characters.

## `removeEmptyRows` (type: `boolean`):

Drop rows where every value is empty.

## `removeEmptyColumns` (type: `boolean`):

Drop columns where every value is empty.

## `removeDuplicates` (type: `string`):

exact: rows that are the same in every column. columns: rows that are the same in the columns you list below. The first row is kept.

## `duplicateColumns` (type: `array`):

Columns used to find duplicates when Remove duplicates is columns.

## `duplicatesIgnoreCase` (type: `boolean`):

Treat "Anna" and "ANNA" as the same.

## `headerStyle` (type: `string`):

How to write the column names.

## `emailColumns` (type: `array`):

Make emails lower case and count values that do not look like emails.

## `phoneColumns` (type: `array`):

Rewrite phone numbers in one format.

## `phoneRegion` (type: `string`):

Two letter country code used for numbers without a + prefix. Example: US, GB, DE, PT.

## `phoneFormat` (type: `string`):

E164: +14155550123. INTERNATIONAL: +1 415-555-0123. NATIONAL: (415) 555-0123.

## `dateColumns` (type: `array`):

Rewrite dates in these columns in one format.

## `dateFormat` (type: `string`):

Format for cleaned dates.

## `dayFirst` (type: `boolean`):

Read 05/02/2026 as 5 February, not May 2.

## `lowercaseColumns` (type: `array`):

Make all text in these columns lower case.

## `uppercaseColumns` (type: `array`):

Make all text in these columns upper case.

## `titleCaseColumns` (type: `array`):

Make Each Word Start With A Capital Letter.

## `outputFormat` (type: `string`):

same keeps the input format (old Excel and ODS become xlsx).

## `rules` (type: `array`):

One rule per column. Fields: column, required, type (string, integer, number, boolean, date, email, url, phone), pattern, min, max, minLength, maxLength, allowedValues, unique, dateFormat, phoneRegion, caseSensitive.

## `jsonSchema` (type: `object`):

Optional JSON Schema (draft 2020-12). Each row is checked against it. Text values are turned into numbers or true/false when the schema asks for them.

## `requiredColumns` (type: `array`):

Columns that must exist in the file.

## `splitValidRows` (type: `boolean`):

Also save two files: valid rows and invalid rows.

## `maxErrorsInReport` (type: `integer`):

All problems are counted. Only this many are listed.

## `keyColumns` (type: `array`):

Columns that identify a row, like id or sku. Rows with the same key are compared cell by cell. Leave empty to match whole rows.

## `ignoreColumns` (type: `array`):

Columns to skip when comparing.

## `ignoreCase` (type: `boolean`):

Treat "Anna" and "ANNA" as the same.

## `trimValues` (type: `boolean`):

Treat " 5" and "5" as the same.

## `numericTolerance` (type: `string`):

Numbers that differ by this much or less count as the same. Example: 0.01.

## `includeUnchanged` (type: `boolean`):

Also list rows that did not change in the report.

## `templateHtml` (type: `string`):

An HTML template with Jinja2 placeholders, like <h1>Invoice {{ id }}</h1>. Use {{ row\['Full Name'] }} for column names with spaces. In single mode, loop with {% for r in rows %}.

## `templateUrl` (type: `string`):

Link to a DOCX, XLSX or HTML template. DOCX templates use {{ placeholders }} (docxtpl). XLSX templates replace {{ placeholders }} in cells.

## `templateKey` (type: `string`):

Key of the template in the key-value store set above.

## `templateInline` (type: `object`):

A small template pasted into the input: {"name": "invoice.docx", "content": "<base64>", "encoding": "base64"}. For HTML you can use "encoding": "text".

## `documentFormat` (type: `string`):

pdf works with all templates. docx needs a DOCX template. xlsx needs an XLSX template. html needs an HTML template.

## `documentMode` (type: `string`):

per-row: one document per data row. single: one document with all rows (use the rows list in the template).

## `fileNameTemplate` (type: `string`):

Name for each document, without extension. Placeholders work, like invoice-{{ id }}.

## `maxDocuments` (type: `integer`):

Stop after this many documents.

## `maxFiles` (type: `integer`):

Safety limit for the number of inputs in one run.

## `maxFileSizeMb` (type: `integer`):

Bigger files are skipped. Packed files (xlsx, docx) may unpack to at most 20 times this size.

## `maxRowsPerFile` (type: `integer`):

Files with more rows are skipped.

## Actor input object example

```json
{
  "operation": "convert",
  "inlineFiles": [
    {
      "name": "customers.csv",
      "content": "id;name;email;signup date\n1; Anna Smith ;ANNA@EXAMPLE.COM;2026-01-05\n2;Ben Lee;ben@example.com;05/02/2026\n2;Ben Lee;ben@example.com;05/02/2026\n"
    }
  ],
  "inputDelimiter": "auto",
  "targetFormat": "xlsx",
  "outputDelimiter": ",",
  "inferTypes": true,
  "excelFriendlyCsv": false,
  "maxPdfPages": 50,
  "pdfTableMode": "lines",
  "trimWhitespace": true,
  "collapseSpaces": true,
  "fixEncoding": true,
  "removeEmptyRows": true,
  "removeEmptyColumns": false,
  "removeDuplicates": "exact",
  "duplicatesIgnoreCase": true,
  "headerStyle": "trim",
  "phoneRegion": "US",
  "phoneFormat": "E164",
  "dateFormat": "YYYY-MM-DD",
  "dayFirst": false,
  "outputFormat": "same",
  "rules": [
    {
      "column": "email",
      "required": true,
      "type": "email",
      "unique": true
    },
    {
      "column": "age",
      "type": "integer",
      "min": 0,
      "max": 120
    }
  ],
  "splitValidRows": false,
  "maxErrorsInReport": 10000,
  "ignoreCase": false,
  "trimValues": true,
  "numericTolerance": "0",
  "includeUnchanged": false,
  "documentFormat": "pdf",
  "documentMode": "per-row",
  "fileNameTemplate": "document-{{ _index }}",
  "maxDocuments": 1000,
  "maxFiles": 100,
  "maxFileSizeMb": 50,
  "maxRowsPerFile": 1000000
}
```

# Actor output Schema

## `results` (type: `string`):

No description

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

No description

## `summary` (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 = {
    "operation": "convert",
    "inlineFiles": [
        {
            "name": "customers.csv",
            "content": "id;name;email;signup date\n1; Anna Smith ;ANNA@EXAMPLE.COM;2026-01-05\n2;Ben Lee;ben@example.com;05/02/2026\n2;Ben Lee;ben@example.com;05/02/2026\n"
        }
    ],
    "targetFormat": "xlsx"
};

// Run the Actor and wait for it to finish
const run = await client.actor("apizilla/data-ops-api").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 = {
    "operation": "convert",
    "inlineFiles": [{
            "name": "customers.csv",
            "content": """id;name;email;signup date
1; Anna Smith ;ANNA@EXAMPLE.COM;2026-01-05
2;Ben Lee;ben@example.com;05/02/2026
2;Ben Lee;ben@example.com;05/02/2026
""",
        }],
    "targetFormat": "xlsx",
}

# Run the Actor and wait for it to finish
run = client.actor("apizilla/data-ops-api").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 '{
  "operation": "convert",
  "inlineFiles": [
    {
      "name": "customers.csv",
      "content": "id;name;email;signup date\\n1; Anna Smith ;ANNA@EXAMPLE.COM;2026-01-05\\n2;Ben Lee;ben@example.com;05/02/2026\\n2;Ben Lee;ben@example.com;05/02/2026\\n"
    }
  ],
  "targetFormat": "xlsx"
}' |
apify call apizilla/data-ops-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,apizilla/data-ops-api"
        }
    }
}
```

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/NNcDzOLHCq3an4I8B/builds/UhOxLEiDEksCEDoEK/openapi.json
