Home › Workflows › Website Data API Python Example: Call a Domain Check
Website Data API Python Example: Call a Domain Check
To call a website checks API from Python, send a GET request to the check’s route with your domain in the path and an Authorization header carrying your bearer token, then read the JSON body. Set a timeout, branch on the HTTP status, and log the raw response so you can adjust your parsing once you see real field names.
What you need first
- An API key. BusinessMCP’s documentation says keys start with
mcph_and are sent as a bearer token. The same key works for the REST endpoint and the MCP endpoint, per the data API overview. - The key stored in an environment variable, not in source code.
- Python 3.9 or later and the
requestspackage.
The base URL and route shapes below come from the vendor’s pages for the website checks API. The documented request has one field, domain (a string, required, maximum 253 characters). The page does not list response fields, so the code below does not assume any; it reads the JSON and hands it back.
A minimal, honest client
import os
import requests
BASE = "https://businessmcp.com/api/hub/v1"
KEY = os.environ["BUSINESSMCP_API_KEY"]
def run_check(domain: str, check: str, timeout: int = 30) -> dict:
url = f"{BASE}/sites/{domain}/{check}"
resp = requests.get(
url,
headers={"Authorization": f"Bearer {KEY}"},
timeout=timeout,
)
return {"status": resp.status_code, "body": resp.text}
if __name__ == "__main__":
out = run_check("example.com", "ai-crawlers")
print(out["status"])
print(out["body"])
The four route names documented are ai-readiness, ai-crawlers, webmcp and email-auth. Run it once against a domain you own and read what comes back. Only then decide which fields to extract.
Key takeaway: write your first client to log everything and parse nothing. Real responses tell you more than any guess about field names.
Turning it into something reusable
Once you have seen the response, add three things: error handling, normalisation and storage.
Error handling
| Status | Meaning | What your code should do |
|---|---|---|
| 200 | Check ran | Parse and store |
| 401 | Missing or bad key | Stop and alert |
| 402 | Balance empty (insufficient_balance per the vendor) | Stop the run, alert a human |
| 4xx other | Bad input, such as a malformed domain | Log and skip that domain |
| 5xx or timeout | Transient trouble | Retry with backoff, then mark unknown |
The 402 behaviour is stated in BusinessMCP’s documentation: after the trial and balance are used up, calls are refused with that status and you are never charged later. Other codes follow ordinary HTTP convention, but confirm specifics in the reference. For a deeper pattern see handling errors and unknown results.
Normalising the domain
Strip the scheme, path and port, lower-case the host and drop a leading www. only if your policy treats them as one site. Reject anything longer than 253 characters, the documented limit. Deduplicate before calling, because every duplicate costs money.
Storing results
Write each response to a JSON-lines file or a database row with the domain, check name, timestamp, HTTP status and the raw body. Keeping the raw body means you can re-parse later without paying again. A diff between two runs is then a simple comparison of stored bodies.
Running several checks per domain
CHECKS = ["ai-readiness", "ai-crawlers", "webmcp", "email-auth"]
def audit(domain: str) -> dict:
return {c: run_check(domain, c) for c in CHECKS}
At the published rates that is $0.06 per domain for all four calls, as worked through in the pricing article. If you only care about mail, call email-auth alone and pay $0.01.
Using the MCP route instead
The same service is available as MCP tools: ai_readiness_grade, ai_crawler_access, webmcp_check and email_auth_check. If you drive the work from an AI agent rather than a script, you do not need the Python above at all; using the checks from an AI agent explains the trade-offs.
Testing the client
- Call one domain you control and confirm status 200.
- Pass a clearly invalid domain and confirm your code logs and continues.
- Temporarily blank the key and confirm the 401 path alerts.
- Simulate a timeout by setting
timeout=0.001and confirm you mark the result unknown, not failed. - Run the same domain twice and confirm your diff reports no change.
Naked reference
For quick reference, the page describing these routes is https://businessmcp.com/data-api/sites and the authoritative response definitions live in the vendor’s API reference. Pricing and behaviour can change, so treat this article as a starting pattern and verify against the current documentation before you ship.
Parsing once you have seen real output
After your first logged response, add a parser that does as little as possible. Pull out only the fields you will act on, and keep the raw body beside them. A defensive pattern looks like this: wrap json.loads in a try block, and if parsing fails, mark the result as an error rather than guessing. Never index into a key without checking it exists, because a field absent from a response is itself information, and a crash halfway through a 200-domain run wastes the calls already paid for.
A useful habit is to write a tiny schema check. List the keys you rely on, and when a response lacks one, log a warning with the domain and check name. If a vendor changes its response format, the warning appears on day one instead of corrupting a month of stored data.
Concurrency without trouble
Looping one domain at a time is fine for a few dozen domains. For hundreds, use a small thread pool or asyncio with a limit of a handful of concurrent requests. Keep it low: BusinessMCP says the API does not have the free tools’ hourly limits but does not publish a numeric rate limit on the sites page, so find the ceiling gently rather than hammering it. Add a short sleep between batches, and back off if latency climbs or errors appear.
| Domains | Sensible approach |
|---|---|
| 1 to 20 | Sequential loop |
| 20 to 200 | Thread pool of 3 to 5 workers |
| 200 and up | Queue, workers, resumable state file |
Secrets and safety
- Read the key from an environment variable or a secrets manager. Never commit it.
- Use a separate key per project so you can revoke one without breaking the rest.
- Do not log the Authorization header. A debug print of the full request is a common leak.
- Run scheduled jobs with the minimum permissions the platform allows.
- Rotate the key if it ever appears in a log, chat or repository.
From script to scheduled job
Once the client works, wrapping it in a scheduler is mostly plumbing: a cron entry, a CI schedule or a serverless timer that runs the script, writes results to storage and sends a message on change. Our guide to bulk domain audits builds on this client with a domain list, spend cap and ranking step.
Keep the first scheduled version boring. One script, one storage file, one alert channel. Add a dashboard only when someone actually asks for it. Most monitoring projects fail from complexity, not from a lack of features.
Frequently asked questions
How do I authenticate to the website checks API?
Send an Authorization header with a Bearer token. BusinessMCP’s examples read the key from the BUSINESSMCP_API_KEY environment variable, and its keys start with mcph_.
What is the request format?
A GET to the sites route with the domain in the path, for example /api/hub/v1/sites/{domain}/ai-readiness. The domain is the only documented request field.
Where do I find the response fields?
In the vendor’s API reference. The sites page links to a full response reference rather than listing fields inline, so check it before relying on specific keys.
Should I use requests or httpx?
Either works. Use whichever you already have; the important parts are the timeout, status-code handling and logging the raw body.