Browser Crawl Engine

AI-assisted business research API

Submit structured business details to the business research worker pool. Each business becomes a task. The API returns task IDs immediately; poll until the task is complete, then download its JSON result.

The customer-facing product name is AI-assisted business research. Existing API paths and permission scopes keep ai-mode in their names.

The service uses the supplied business identity and location to research the matching legal entity and individual business locations. Results are returned as structured JSON, including the submitted details, registry status, company-number verification, location records, and an evidence-based data-quality assessment. A completed task's result is JSON data; it is not a claim that every field was found or independently verified.

Accuracy notice: AI-assisted business research results may be inaccurate, outdated, or incomplete. Independently verify important details against authoritative sources before relying on them, particularly for legal, financial, or compliance decisions. This service does not provide an official registry confirmation.

Before you start

  1. Sign in to the customer portal and create an API key.
  2. Ask your account administrator to grant the key both ai-mode:create and ai-mode:read.
  3. Set the key as the API_KEY environment variable. Keep it private; do not commit it to source control.

Examples use https://bankworks.info as the API base URL. Python requires requests (pip install requests). The Node.js example uses built-in fetch, needs Node 18 or newer, and should be saved as an ES module such as ai_mode.mjs. The cURL example also uses jq to read JSON fields.

Shell
export API="https://bankworks.info"
export API_KEY="your-api-key"

Load API_KEY from your secret manager in production. Each POST creates new tasks; poll an existing task while it is still running. Resubmitting creates a new task and may incur another charge.

Request fields

Send between 1 and 100 entities in one request. The first three fields are required. address is a free-text location field: include any available street, city, region, or postal code in one string. companyNumber is optional and represents the provided corporate registration or tax number.

Set the top-level mode to control how much of the result the result endpoint returns. regular includes the submitted entity, requested-location status, company-number verification, and data quality. advance also includes the parent company and business locations. premium returns the complete JSON result. If omitted, mode defaults to regular. The same mode applies to every entity in the request and is shown as task.resultMode when polling task status. This controls response detail only; it does not change task routing or billing, which remains one REGULAR API task per entity when billing is enabled.

The sample business details below are entirely fictional.

JSON fieldRequiredMeaningMaximum
modeNoregular, advance, or premium; controls result detailOne value per request
businessNameYesBusiness or group name500 characters
addressYesAddress, city, region, and/or postal code as supplied1,000 characters
countryYesCountry where the business is located200 characters
companyNumberNoProvided corporate ID or tax number; use null or omit it when unknown200 characters

Complete example

Pick a language tab. Each complete example submits two fictional businesses in one request, polls each task, and saves each returned JSON to a local file. One request accepts 1–100 businesses; each entry creates a separate task. The cURL example requires jq.

Python
import os
import time
from pathlib import Path

import requests

API = os.environ.get("API", "https://bankworks.info")
API_KEY = os.environ["API_KEY"]
headers = {"Authorization": f"Bearer {API_KEY}"}

created = requests.post(
    f"{API}/v1/ai-mode/tasks",
    headers=headers,
    json={"mode": "regular", "entities": [
        {
            "businessName": "BLUE COMET PAPERWORK LAB (FICTIONAL)",
            "address": "42 Imaginary Lane, Sample City, ZZ 00000",
            "country": "Fictionland",
            "companyNumber": "FICTIONAL-0001",
        },
        {
            "businessName": "MOON LANTERN DESIGN HOUSE (FICTIONAL)",
            "address": "8 Paper Street, Example Bay, YY 11111",
            "country": "Fictionland",
        },
    ]},
    timeout=30,
)
created.raise_for_status()
job = created.json()
task_ids = job["taskIds"]
print(f"Created {len(task_ids)} tasks")

for index, task_id in enumerate(task_ids, start=1):
    while True:
        status_response = requests.get(
            f"{API}/v1/ai-mode/tasks/{task_id}", headers=headers, timeout=30,
        )
        status_response.raise_for_status()
        task = status_response.json()["task"]
        if task["status"] == "DONE" and task["resultAvailable"]:
            break
        if task["status"] in {"FAILED", "CANCELLED"}:
            print(f"Task {task_id} {task['status']}: {task.get('error', 'no details')}")
            break
        time.sleep(5)

    if task["status"] != "DONE" or not task["resultAvailable"]:
        continue
    result = requests.get(
        f"{API}/v1/ai-mode/tasks/{task_id}/result", headers=headers, timeout=60,
    )
    result.raise_for_status()
    output = Path(f"ai-searching-{index}-{task_id}.json")
    output.write_bytes(result.content)
    print("Saved JSON to", output)
Node.js
import { writeFile } from "node:fs/promises";
import { setTimeout as delay } from "node:timers/promises";

const API = process.env.API || "https://bankworks.info";
const API_KEY = process.env.API_KEY;
if (!API_KEY) throw new Error("Set API_KEY first");
const headers = { Authorization: "Bearer " + API_KEY };

const created = await fetch(API + "/v1/ai-mode/tasks", {
  method: "POST",
  headers: { ...headers, "Content-Type": "application/json" },
  body: JSON.stringify({ mode: "regular", entities: [
    {
      businessName: "BLUE COMET PAPERWORK LAB (FICTIONAL)",
      address: "42 Imaginary Lane, Sample City, ZZ 00000",
      country: "Fictionland",
      companyNumber: "FICTIONAL-0001",
    },
    {
      businessName: "MOON LANTERN DESIGN HOUSE (FICTIONAL)",
      address: "8 Paper Street, Example Bay, YY 11111",
      country: "Fictionland",
    },
  ] }),
});
if (!created.ok) throw new Error(created.status + ": " + await created.text());
const job = await created.json();
console.log("Created tasks:", job.taskIds.length);

for (const [index, taskId] of job.taskIds.entries()) {
  let task;
  while (true) {
    const response = await fetch(API + "/v1/ai-mode/tasks/" + taskId, { headers });
    if (!response.ok) throw new Error(response.status + ": " + await response.text());
    task = (await response.json()).task;
    if (task.status === "DONE" && task.resultAvailable) break;
    if (["FAILED", "CANCELLED"].includes(task.status)) {
      console.error("Task", taskId, task.status + ":", task.error || "no details");
      break;
    }
    await delay(5000);
  }
  if (task.status !== "DONE" || !task.resultAvailable) continue;

  const result = await fetch(API + "/v1/ai-mode/tasks/" + taskId + "/result", { headers });
  if (!result.ok) throw new Error(result.status + ": " + await result.text());
  const output = "ai-searching-" + (index + 1) + "-" + taskId + ".json";
  await writeFile(output, Buffer.from(await result.arrayBuffer()));
  console.log("Saved JSON to", output);
}
cURL
: "${API_KEY:?Set API_KEY first}"
API="${API:-https://bankworks.info}"

CREATED="$(curl --fail --silent --show-error \
  -X POST "$API/v1/ai-mode/tasks" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"mode":"regular","entities":[{"businessName":"BLUE COMET PAPERWORK LAB (FICTIONAL)","address":"42 Imaginary Lane, Sample City, ZZ 00000","country":"Fictionland","companyNumber":"FICTIONAL-0001"},{"businessName":"MOON LANTERN DESIGN HOUSE (FICTIONAL)","address":"8 Paper Street, Example Bay, YY 11111","country":"Fictionland"}]}')"
TASK_IDS="$(printf '%s' "$CREATED" | jq -r '.taskIds[]')"
printf 'Created %s tasks\n' "$(printf '%s\n' "$TASK_IDS" | wc -l | tr -d ' ')"

INDEX=0
for TASK_ID in $TASK_IDS; do
  INDEX=$((INDEX + 1))
  while true; do
    STATUS_JSON="$(curl --fail --silent --show-error \
      -H "Authorization: Bearer $API_KEY" \
      "$API/v1/ai-mode/tasks/$TASK_ID")"
    STATUS="$(printf '%s' "$STATUS_JSON" | jq -r '.task.status')"
    RESULT_AVAILABLE="$(printf '%s' "$STATUS_JSON" | jq -r '.task.resultAvailable')"
    if [ "$STATUS" = "DONE" ] && [ "$RESULT_AVAILABLE" = "true" ]; then break; fi
    case "$STATUS" in
      FAILED|CANCELLED) printf 'Task %s failed: %s\n' "$TASK_ID" "$(printf '%s' "$STATUS_JSON" | jq -r '.task.error // "no details"')"; break ;;
    esac
    sleep 5
  done
  if [ "$STATUS" != "DONE" ] || [ "$RESULT_AVAILABLE" != "true" ]; then continue; fi
  OUTPUT="ai-searching-$INDEX-$TASK_ID.json"
  curl --fail --silent --show-error \
    -H "Authorization: Bearer $API_KEY" \
    "$API/v1/ai-mode/tasks/$TASK_ID/result" \
    -o "$OUTPUT"
  printf 'Saved JSON to %s\n' "$OUTPUT"
done

Track a task

The submit response includes jobId, a taskIds array, taskCount, dispatched, and duplicate. Save a task ID and poll GET /v1/ai-mode/tasks/{taskId}. The status response wraps details in a task object; when task.status is DONE and task.resultAvailable is true, fetch the result. While the task is queued or running, wait a few seconds before polling again. A worker can claim it only after completing all four current setup prompts.

JSON
{
  "ok": true,
  "task": {
    "taskId": "TASK_ID",
    "status": "DONE",
    "resultAvailable": true
  }
}

Download the JSON

The result endpoint returns the stored JSON as an attachment. Save the response body to a file on the machine running your client.

Understand the JSON result

The response uses the schema below. Every company, identifier, address, source, and contact detail is invented for this example; it does not describe a real business or research result. Most fields are populated so you can see the shape of a complete response. The actual result can have multiple entries in businessLocations when separate businesses are supported by the research.

Use the tabs to compare the exact response shape for each mode. The regular result contains submittedEntity, companyNumberVerification, and dataQuality. advance adds parentCompany and businessLocations, without coordinates, map identifiers, or marketplace profiles. premium includes the complete response.

JSON
{
  "submittedEntity": {
    "providedDetails": {
      "businessName": "AURORA CRAFT SYSTEMS (FICTIONAL)",
      "street": "17 Example Row",
      "postalCode": "EX 2048",
      "city": "Sampleville",
      "country": "Example Republic",
      "companyNumber": "EXAMPLE-REG-2048"
    },
    "requestedLocationStatus": {
      "status": "MOVED",
      "registryAction": "Fictional record of relocation to a new workshop",
      "statusEffectiveDate": "2024-06-15",
      "relocation": {
        "movedWithinSameCountry": true,
        "newAddress": {
          "streetNumber": "88",
          "streetName": "Fictional Harbor Road",
          "city": "Sampleville",
          "postalCode": "EX 2088",
          "region": "North Example District",
          "country": "Example Republic"
        }
      }
    }
  },
  "companyNumberVerification": {
    "providedCompanyNumber": "EXAMPLE-REG-2048",
    "verificationStatus": "VALID",
    "resolvedCompanyNumber": "EXAMPLE-REG-2048",
    "resolutionNotes": "Illustrative match only; this fictional identifier was not checked against a registry."
  },
  "dataQuality": {
    "confidenceLevel": "LOW",
    "confidenceScore": 0,
    "assessmentReason": "All values are fictional examples; no registries, maps, marketplaces, or other sources were checked."
  }
}
JSON
{
  "submittedEntity": {
    "providedDetails": {
      "businessName": "AURORA CRAFT SYSTEMS (FICTIONAL)",
      "street": "17 Example Row",
      "postalCode": "EX 2048",
      "city": "Sampleville",
      "country": "Example Republic",
      "companyNumber": "EXAMPLE-REG-2048"
    },
    "requestedLocationStatus": {
      "status": "MOVED",
      "registryAction": "Fictional record of relocation to a new workshop",
      "statusEffectiveDate": "2024-06-15",
      "relocation": {
        "movedWithinSameCountry": true,
        "newAddress": {
          "streetNumber": "88",
          "streetName": "Fictional Harbor Road",
          "city": "Sampleville",
          "postalCode": "EX 2088",
          "region": "North Example District",
          "country": "Example Republic"
        }
      }
    }
  },
  "parentCompany": {
    "legalName": "AURORA IMAGINARY HOLDINGS LTD (FICTIONAL)",
    "companyRegistrationNumber": "EXAMPLE-HOLDCO-2048",
    "currentSiteStatus": "ACTIVE"
  },
  "companyNumberVerification": {
    "providedCompanyNumber": "EXAMPLE-REG-2048",
    "verificationStatus": "VALID",
    "resolvedCompanyNumber": "EXAMPLE-REG-2048",
    "resolutionNotes": "Illustrative match only; this fictional identifier was not checked against a registry."
  },
  "businessLocations": [
    {
      "brandOrDepartmentName": "Harbor Studio (FICTIONAL)",
      "publicName": "AURORA CRAFT SYSTEMS (FICTIONAL)",
      "companyRegistrationNumber": "EXAMPLE-REG-2048",
      "locationRegistrationNumber": "EXAMPLE-BRANCH-01",
      "vatNumber": "EXAMPLE-VAT-2048",
      "franchiseType": "INDEPENDENT",
      "organizationType": "PRIVATE_LIMITED_COMPANY",
      "parentCompanyName": "AURORA IMAGINARY HOLDINGS LTD (FICTIONAL)",
      "networkName": "Aurora Craft Collective (FICTIONAL)",
      "businessStartDate": "2020-03-12",
      "businessEndDate": null,
      "operatingStatus": "ACTIVE",
      "industry": "Custom stationery and paper goods",
      "address": {
        "streetNumber": "88",
        "streetName": "Fictional Harbor Road",
        "city": "Sampleville",
        "postalCode": "EX 2088",
        "region": "North Example District",
        "country": "Example Republic"
      },
      "contact": {
        "internationalPhone": "+1-202-555-0147",
        "localPhone": "(202) 555-0147",
        "website": "https://aurora-craft.example"
      }
    }
  ],
  "dataQuality": {
    "confidenceLevel": "LOW",
    "confidenceScore": 0,
    "assessmentReason": "All values are fictional examples; no registries, maps, marketplaces, or other sources were checked."
  }
}
JSON
{
  "submittedEntity": {
    "providedDetails": {
      "businessName": "AURORA CRAFT SYSTEMS (FICTIONAL)",
      "street": "17 Example Row",
      "postalCode": "EX 2048",
      "city": "Sampleville",
      "country": "Example Republic",
      "companyNumber": "EXAMPLE-REG-2048"
    },
    "requestedLocationStatus": {
      "status": "MOVED",
      "registryAction": "Fictional record of relocation to a new workshop",
      "statusEffectiveDate": "2024-06-15",
      "relocation": {
        "movedWithinSameCountry": true,
        "newAddress": {
          "streetNumber": "88",
          "streetName": "Fictional Harbor Road",
          "city": "Sampleville",
          "postalCode": "EX 2088",
          "region": "North Example District",
          "country": "Example Republic"
        }
      }
    }
  },
  "parentCompany": {
    "legalName": "AURORA IMAGINARY HOLDINGS LTD (FICTIONAL)",
    "companyRegistrationNumber": "EXAMPLE-HOLDCO-2048",
    "currentSiteStatus": "ACTIVE"
  },
  "companyNumberVerification": {
    "providedCompanyNumber": "EXAMPLE-REG-2048",
    "verificationStatus": "VALID",
    "resolvedCompanyNumber": "EXAMPLE-REG-2048",
    "resolutionNotes": "Illustrative match only; this fictional identifier was not checked against a registry."
  },
  "businessLocations": [
    {
      "brandOrDepartmentName": "Harbor Studio (FICTIONAL)",
      "publicName": "AURORA CRAFT SYSTEMS (FICTIONAL)",
      "companyRegistrationNumber": "EXAMPLE-REG-2048",
      "locationRegistrationNumber": "EXAMPLE-BRANCH-01",
      "vatNumber": "EXAMPLE-VAT-2048",
      "franchiseType": "INDEPENDENT",
      "organizationType": "PRIVATE_LIMITED_COMPANY",
      "parentCompanyName": "AURORA IMAGINARY HOLDINGS LTD (FICTIONAL)",
      "networkName": "Aurora Craft Collective (FICTIONAL)",
      "businessStartDate": "2020-03-12",
      "businessEndDate": null,
      "operatingStatus": "ACTIVE",
      "industry": "Custom stationery and paper goods",
      "address": {
        "streetNumber": "88",
        "streetName": "Fictional Harbor Road",
        "city": "Sampleville",
        "postalCode": "EX 2088",
        "region": "North Example District",
        "country": "Example Republic"
      },
      "coordinates": {
        "latitude": 12.345678,
        "longitude": -98.765432
      },
      "contact": {
        "internationalPhone": "+1-202-555-0147",
        "localPhone": "(202) 555-0147",
        "website": "https://aurora-craft.example"
      },
      "googleMaps": {
        "placeId": "FICTIONAL_PLACE_ID_2048",
        "cid": "FICTIONAL_CID_2048"
      },
      "marketplaceProfiles": [
        {
          "platformName": "Example Handmade Market (FICTIONAL)",
          "profileUrl": "https://market.example/aurora-craft",
          "profileType": "SELLER_PROFILE"
        }
      ]
    }
  ],
  "dataQuality": {
    "confidenceLevel": "LOW",
    "confidenceScore": 0,
    "assessmentReason": "All values are fictional examples; no registries, maps, marketplaces, or other sources were checked."
  }
}
JSON REFERENCE

Field meanings

Each tab shows only the fields added by that mode compared with the previous one.

Regular · Advance · Premium
FieldMeaning
REGULAR · Core fields
submittedEntityThe business and location submitted for research, with the result for that requested location.
submittedEntity.providedDetailsThe original input values, preserved so the result can be matched to the submitted entity.
submittedEntity.providedDetails.businessNameBusiness or group name as supplied by the caller.
submittedEntity.providedDetails.streetStreet portion of the supplied address, when it can be separated.
submittedEntity.providedDetails.postalCodePostal or ZIP code from the supplied address, when available.
submittedEntity.providedDetails.cityCity from the supplied address, when available.
submittedEntity.providedDetails.countryCountry supplied for the business.
submittedEntity.providedDetails.companyNumberCorporate or tax number supplied by the caller; null when none was provided.
submittedEntity.requestedLocationStatusRegistry status and any relocation information for the exact submitted location.
submittedEntity.requestedLocationStatus.statusACTIVE, CLOSED, MOVED, or UNKNOWN for the requested location.
submittedEntity.requestedLocationStatus.registryActionRelevant registry action or event behind the status, when supported by evidence.
submittedEntity.requestedLocationStatus.statusEffectiveDateDate the status or registry action took effect, formatted as YYYY-MM-DD.
submittedEntity.requestedLocationStatus.relocationRelocation details when the requested location is marked MOVED; otherwise null.
submittedEntity.requestedLocationStatus.relocation.movedWithinSameCountryWhether evidence indicates the business moved within the same country.
submittedEntity.requestedLocationStatus.relocation.newAddressStructured destination address after a move.
submittedEntity.requestedLocationStatus.relocation.newAddress.streetNumberHouse or building number at the new address.
submittedEntity.requestedLocationStatus.relocation.newAddress.streetNameStreet name at the new address.
submittedEntity.requestedLocationStatus.relocation.newAddress.cityCity at the new address.
submittedEntity.requestedLocationStatus.relocation.newAddress.postalCodePostal or ZIP code at the new address.
submittedEntity.requestedLocationStatus.relocation.newAddress.regionState, province, or region at the new address.
submittedEntity.requestedLocationStatus.relocation.newAddress.countryCountry at the new address.
companyNumberVerificationComparison of the submitted company number with the resolved entity and registry evidence.
companyNumberVerification.providedCompanyNumberCompany number supplied by the caller.
companyNumberVerification.verificationStatusVALID, INVALID_OR_NOT_FOUND, or NOT_PROVIDED.
companyNumberVerification.resolvedCompanyNumberOfficial number resolved for the matching company, if available.
companyNumberVerification.resolutionNotesShort explanation of the number match, mismatch, or resolution.
dataQualitySummary of how complete and consistent the evidence is for this result.
dataQuality.confidenceLevelText label describing the overall evidence strength.
dataQuality.confidenceScoreEvidence-based integer from 0 to 100; it is not a statistically measured probability.
dataQuality.assessmentReasonExplanation of the evidence and any uncertainty behind the quality assessment.
ADVANCE · Additional fields beyond Regular
parentCompanyThe resolved parent organization, when a relationship is supported by evidence.
parentCompany.legalNameParent company's legal name.
parentCompany.companyRegistrationNumberParent company's official registration number.
parentCompany.currentSiteStatusCurrent status of the parent company's site: ACTIVE, CLOSED, MOVED, or UNKNOWN.
businessLocationsArray of separately identified businesses or locations at the submitted address; may be empty or contain multiple entries.
businessLocations[].brandOrDepartmentNameBrand or department name associated with this location.
businessLocations[].publicNameName used publicly by this business location.
businessLocations[].companyRegistrationNumberRegistration number of the company operating this location.
businessLocations[].locationRegistrationNumberRegistration identifier specific to the branch or location.
businessLocations[].vatNumberVAT registration number for this business, when available.
businessLocations[].franchiseTypeFRANCHISE or INDEPENDENT when evidence supports a classification.
businessLocations[].organizationTypeBusiness or legal organization type, when known.
businessLocations[].parentCompanyNameName of the parent company associated with this location.
businessLocations[].networkNameDealer group, franchise network, or other business network name.
businessLocations[].businessStartDateStart date of this business or location, if known.
businessLocations[].businessEndDateClosure or end date, if known.
businessLocations[].operatingStatusACTIVE, INACTIVE, or UNKNOWN for this individual location.
businessLocations[].industryIndustry or business activity associated with the location.
businessLocations[].addressStructured address for this individual location: street number/name, city, postal code, region, and country.
businessLocations[].address.streetNumberHouse or building number for the location.
businessLocations[].address.streetNameStreet name for the location.
businessLocations[].address.cityCity where the location operates.
businessLocations[].address.postalCodePostal or ZIP code for the location.
businessLocations[].address.regionState, province, or region for the location.
businessLocations[].address.countryCountry where the location operates.
businessLocations[].contactContact details associated with the location: international/local phone and website.
businessLocations[].contact.internationalPhonePhone number in international dialing format.
businessLocations[].contact.localPhonePhone number in the local format used by the source.
businessLocations[].contact.websiteOfficial website URL for this location or business.
PREMIUM · Additional fields beyond Advance
businessLocations[].coordinatesLatitude and longitude as JSON numbers, or null when unavailable.
businessLocations[].coordinates.latitudeNorth/south coordinate as a JSON number.
businessLocations[].coordinates.longitudeEast/west coordinate as a JSON number.
businessLocations[].googleMapsGoogle Maps identifiers for the matching location, when found.
businessLocations[].googleMaps.placeIdGoogle Maps Place ID for the matching place.
businessLocations[].googleMaps.cidGoogle Maps customer identifier (CID) for the matching place.
businessLocations[].marketplaceProfilesArray of supported vehicle-marketplace profiles; each item identifies a platform, direct profile URL, and profile type.
businessLocations[].marketplaceProfiles[].platformNameName of the vehicle marketplace hosting the profile.
businessLocations[].marketplaceProfiles[].profileUrlDirect URL to the dealer profile, inventory, or relevant listing page.
businessLocations[].marketplaceProfiles[].profileTypeType of marketplace page represented by the URL.

Responses and errors

When billing is enabled, each entity is charged as one REGULAR API task. The full JSON result is stored with the task in MySQL and follows its one-year result retention period. Keep the downloaded copy if you need it longer.

This API submits a business research request and returns its response; it does not guarantee that every business detail is present or independently verified. Review the returned JSON before using it for consequential decisions.