To find a company website from a company name in Python, send the name and any available country context to Datablist's Company Name to Domain API. The API processes the lookup in the background, then returns the domain and full website URL.

I will first show you a simple Python API request. Then I will reuse the same function to fill only the missing websites in a list of company records while preserving the URLs already present.

If you prefer a spreadsheet-like interface, follow the bulk company name to website guide.

💡 Summary For Those In a Rush

Build one Python function that finds websites from company names, then use it to complete records with blank websites without replacing known URLs.

  • Input: company names with optional country context.
  • Output: domain, full website URL, confidence, result status, and credits used.

Set up Python and your Datablist API key

For this example, I use the Requests package to make synchronous HTTP calls. Install it in a virtual environment:

shell
python3 -m venv .venv
source .venv/bin/activate
python -m pip install requests

You also need a Datablist Growth plan because REST API access is a Growth feature. Create a Personal API Key from your Datablist API account page, then put it in an environment variable:

shell
export DATABLIST_API_KEY="auth0|exampleuser:exampleaccount:EXAMPLE_TOKEN_NOT_VALID:1"

Replace the sample value above with the key generated on your account page. Company website lookups consume credits. I explain the 1-credit and 2.5-credit paths before scaling the script, and current plan values are on the Datablist pricing page.

Run one company website lookup in Python

Create a file named find_company_websites.py. The script submits the names, waits for the task, and fetches the results in one function. Each input uses your stable record ID as inputId, so you can match every result to the right record even if the response order changes.

python
import json
import os
import time
import uuid
import requests
API_BASE_URL = "https://api.datablist.com/v1"
def find_domains(companies, api_key):
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
"X-API-Key": api_key,
}
inputs = [
{
"inputId": company["id"],
"data": {
"companyName": company["company_name"],
"targetCountry": company.get("country", ""),
},
}
for company in companies
]
unique_id = f"python-domain-lookup-{uuid.uuid4().hex}"
payload = {
"enrichmentId": "company-name-to-domain",
"uniqueId": unique_id,
"settings": {
"workflow": "dataset_google",
"countryOverwrite": True,
"acceptNonRoot": True,
},
"inputs": inputs,
}
print(f"Task uniqueId: {unique_id}")
response = requests.post(
f"{API_BASE_URL}/enrichments/tasks",
headers=headers,
json=payload,
)
response.raise_for_status()
task_id = response.json()["@id"]
while True:
response = requests.get(
f"{API_BASE_URL}/enrichments/tasks/{task_id}",
headers=headers,
)
response.raise_for_status()
task = response.json()
if task["status"] in {"completed", "failed", "stopped"}:
break
time.sleep(3)
if task["status"] != "completed":
raise RuntimeError(
f"Task {task_id} ended with status {task['status']}: {task.get('error')}"
)
results = []
cursor = None
while True:
params = {"limit": 100}
if cursor is not None:
params["cursor"] = cursor
response = requests.get(
f"{API_BASE_URL}/enrichments/tasks/{task_id}/results",
headers=headers,
params=params,
)
response.raise_for_status()
page = response.json()
results.extend(page["results"])
cursor = page.get("nextCursor")
if cursor is None:
break
return results
api_key = os.environ["DATABLIST_API_KEY"]
companies = [
{
"id": "direct-microsoft-us",
"company_name": "Microsoft",
"country": "US",
}
]
lookup_results = find_domains(companies, api_key)
for result in lookup_results:
print(json.dumps(result, indent=2))

Run it from the terminal where you exported the key:

shell
python find_company_websites.py

Here is the Microsoft result:

json
{
"inputId": "direct-microsoft-us",
"status": "success",
"outputs": {
"companyUrl": "https://microsoft.com",
"companyDomain": "microsoft.com",
"domainConfidence": "High"
},
"creditsUsed": "1",
"error": null
}

Use inputId to match this result to the original record. status is success, no_result, error, or skipped. A successful result can include companyDomain, the full companyUrl, and domainConfidence. creditsUsed shows the charge for this input, while error explains an item-level failure.

The function makes three types of API calls in order.

First, it submits the lookup. The payload contains the settings and company records. The POST returns 202 Accepted, and @id is the task ID needed by the next calls:

python
response = requests.post(
f"{API_BASE_URL}/enrichments/tasks",
headers=headers,
json=payload,
)
response.raise_for_status()
task_id = response.json()["@id"]

If DATABLIST_API_KEY is not set, Python raises KeyError at the environment lookup before making an HTTP request. Export the variable, then run the script again. If the variable contains an invalid key, the POST reaches the API and returns HTTP 401. Copy a current Personal API Key from your account page and replace the invalid value.

Second, it polls the task. The POST starts background work, so the script reads the task every three seconds until it reaches completed, failed, or stopped:

python
while True:
response = requests.get(
f"{API_BASE_URL}/enrichments/tasks/{task_id}",
headers=headers,
)
response.raise_for_status()
task = response.json()
if task["status"] in {"completed", "failed", "stopped"}:
break
time.sleep(3)

If the task fails because credits are unavailable, its error has the reason credits_error. Add credits or wait for your monthly credits to renew, inspect any results already returned, then submit only the unfinished inputs in a new task.

Third, it retrieves every result page. Each response adds results to the list and supplies the cursor for the next request:

python
results.extend(page["results"])
cursor = page.get("nextCursor")
if cursor is None:
break

It fetches the next page until nextCursor is null.

The script prints the generated uniqueId before the POST. If the connection drops before you receive the creation response, list your tasks first to check their status before creating another task:

shell
curl --get "https://api.datablist.com/v1/enrichments/tasks" \
--header "X-API-Key: $DATABLIST_API_KEY" \
--data-urlencode "enrichmentId=company-name-to-domain"

Find the task whose uniqueId matches the value generated by the script, then copy its @id. The list endpoint can filter by enrichmentId, but not by uniqueId. Use the @id with the same status and results URLs used by the script. If the task is still active, keep polling it. If it has stopped or failed, check for partial results before submitting the inputs again.

Understand dataset matching and the country-aware fallback

The script uses dataset_google, the recommended default. Datablist checks its company datasets first. If the match is missing or conflicting, it can use Google as a fallback. It checks possible matches before returning a confidence level.

Company website lookup that checks a dataset first and conditionally uses Google before returning a domain, URL, and confidence
Company website lookup that checks a dataset first and conditionally uses Google before returning a domain, URL, and confidence

Country context helps with ambiguous names. In this example, the same company name produced different results:

  • Mercury with US returned shipmercury.com and https://www.shipmercury.com/.
  • Mercury with IE returned mercuryeng.com and http://www.mercuryeng.com.

Both had High confidence. Country context helps the lookup choose between companies with the same name, while confidence helps you decide which results need review.

When the match also depends on industry, company size, or other business context, use the AI Agent research workflow. Add those details to the AI Agent prompt so it can research the intended company with richer business context.

Fill only the missing websites in your application records

Now that find_domains() can find a website from a company name, reuse it to fill only missing websites in your company records. Records that already have a website bypass the API, so their values stay unchanged and consume no lookup credits.

In find_company_websites.py, replace everything from companies = [ through the final print loop with the block below. Keep the api_key assignment above it. The blank check handles None, an empty string, and whitespace. It makes no API call when every website is filled.

python
records = [
{
"id": "crm-001",
"company_name": "Microsoft",
"country": "US",
"website": "https://www.microsoft.com",
},
{
"id": "crm-002",
"company_name": "boulangerie du palais lyon",
"country": "FR",
"website": "",
},
{
"id": "crm-003",
"company_name": "Mercury Engineering",
"country": "IE",
"website": None,
},
{
"id": "crm-004",
"company_name": "Mercury",
"country": "US",
"website": " ",
},
{
"id": "crm-005",
"company_name": "Datablist",
"country": "FR",
"website": "https://www.datablist.com",
},
{
"id": "crm-006",
"company_name": "Mercury",
"country": "IE",
"website": None,
},
]
def website_is_missing(value):
return not isinstance(value, str) or not value.strip()
records_to_lookup = [
record for record in records if website_is_missing(record.get("website"))
]
lookup_results = (
find_domains(records_to_lookup, api_key) if records_to_lookup else []
)
results_by_id = {result["inputId"]: result for result in lookup_results}
for record in records:
if not website_is_missing(record.get("website")):
record["website_lookup"] = {"status": "not_requested"}
continue
result = results_by_id.get(record["id"])
if result is None:
record["website_lookup"] = {
"status": "missing_result",
"domain": None,
"confidence": None,
"credits": None,
"error": {
"code": "missing_result",
"message": "No result was returned for this inputId.",
},
}
continue
outputs = result.get("outputs") or {}
if result["status"] == "success" and outputs.get("companyUrl"):
record["website"] = outputs["companyUrl"]
record["website_lookup"] = {
"status": result["status"],
"domain": outputs.get("companyDomain"),
"confidence": outputs.get("domainConfidence"),
"credits": result.get("creditsUsed"),
"error": result.get("error"),
}
print(json.dumps(records, indent=2))

The code indexes results by inputId, then walks through the original records in order. The website_lookup object keeps the outcome and review details next to each attempted record, including unsuccessful or missing results.

For crm-001, website_is_missing() returns False because the Microsoft URL is already present. The record is not added to records_to_lookup, so the API never receives it. The merge keeps its website and records the status as not_requested.

For crm-002, the website is blank, so the request sends the bakery with inputId: crm-002. The API returns the same inputId. results_by_id uses it to find the right result, and the merge writes https://boulangerie-du-palais-lyon.eatbu.com to that record without relying on the result order.

IDCompanyWebsite after mergeStatusDomainConfidenceCredits
crm-001Microsoft · UShttps://www.microsoft.comnot_requested
crm-002boulangerie du palais lyon · FRhttps://boulangerie-du-palais-lyon.eatbu.comsuccessboulangerie-du-palais-lyon.eatbu.comHigh1
crm-003Mercury Engineering · IEhttps://mercuryeng.comsuccessmercuryeng.comHigh1
crm-004Mercury · UShttps://www.shipmercury.com/successshipmercury.comHigh1
crm-005Datablist · FRhttps://www.datablist.comnot_requested
crm-006Mercury · IEhttp://www.mercuryeng.comsuccessmercuryeng.comHigh1

The bakery uses a business-specific subdomain, boulangerie-du-palais-lyon.eatbu.com. Keep that value instead of reducing it to eatbu.com, and save the exact address from companyUrl. The acceptNonRoot: true setting also allows a hosted business page whose address includes a path after the hostname, so the full URL matters in both cases.

A completed task can still contain no_result, error, or skipped items. The example changes website only when the status is success and companyUrl is present. For no_result, the website stays blank and the status remains visible in website_lookup. Check the company name and country first. If either input is wrong, correct it and submit that record in a new task. Otherwise, keep the blank website visible for manual review.

Estimate lookup credits before scaling the script

The five example lookups all returned success with High confidence and used 5 credits total.

A lookup resolved from the dataset costs 1 credit. A lookup processed with Google costs 2.5 credits. You pay for the path used, not both. For 1,000 inputs, that means 1,000 credits if all resolve through the dataset or 2,500 credits if all use Google. These are planning scenarios, not a promise that every lookup will succeed.

At $20 for 20,000 credits, those scenarios cost $1 and $2.50. The Growth subscription is separate and currently includes 20,000 monthly credits, which are used before top-ups. Check current pricing because plan and package values can change.

One task accepts up to 10,000 inputs, with a 16 KiB limit per input and 10 MiB per request. This example uses blocking Requests calls to submit, poll, and fetch results from one small asynchronous Datablist task. The maintained repository also includes CSV batching and non-blocking client examples.

Next steps

Replace the sample records with a small slice of your own data, then run the script and inspect the merged records. Keep stable IDs and country context, and scale up only after the script preserves known websites and fills the expected blanks. You can start from the maintained Company Name to Domain API examples on GitHub if you want the downloadable script, CSV batching, or an asynchronous version.