{
  "openapi": "3.0.1",
  "info": {
    "title": "Dataset Diff & Change Detector: Only New Items",
    "description": "Returns what was added, removed or changed between two Apify datasets, files, Google Sheets or JSON arrays, matched by key, or since its own last run. Only-new-items mode returns just rows never seen on any earlier run. CSV/Excel report, change log, webhook. Agent-ready: pay per event (x402, MCP).",
    "version": "0.1",
    "x-build-id": "18vwHx6LJw9ngo9u8"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/nerolabs~dataset-diff-detector/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-nerolabs-dataset-diff-detector",
        "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/nerolabs~dataset-diff-detector/runs": {
      "post": {
        "operationId": "runs-sync-nerolabs-dataset-diff-detector",
        "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/nerolabs~dataset-diff-detector/run-sync": {
      "post": {
        "operationId": "run-sync-nerolabs-dataset-diff-detector",
        "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": {
          "oldDatasetId": {
            "title": "Old dataset (the 'before' snapshot)",
            "type": "string",
            "description": "Pick an existing Apify dataset holding the earlier version of your data. Use this OR 'Old file URL' OR 'Old data (inline)' below; leave all three empty when a 'Snapshot name' is set further down. Declaring it this way is what lets this Actor run with limited permissions: it may read the dataset you point at, and nothing else on your account."
          },
          "oldFileUrl": {
            "title": "Old file URL (CSV, Excel, JSON or Google Sheet)",
            "type": "string",
            "description": "Instead of a dataset, download the 'before' snapshot from a public link: a CSV or TSV file, an Excel .xlsx file (first sheet, header row), a JSON array or JSON Lines file, or a Google Sheet (paste the normal sheet link, sharing set to 'Anyone with the link can view'). The format is detected automatically. Up to 100 MB. Never charged. Ignored when 'Old dataset' is set."
          },
          "oldData": {
            "title": "Old data (inline)",
            "type": "array",
            "description": "A JSON array of records for the 'before' snapshot, for ad-hoc data instead of a dataset ID or file URL."
          },
          "newDatasetId": {
            "title": "New dataset (the 'after' snapshot)",
            "type": "string",
            "description": "Pick an existing Apify dataset holding the newer version of your data. Use this OR 'New file URL' OR 'New data (inline)' below."
          },
          "newFileUrl": {
            "title": "New file URL (CSV, Excel, JSON or Google Sheet)",
            "type": "string",
            "description": "Instead of a dataset, download the 'after' snapshot from a public link (same formats as above). Combined with a 'Snapshot name' below this watches a Google Sheet or a published CSV for changes: every run reports only what changed since the last one. Never charged. Ignored when 'New dataset' is set."
          },
          "newData": {
            "title": "New data (inline)",
            "type": "array",
            "description": "A JSON array of records for the 'after' snapshot, for ad-hoc data instead of a dataset ID or file URL."
          },
          "fileFormat": {
            "title": "File format (for file URLs)",
            "enum": [
              "auto",
              "csv",
              "tsv",
              "json",
              "jsonl",
              "xlsx"
            ],
            "type": "string",
            "description": "Only needed if automatic detection gets a file URL's format wrong. Applies to both file URLs.",
            "default": "auto"
          },
          "snapshotName": {
            "title": "Snapshot name (compare against this Actor's previous run)",
            "pattern": "^[A-Za-z0-9][A-Za-z0-9_-]{0,62}$",
            "type": "string",
            "description": "Optional. 1 to 63 letters, digits, dashes or underscores, for example 'shop-prices'. With a name set you can leave 'Old dataset' and 'Old data' empty: the first run saves the baseline and reports nothing, every later run compares the new data against the saved snapshot and then replaces it. Fill 'Old dataset' or 'Old data' as well on the first run to seed the baseline without a wasted run. When a baseline is saved and no old snapshot is supplied, an empty new snapshot is skipped and the baseline is kept (a webhook, if set, is still delivered and charged). If you also supply an old snapshot on that run, an empty new side is compared as normal, every old row is charged as removed, and the empty set is saved. Snapshots live in a key-value store named 'nerolabs-dataset-diff-snapshots' in your own account."
          },
          "resetSnapshot": {
            "title": "Reset snapshot",
            "type": "boolean",
            "description": "Optional. Turn on for one run to forget whatever is saved under the snapshot name above: this run compares nothing (unless you also supply an old snapshot) and saves the new data as a fresh baseline. Turn it off again afterwards.",
            "default": false
          },
          "onlyNewItems": {
            "title": "Only new items (remember every row ever seen)",
            "type": "boolean",
            "description": "Optional, off by default. Needs 'Snapshot name'. Returns only rows never seen on ANY earlier run under that name, so each scheduled run after a scraper gives you just the new items: a row that disappears and later comes back is not reported again, and removed or changed rows are left out. Rows come back as 'added' with the full row in 'newValues', charged per new row only. Set 'Key field(s)' (for example a URL or place ID) so a changed price does not count as a new item. The first run with a new name saves a baseline and returns nothing. Up to 500,000 rows are remembered per name (only short hashes of the key are stored, never row content); 'Reset snapshot' clears the memory.",
            "default": false
          },
          "keyFields": {
            "title": "Key field(s)",
            "type": "array",
            "description": "The field name(s) that uniquely identify a row across both snapshots (e.g. 'sku', 'id', or 'email'). This is what lets the Actor tell 'this row changed' apart from 'this row was removed and a different one was added'. Leave empty to match rows by their full content instead (fine for simple lists, but then any change to any field makes a row look like a remove+add pair rather than a 'changed' row).",
            "items": {
              "type": "string"
            }
          },
          "compareFields": {
            "title": "Fields to compare",
            "type": "array",
            "description": "Optional. Only compare these specific fields when deciding if a matched row changed. Leave empty to compare every field except any listed in 'Fields to ignore' below.",
            "items": {
              "type": "string"
            }
          },
          "ignoreFields": {
            "title": "Fields to ignore",
            "type": "array",
            "description": "Optional. Field names to exclude from comparison, useful for things like a 'scrapedAt' or 'lastChecked' timestamp that always differs between runs and would otherwise mark every row as changed.",
            "items": {
              "type": "string"
            }
          },
          "includeUnchanged": {
            "title": "Include unchanged rows in the output",
            "type": "boolean",
            "description": "When on, rows present in both snapshots with no real difference are also written to the output dataset (charged at a much lower rate, see Pricing). Off by default, since a diff tool's whole point is usually just the things that changed.",
            "default": false
          },
          "maxItems": {
            "title": "Max rows to process",
            "type": "integer",
            "description": "Safety cap applied to each side separately: only the first N rows of the new data, and of the old data if you supply it, are loaded. A snapshot saved by an earlier run is never capped, so a cap smaller than that snapshot can report rows past the cap as removed (charged) and saves the shorter set as the next baseline. Leave at 0 for no cap (up to the Actor's own 100,000-rows-per-side hard limit).",
            "default": 0
          },
          "outputDatasetName": {
            "title": "Also append to a named dataset",
            "type": "string",
            "description": "Optional. A name (3 to 63 letters, digits or hyphens, e.g. 'price-change-log'). Every run's added, removed and changed rows are appended to a dataset with this name in your account, created on the first run, so a scheduled watch builds one running change log instead of one dataset per run. Not charged."
          },
          "exportFormats": {
            "title": "Export diff report as file",
            "type": "array",
            "description": "Optional. Generate a real downloadable diff report on top of the dataset. Leave empty to skip file export entirely.",
            "items": {
              "type": "string",
              "enum": [
                "csv",
                "xlsx"
              ],
              "enumTitles": [
                "CSV",
                "Excel (.xlsx)"
              ]
            },
            "default": []
          },
          "webhookUrl": {
            "title": "Webhook URL (optional)",
            "type": "string",
            "description": "Optional. If set, the diff rows (plus the added/removed/changed counts, snapshot details and download links) are POSTed here as JSON on every run, including a baseline run, a run with no changes and a run skipped for an empty new snapshot, so a scheduled watch always reports back to Slack, Zapier, Make, n8n or your own endpoint. Charged on every run where the endpoint actually confirms receipt (HTTP 2xx), those runs included; a failed delivery is reported as a warning in the run's output and costs nothing."
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}