{
  "openapi": "3.0.1",
  "info": {
    "title": "Phone Number Finder — Direct Dials from Websites",
    "description": "Find mobile, direct-dial, and company phone numbers for any prospect list. Two-step waterfall: 3B-record database first, then company website scraping as fallback. Pay $0.10 only when a number is found — no subscription, no per-seat fee.",
    "version": "2.1",
    "x-build-id": "CcgYYdHrIwa67lYBO"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/ryanclinton~phone-number-finder/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-ryanclinton-phone-number-finder",
        "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~phone-number-finder/runs": {
      "post": {
        "operationId": "runs-sync-ryanclinton-phone-number-finder",
        "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~phone-number-finder/run-sync": {
      "post": {
        "operationId": "run-sync-ryanclinton-phone-number-finder",
        "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",
        "required": [
          "persons"
        ],
        "properties": {
          "persons": {
            "title": "Persons to look up",
            "type": "array",
            "description": "List of people to find phone numbers for. Each entry must include at least: name + domain, email, or name + company. Optional fields (industry, companySize, title, lastVerifiedAt, hubspotId, etc.) flow into the decision/economics layer.",
            "default": [
              {
                "name": "John Smith",
                "email": "john.smith@acme.com",
                "company": "Acme Corp",
                "domain": "acme.com"
              }
            ]
          },
          "pdlApiKey": {
            "title": "People Data Labs API Key",
            "type": "string",
            "description": "Your People Data Labs API key. A built-in key is used if omitted. Bring your own key for higher rate limits."
          },
          "maxPersons": {
            "title": "Max persons",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "Maximum number of persons to process. Default: 100. Max: 1000.",
            "default": 100
          },
          "scrapeWebsites": {
            "title": "Scrape company websites",
            "type": "boolean",
            "description": "When enabled, scrapes the company website (homepage, /contact, /about, /team) for phone numbers as a fallback when PDL finds nothing.",
            "default": true
          },
          "includePersonDetails": {
            "title": "Include person details",
            "type": "boolean",
            "description": "When enabled, also returns the person's full name, job title, and work email from PDL alongside the phone numbers.",
            "default": false
          },
          "mode": {
            "title": "Mode",
            "enum": [
              "fast",
              "balanced",
              "thorough",
              "auto"
            ],
            "type": "string",
            "description": "fast = PDL only, no website fallback. balanced (default) = PDL + website fallback. thorough = PDL + website + extended retries. auto = picks based on batch size.",
            "default": "balanced"
          },
          "persona": {
            "title": "Persona",
            "enum": [
              "outbound-sdr",
              "account-exec",
              "growth-marketer",
              "generic"
            ],
            "type": "string",
            "description": "Adjusts scoring weights to favour what each role cares about. outbound-sdr prioritises mobile dials; account-exec prioritises high-confidence direct dials; growth-marketer prioritises volume.",
            "default": "generic"
          },
          "goal": {
            "title": "Goal",
            "enum": [
              "pipeline-growth",
              "quick-wins",
              "cost-efficiency",
              "high-ltv",
              "generic"
            ],
            "type": "string",
            "description": "What outcome are you optimising for? pipeline-growth = volume; quick-wins = highest-confidence calls only; cost-efficiency = penalise low-source-quality numbers; high-ltv = bias toward enterprise dealSize.",
            "default": "generic"
          },
          "scoringWeights": {
            "title": "Scoring weights (advanced)",
            "type": "object",
            "description": "Per-dimension weight overrides. Sum is renormalised. Keys: pdlMatch, phoneCount, sourceQuality, identifierStrength."
          },
          "outputProfile": {
            "title": "Output profile",
            "enum": [
              "minimal",
              "standard",
              "full",
              "llm"
            ],
            "type": "string",
            "description": "Strip optional fields from the dataset records. minimal = phones + decision only; standard = full minus deep diagnostics; full (default) = all blocks; llm = compact summary for AI consumers.",
            "default": "full"
          },
          "scorecardTemplate": {
            "title": "Scorecard template",
            "enum": [
              "b2b-saas-cold-call",
              "enterprise-account-research",
              "local-business-leads",
              "recruiter-sourcing",
              "custom"
            ],
            "type": "string",
            "description": "Pre-built bundles: b2b-saas-cold-call (mobile-first, personal-email penalties), enterprise-account-research (AE ownership, longer SLA), local-business-leads (website-friendly, lower cost-per-touch), recruiter-sourcing (mobile-only, HR-alias penalty).",
            "default": "custom"
          },
          "negativeRules": {
            "title": "Negative scoring rules",
            "type": "array",
            "description": "User-configurable penalties. Each rule: {field, contains|equals|matches, penalty, reason?}. Total penalty per record capped at 50 points (out of 100).",
            "default": []
          },
          "freshnessConfig": {
            "title": "Freshness decay",
            "type": "object",
            "description": "Penalise stale records: {dateField?, decayAfterDays? (default 90), maxPenalty? (default 25)}. Auto-detects lastVerifiedAt / verifiedAt / updatedAt / scrapedAt / fetchedAt / lastSeenAt / lastUpdated."
          },
          "circuitBreakerThreshold": {
            "title": "Circuit breaker threshold",
            "minimum": 1,
            "maximum": 100,
            "type": "integer",
            "description": "Stop the run cleanly after N consecutive no-phone records. Default: 5. Minimum 1, maximum 100.",
            "default": 5
          },
          "watchlistName": {
            "title": "Watchlist name",
            "type": "string",
            "description": "Optional name for cross-run state. Stored at phone-number-finder-history-{watchlistName}. Leave blank to run stateless."
          },
          "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 phone-number-finder, waterfall-contact-enrichment, 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 state against the snapshot at action time and emits decisionMemory with an inferred outcome. Honest: only signal-change is observable — direct call-connect / voicemail / conversation outcomes are not. Shape: { type: 'called' | 'left-voicemail' | 'sent-text' | string, takenAt: ISO date, note?: string }. Requires watchlistName / monitorStateKey to load history."
          },
          "referenceRunId": {
            "title": "Reference run ID",
            "type": "string",
            "description": "When set, switches the actor into diff-me-against-this-prior-run mode and emits changeFlags per record."
          },
          "enableDedup": {
            "title": "Flag duplicate domains",
            "type": "boolean",
            "description": "Annotate records when multiple persons share a canonical domain. Records are FLAGGED, not dropped.",
            "default": false
          },
          "enableAccountRollup": {
            "title": "Account-level rollup",
            "type": "boolean",
            "description": "Group records by company domain and emit accountReadiness[] in the summary record (sales-ready / developing / cold / unknown plus coverage classification).",
            "default": false
          },
          "enableEconomics": {
            "title": "Enable ROI / economics",
            "type": "boolean",
            "description": "Compute expectedRevenue / costToAct / ROI per record and a portfolioRoi rollup in the summary. Off by default — dealSize proxies are domain-specific.",
            "default": false
          },
          "industryDealSizeOverrides": {
            "title": "Industry deal-size overrides",
            "type": "object",
            "description": "Override the proxy table. Keys are lowercase industry tokens (e.g. \"software\"), values are USD numbers. User overrides win over the proxy."
          },
          "sdrCostPerTouch": {
            "title": "SDR labour cost per touch (USD)",
            "minimum": 0,
            "type": "number",
            "description": "Used in costToAct computation when economics is enabled. Default $1.50 per touchpoint.",
            "default": 1.5
          },
          "enrichmentCostPerLead": {
            "title": "Enrichment cost per lead (USD)",
            "minimum": 0,
            "type": "number",
            "description": "Used in costToAct when a record decision requires enrichment first. Default $0.50.",
            "default": 0.5
          },
          "constraints": {
            "title": "Allocation constraints",
            "type": "object",
            "description": "Run-level caps: {maxOutreachPerRun?, maxEnrichmentPerRun?, budgetUsd?}. Greedy ROI-first allocator selects records under all caps; selection result attaches to each record's allocationDecision block."
          },
          "simulate": {
            "title": "Simulation override weights",
            "type": "object",
            "description": "Re-score every record under override weights and emit a simulation block per record + simulationSummary in the run summary. Pure compute — does not double-charge."
          },
          "enableSavingsReport": {
            "title": "Savings report",
            "type": "boolean",
            "description": "Emit a savings block in the summary tallying enrichment cost / SDR touches / spend avoided by allocation rules. Auto-emits when constraints are set.",
            "default": false
          },
          "outcomeDatasetId": {
            "title": "Outcome dataset ID",
            "type": "string",
            "description": "Apify dataset ID with prior outcome records. Must include the joinKey (default 'domain') plus the won field (default 'won')."
          },
          "outcomeJoinKey": {
            "title": "Outcome join key",
            "type": "string",
            "description": "Field name to join outcomes against — defaults to 'domain'.",
            "default": "domain"
          },
          "outcomeFields": {
            "title": "Outcome field mapping",
            "type": "object",
            "description": "Map your outcome dataset's column names: {won?: 'isWon', revenue?: 'dealValue'}. Defaults: {won: 'won'}."
          },
          "webhookUrl": {
            "title": "Notification webhook URL",
            "type": "string",
            "description": "Slack / Discord / generic webhook. Posts a rich embed with run totals + calibration grade when the run completes."
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}