# Merchant Website Underwriting Signals (Public Pages) (`tomwang/merchant-underwriting-check`) Actor

Public-site screening signals for payments onboarding and periodic merchant review: policy-page presence, category keyword leads, payment-stack hints and domain registration date. Screening leads for a HUMAN reviewer - not a compliance verdict, KYB check, or approve/decline decision.

- **URL**: https://apify.com/tomwang/merchant-underwriting-check.md
- **Developed by:** [Tom](https://apify.com/tomwang) (community)
- **Categories:** Business, E-commerce, Developer tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$100.00 / 1,000 domain screeneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Merchant Website Underwriting Check

Public-site screening signals for payments onboarding and periodic merchant review. Submit merchant domains, then review policy pages, category keyword leads, payment technology and domain registration date in one dataset. **This does not verify a legal entity, certify compliance or approve/decline a merchant. A human must review findings.**

### Scope

- Reads the homepage and up to six same-site policy/contact/shipping pages linked from it. A footer link alone does not count as a published policy. A found policy page needs both a matching title/path and matching visible text. Results include checked page URLs and policy URLs.
- Checks for selected high-review terms on visible page text and reports only category and URL, not excerpts. A mention may be negated, historic or incidental. There is no jurisdictional prohibition verdict.
- Reports PSP/BNPL and platform hints from the public page using the Payment Stack Detector signature library. A missing gateway is `GATEWAY_NOT_CONFIRMED`, not proof it is absent.
- Gets domain registration date from official registry RDAP services selected by the IANA DNS bootstrap. If the registry does not disclose it or RDAP is unavailable, age is unknown. **Registration date is not the operating age or ownership history of the business.** Registrant details are not read into the output.
- Skips pages disallowed by robots.txt, fails closed when robots.txt cannot be verified, stays on same registered domain via HTTPS, does not log in, add to cart, submit a form or use personal data. Rate is limited by input concurrency. Some sites' terms may be more restrictive than robots.txt; operators should check their own target-specific permissions.

### Input

```json
{"domains":["allbirds.com","huel.com"],"maxPolicyPages":6,"checkRdap":true,"concurrency":3}
```

Use at most 1,000 domains per run. `maxPolicyPages` 0-10; concurrency 1-10. Only public HTTPS destinations are accepted. Timeouts and blocked pages return an error. No proxy or captcha bypass.

### Output

```json
{
  "domain": "merchant.example",
  "checkedPageCount": 3,
  "policies": { "returns": { "status": "page_found", "urls": ["https://merchant.example/policies/returns"] }, "privacy": {"status":"not_found_on_checked_pages","urls":[]} },
  "categorySignals": [{"category":"controlled","label":"Controlled-substance term","pageUrl":"https://merchant.example/","note":"Keyword in page text; may be incidental or negated. Human review required."}],
  "paymentStack": {"platform":"Shopify","gateways":[],"bnpl":[]},
  "rdap": {"status":"found","registrationDate":"2020-01-01","ageDays":2459},
  "reviewFlags": ["CHECK_PRIVACY_DISCLOSURE", "REVIEW_CATEGORY_TERMS", "GATEWAY_NOT_CONFIRMED"]
}
```

Example above is illustrative. Actual data includes all five policy categories (returns, terms, privacy, contact, shipping), all reviewed pages, timestamp, errors and the interpretation caveat.

### Development

```sh
npm ci
npm test
APIFY_LOCAL_STORAGE_DIR=./storage npm start
```

For a local run, write `storage/key_value_stores/default/INPUT.json` with your input. The offline tests cover URL safety, link selection, policy evidence, keyword caveats, RDAP and bot blocks. Deploy to an Apify account only after its owner has reviewed the Store page and price.

### Proposed Store pricing (not configured or published)

$0.07 per successfully screened domain, with no charge for a blocked or failed homepage. Estimate only; run-time costs and demand must be measured in Apify before setting final price. This Actor uses pay-per-event `domain-screened`; configure that event in Console before publishing.

### Limits and disclaimer

Absence from sampled pages is not absence from the website. Legal compliance depends on product, geography, merchant agreement and processor policy. Keyword triggers are intentionally broad. This is not a sanction-screening or identity-verification tool. Privacy, returns and delivery content are located, **not judged for sufficiency or legal correctness**. This Actor is unofficial and not affiliated with, endorsed or sponsored by Apify, Visa, Mastercard, any registry or any technology provider mentioned.

Sources: [IANA RDAP bootstrap](https://data.iana.org/rdap/dns.json), [RDAP response specification](https://www.rfc-editor.org/rfc/rfc9083.html), [Apify pricing and costs](https://docs.apify.com/actors/publishing/monetize/pricing-and-costs).

# Actor input Schema

## `domains` (type: `array`):

Public merchant domains to screen (max 1,000 per run). Reads each homepage plus up to maxPolicyPages same-site policy pages, respecting robots.txt (fails closed if unverifiable). No login, no forms, no CAPTCHA bypass. The default screens the developer's own domain so the automatic Store test runs without third-party traffic; replace with your merchants.

## `maxPolicyPages` (type: `integer`):

Same-site policy/contact/shipping pages to read per domain (0-10)

## `checkRdap` (type: `boolean`):

Look up the domain registration date via official registry RDAP. Registration date is not business operating age.

## `concurrency` (type: `integer`):

Domains screened in parallel (1-10). Keep low to stay gentle on target sites.

## Actor input object example

```json
{
  "domains": [
    "tomcn.uk"
  ],
  "maxPolicyPages": 6,
  "checkRdap": true,
  "concurrency": 3
}
```

# Actor output Schema

## `results` (type: `string`):

Default dataset: one item per screened domain.

# 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 = {
    "domains": [
        "tomcn.uk"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tomwang/merchant-underwriting-check").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 = { "domains": ["tomcn.uk"] }

# Run the Actor and wait for it to finish
run = client.actor("tomwang/merchant-underwriting-check").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "domains": [
    "tomcn.uk"
  ]
}' |
apify call tomwang/merchant-underwriting-check --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tomwang/merchant-underwriting-check"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/0gAeak0aifl1uhabu/builds/aP2vhjtaNekfC0msJ/openapi.json
