# Apify output contract checks by Check Charlie (`automatron/check-charlie-output-qa`) Actor

Check up to 20 supplied JSON rows for missing fields, incorrect types, duplicate IDs and timestamp inconsistencies. Exact failing rows in JSON and Markdown. Deterministic checks, no AI model or target Actor calls. $0.01/completed report; no certification.

- **URL**: https://apify.com/automatron/check-charlie-output-qa.md
- **Developed by:** [Automatron](https://apify.com/automatron) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

$0.01 / completed report

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

## Apify output contract checks by Check Charlie

Check a small JSON export before feeding it into a spreadsheet, CRM, report or automation. Charlie compares supplied rows with the contract you declare and returns **PASS, FAIL or NOT TESTED** for each rule, with exact failing row indices.

**$0.01 per completed report**, up to 20 rows and 16 field rules. No model fee, subscription, scraping or upstream Actor calls. The Store may display this as $10 per 1,000 reports. This is a deterministic validator with a specialist persona; it does not use an AI model.

### Quick start

1. Keep the fictional default bundle for a demonstration, or replace it with a redacted sample and your expected contract.
2. Run with at least $0.01 as the maximum charge. One report is produced per run.
3. Open **REPORT**, **REPORT-MARKDOWN** or the default dataset. **SUMMARY** records completion and billing status.

The default deliberately contains three defects in row **1** (the second row): a duplicate `id`, a string where `views` should be a number, and an invalid `observedAt` timestamp. Charlie should report precisely those failures. A report that finds defects is a successful delivery, not a runtime failure.

For a clean result, change the second ID to `fictional-2`, the second views value to the number `14`, and its timestamp to `2026-10-01T10:00:00Z`.

### Input contract

Send one `bundle` object with `schemaVersion: 1`, `actorUrl`, `declaredBuild`, `contract` and `sample`. The Actor URL and build are unverified labels: Charlie does not visit them or execute the target Actor. A complete fictional input is included in the Input tab.

- `sample`: 0–20 JSON objects. The serialized bundle must fit within 20,000 UTF-8 bytes, with nesting depth at most 8.
- `contract.fields`: 1–16 unique paths, each with `path` and `type`. Types: `string`, `number`, `boolean`, `object`, `array`, `null`. Paths address up to four nested object keys; arrays are not traversed.
- Optional field flags: `required`, `nonEmpty`, `unique`, `timestamp` (booleans). Uniqueness supports scalar strings, numbers and booleans; it needs at least two values of the declared type. Timestamps must be strings in strict UTC ISO format, such as `2026-10-01T09:00:00Z` or with exactly three millisecond digits.
- `contract.maxItems`: optional maximum **sample** size; it never establishes a full run's item count.
- `contract.observationWindow`: optional `{ "from": "2026-10-01T00:00:00Z", "through": "2026-10-02T00:00:00Z" }` bounds for valid timestamp fields.
- `contract.orderedPairs`: up to eight `{ "earlier": "createdAt", "later": "updatedAt" }` pairs referencing declared timestamp fields.

Optional absent values are not type-checked. Use `required: true` if absence is a defect. A missing prerequisite results in NOT TESTED, rather than a fabricated pass. Uniqueness reports subsequent duplicate rows, not the first occurrence.

Use only redacted, non-sensitive samples. Credential-like fields, personal email addresses, executable content, remote schemas and some unsafe text are rejected conservatively. This screening is not a complete personal-data detector. Do not submit secrets or private customer records. Samples stay in your Apify run input according to your storage settings; reports contain rule outcomes and row indices, not original sample values.

### Output and billing

One dataset item contains the report: sample count, check counts, per-check status, tested rows, zero-based failing row indices, limitations and a digest of the serialized evidence. The same report is available as JSON and Markdown in the run's key-value store.

The $0.01 completion event is requested **only after** both report files and the dataset item have been saved. Valid reports with defects are billable. Empty samples return a usable NOT TESTED report without the completion fee. Samples with no testable field checks return `incomplete`, also without the completion fee. Invalid input, exhausted report budgets and failed delivery incur no completion fee. No start or per-dataset-item fee is configured. Any platform charges separately imposed by your Apify plan remain subject to that plan.

If SUMMARY says `reconciliation_required`, inspect the stored report, PROGRESS and Apify charge receipt before starting another run. An uncertain append or charge is never automatically retried. Repeated separate runs are separate reports and may incur separate fees. Error details use safe codes rather than echoing your data.

### API and agent use

POST the input JSON to `https://api.apify.com/v2/actors/automatron~check-charlie-output-qa/runs?maxTotalChargeUsd=0.01` with your own Apify bearer token. Read the returned run until terminal, then retrieve its default dataset and SUMMARY. Do not put credentials in the input. For reproducible workflows, specify a qualified build explicitly.

Example automation: take at most 20 already-collected output rows, declare the required downstream columns, submit the bundle, and branch on `counts.fail > 0`. Treat NOT TESTED separately. Apify-compatible agent tooling can invoke the same Actor; Charlie accepts declarative rules, not natural-language tool instructions.

### What this report cannot establish

Charlie does not certify live Actor reliability, build authenticity, security, factual correctness, marketplace quality, pricing or full-run coverage. A small sample passing checks is not a release certificate. The evidence digest identifies submitted bytes after serialization; it does not prove their source. No overall star rating or customer review is generated.

Found a reproducible problem with Charlie? Share a redacted input and the exact unexpected check through this Actor's Issues tab. Honest reviews after actual use are welcome, regardless of rating.

# Actor input Schema

## `bundle` (type: `object`):

At most 20 JSON rows and 20 KB. The fictional example intentionally contains three defects. Replace with your redacted sample. No credentials or customer personal data. Declared Actor/build are unverified labels, never fetched.

## Actor input object example

```json
{
  "bundle": {
    "schemaVersion": 1,
    "actorUrl": "https://apify.com/example/demo",
    "declaredBuild": "demo-1",
    "contract": {
      "fields": [
        {
          "path": "id",
          "type": "string",
          "required": true,
          "unique": true
        },
        {
          "path": "views",
          "type": "number",
          "required": true
        },
        {
          "path": "observedAt",
          "type": "string",
          "required": true,
          "timestamp": true
        }
      ],
      "maxItems": 20
    },
    "sample": [
      {
        "id": "fictional-1",
        "views": 12,
        "observedAt": "2026-10-01T09:00:00Z"
      },
      {
        "id": "fictional-1",
        "views": "14",
        "observedAt": "not-a-date"
      }
    ]
  }
}
```

# Actor output Schema

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

No description

## `summary` (type: `string`):

No description

## `report` (type: `string`):

No description

## `markdown` (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 = {
    "bundle": {
        "schemaVersion": 1,
        "actorUrl": "https://apify.com/example/demo",
        "declaredBuild": "demo-1",
        "contract": {
            "fields": [
                {
                    "path": "id",
                    "type": "string",
                    "required": true,
                    "unique": true
                },
                {
                    "path": "views",
                    "type": "number",
                    "required": true
                },
                {
                    "path": "observedAt",
                    "type": "string",
                    "required": true,
                    "timestamp": true
                }
            ],
            "maxItems": 20
        },
        "sample": [
            {
                "id": "fictional-1",
                "views": 12,
                "observedAt": "2026-10-01T09:00:00Z"
            },
            {
                "id": "fictional-1",
                "views": "14",
                "observedAt": "not-a-date"
            }
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("automatron/check-charlie-output-qa").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 = { "bundle": {
        "schemaVersion": 1,
        "actorUrl": "https://apify.com/example/demo",
        "declaredBuild": "demo-1",
        "contract": {
            "fields": [
                {
                    "path": "id",
                    "type": "string",
                    "required": True,
                    "unique": True,
                },
                {
                    "path": "views",
                    "type": "number",
                    "required": True,
                },
                {
                    "path": "observedAt",
                    "type": "string",
                    "required": True,
                    "timestamp": True,
                },
            ],
            "maxItems": 20,
        },
        "sample": [
            {
                "id": "fictional-1",
                "views": 12,
                "observedAt": "2026-10-01T09:00:00Z",
            },
            {
                "id": "fictional-1",
                "views": "14",
                "observedAt": "not-a-date",
            },
        ],
    } }

# Run the Actor and wait for it to finish
run = client.actor("automatron/check-charlie-output-qa").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 '{
  "bundle": {
    "schemaVersion": 1,
    "actorUrl": "https://apify.com/example/demo",
    "declaredBuild": "demo-1",
    "contract": {
      "fields": [
        {
          "path": "id",
          "type": "string",
          "required": true,
          "unique": true
        },
        {
          "path": "views",
          "type": "number",
          "required": true
        },
        {
          "path": "observedAt",
          "type": "string",
          "required": true,
          "timestamp": true
        }
      ],
      "maxItems": 20
    },
    "sample": [
      {
        "id": "fictional-1",
        "views": 12,
        "observedAt": "2026-10-01T09:00:00Z"
      },
      {
        "id": "fictional-1",
        "views": "14",
        "observedAt": "not-a-date"
      }
    ]
  }
}' |
apify call automatron/check-charlie-output-qa --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automatron/check-charlie-output-qa"
        }
    }
}
```

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/RGZeEdjlcn1xtIYTe/builds/AWiBTBLQcGZMswjmO/openapi.json
