{
  "openapi": "3.0.1",
  "info": {
    "title": "CRM Contact Cleanup & Dedupe Prep",
    "description": "Turn supplied contact rows into a reimport-ready cleaned file plus focused review and possible-match files. Normalize mapped URL, email, and U.S.-leaning address values while preserving original fields. No scraping, finding, verification, enrichment, geocoding, survivor selection, or merging.",
    "version": "2.0",
    "x-build-id": "eWJP20dIgcPqge8yb"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/critd~contact-cleanup/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-critd-contact-cleanup",
        "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/critd~contact-cleanup/runs": {
      "post": {
        "operationId": "runs-sync-critd-contact-cleanup",
        "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/critd~contact-cleanup/run-sync": {
      "post": {
        "operationId": "run-sync-critd-contact-cleanup",
        "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": {
          "records": {
            "title": "Records",
            "minItems": 1,
            "maxItems": 1000,
            "type": "array",
            "description": "Inline whole-row records. Use this route without Source; Rust rejects mixed inline and source routes. The Console prefill is a fictional 12-row deterministic example and is also the committed smoke input. API, task, CLI, and scheduler callers must submit records or a source because prefill is UI-only. recordId, url, email, and address have fixed inline mappings, while additional original fields remain available to the whole-row workflow. Invalid-looking supported values remain review evidence instead of being silently dropped.",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "recordId": {
                  "title": "Record ID",
                  "type": "string",
                  "description": "Optional source identifier to map output rows back to your system. It is not required to be unique and does not authorize automatic dedupe or merge.",
                  "editor": "textfield",
                  "nullable": true,
                  "maxLength": 256
                },
                "url": {
                  "title": "URL",
                  "type": "string",
                  "description": "Optional supplied website URL or bare domain to normalize. Malformed values remain row diagnostics; this Actor does not crawl the site or prove reachability.",
                  "editor": "textfield",
                  "nullable": true,
                  "maxLength": 4096
                },
                "email": {
                  "title": "Email",
                  "type": "string",
                  "description": "Optional supplied email address to normalize for cleanup and matching signals. This Actor does not verify deliverability, inbox existence, or inbox ownership.",
                  "editor": "textfield",
                  "nullable": true,
                  "maxLength": 320
                },
                "address": {
                  "title": "Address",
                  "type": "string",
                  "description": "Optional supplied U.S.-leaning address text to normalize for cleanup and comparison-key signals. This Actor does not certify postal deliverability or geocode addresses.",
                  "editor": "textarea",
                  "nullable": true,
                  "maxLength": 1024
                }
              }
            }
          },
          "source": {
            "title": "Source",
            "required": [
              "type"
            ],
            "type": "object",
            "description": "Choose one whole-row source: file, Dataset, or Key-Value Store record. Set type and only its matching route fields, then map recordId, url, email, and address when source names differ. Rust rejects a Source combined with inline Records or fields from another route. Preview first, then stay within one qualified local profile: 1,000 accepted rows at 6 source fields or 261 source fields at 12 rows. Their cross-product was not qualified. This form is not proof that a source exists, was read, or is supported beyond those profiles.",
            "properties": {
              "type": {
                "title": "Source Route",
                "type": "string",
                "description": "Exactly one source route. Rust validation rejects mixed inline records and source routes, and rejects fields that do not match this selected route.",
                "editor": "select",
                "enum": [
                  "file",
                  "dataset",
                  "keyValueStore"
                ],
                "enumTitles": [
                  "File upload",
                  "Dataset",
                  "Key-value store record"
                ]
              },
              "file": {
                "title": "File",
                "type": "string",
                "description": "File-upload reference for type=file. The editor supplies a string; Rust accepts only supported Apify KVS-record URL or KVS-reference shapes, strips query credentials from selected diagnostics, and applies bounded UTF-8 and format checks. A form selection is not proof that the record exists or was read.",
                "editor": "fileupload",
                "nullable": true,
                "maxLength": 4096,
                "example": "apify://key-value-stores/synthetic-source/records/contacts.csv"
              },
              "datasetId": {
                "title": "Source Dataset",
                "type": "string",
                "description": "Dataset ID or unique name for type=dataset. The route requests READ-only access, consumes complete object rows without field projection, pages through bounded preflight, and treats Dataset metadata counts as advisory. Picker selection is not storage readback or live-run proof.",
                "resourceType": "dataset",
                "resourcePermissions": [
                  "READ"
                ],
                "nullable": true,
                "maxLength": 256,
                "example": "synthetic-dataset-name"
              },
              "storeId": {
                "title": "Source Key-Value Store",
                "type": "string",
                "description": "Key-value-store ID or unique name for type=keyValueStore. The route requests READ-only access and reads only the selected text record under byte and format guardrails. Picker selection is not storage readback or live-run proof.",
                "resourceType": "keyValueStore",
                "resourcePermissions": [
                  "READ"
                ],
                "nullable": true,
                "maxLength": 256,
                "example": "synthetic-source-store"
              },
              "recordKey": {
                "title": "KVS Record Key",
                "type": "string",
                "description": "Record key inside the selected key-value store for type=keyValueStore. The selected text is parsed as csv, jsonl, or json_array under the same bounded whole-row contract.",
                "editor": "textfield",
                "nullable": true,
                "maxLength": 512,
                "example": "contacts.jsonl"
              },
              "format": {
                "title": "Source Format",
                "type": "string",
                "description": "Declared body format for file and key-value-store routes. When auto or omitted, Rust detects csv, jsonl, or json_array from the selected record key, extension, or content type. Dataset sources already provide object rows and must leave this empty.",
                "editor": "select",
                "nullable": true,
                "enum": [
                  "auto",
                  "csv",
                  "jsonl",
                  "json_array"
                ],
                "enumTitles": [
                  "Auto-detect",
                  "CSV with header",
                  "JSON Lines",
                  "JSON array"
                ],
                "example": "csv"
              },
              "fieldMap": {
                "title": "Field Map",
                "type": "object",
                "description": "Optional map from supported Contact Cleanup fields to source column or object-field names. Only recordId, url, email, and address are mapping targets. Unmapped original columns and values stay in the whole-row representation; the map does not authorize dropping them.",
                "editor": "json",
                "additionalProperties": false,
                "example": {
                  "recordId": "crm_id",
                  "url": "website",
                  "email": "email_address",
                  "address": "mailing_address"
                },
                "properties": {
                  "recordId": {
                    "title": "Record ID Field",
                    "type": "string",
                    "description": "Source field or column name that maps to recordId.",
                    "nullable": true,
                    "maxLength": 256
                  },
                  "url": {
                    "title": "URL Field",
                    "type": "string",
                    "description": "Source field or column name that maps to url.",
                    "nullable": true,
                    "maxLength": 256
                  },
                  "email": {
                    "title": "Email Field",
                    "type": "string",
                    "description": "Source field or column name that maps to email.",
                    "nullable": true,
                    "maxLength": 256
                  },
                  "address": {
                    "title": "Address Field",
                    "type": "string",
                    "description": "Source field or column name that maps to address.",
                    "nullable": true,
                    "maxLength": 256
                  }
                }
              },
              "offset": {
                "title": "Dataset Offset",
                "type": "integer",
                "description": "Optional starting offset for type=dataset. It is ignored by other routes and rejected by Rust validation if mixed with them.",
                "editor": "number",
                "minimum": 0
              }
            },
            "additionalProperties": false
          },
          "previewOnly": {
            "title": "Preview Only",
            "type": "boolean",
            "description": "Source-route control. true runs bounded source preflight and local workflow preparation with zero KVS, Dataset, final OUTPUT, or custom-charge writes. false or omitted selects execution after preflight and spend-cap checks. Preview is not provider storage, billing, or live-run proof."
          },
          "sourceMaxRows": {
            "title": "Source Row Cap",
            "minimum": 1,
            "maximum": 10000,
            "type": "integer",
            "description": "Set this source-route cap explicitly to 1-1000. The machine-qualified local row profile is 1,000 accepted rows at 6 source fields; the separate width profile is 261 source fields at 12 rows, and their cross-product was not qualified. The schema and parser retain a backward-compatible maximum and omitted-field runtime fallback of 10000, but the 10,000-row qualification candidate failed at KVS publication and is not supported buyer capacity. There is intentionally no schema default because platform injection would add a source-only field to inline runs. Physical blank CSV and JSONL lines do not consume the cap; accepted rows with no actionable mapped value do."
          },
          "rowLimitBehavior": {
            "title": "Row Limit Behavior",
            "enum": [
              "fail_over_limit"
            ],
            "type": "string",
            "description": "First-release source row-limit mode. The first record beyond the accepted sourceMaxRows cap is rejected before default dataset rows or OUTPUT; silent truncation is not supported."
          },
          "workflow": {
            "title": "Cleaned Review File",
            "required": [],
            "type": "object",
            "description": "Choose the Contact 2.0 reimport file shape. Omission resolves to side_by_side CSV with the contactCleanup generated-field namespace. side_by_side keeps source values next to proposed values; replace_supported_fields changes only exact safe no-review URL, email, or address cells and retains displaced originals.",
            "properties": {
              "exportMode": {
                "title": "Export Mode",
                "type": "string",
                "description": "side_by_side preserves every original field first and appends generated workflow fields. replace_supported_fields changes only mapped URL, email, or address values that have an exact no-review safe replacement and retains displaced originals in generated fields.",
                "editor": "select",
                "default": "side_by_side",
                "prefill": "side_by_side",
                "enum": [
                  "side_by_side",
                  "replace_supported_fields"
                ],
                "enumTitles": [
                  "Side by side",
                  "Replace safe supported fields"
                ],
                "example": "side_by_side"
              },
              "exportFormat": {
                "title": "Export Format",
                "type": "string",
                "description": "CSV emits a headered UTF-8 reimport file with deterministic cell encoding. JSON emits a compact UTF-8 array and preserves native JSON value types.",
                "editor": "select",
                "default": "csv",
                "prefill": "csv",
                "enum": [
                  "csv",
                  "json"
                ],
                "enumTitles": [
                  "CSV",
                  "JSON"
                ],
                "example": "csv"
              },
              "generatedFieldNamespace": {
                "title": "Generated Field Namespace",
                "type": "string",
                "description": "Base prefix for generated workflow fields. Use 1-64 ASCII alphanumeric characters beginning with a lowercase letter. Rust deterministically selects a numbered collision-free derivative when an original field already uses this prefix.",
                "editor": "textfield",
                "default": "contactCleanup",
                "prefill": "contactCleanup",
                "example": "contactCleanup",
                "minLength": 1,
                "maxLength": 64,
                "pattern": "^[a-z][A-Za-z0-9]{0,63}$"
              }
            },
            "default": {
              "exportMode": "side_by_side",
              "exportFormat": "csv",
              "generatedFieldNamespace": "contactCleanup"
            },
            "additionalProperties": false
          },
          "fieldGroups": {
            "title": "Field Groups",
            "minItems": 1,
            "uniqueItems": true,
            "type": "array",
            "description": "Accepted compatibility control retained so existing input shapes remain valid. Contact 2.0 evaluates URL, email, and address under fixed versioned semantics and does not use this field as a runtime-version selector or to change its artifact package.",
            "items": {
              "type": "string",
              "enum": [
                "url",
                "email",
                "address"
              ],
              "enumTitles": [
                "URL",
                "Email",
                "Address"
              ]
            },
            "default": [
              "url",
              "email",
              "address"
            ]
          },
          "reviewStrictness": {
            "title": "Review Strictness",
            "enum": [
              "minimal",
              "standard",
              "strict"
            ],
            "type": "string",
            "description": "Accepted compatibility control retained so existing input shapes remain valid. Contact 2.0 uses fixed versioned review-decision semantics and never treats this field as a runtime-version selector, verification, confidence, enrichment, survivor choice, or merge authority.",
            "default": "standard"
          },
          "dedupeKeyMode": {
            "title": "Dedupe Key Mode",
            "enum": [
              "off",
              "keys_only",
              "keys_and_candidates"
            ],
            "type": "string",
            "description": "Accepted compatibility control retained so existing input shapes remain valid. The Console prefill is keys_and_candidates and the omitted-input default is keys_only. Contact 2.0 always builds its fixed possible-match file and never uses this field as a runtime-version selector, deletes rows, ranks records, chooses survivors, or merges contacts.",
            "default": "keys_only"
          }
        }
      },
      "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
                  }
                }
              },
              "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}