{
  "openapi": "3.0.1",
  "info": {
    "title": "Lead Scoring Engine — ICP Score Leads 0-100",
    "description": "Score leads 0-100 against your Ideal Customer Profile across 6 weighted dimensions: industry, company size, services, contact presence, intent signals, and data completeness. Returns A-F grades + per-dimension notes. No API calls. $0.03/lead.",
    "version": "1.4",
    "x-build-id": "3g6l4FIqf4FcHoLgn"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/ryanclinton~lead-scoring-engine/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-ryanclinton-lead-scoring-engine",
        "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/ryanclinton~lead-scoring-engine/runs": {
      "post": {
        "operationId": "runs-sync-ryanclinton-lead-scoring-engine",
        "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/ryanclinton~lead-scoring-engine/run-sync": {
      "post": {
        "operationId": "run-sync-ryanclinton-lead-scoring-engine",
        "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": {
          "leads": {
            "title": "Leads (inline)",
            "maxItems": 100000,
            "type": "array",
            "description": "Array of lead objects to score. Each object should have fields like domain, companyName, industry, services, emails, contacts, etc. Use this OR datasetId — not both.",
            "default": [
              {
                "domain": "brightedge.com",
                "companyName": "BrightEdge",
                "industry": "Marketing Agency",
                "services": [
                  "SEO",
                  "Content Marketing",
                  "Analytics"
                ],
                "companySize": "51-200",
                "emails": [
                  "hello@brightedge.com"
                ],
                "contacts": [
                  {
                    "name": "Sarah Chen",
                    "title": "Head of SEO",
                    "email": "s.chen@brightedge.com"
                  }
                ],
                "phones": [
                  "+1 415-555-0182"
                ],
                "address": "1 Market St, San Francisco, CA",
                "rating": 4.7,
                "reviewCount": 143,
                "hasChatWidget": true,
                "hasContactForm": true,
                "techStack": [
                  "HubSpot",
                  "Google Analytics",
                  "Salesforce"
                ],
                "foundedYear": 2011,
                "description": "Enterprise SEO and content performance platform for B2B companies."
              }
            ]
          },
          "datasetId": {
            "title": "Dataset ID (from upstream actor)",
            "type": "string",
            "description": "Apify dataset ID to load leads from. Use this instead of inline leads when chaining with another actor in a pipeline."
          },
          "goal": {
            "title": "Goal",
            "enum": [
              "generic",
              "pipeline-growth",
              "quick-wins",
              "cost-efficiency",
              "high-ltv"
            ],
            "type": "string",
            "description": "What outcome to optimise for. 'pipeline-growth' accepts more leads (B/C also pass). 'quick-wins' biases hard toward intent + reachable contacts. 'cost-efficiency' penalises enrichment-required leads. 'high-ltv' biases enterprise + strong ICP. 'generic' = no goal bias. Goal layers ON TOP of mode + persona — per-dimension weights still win.",
            "default": "generic"
          },
          "mode": {
            "title": "Scoring Mode",
            "enum": [
              "auto",
              "fast",
              "balanced",
              "thorough"
            ],
            "type": "string",
            "description": "Preset that shapes HOW scoring runs. 'auto' picks based on cohort size + data richness. 'fast' weights industry + size, ignores completeness. 'balanced' is the default 25/20/20/15/10/10 mix. 'thorough' up-weights intent + completeness for fully-enriched cohorts. Per-dimension weights below override the preset.",
            "default": "auto"
          },
          "persona": {
            "title": "Persona",
            "enum": [
              "generic",
              "outbound-sdr",
              "account-exec",
              "growth-marketer"
            ],
            "type": "string",
            "description": "Preset that shapes WHO scoring serves. SDRs need reachable contacts; AEs need fit before reach; Growth marketers prioritise intent + recency. 'generic' defers to mode preset.",
            "default": "generic"
          },
          "outputProfile": {
            "title": "Output Profile",
            "enum": [
              "minimal",
              "standard",
              "full",
              "llm"
            ],
            "type": "string",
            "description": "Controls how much detail goes into each pushed record. 'minimal' = decision + action only. 'standard' = decision + factors + notes (drops scoringTrace). 'full' = everything. 'llm' = optimised for AI agents (summary, why, opening angle, scoring trace).",
            "default": "standard"
          },
          "qualifyThreshold": {
            "title": "Qualify Threshold",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "Score at or above this becomes decision='qualify' (default 65 = grade B+). Tune for your team's bandwidth.",
            "default": 65
          },
          "disqualifyThreshold": {
            "title": "Disqualify Threshold",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "Score below this becomes decision='disqualify' (default 35 = grade D-). Leads between disqualify and qualify thresholds get decision='nurture'.",
            "default": 35
          },
          "csvExport": {
            "title": "Write CSV to Key-Value Store",
            "type": "boolean",
            "description": "When enabled, writes OUTPUT.csv with Apollo / Outreach.io / Salesloft compatible columns to the run's default Key-Value Store. Download from the Storage tab.",
            "default": true
          },
          "watchlistName": {
            "title": "Watchlist Name (Temporal Intelligence)",
            "type": "string",
            "description": "Set to enable cross-run trend tracking. Two runs with the same watchlistName attach `temporalSignals` (trend / momentumScore / scoreDelta / runsSeen / reengage flag) to each lead by canonical eventId. First run shows trend='new' for everything; subsequent runs surface rising/falling/re-engagement leads. Stored in a named KV store, capped at 25k leads FIFO."
          },
          "monitorStateKey": {
            "title": "Monitor State Key (alias for watchlistName)",
            "type": "string",
            "description": "Suite-aligned alias for watchlistName. Either input works; if both are set, watchlistName wins. Lets the same upstream orchestrator pass one consistent field name across lead-scoring-engine, waterfall-contact-enrichment, phone-number-finder, bulk-email-verifier, company-deep-research, and lead-enrichment-pipeline."
          },
          "lastAction": {
            "title": "Last Action (closes the feedback loop)",
            "type": "object",
            "description": "Optional. Tells the actor what action you took on this watchlist since the last run. On the next scheduled run, the actor compares the current ICP score against the snapshot at action time and emits decisionMemory with an inferred outcome. Honest: only signal-change is observable — direct conversion / closed-deal / off-platform engagement are not. Shape: { type: 'sent-pitch' | 'qualified' | 'disqualified' | string, takenAt: ISO date, note?: string }. Requires watchlistName / monitorStateKey."
          },
          "enableIcpInsights": {
            "title": "Enable Passive ICP Insights",
            "type": "boolean",
            "description": "Detect ICP-drift from the current run's top performers (grade A leads) and surface industries/sizes that aren't in your declared ICP. Adds an `icpInsights` block to the summary record with `topIndustries`, `topCompanySizes`, `topServices`, and an `icpVsTopPerformerDrift.suggestion` string. Pure compute on this run — no cross-run state needed.",
            "default": false
          },
          "enableDedup": {
            "title": "Enable Same-Run Deduplication",
            "type": "boolean",
            "description": "Detect duplicate leads (by canonical domain) within this run's input. Each duplicate gets an `identity` block with `canonicalDomain`, `duplicateCount`, `duplicateRunIndices`, and `isCanonical`. The first occurrence is treated as canonical; later ones are flagged. Does not skip duplicates — flags them so you can choose how to merge upstream.",
            "default": false
          },
          "enableEconomics": {
            "title": "Enable ROI / Expected-Value Engine",
            "type": "boolean",
            "description": "Compute expectedValue per lead: conversion-probability proxy (from icpScore × intent × contact richness) × estimated deal size (industry × size proxy table) ÷ cost-to-act (enrichment + verification + SDR labour). Output: `expectedValue.expectedRoi`, `expectedRevenueUsd`, `costToActUsd`, plus `actionDecision: act|delay|ignore` driven by ROI. Industry deal-size proxies are conservative midpoints from public B2B benchmarks — override with `industryDealSizeOverrides` for accuracy.",
            "default": false
          },
          "industryDealSizeOverrides": {
            "title": "Industry Deal-Size Overrides (USD)",
            "type": "object",
            "description": "Per-industry estimated deal size in USD. User-supplied overrides win against the proxy table. Example: { \"SaaS\": 25000, \"Marketing Agency\": 12000, \"Real Estate\": 8000 }. Applies size multiplier (small × 0.4, mid × 1.0, enterprise × 5.0) on top."
          },
          "sdrCostPerTouch": {
            "title": "SDR Cost Per Touchpoint (USD)",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "Override the default SDR labour cost per outreach touch. Default: $5 (12 minutes at $25/hr fully-loaded). Used in cost-to-act computation."
          },
          "constraints": {
            "title": "Run-Level Constraints (Allocation)",
            "type": "object",
            "description": "Resource limits for this run. When set, the actor sorts leads by ROI and selects the top set within constraints. Each lead gets `allocationDecision: { selected, reason, excludedDueTo, rankInAllocation }`. Example: { \"maxOutreachPerRun\": 50, \"maxEnrichmentPerRun\": 100, \"budgetUsd\": 200 }."
          },
          "simulate": {
            "title": "Simulation Mode (Override Weights)",
            "type": "object",
            "description": "When set, the actor scores every lead twice — once with current weights, once with override weights — and emits a `simulation` block per lead showing the score delta and decision change. Use this to test ICP hypotheses without re-running. Example: { \"weightIndustry\": 30, \"weightIntentSignals\": 25 }. Doubles compute time but does NOT double PPE charges (you only pay for the primary score)."
          },
          "scorecardTemplate": {
            "title": "Scorecard Template (GTM Motion)",
            "enum": [
              "custom",
              "local-agency-outbound",
              "b2b-saas-abm",
              "ecommerce-services",
              "recruiter-sourcing"
            ],
            "type": "string",
            "description": "Pre-built configuration bundle for a common GTM motion. 'local-agency-outbound' (SMB/mid-market agencies, balanced fit). 'b2b-saas-abm' (enterprise SaaS, AE-led, high-LTV bias, personal-email penalties). 'ecommerce-services' (DTC brands, growth-marketer persona). 'recruiter-sourcing' (intent-heavy for actively-hiring companies). 'custom' (no template — your inputs win). Template fields fill in only where you haven't set them.",
            "default": "custom"
          },
          "outcomeDatasetId": {
            "title": "Outcome Dataset ID (Validate Scoring)",
            "type": "string",
            "description": "Apify dataset ID containing past lead outcomes (won deals, meetings booked, revenue). The actor joins your scored leads against this dataset on `outcomeJoinKey` (default 'domain') and computes win rate per grade — proves whether the score is actually predictive. Without this, calibration uses benchmark priors only."
          },
          "outcomeJoinKey": {
            "title": "Outcome Join Key",
            "type": "string",
            "description": "Field on outcome dataset records used to match against scored leads. Defaults to 'domain'. Both sides are normalised to canonical lowercase domain.",
            "default": "domain"
          },
          "outcomeFields": {
            "title": "Outcome Field Names",
            "type": "object",
            "description": "Map outcome dataset field names to the actor's expectations. Example: { \"won\": \"dealWon\", \"revenue\": \"closedRevenueUsd\", \"meetingBooked\": \"meetingBooked\" }. Win-flag values like true/won/closed-won/y/yes/1 all match."
          },
          "negativeRules": {
            "title": "Negative Scoring Rules",
            "type": "array",
            "description": "Array of penalty rules. Each rule deducts `penalty` (0-100) from the final score when the rule matches. Match types: `contains` (substring), `equals` (exact), `matches` (regex). Total penalty per lead is capped at 50 to prevent over-correction. Example: [{\"field\":\"email\",\"contains\":\"gmail.com\",\"penalty\":15,\"reason\":\"personal-email\"}]."
          },
          "freshnessConfig": {
            "title": "Freshness Decay Config",
            "type": "object",
            "description": "Penalise stale records. `dateField` (auto-detected from common date fields like lastVerifiedAt / scrapedAt if blank), `decayAfterDays` (default 90 — penalty starts beyond this), `maxPenalty` (default 25 — cap on penalty). Output: `freshness: { status, ageDays, scorePenalty, recommendedAction }`."
          },
          "enableAccountRollup": {
            "title": "Enable Account-Level Rollup",
            "type": "boolean",
            "description": "When enabled, the actor groups leads by canonical domain and emits `accountReadiness[]` in the run summary — per-account: contacts found, decision-makers, champions, coverage (single-thread / multi-threaded / no-coverage), readiness (sales-ready / developing / cold). Useful for ABM / buying-committee workflows where account-level signal matters more than per-lead.",
            "default": false
          },
          "enableSavingsReport": {
            "title": "Enable Savings Report",
            "type": "boolean",
            "description": "When enabled (auto-on when `constraints` is set), the run summary includes a `savings` block reporting avoided cost from excluded leads — leads skipped, enrichment-cost avoided, SDR touches avoided, total spend avoided. Proves the actor's value as a resource-allocator."
          },
          "targetIndustries": {
            "title": "Target Industries",
            "type": "array",
            "description": "Industries that match your Ideal Customer Profile. Examples: 'Marketing Agency', 'SEO', 'Web Design', 'SaaS', 'Ecommerce'. Fuzzy matching and synonyms are applied automatically.",
            "default": [
              "Marketing Agency",
              "Digital Agency"
            ],
            "items": {
              "type": "string"
            }
          },
          "targetCompanySizes": {
            "title": "Target Company Sizes",
            "type": "array",
            "description": "Employee count bands that match your ICP. Use standard bands: '1-10', '11-50', '51-200', '201-500', '501-1000', '1001-5000'. Aliases like 'small', 'mid-market', 'enterprise' are also accepted.",
            "default": [
              "11-50",
              "51-200"
            ],
            "items": {
              "type": "string"
            }
          },
          "targetServices": {
            "title": "Target Services",
            "type": "array",
            "description": "Services your ideal clients offer or use. Examples: 'SEO', 'PPC', 'Web Design', 'Content Marketing'. Used to check lead.services field.",
            "default": [
              "SEO",
              "Content Marketing"
            ],
            "items": {
              "type": "string"
            }
          },
          "targetTechStack": {
            "title": "Target Tech Stack",
            "type": "array",
            "description": "Technologies your ideal clients use. Examples: 'HubSpot', 'Shopify', 'WordPress', 'Salesforce'. Used to check lead.techStack field.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "weightIndustry": {
            "title": "Weight: Industry Match (override)",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "Override the preset's industry weight. Leave blank to use the resolved preset."
          },
          "weightCompanySize": {
            "title": "Weight: Company Size Match (override)",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "Override the preset's company-size weight."
          },
          "weightServices": {
            "title": "Weight: Services Match (override)",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "Override the preset's services weight."
          },
          "weightContactPresence": {
            "title": "Weight: Contact Presence (override)",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "Override the preset's contact-presence weight."
          },
          "weightIntentSignals": {
            "title": "Weight: Intent Signals (override)",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "Override the preset's intent-signals weight."
          },
          "weightDataCompleteness": {
            "title": "Weight: Data Completeness (override)",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "Override the preset's data-completeness weight."
          },
          "minScoreToInclude": {
            "title": "Minimum Score to Include",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "Leads with an ICP score below this threshold are excluded from the output dataset entirely. This filter runs BEFORE charging — filtered leads are never pushed and never charged.",
            "default": 0
          },
          "outputSortedByScore": {
            "title": "Sort Output by Score (Highest First)",
            "type": "boolean",
            "description": "When enabled, the output dataset is sorted by icpScore descending so the best leads appear first.",
            "default": true
          },
          "maxLeads": {
            "title": "Maximum Leads to Score",
            "minimum": 1,
            "maximum": 100000,
            "type": "integer",
            "description": "Safety cap on the total number of leads processed. Prevents runaway costs when datasetId points to a very large dataset. Default: 10000.",
            "default": 10000
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}