# B2B SaaS Account Qualifier for AI Agents (`deepapi/b2b-saas-lead-qualifier`) Actor

Qualify B2B SaaS account URLs into AI-ready lead records with hiring demand, source evidence, compact rows, and next-action routing.

- **URL**: https://apify.com/deepapi/b2b-saas-lead-qualifier.md
- **Developed by:** [DeepAPI](https://apify.com/deepapi) (community)
- **Categories:** Lead generation, AI, Agents
- **Stats:** 2 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 valid leads

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## B2B SaaS Account Qualifier for AI Agents

Turn B2B SaaS company URLs into AI-ready account qualification records with hiring demand, source evidence, compact lead rows, confidence scores, and next-action routing.

This Actor is built for workflows where an AI agent, sales operator, recruiter, or analyst already has a target account list and needs a fast, source-backed answer:

```text
Should we act on this account now, why, and what should happen next?
````

### What It Does

- Accepts company URLs or bare domains, skips invalid entries, and reports batch input diagnostics in the Actor output.
- Crawls each accepted company website, including likely signal pages such as homepage, careers, jobs, about, and contact pages.
- Follows career subpages, localized jobs paths, and branded external careers sites such as `lifeat{brand}` when they are reached from the company's own careers URL.
- Follows supported public job-board links from company pages, including Greenhouse, Lever, Ashby, Workable, SmartRecruiters, Teamtailor, Breezy, and Workday.
- Uses provider-specific parsing for Ashby, Lever, and Greenhouse job boards when structured posting data is available.
- Reads embedded Ashby job records from company careers pages when roles are shipped inside script payloads.
- Extracts company-level lead signals:
  - hiring or growth language,
  - matched role keywords,
  - public company emails,
  - public LinkedIn company URLs,
  - matched public job titles and posting URLs,
  - optional country matches.
- Deduplicates results by company domain.
- Merges evidence from company pages and linked job boards into one company-level lead.
- Returns detailed dataset rows, compact lead rows, and run-level recommendations designed for AI agent chaining.

### Why It Is Useful

Most lead tools return raw company or contact data. This Actor qualifies accounts by answering whether there is current public hiring demand worth acting on, then returns evidence an agent or operator can audit.

For an AI agent inside Claude, Cowork, or another workflow runner, this means the agent can:

- take a target account list,
- qualify each company,
- inspect structured evidence,
- decide whether to enrich, monitor, recruit, or start outreach,
- pass the record into another Actor or CRM workflow.

No LLM is required for the MVP. The current version uses deterministic extraction and scoring so results are cheaper, repeatable, and easier to audit. LLM enrichment can be added later as a premium mode for buyer-intent summaries, outreach angles, or account prioritization.

### Input

Use `companyUrls` as the primary input. Public full URLs and bare domains are accepted. Localhost, private-network, and invalid entries are skipped and reported in diagnostics.

```json
{
  "companyUrls": [
    "https://www.hubspot.com",
    "https://www.intercom.com"
  ],
  "country": "United States",
  "maxCompanies": 100,
  "includeContactEmails": true,
  "includeLinkedInCompanyUrl": true,
  "requireContactEmail": false,
  "requireLinkedInCompanyUrl": false,
  "requireJobPostingUrl": false,
  "roleKeywords": [
    "sales",
    "account executive",
    "customer success",
    "sales engineer"
  ],
  "maxOpenRolesPerCompany": 25,
  "minConfidence": 0.75
}
```

Optional discovery mode:

```json
{
  "searchTerms": [
    "B2B SaaS companies hiring sales"
  ],
  "maxCompanies": 25
}
```

Search discovery is optional and less reliable than direct company URLs. For production agent workflows, pass known company URLs.

Invalid or non-public company URL entries do not stop the whole run when at least one usable company URL or search term is present. They are skipped and reported in the Actor output diagnostics. `maxCompanies` caps accepted company URLs to crawl and returned valid leads.

Clean mode toggles can return only rows that are immediately ready for a specific workflow:

| Toggle | Effect |
|---|---|
| `requireContactEmail` | Return only leads with at least one public contact email. |
| `requireLinkedInCompanyUrl` | Return only leads with a public LinkedIn company URL. |
| `requireJobPostingUrl` | Return only leads with at least one matched public job posting URL. |

### Starter Inputs

The `examples` folder includes validated starter inputs for common buyer workflows:

| File | Use case |
|---|---|
| `examples/sales-outreach.json` | Qualify target accounts for sales outreach using sales, sales engineering, and customer success hiring signals. |
| `examples/recruiting-demand.json` | Find B2B SaaS companies with engineering hiring demand for recruiting, talent research, or market mapping. |
| `examples/agent-batch-qa.json` | Test a messy account list with duplicates, invalid entries, over-limit URLs, `runRecommendations`, and compact output rows. |

For the first paid run, start with `sales-outreach.json` and replace `companyUrls` with your own target account list.

### First Run Checklist

Use this for the first Store run or saved task:

1. Start with 10 to 25 known B2B SaaS account URLs.
2. Pick one workflow: sales outreach, recruiting demand, or agent batch QA.
3. Keep `maxOpenRolesPerCompany` between 3 and 10 so the dataset preview stays readable.
4. Set `minConfidence` between `0.6` and `0.75` while calibrating your market.
5. Check `OUTPUT.runRecommendations` first, then open the dataset rows for source evidence.
6. Send only `qualifiedLeadsCompact` or dataset rows with `signalStrength` of `medium` or `strong` into the next agent, CRM, or enrichment step.

Sales outreach:

```json
{
  "companyUrls": ["https://cursor.com", "https://www.hubspot.com", "https://www.intercom.com"],
  "country": "United States",
  "maxCompanies": 25,
  "includeContactEmails": true,
  "includeLinkedInCompanyUrl": true,
  "roleKeywords": ["account executive", "sales engineer", "customer success", "sales development"],
  "maxOpenRolesPerCompany": 5,
  "minConfidence": 0.7
}
```

Recruiting demand:

```json
{
  "companyUrls": ["https://cursor.com", "https://www.rippling.com", "https://www.deel.com"],
  "country": "United States",
  "maxCompanies": 25,
  "includeContactEmails": false,
  "includeLinkedInCompanyUrl": true,
  "roleKeywords": ["software engineer", "product engineer", "backend engineer", "machine learning", "infrastructure"],
  "maxOpenRolesPerCompany": 10,
  "minConfidence": 0.65
}
```

Agent batch QA:

```json
{
  "companyUrls": ["cursor.com", "https://www.cursor.com/pricing", "https://intercom.com", "not a url", "https://overflow.example.com"],
  "maxCompanies": 2,
  "includeContactEmails": true,
  "includeLinkedInCompanyUrl": true,
  "roleKeywords": ["account executive", "customer success", "engineer"],
  "maxOpenRolesPerCompany": 3,
  "minConfidence": 0.6
}
```

### Output

Each pushed dataset item is a validated company-level lead.

```json
{
  "companyName": "HubSpot",
  "websiteUrl": "https://hubspot.com",
  "domain": "hubspot.com",
  "sourceUrl": "https://www.hubspot.com/careers",
  "hiringSignal": "Strong hiring signal found for sales, customer success",
  "signalStrength": "strong",
  "signalSourceType": "careers_page",
  "openRolesCount": 2,
  "openRoleTitlesReturnedCount": 2,
  "openRolesTruncated": false,
  "roleKeywordGroups": [
    {
      "keyword": "sales",
      "openRolesCount": 1,
      "sampleTitles": ["Senior Sales Engineer"]
    },
    {
      "keyword": "customer success",
      "openRolesCount": 1,
      "sampleTitles": ["Customer Success Manager"]
    }
  ],
  "openRoleTitles": ["Senior Sales Engineer", "Customer Success Manager"],
  "jobPostingUrls": [
    "https://jobs.example.com/senior-sales-engineer",
    "https://jobs.example.com/customer-success-manager"
  ],
  "roleKeywords": ["sales", "customer success"],
  "roleKeywordsText": "sales | customer success",
  "contactEmails": [],
  "contactEmailsText": "",
  "openRoleTitlesText": "Senior Sales Engineer | Customer Success Manager",
  "jobPostingUrlsText": "https://jobs.example.com/senior-sales-engineer | https://jobs.example.com/customer-success-manager",
  "linkedinCompanyUrl": "https://www.linkedin.com/company/hubspot",
  "qualificationSummary": "HubSpot qualified with strong role signals for sales, customer success, a LinkedIn company URL at 90% confidence.",
  "evidence": [
    {
      "type": "hiring_signal",
      "value": "Strong hiring signal found for sales, customer success",
      "sourceUrl": "https://www.hubspot.com/careers"
    }
  ],
  "evidenceSummary": "hiring_signal: Strong hiring signal found for sales, customer success (https://www.hubspot.com/careers)",
  "recommendedAction": "Prioritize for sales or recruiting outreach with the cited hiring evidence.",
  "warnings": [
    "No public contact email found.",
    "Hiring signal is keyword-based and should be verified before outreach."
  ],
  "warningsText": "No public contact email found. | Hiring signal is keyword-based and should be verified before outreach.",
  "confidence": 0.9,
  "scrapedAt": "2026-06-28T18:44:36.496Z"
}
```

Spreadsheet preview:

| companyName | domain | confidence | signalStrength | roleKeywordsText | openRoleTitlesText | linkedinCompanyUrl | warningsText |
|---|---|---:|---|---|---|---|---|
| HubSpot | hubspot.com | 0.9 | strong | sales | customer success | Senior Sales Engineer | Customer Success Manager | https://www.linkedin.com/company/hubspot | No public contact email found. | Hiring signal is keyword-based and should be verified before outreach. |

The Actor also writes a run-level `OUTPUT` record for batch workflows:

```json
{
  "qualifiedLeadsUrl": "https://api.apify.com/v2/datasets/example/items",
  "summary": {
    "requestedCompanyUrlCount": 2,
    "acceptedCompanyUrlCount": 1,
    "searchTermsCount": 0,
    "maxCompanies": 100,
    "candidateDomains": 1,
    "requestsProcessed": 5,
    "rawLeads": 1,
    "validLeads": 1,
    "pushedLeads": 1,
    "chargeLimitReached": false
  },
  "qualifiedLeadsCompact": [
    {
      "companyName": "HubSpot",
      "domain": "hubspot.com",
      "websiteUrl": "https://hubspot.com",
      "sourceUrl": "https://www.hubspot.com/careers",
      "confidence": 0.9,
      "signalStrength": "strong",
      "signalSourceType": "careers_page",
      "openRolesCount": 2,
      "openRoleTitlesReturnedCount": 2,
      "openRolesTruncated": false,
      "roleKeywordsText": "sales | customer success",
      "openRoleTitlesText": "Senior Sales Engineer | Customer Success Manager",
      "jobPostingUrlsText": "https://jobs.example.com/senior-sales-engineer | https://jobs.example.com/customer-success-manager",
      "linkedinCompanyUrl": "https://www.linkedin.com/company/hubspot",
      "qualificationSummary": "HubSpot qualified with strong role signals for sales, customer success, a LinkedIn company URL at 90% confidence.",
      "recommendedAction": "Prioritize for sales or recruiting outreach with the cited hiring evidence.",
      "scrapedAt": "2026-06-28T18:44:36.496Z"
    }
  ],
  "runRecommendations": {
    "totalCompanyStatuses": 3,
    "billableLeadCount": 1,
    "retryableCount": 1,
    "flows": [
      {
        "nextActionType": "use_qualified_lead",
        "count": 1,
        "billableLeadAvailable": true,
        "retryable": false,
        "inputUrls": ["https://hubspot.com"],
        "domains": ["hubspot.com"]
      },
      {
        "nextActionType": "review_non_qualified_company",
        "count": 1,
        "billableLeadAvailable": false,
        "retryable": false,
        "inputUrls": ["https://example.com"],
        "domains": ["example.com"]
      },
      {
        "nextActionType": "fix_input_url",
        "count": 1,
        "billableLeadAvailable": false,
        "retryable": true,
        "inputUrls": ["bad value"],
        "domains": []
      }
    ]
  },
  "diagnostics": {
    "requestedCompanyUrlCount": 2,
    "acceptedCompanyUrlCount": 1,
    "invalidCompanyUrls": ["bad value"],
    "duplicateCompanyDomains": [],
    "skippedCompanyUrlsOverMaxCompanies": [],
    "companyStatuses": [
      {
        "inputUrl": "https://hubspot.com",
        "status": "qualified",
        "domain": "hubspot.com",
        "websiteUrl": "https://hubspot.com",
        "companyName": "HubSpot",
        "nextAction": {
          "type": "use_qualified_lead",
          "billableLeadAvailable": true,
          "retryable": false
        }
      },
      {
        "inputUrl": "https://example.com",
        "status": "not_qualified",
        "domain": "example.com",
        "websiteUrl": "https://example.com",
        "reason": "no_matching_hiring_signal",
        "pagesProcessed": 5,
        "failedRequests": 0,
        "nextAction": {
          "type": "review_non_qualified_company",
          "billableLeadAvailable": false,
          "retryable": false
        }
      },
      {
        "inputUrl": "bad value",
        "status": "input_skipped",
        "reason": "invalid_url",
        "nextAction": {
          "type": "fix_input_url",
          "billableLeadAvailable": false,
          "retryable": true
        }
      }
    ],
    "nonQualifiedCompanies": [
      {
        "domain": "example.com",
        "websiteUrl": "https://example.com",
        "reason": "no_matching_hiring_signal",
        "pagesProcessed": 5,
        "failedRequests": 0
      }
    ]
  }
}
```

### Output Fields

| Field | Meaning |
|---|---|
| `companyName` | Normalized company name. |
| `websiteUrl` | Normalized company website origin. |
| `domain` | Deduplication key. |
| `sourceUrl` | Page where the strongest qualifying evidence was found. |
| `hiringSignal` | Human-readable hiring or growth signal. |
| `signalStrength` | Signal quality tier: `strong`, `medium`, or `weak`. Billable leads require non-weak hiring evidence. |
| `signalSourceType` | Type of source page: `job_board`, `careers_page`, `company_page`, or `homepage`. |
| `jobBoardProvider` | Detected provider for known public job boards such as Greenhouse, Lever, Ashby, or Workable. |
| `openRoleTitles` | Matched public role titles extracted from job board links, individual job pages, or careers page links. |
| `jobPostingUrls` | Public URLs for matched role postings. |
| `openRolesCount` | Count of matched public roles when available, otherwise matched role keyword groups. |
| `openRoleTitlesReturnedCount` | Number of role titles returned after applying `maxOpenRolesPerCompany`. |
| `openRolesTruncated` | Whether more matched roles exist than were returned in `openRoleTitles` and `jobPostingUrls`. |
| `roleKeywordGroups` | Grouped role summary by configured role keyword with counts and sample titles. |
| `roleKeywords` | Matched role/function keywords. |
| `roleKeywordsText` | Pipe-separated matched role keywords for CSV, Excel, Google Sheets, and CRM imports. |
| `contactEmails` | Public company emails found on crawled pages. |
| `contactEmailsText` | Pipe-separated public company emails for CSV, Excel, Google Sheets, and CRM imports. |
| `openRoleTitlesText` | Pipe-separated matched role titles for CSV, Excel, Google Sheets, and CRM imports. |
| `jobPostingUrlsText` | Pipe-separated matched job posting URLs for CSV, Excel, Google Sheets, and CRM imports. |
| `linkedinCompanyUrl` | Public LinkedIn company URL found on the website. |
| `qualificationSummary` | Short explanation for AI agents and operators. |
| `evidence` | Structured source-backed evidence items. |
| `evidenceSummary` | Pipe-separated source evidence summary for spreadsheet review and no-code tools. |
| `recommendedAction` | Suggested next workflow step. |
| `warnings` | Quality or verification caveats. |
| `warningsText` | Pipe-separated quality caveats for spreadsheet review and no-code tools. |
| `confidence` | Deterministic confidence score from `0` to `1`. |
| `scrapedAt` | ISO timestamp for the crawl. |

### Run Diagnostics

The `OUTPUT` record is intended for AI agents and batch automations that need to decide what happened after a run without reading every dataset row.

| Field | Meaning |
|---|---|
| `qualifiedLeadsUrl` | API URL for the default dataset items. |
| `summary.requestedCompanyUrlCount` | Number of company URL entries submitted. |
| `summary.acceptedCompanyUrlCount` | Number of unique company domains accepted for crawling after validation, deduplication, and `maxCompanies`. |
| `summary.validLeads` | Number of company-level leads that passed validation. |
| `summary.pushedLeads` | Number of leads written to the dataset before any charge limit stopped writes. |
| `summary.chargeLimitReached` | Whether Apify pay-per-event charge capping stopped dataset writes. |
| `qualifiedLeadsCompact` | Flat, spreadsheet-friendly summary rows for valid leads. Multi-value fields are joined with a pipe separator so each row can map cleanly to CSV or CRM columns. |
| `runRecommendations` | Agent-ready aggregate of next-action flows, including counts, retryability, billable lead availability, input URLs, and domains by action type. |
| `diagnostics.invalidCompanyUrls` | Submitted company URL entries that could not be normalized into public HTTP(S) company URLs. |
| `diagnostics.duplicateCompanyDomains` | Duplicate company domains skipped before crawling. |
| `diagnostics.skippedCompanyUrlsOverMaxCompanies` | Usable company URL entries skipped because `maxCompanies` had already been reached. |
| `diagnostics.companyStatuses` | Per-submission routing list for agent workflows. Status values are `qualified`, `not_qualified`, and `input_skipped`; reasons include invalid URL, duplicate domain, over max companies, no matching hiring signal, not crawled, crawl failed, and blocked by security. |
| `diagnostics.companyStatuses[].nextAction` | Machine-readable routing recommendation. Action types include `use_qualified_lead`, `review_non_qualified_company`, `fix_input_url`, `use_original_domain_result`, `increase_max_companies`, and `retry_crawl`. |
| `diagnostics.nonQualifiedCompanies` | Accepted company domains that were crawled but did not become valid leads. Reasons include `no_matching_hiring_signal`, `not_crawled`, `crawl_failed`, and `blocked_by_security`. |

### What You Pay For

The paid unit is a validated account qualification result, not every submitted URL. A `validLead` is charged only when the Actor finds a company with non-weak hiring evidence, matched role keywords, source evidence, and a validated dataset row.

Invalid URLs, duplicate domains, over-limit URLs, and companies that do not qualify are still reported in `OUTPUT` diagnostics and `runRecommendations`, but they are not charged as `validLead` events. Apify platform usage and the Actor start event may still apply according to the Store pricing settings.

### Pricing Unit

Recommended pay-per-event unit:

```text
validLead
```

The Actor calls `Actor.pushData(lead, "validLead")` so the paid event is tied to the dataset write. The event name is defined in `src/monetization.ts` and covered by tests to avoid accidental pricing drift.

Active Store price:

```text
$10.00 per 1,000 valid leads
```

### Limits

- This Actor does not scrape logged-in LinkedIn pages.
- Public emails are extracted only from company pages crawled by the Actor.
- Hiring signals are keyword-based and should be verified before outreach.
- Search discovery is available, but direct company URL qualification is the stronger product path.

### Troubleshooting

| Symptom | Most likely reason | What to do |
|---|---|---|
| No `validLead` rows | Company pages did not expose public hiring evidence matching your `roleKeywords`. | Lower `minConfidence`, broaden `roleKeywords`, or use known careers/job-board URLs as company sources. |
| Company appears in diagnostics only | The URL was invalid, duplicated, over `maxCompanies`, blocked by network safety, or crawled without qualifying signals. | Check `OUTPUT.diagnostics.companyStatuses` for the exact reason and next action. |
| Missing emails or job URLs | The company did not publish those fields on crawled public pages, or the roles are rendered behind unsupported JavaScript. | Use the lead anyway when confidence and evidence are strong, or rerun with a direct public job-board URL. |

### Quality Benchmark

The repository includes a local benchmark workflow for measuring whether the Actor is improving over time.

Run it from the portfolio root:

```bash
pnpm b2b:benchmark
pnpm b2b:benchmark:buyer
```

Named benchmark inputs:

| Name | File | Purpose |
|---|---|---|
| `smoke` | `benchmark/b2b-saas-accounts.json` | Fast 10-company regression check. |
| `buyer-validation` | `benchmark/b2b-saas-buyer-validation.json` | Larger 25-company product quality check. |

You can also pass a direct JSON path to `pnpm --filter b2b-saas-lead-qualifier benchmark <path>`.

The script writes run artifacts to `data/b2b-saas-lead-qualifier/benchmark/<timestamp>/`:

| File | Purpose |
|---|---|
| `summary.json` | Buyer-facing quality metrics: valid lead rate, accepted lead rate, average confidence, failure reasons, provider coverage, and request efficiency. |
| `output.json` | Full run-level `OUTPUT` record with diagnostics and recommendations. |
| `leads.json` | Full qualified lead records returned by the crawler. |
| `stats.json` | Raw crawler statistics. |

Latest local snapshot from the default 10-company benchmark:

| Metric | Value |
|---|---:|
| Valid lead rate | 100% |
| Accepted lead rate | 100% |
| Valid leads | 10 / 10 |
| Average confidence | 0.88 |
| Strong signal rate | 90% |
| Requests per accepted company | 19.9 |
| Runtime | 13.005 seconds |

There were no non-qualified companies in that run. Treat these snapshots as directional because public websites and job boards change over time.

Latest local snapshot from the 25-company buyer-validation benchmark:

| Metric | Value |
|---|---:|
| Valid lead rate | 92% |
| Accepted lead rate | 92% |
| Valid leads | 23 / 25 |
| Average confidence | 0.8935 |
| Strong signal rate | 82.61% |
| Requests per accepted company | 19.16 |
| Runtime | 66.033 seconds |

The remaining non-qualified companies in that run were Confluent and Canva. Confluent was classified as `blocked_by_security` and routed to `retry_crawl`; Canva was classified as `no_matching_hiring_signal`.

### Local Development

From the portfolio root:

```bash
pnpm b2b:test
pnpm b2b:typecheck
pnpm b2b:sample
pnpm b2b:benchmark
```

Actor-local commands:

```bash
pnpm test
pnpm typecheck
pnpm sample
pnpm benchmark
```

The sample script uses a separate `storage-live-sample` local storage directory so it does not conflict with `apify run`.
The benchmark script uses `storage-benchmark` and writes generated artifacts under the repo-level `data/` folder.

Apify CLI checks from the Actor folder:

```bash
npx apify-cli validate-schema
npx apify-cli run
```

Docker build check from the Actor folder:

```bash
docker build -f .actor/Dockerfile -t b2b-saas-lead-qualifier:local .
```

Deployment check from the Actor folder:

```bash
npx apify-cli push --wait-for-finish=300
```

# Actor input Schema

## `companyUrls` (type: `array`):

Public company website URLs or bare domains to qualify. Localhost, private-network, and invalid entries are skipped and reported in the run diagnostics.

## `searchTerms` (type: `array`):

Optional search queries used to discover B2B SaaS companies when company URLs are not provided.

## `country` (type: `string`):

Optional geography signal used for search discovery and confidence scoring.

## `maxCompanies` (type: `integer`):

Maximum number of accepted company URLs to crawl and valid company leads to return.

## `includeContactEmails` (type: `boolean`):

Extract public contact emails from company websites.

## `includeLinkedInCompanyUrl` (type: `boolean`):

Extract public LinkedIn company links from company websites.

## `requireContactEmail` (type: `boolean`):

Clean mode: return only leads with at least one public contact email. Requires Include Contact Emails.

## `requireLinkedInCompanyUrl` (type: `boolean`):

Clean mode: return only leads with a public LinkedIn company URL. Requires Include LinkedIn Company URL.

## `requireJobPostingUrl` (type: `boolean`):

Clean mode: return only leads with at least one matched public job posting URL.

## `roleKeywords` (type: `array`):

Keywords used to classify hiring signals.

## `maxOpenRolesPerCompany` (type: `integer`):

Maximum number of matched role titles and posting URLs to include per company. The total open role count and grouped keyword summary still reflect all matched roles.

## `minConfidence` (type: `number`):

Minimum confidence score required before a lead is returned.

## `enableLlmEnrichment` (type: `boolean`):

Use LiteLLM after deterministic qualification to add ICP fit, buyer persona, sales angle, and next-step guidance. Requires LiteLLM environment variables.

## `llmModelTier` (type: `string`):

LiteLLM model tier to use when LLM enrichment is enabled. Mapped from CHEAP\_MODEL, DEFAULT\_MODEL, and PREMIUM\_MODEL environment variables.

## `maxLlmEnrichedLeads` (type: `integer`):

Maximum number of valid leads to enrich with LiteLLM in one run.

## Actor input object example

```json
{
  "companyUrls": [
    "https://www.hubspot.com",
    "https://www.intercom.com"
  ],
  "searchTerms": [],
  "country": "United States",
  "maxCompanies": 100,
  "includeContactEmails": true,
  "includeLinkedInCompanyUrl": true,
  "requireContactEmail": false,
  "requireLinkedInCompanyUrl": false,
  "requireJobPostingUrl": false,
  "roleKeywords": [
    "sales",
    "account executive",
    "customer success",
    "marketing",
    "engineer"
  ],
  "maxOpenRolesPerCompany": 25,
  "minConfidence": 0.6,
  "enableLlmEnrichment": false,
  "llmModelTier": "default",
  "maxLlmEnrichedLeads": 25
}
```

# Actor output Schema

## `qualifiedLeadsUrl` (type: `string`):

Dataset items returned by this Actor. Each item is a validated company-level lead.

## `runOutput` (type: `string`):

OUTPUT key-value store record with batch-level counts, compact qualified lead rows, run recommendations, per-company statuses, next actions, input diagnostics, and the qualified leads dataset URL.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "companyUrls": [
        "https://www.hubspot.com",
        "https://www.intercom.com"
    ],
    "searchTerms": [],
    "country": "United States"
};

// Run the Actor and wait for it to finish
const run = await client.actor("deepapi/b2b-saas-lead-qualifier").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "companyUrls": [
        "https://www.hubspot.com",
        "https://www.intercom.com",
    ],
    "searchTerms": [],
    "country": "United States",
}

# Run the Actor and wait for it to finish
run = client.actor("deepapi/b2b-saas-lead-qualifier").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "companyUrls": [
    "https://www.hubspot.com",
    "https://www.intercom.com"
  ],
  "searchTerms": [],
  "country": "United States"
}' |
apify call deepapi/b2b-saas-lead-qualifier --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=deepapi/b2b-saas-lead-qualifier",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "B2B SaaS Account Qualifier for AI Agents",
        "description": "Qualify B2B SaaS account URLs into AI-ready lead records with hiring demand, source evidence, compact rows, and next-action routing.",
        "version": "0.1",
        "x-build-id": "CeLrCpRn9bNN5ZdSV"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/deepapi~b2b-saas-lead-qualifier/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-deepapi-b2b-saas-lead-qualifier",
                "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/deepapi~b2b-saas-lead-qualifier/runs": {
            "post": {
                "operationId": "runs-sync-deepapi-b2b-saas-lead-qualifier",
                "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/deepapi~b2b-saas-lead-qualifier/run-sync": {
            "post": {
                "operationId": "run-sync-deepapi-b2b-saas-lead-qualifier",
                "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": {
                    "companyUrls": {
                        "title": "Company URLs",
                        "type": "array",
                        "description": "Public company website URLs or bare domains to qualify. Localhost, private-network, and invalid entries are skipped and reported in the run diagnostics.",
                        "items": {
                            "type": "string",
                            "minLength": 1
                        }
                    },
                    "searchTerms": {
                        "title": "Search Terms",
                        "type": "array",
                        "description": "Optional search queries used to discover B2B SaaS companies when company URLs are not provided.",
                        "items": {
                            "type": "string",
                            "minLength": 1
                        }
                    },
                    "country": {
                        "title": "Country",
                        "type": "string",
                        "description": "Optional geography signal used for search discovery and confidence scoring."
                    },
                    "maxCompanies": {
                        "title": "Max Companies",
                        "minimum": 1,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "Maximum number of accepted company URLs to crawl and valid company leads to return.",
                        "default": 100
                    },
                    "includeContactEmails": {
                        "title": "Include Contact Emails",
                        "type": "boolean",
                        "description": "Extract public contact emails from company websites.",
                        "default": true
                    },
                    "includeLinkedInCompanyUrl": {
                        "title": "Include LinkedIn Company URL",
                        "type": "boolean",
                        "description": "Extract public LinkedIn company links from company websites.",
                        "default": true
                    },
                    "requireContactEmail": {
                        "title": "Require Contact Email",
                        "type": "boolean",
                        "description": "Clean mode: return only leads with at least one public contact email. Requires Include Contact Emails.",
                        "default": false
                    },
                    "requireLinkedInCompanyUrl": {
                        "title": "Require LinkedIn Company URL",
                        "type": "boolean",
                        "description": "Clean mode: return only leads with a public LinkedIn company URL. Requires Include LinkedIn Company URL.",
                        "default": false
                    },
                    "requireJobPostingUrl": {
                        "title": "Require Job Posting URL",
                        "type": "boolean",
                        "description": "Clean mode: return only leads with at least one matched public job posting URL.",
                        "default": false
                    },
                    "roleKeywords": {
                        "title": "Role Keywords",
                        "type": "array",
                        "description": "Keywords used to classify hiring signals.",
                        "items": {
                            "type": "string",
                            "minLength": 1
                        },
                        "default": [
                            "sales",
                            "account executive",
                            "customer success",
                            "marketing",
                            "engineer"
                        ]
                    },
                    "maxOpenRolesPerCompany": {
                        "title": "Max Open Roles Per Company",
                        "minimum": 1,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Maximum number of matched role titles and posting URLs to include per company. The total open role count and grouped keyword summary still reflect all matched roles.",
                        "default": 25
                    },
                    "minConfidence": {
                        "title": "Minimum Confidence",
                        "minimum": 0,
                        "maximum": 1,
                        "type": "number",
                        "description": "Minimum confidence score required before a lead is returned.",
                        "default": 0.6
                    },
                    "enableLlmEnrichment": {
                        "title": "Enable LLM Enrichment",
                        "type": "boolean",
                        "description": "Use LiteLLM after deterministic qualification to add ICP fit, buyer persona, sales angle, and next-step guidance. Requires LiteLLM environment variables.",
                        "default": false
                    },
                    "llmModelTier": {
                        "title": "LLM Model Tier",
                        "enum": [
                            "cheap",
                            "default",
                            "premium"
                        ],
                        "type": "string",
                        "description": "LiteLLM model tier to use when LLM enrichment is enabled. Mapped from CHEAP_MODEL, DEFAULT_MODEL, and PREMIUM_MODEL environment variables.",
                        "default": "default"
                    },
                    "maxLlmEnrichedLeads": {
                        "title": "Max LLM Enriched Leads",
                        "minimum": 1,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "Maximum number of valid leads to enrich with LiteLLM in one run.",
                        "default": 25
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
