{
  "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": "NsNVZjySHmOOJa0TV"
  },
  "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": {
          "confidentialRecords": {
            "title": "Confidential Records",
            "minItems": 1,
            "maxItems": 1000,
            "type": "array",
            "description": "Sensitive inline whole-row records for API or Console submission. Apify encrypts this top-level secret field before storing run input and the Actor decrypts it only at runtime. Use exactly one of Confidential Records, Source, or Records. This input protection does not encrypt Dataset, Key-Value Store, or OUTPUT results; those retain the same buyer-visible workflow meanings and platform retention controls.",
            "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": "Preferred when contact data is already stored or larger than a small inline job. 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 Source combined with Confidential Records, 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
          },
          "records": {
            "title": "Records",
            "minItems": 1,
            "maxItems": 1000,
            "type": "array",
            "description": "Permanent plaintext compatibility input for affirmatively non-sensitive inline whole-row records. Sensitive rows belong in Confidential Records; already-stored or larger data belongs in Source. Rust rejects mixed inline and source routes, mixed inline lanes, and empty selections. 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 exactly one route 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
                }
              }
            }
          },
          "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}