{
  "openapi": "3.0.1",
  "info": {
    "title": "Salesforce AppExchange Scraper - Apps & Publisher Leads",
    "description": "Scrape Salesforce AppExchange into rich B2B vendor leads: publisher name, email, website, HQ, employees, ratings, reviews, pricing, security review, editions & categories. Filter by keyword, category, rating or HQ country. Monitor mode + email enrichment.",
    "version": "0.1",
    "x-build-id": "zfAgT4IoTWeZk4Ql0"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/scrapesage~salesforce-appexchange-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-scrapesage-salesforce-appexchange-scraper",
        "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/scrapesage~salesforce-appexchange-scraper/runs": {
      "post": {
        "operationId": "runs-sync-scrapesage-salesforce-appexchange-scraper",
        "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/scrapesage~salesforce-appexchange-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-scrapesage-salesforce-appexchange-scraper",
        "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": {
          "keywords": {
            "title": "Keywords",
            "type": "array",
            "description": "Free-text terms to match against the app name, description and publisher name (case-insensitive, matched at the start of a word, so <code>ai</code> finds \"AI\" but not \"Mailchimp\"; an app is kept if it matches ANY term). Leave empty to scan the whole marketplace. Example: <code>marketing</code>, <code>data quality</code>, <code>Docusign</code>.",
            "items": {
              "type": "string"
            }
          },
          "categories": {
            "title": "Categories",
            "type": "array",
            "description": "Only keep apps in these AppExchange categories. Use a friendly term that matches the category name (case-insensitive, partial match): <code>Sales</code>, <code>Marketing</code>, <code>Customer Service</code>, <code>Analytics</code>, <code>IT Administration</code>, <code>Productivity</code>, <code>Collaboration</code>, <code>Finance</code>, <code>Human Resources</code>, <code>ERP</code>, <code>Commerce</code>, <code>Integration</code>. Leave empty for all categories.",
            "items": {
              "type": "string"
            }
          },
          "startUrls": {
            "title": "Start URLs",
            "type": "array",
            "description": "Specific AppExchange listings to scrape directly: paste listing-detail URLs (<code>https://appexchange.salesforce.com/appxListingDetail?listingId=a0N3u00000Qt7LiEAJ</code>). Bare listing IDs go in <b>Listing IDs</b> below. Used in addition to the keyword/category scan. A URL that is not an AppExchange listing is skipped and named in the run's status message; when none is, the run stops without charging anything.",
            "items": {
              "type": "object",
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "title": "URL of a web page",
                  "format": "uri"
                }
              }
            }
          },
          "listingIds": {
            "title": "Listing IDs",
            "type": "array",
            "description": "Bare AppExchange listing IDs to scrape directly, one per row (e.g. <code>a0N3u00000Qt7LiEAJ</code>, the <code>listingId</code> in a listing URL). Used like Start URLs.",
            "items": {
              "type": "string"
            }
          },
          "maxItems": {
            "title": "Max apps",
            "minimum": 1,
            "type": "integer",
            "description": "Maximum number of app records to scrape.",
            "default": 100
          },
          "includeDetails": {
            "title": "Include publisher & full details",
            "type": "boolean",
            "description": "Fetch each app's detail for the full B2B record: publisher (vendor) name, email, website, HQ location, employee count & description, pricing model, security-review status, supported editions, app type and full description. Turn off for a faster, lighter run that returns only listing-level fields (name, rating, reviews, categories, publisher name).",
            "default": true
          },
          "includeReviews": {
            "title": "Include customer reviews",
            "type": "boolean",
            "description": "Fetch customer reviews for each app (title, rating, body, author, company, date). Adds one request per app.",
            "default": false
          },
          "maxReviews": {
            "title": "Max reviews per app",
            "minimum": 1,
            "maximum": 50,
            "type": "integer",
            "description": "How many reviews to keep per app when reviews are enabled.",
            "default": 10
          },
          "enrichPublisherEmails": {
            "title": "Enrich emails from the publisher website",
            "type": "boolean",
            "description": "For each app whose publisher has a website, crawl it (home + contact/about, up to 3 pages) to extract contact emails, phone numbers and social links. Boosts contactability for publishers that don't list an email on AppExchange. The enrichment is charged only when the crawl finds an email the listing did not already give. Requires details.",
            "default": false
          },
          "emitPublisherLeads": {
            "title": "Also output one lead per publisher",
            "type": "boolean",
            "description": "In addition to per-app rows, output one deduplicated B2B lead per unique publisher (vendor) with their app count, average rating, total reviews and contact details. Requires details.",
            "default": false
          },
          "minRating": {
            "title": "Minimum rating (0–5)",
            "minimum": 0,
            "maximum": 5,
            "type": "number",
            "description": "Only keep apps with at least this average star rating. 0 = no minimum.",
            "default": 0
          },
          "freeOnly": {
            "title": "Only free apps",
            "type": "boolean",
            "description": "Keep only apps that are free to install.",
            "default": false
          },
          "paidOnly": {
            "title": "Only paid apps",
            "type": "boolean",
            "description": "Keep only paid / commercial apps (stronger vendor-spend signal).",
            "default": false
          },
          "lightningReadyOnly": {
            "title": "Only Lightning Ready apps",
            "type": "boolean",
            "description": "Keep only apps marked Lightning Ready.",
            "default": false
          },
          "securityReviewedOnly": {
            "title": "Only security-reviewed apps",
            "type": "boolean",
            "description": "Keep only apps that have passed the Salesforce Security Review. Requires details.",
            "default": false
          },
          "withPublisherEmailOnly": {
            "title": "Only apps whose publisher has an email",
            "type": "boolean",
            "description": "Skip apps where no publisher email is available (from AppExchange or website enrichment). Requires details.",
            "default": false
          },
          "withWebsiteOnly": {
            "title": "Only apps whose publisher has a website",
            "type": "boolean",
            "description": "Skip apps where the publisher has no website. Requires details.",
            "default": false
          },
          "hqCountries": {
            "title": "Publisher HQ countries",
            "type": "array",
            "description": "Only keep apps whose publisher is headquartered in one of these countries. A country code or name (<code>US</code>, <code>United Kingdom</code>, <code>UK</code>, <code>India</code>, <code>IN</code>) matches the publisher's country, read from its HQ location (or the listing's own country field); any other text (<code>California</code>, <code>London</code>) matches the HQ location at the start of a word. Requires details.",
            "items": {
              "type": "string"
            }
          },
          "editions": {
            "title": "Supported editions",
            "type": "array",
            "description": "Only keep apps that support at least one of these Salesforce editions, by name or code: <code>Enterprise</code> (EE), <code>Unlimited</code> (UE), <code>Performance</code> (PP), <code>Developer</code> (DE), <code>Professional</code> (PE), <code>Essentials</code> (ES), <code>Force.com</code> (FE). The older code EC is read as ES.",
            "items": {
              "type": "string"
            }
          },
          "maxScan": {
            "title": "Max apps to scan",
            "minimum": 24,
            "type": "integer",
            "description": "Upper bound on how many listings to examine while applying keyword/category/edition filters. Protects you from scanning the whole 5,000+ catalog when a filter matches few apps. When it is reached before Max apps, the run's status message says so.",
            "default": 1500
          },
          "monitorMode": {
            "title": "Monitor mode (only new apps)",
            "type": "boolean",
            "description": "Remember listing IDs returned in previous runs (in a named key-value store) and emit only NEW apps on each run. Perfect with Apify Schedules for a steady new-vendor feed; it does not conflict with scheduling: the schedule triggers the run, monitor mode deduplicates this run's records against everything earlier runs already returned.",
            "default": false
          },
          "monitorStoreName": {
            "title": "Monitor store name",
            "type": "string",
            "description": "Name of the key-value store that holds the seen-listing memory for monitor mode. Use different names to track independent searches separately (lowercase letters, digits and hyphens only).",
            "default": "salesforce-appexchange-monitor"
          },
          "maxConcurrency": {
            "title": "Max concurrency",
            "minimum": 1,
            "maximum": 25,
            "type": "integer",
            "description": "How many API requests to run in parallel. 10 is a good default for the AppExchange API.",
            "default": 10
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Proxies to use. The AppExchange API works from plain datacenter IPs, so the default Apify Proxy (automatic) is enough and cheapest.",
            "default": {
              "useApifyProxy": true
            }
          },
          "urlsFromFile": {
            "title": "Import URLs from a file",
            "type": "string",
            "description": "Paste a list of URLs (one per line), OR one link to a .txt/.csv file, Google Sheet or Google Drive file containing them. Lets you import many Start URLs at once instead of typing each. Google Sheet/Drive share links are handled automatically."
          }
        }
      },
      "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
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "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
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}