> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wokelo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Company Research

> Generate a comprehensive, source-cited company intelligence report — covering firmographics, executive summary, key insights, product portfolio, and M&A activity — as a structured JSON, PDF, DOCX, or PPT deliverable.

## 1. Overview

The Company Research API generates an in-depth intelligence report on any company, covering firmographics, financial signals, executive commentary, product portfolio, product launches, and M\&A history. The report is fully source-cited and delivered as structured JSON or as a formatted document (PDF, DOCX, or PPT).

This is an **asynchronous POST API** — submitting a request returns a `report_id` immediately. You then poll for completion using the [Report Status](/supporting-apis-doc#report-status) endpoint and retrieve the finished report using the [Download Report](/supporting-apis-doc#download-report) endpoint.

**The three-step workflow:**

```text theme={"system"}
Step 1: POST /api/workflow_manager/start/         → returns report_id
Step 2: GET  /api/assets/get_notebook_status/     → poll until status = "Completed"
Step 3: POST /api/assets/download_report/         → retrieve JSON / PDF / DOCX / PPT
```

The completed report is structured into five major sections, each returned as a named key in the JSON output:

* **Quick Snapshot** — firmographic card with financials, headcount, funding stage, HQ, and product summary
* **Executive Summary** — multi-paragraph narrative covering strategy, recent developments, competitive dynamics, and key capabilities; fully source-cited
* **Key Insights** — 8–10 analyst-style insight cards, each with a headline metric, supporting data paragraph, multi-point commentary, and source citations
* **Product Insights** — product overview narrative, categorised product/service list, product launch timeline with summaries, and a screenshot
* **Transaction Highlights** — M\&A and investment map as structured data, plus a detailed acquisition timeline with deal amounts and strategic commentary

**Common use cases:**

* **Pre-meeting company briefings** — generate a sourced, structured brief on any target or prospect before a call, in minutes rather than hours
* **Deal screening packages** — run Company Research on a shortlist of acquisition targets and export as PDF or PPT for IC review
* **Portfolio company monitoring** — schedule quarterly runs on portfolio companies and diff the Key Insights across periods to track strategic shifts
* **Competitive intelligence** — run against a set of competitors and compare product portfolios and M\&A timelines side by side
* **CRM enrichment** — ingest the JSON output and push firmographic and financial fields into Salesforce, HubSpot, or DealCloud records automatically
* **Custom report augmentation** — supply `custom_files` to layer proprietary internal data (CIM, management presentation, diligence notes) on top of Wokelo's synthesis

<Info>
  This API is asynchronous. The initial POST returns a `report_id` only — not the report content. Report generation typically completes in 2–5 minutes. See [How Async APIs work](/how-async-apis-work) for a full explanation of the polling lifecycle.
</Info>

***

## 2. Quick Start

**Step 1 — Submit the report request**

<CodeGroup>
  ```bash cURL theme={"system"}
  curl --location 'https://api.wokelo.ai/api/workflow_manager/start/' \
    --header 'Authorization: Bearer <YOUR_API_TOKEN>' \
    --header 'Content-Type: application/json' \
    --data '{
      "workflow": "company_primer",
      "permalink": "salesforce"
    }'
  ```

  ```python Python theme={"system"}
  import requests

  response = requests.post(
      "https://api.wokelo.ai/api/workflow_manager/start/",
      headers={
          "Authorization": "Bearer <YOUR_API_TOKEN>",
          "Content-Type": "application/json"
      },
      json={
          "workflow": "company_primer",
          "permalink": "salesforce"
      }
  )
  report_id = response.json()["report_id"]
  print(f"Report submitted. report_id: {report_id}")
  ```
</CodeGroup>

**Step 2 — Poll for completion**

```python theme={"system"}
import time

def wait_for_report(report_id, api_key, poll_interval=15, timeout=600):
    headers = {"Authorization": f"Bearer {api_key}"}
    elapsed = 0
    while elapsed < timeout:
        r = requests.get(
            "https://api.wokelo.ai/api/assets/get_notebook_status/",
            headers=headers,
            params={"report_id": report_id}
        )
        status = r.json().get("status", "")
        print(f"[{elapsed}s] Status: {status}")
        if status == "Completed":
            return True
        if status == "Failed":
            raise Exception(f"Report {report_id} failed")
        time.sleep(poll_interval)
        elapsed += poll_interval
    raise TimeoutError(f"Report {report_id} did not complete within {timeout}s")

wait_for_report(report_id, api_key="<YOUR_API_TOKEN>")
```

**Step 3 — Download the report**

```python theme={"system"}
# Fetch as JSON for programmatic processing
result = requests.post(
    "https://api.wokelo.ai/api/assets/download_report/",
    headers={"Authorization": "Bearer <YOUR_API_TOKEN>"},
    json={"report_id": report_id, "file_type": "json"}
)
report = result.json()

# Or download as a formatted document
pdf_result = requests.post(
    "https://api.wokelo.ai/api/assets/download_report/",
    headers={"Authorization": "Bearer <YOUR_API_TOKEN>"},
    json={"report_id": report_id, "file_type": "pdf"}
)
with open("company_research.pdf", "wb") as f:
    f.write(pdf_result.content)
```

***

## 3. Authentication

All requests must include a **Bearer token** in the `Authorization` HTTP header.

```text theme={"system"}
Authorization: Bearer <YOUR_API_TOKEN>
```

API tokens are issued from your Wokelo account. Navigate to **Account Details → API Credentials** in the Wokelo dashboard to get your client id and client secret. Contact [support@wokelo.ai](mailto:support@wokelo.ai) if you do not yet have API access.

<Warning>
  Never expose your token in client-side code, browser requests, or public repositories. A missing or invalid token returns `401 Unauthorized`. A valid token without sufficient plan permissions returns `403 Forbidden`.
</Warning>

***

## 4. Request Reference

**Endpoint**

```text theme={"system"}
POST https://api.wokelo.ai/api/workflow_manager/start/
```

All parameters are passed as JSON in the request body.

| Parameter       | Type      | Required     | Description                                                                                                                                                                                                                                                                           |
| --------------- | --------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `workflow`      | string    | **Required** | Must always be `"company_primer"`. This fixed value tells Wokelo's workflow engine to run the Company Research report.                                                                                                                                                                |
| `permalink`     | string    | Required\*   | Wokelo/Crunchbase permalink of the company (e.g. `"salesforce"`, `"tesla-motors"`). Use the [Company Search API](/supporting-apis-doc#company-search) to look up a company's permalink by name.                                                                                       |
| `website`       | string    | Required\*   | Full URL of the company's website (e.g. `"https://www.salesforce.com"`). Accepted as an alternative to `permalink` when the permalink is unknown.                                                                                                                                     |
| `industry`      | string    | Optional     | Company's industry vertical. If omitted, Wokelo auto-detects the industry from its knowledge base. Providing this speeds up processing and can improve industry-specific framing in the report.                                                                                       |
| `workbook_name` | string    | Optional     | Label for the generated report workbook. Defaults to the company name if omitted.                                                                                                                                                                                                     |
| `custom_files`  | object\[] | Optional     | Array of file references to include in the report alongside Wokelo's synthesis. Each object should use the `fileName` value returned by the [File Upload API](/supporting-apis-doc#file-upload). Use this to incorporate CIMs, management presentations, or internal diligence notes. |

<Info>
  Either `permalink` or `website` is required — at least one must be provided. If both are supplied, `permalink` takes precedence. If you cannot find a company's permalink via Company Search, pass the full company website URL instead.
</Info>

**Full request example:**

<CodeGroup>
  ```bash cURL theme={"system"}
  curl --location 'https://api.wokelo.ai/api/workflow_manager/start/' \
    --header 'Authorization: Bearer <YOUR_API_TOKEN>' \
    --header 'Content-Type: application/json' \
    --data '{
      "workflow": "company_primer",
      "permalink": "salesforce",
      "industry": "Enterprise Software & Cloud",
      "workbook_name": "Salesforce Q2 2026 Research"
    }'
  ```

  ```python Python theme={"system"}
  import requests

  response = requests.post(
      "https://api.wokelo.ai/api/workflow_manager/start/",
      headers={
          "Authorization": "Bearer <YOUR_API_TOKEN>",
          "Content-Type": "application/json"
      },
      json={
          "workflow": "company_primer",
          "permalink": "salesforce",
          "industry": "Enterprise Software & Cloud",
          "workbook_name": "Salesforce Q2 2026 Research"
      }
  )
  print(response.json())   # {"report_id": 123345}
  ```
</CodeGroup>

***

## 5. Response

### Submission response

The initial POST returns immediately with a single field:

```json theme={"system"}
{
  "report_id": 123345
}
```

| Field       | Type    | Description                                                                                                                                                                                             |
| ----------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `report_id` | integer | Unique identifier for this report job. Use it with the Report Status and Download Report endpoints to track and retrieve the completed report. Store this value — it is the only handle to your report. |

### Report status response

Poll `GET /api/assets/get_notebook_status/?report_id={report_id}` until the status field is `"Completed"`.

| Status value   | Meaning                                                       |
| -------------- | ------------------------------------------------------------- |
| `"Pending"`    | Report is queued and waiting to start.                        |
| `"Processing"` | Report generation is in progress.                             |
| `"Completed"`  | Report is ready to download.                                  |
| `"Failed"`     | Report generation encountered an error. Retry the submission. |

### Downloaded report structure

When you call Download Report with `"file_type": "json"`, the response is a deeply nested JSON object. Each top-level key is a named report section. The five sections produced by Company Research are:

**Quick Snapshot**

Contains a `quick_snapshot` object with two sub-objects:

* `company_firmographics` — organisation name, logo, dashboard URL, and a `details` object covering: `industry`, `founded_year`, `website`, `hq`, `operating_status`, `company_type`, `employees_in_crunchbase`, `employees_in_linkedin`, `last_funding_round`, `ticker`, and a `financials` object with `revenue`, `ebitda`, `pat`, and `market_cap` (each with `currency`, `value`, and `period` fields)
* `product_details` — `product_category` (short label) and `summary` (one-paragraph product description)

**Executive Summary**

Contains a `summary` field with a full markdown-formatted multi-section narrative (Overview, Strategic Positioning, Recent Developments, Competitive Dynamics, Key Capabilities), plus a `source` array of citation objects, each with `id`, `title`, `url`, `publisher`, and `date`.

**Key Insights**

Contains a `key_insights` array of 8–10 insight card objects. Each card has:

* `insight` — object with `title` (bold headline with key metric), `paragraph` (supporting data sentence), and `sources` array
* `commentary` — array of 2–3 commentary paragraph objects, each with `paragraph` (analyst interpretation) and `sources` array

**Product Insights**

Contains two sub-sections:

* `Product and services` — `product_overview` (summary narrative + `screenshot_url`) and `products_and_services` (array of product area objects, each with `product_area` label, `details` array of `{title, summary}` objects, and `sources` citation range)
* `Product launches and initiatives` — `released_products` array of launch objects, each with `date`, `initiative`, `summary` (bullet array), and `sources` array of `{url, title, publisher, publishedDate}` objects; and `future_announcements` array

**Transaction Highlights**

Contains two sub-sections:

* `M&A and Investments map` — `m_andn_a_map` with a `charts` object containing `m_and_a_investment_map`, which has a `data` array of deal objects (`year`, `company_name`, `product_category`, `headquarters`, `permalink`, `website`, `type` as `"mna"` or `"investment"`, plus parent company fields), a `source` attribution string, and a `url` to the chart image
* `M&A Strategy` — `acquisitions` with `m_and_a_timeline` array of detailed acquisition objects, each with a nested `company` card (firmographics + description), `acquisition_date`, `acquisition_amount` (numeric USD or empty string), and `commentary`

<Info>
  The `acquisition_amount` field is a raw numeric USD value (e.g. `1900000000.0` for \$1.9B) or an empty string when the deal value was not publicly disclosed. Always check for empty string before converting to currency.
</Info>

### Download format options

The `file_type` parameter in the Download Report request controls the output format.

| `file_type` | Description                                                                                                                                   |
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `"json"`    | Fully structured JSON — all sections, fields, and source citations. Best for programmatic processing, CRM ingestion, or downstream pipelines. |
| `"pdf"`     | Formatted PDF report with charts, tables, and narrative sections. Best for sharing with stakeholders.                                         |
| `"docx"`    | Editable Word document. Best for teams that customise reports before distribution.                                                            |
| `"ppt"`     | PowerPoint presentation with section slides. Best for IC presentations and LP updates.                                                        |

***

## 6. Examples

### Basic company research — by permalink

The most common pattern: look up the permalink, submit, poll, and download JSON.

<CodeGroup>
  ```bash cURL theme={"system"}
  # Step 1: Submit
  curl --location 'https://api.wokelo.ai/api/workflow_manager/start/' \
    --header 'Authorization: Bearer <YOUR_API_TOKEN>' \
    --header 'Content-Type: application/json' \
    --data '{"workflow": "company_primer", "permalink": "salesforce"}'

  # Step 2: Poll (replace 123345 with your report_id)
  curl --location 'https://api.wokelo.ai/api/assets/get_notebook_status/?report_id=123345' \
    --header 'Authorization: Bearer <YOUR_API_TOKEN>'

  # Step 3: Download
  curl --location 'https://api.wokelo.ai/api/assets/download_report/' \
    --header 'Authorization: Bearer <YOUR_API_TOKEN>' \
    --header 'Content-Type: application/json' \
    --data '{"report_id": 123345, "file_type": "json"}'
  ```

  ```python Python theme={"system"}
  import requests, time

  API_KEY = "<YOUR_API_TOKEN>"
  HEADERS = {
      "Authorization": f"Bearer {API_KEY}",
      "Content-Type": "application/json"
  }

  # Step 1: Submit
  submit = requests.post(
      "https://api.wokelo.ai/api/workflow_manager/start/",
      headers=HEADERS,
      json={"workflow": "company_primer", "permalink": "salesforce"}
  )
  report_id = submit.json()["report_id"]
  print(f"Submitted. report_id: {report_id}")

  # Step 2: Poll
  while True:
      status_r = requests.get(
          "https://api.wokelo.ai/api/assets/get_notebook_status/",
          headers=HEADERS,
          params={"report_id": report_id}
      )
      status = status_r.json().get("status")
      print(f"Status: {status}")
      if status == "Completed":
          break
      if status == "Failed":
          raise Exception("Report failed")
      time.sleep(15)

  # Step 3: Download
  result = requests.post(
      "https://api.wokelo.ai/api/assets/download_report/",
      headers=HEADERS,
      json={"report_id": report_id, "file_type": "json"}
  )
  report = result.json()
  print(f"Sections: {list(report.keys())}")
  ```
</CodeGroup>

**Sample submission response:**

```json theme={"system"}
{
  "report_id": 123345
}
```

### Using a website URL instead of a permalink

When the company's permalink is unknown or unavailable, pass the full website URL.

```python theme={"system"}
response = requests.post(
    "https://api.wokelo.ai/api/workflow_manager/start/",
    headers=HEADERS,
    json={
        "workflow": "company_primer",
        "website": "https://www.stripe.com"
    }
)
report_id = response.json()["report_id"]
```

### Resolving a permalink via Company Search before submitting

Use the Company Search API to find a company's permalink by name, then pass it to Company Research.

```python theme={"system"}
# Search for the company
search = requests.get(
    "https://api.wokelo.ai/api/enterprise/company/search",
    headers=HEADERS,
    params={"query": "HubSpot", "search_by": "name", "company_type": "all"}
)
permalink = search.json()["data"][0]["permalink"]  # e.g. "hubspot"

# Submit research report
submit = requests.post(
    "https://api.wokelo.ai/api/workflow_manager/start/",
    headers=HEADERS,
    json={"workflow": "company_primer", "permalink": permalink}
)
report_id = submit.json()["report_id"]
print(f"Research for {permalink} started. report_id: {report_id}")
```

### Batch research on a watchlist

Submit Company Research for multiple companies concurrently, then collect all reports once completed.

```python theme={"system"}
import requests, time, concurrent.futures

API_KEY  = "<YOUR_API_TOKEN>"
HEADERS  = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}

COMPANIES = ["salesforce", "hubspot", "pipedrive", "zoho", "freshworks"]

def submit_research(permalink):
    r = requests.post(
        "https://api.wokelo.ai/api/workflow_manager/start/",
        headers=HEADERS,
        json={"workflow": "company_primer", "permalink": permalink}
    )
    return permalink, r.json()["report_id"]

def poll_until_done(report_id, interval=20, timeout=900):
    elapsed = 0
    while elapsed < timeout:
        r = requests.get(
            "https://api.wokelo.ai/api/assets/get_notebook_status/",
            headers=HEADERS,
            params={"report_id": report_id}
        )
        status = r.json().get("status")
        if status == "Completed":
            return True
        if status == "Failed":
            return False
        time.sleep(interval)
        elapsed += interval
    return False

def fetch_report(report_id):
    r = requests.post(
        "https://api.wokelo.ai/api/assets/download_report/",
        headers=HEADERS,
        json={"report_id": report_id, "file_type": "json"}
    )
    return r.json()

# Submit all concurrently
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as pool:
    futures = {pool.submit(submit_research, c): c for c in COMPANIES}
    jobs = {}
    for future in concurrent.futures.as_completed(futures):
        permalink, report_id = future.result()
        jobs[permalink] = report_id
        print(f"Submitted: {permalink} → report_id {report_id}")

# Poll and collect
reports = {}
for permalink, report_id in jobs.items():
    ok = poll_until_done(report_id)
    if ok:
        reports[permalink] = fetch_report(report_id)
        print(f"Collected: {permalink}")
    else:
        print(f"Failed or timed out: {permalink}")

print(f"\nCollected {len(reports)} / {len(COMPANIES)} reports")
```

### Research with a custom file (CIM or management deck)

Upload a proprietary file and attach it to the report so Wokelo synthesises it alongside its own research.

```python theme={"system"}
import requests

API_KEY = "<YOUR_API_TOKEN>"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

# Step 1: Upload the file
with open("target_company_cim.pdf", "rb") as f:
    upload_r = requests.post(
        "https://api.wokelo.ai/api/assets/upload/",
        headers=HEADERS,
        files={"files": ("target_company_cim.pdf", f, "application/pdf")}
    )
file_name = upload_r.json()["fileName"]  # unique file identifier

# Step 2: Submit report referencing the uploaded file
submit_r = requests.post(
    "https://api.wokelo.ai/api/workflow_manager/start/",
    headers={**HEADERS, "Content-Type": "application/json"},
    json={
        "workflow":     "company_primer",
        "permalink":    "target-company-permalink",
        "custom_files": [{"fileName": file_name}]
    }
)
report_id = submit_r.json()["report_id"]
print(f"Report with custom file submitted. report_id: {report_id}")
```

### Extracting specific sections from the JSON report

Work with individual sections of the downloaded JSON for targeted downstream processing.

```python theme={"system"}
# Assume report is already downloaded as a dict
report = fetch_report(report_id)

# --- Quick Snapshot ---
snapshot   = report["Quick Snapshot"]["Quick Snapshot"]["quick_snapshot"]
firmograph  = snapshot["company_firmographics"]["details"]
financials  = firmograph["financials"]

print(f"Company:    {snapshot['company_firmographics']['organization']['name']}")
print(f"HQ:         {firmograph['hq']}")
print(f"Employees:  {firmograph['employees_in_linkedin']:,}")
print(f"Revenue:    ${financials['revenue']['value'] / 1e9:.1f}B ({financials['revenue']['period']})")
print(f"Market Cap: ${financials['market_cap']['value'] / 1e9:.1f}B")

# --- Key Insights (headlines only) ---
insights = report["Executive Summary"]["Key Insights"]["key_insights"]
print(f"\nKey Insights ({len(insights)} total):")
for i, card in enumerate(insights, 1):
    print(f"  {i}. {card['insight']['title']}")

# --- Recent M&A (2024+) ---
timeline = report["Transaction highlights"]["M&A Strategy"]["acquisitions"]["m_and_a_timeline"]
recent_ma = [t for t in timeline if int(t["acquisition_date"][:4]) >= 2024]
print(f"\nAcquisitions since 2024: {len(recent_ma)}")
for t in recent_ma:
    amt = t["acquisition_amount"]
    amt_str = f"${amt / 1e9:.1f}B" if isinstance(amt, float) and amt > 0 else "undisclosed"
    print(f"  {t['acquisition_date'][:10]}  {t['company']['organization']['name']}  ({amt_str})")

# --- Product areas ---
products = report["Product insights"]["Product and services"]["products_and_services"]
print(f"\nProduct areas ({len(products)}):")
for area in products:
    titles = [p["title"] for p in area["details"]]
    print(f"  {area['product_area']}: {', '.join(titles)}")
```

### Exporting a PPT for IC review

```python theme={"system"}
import requests

HEADERS = {"Authorization": "Bearer <YOUR_API_TOKEN>"}

ppt_r = requests.post(
    "https://api.wokelo.ai/api/assets/download_report/",
    headers=HEADERS,
    json={"report_id": 123345, "file_type": "ppt"}
)

with open("salesforce_research.pptx", "wb") as f:
    f.write(ppt_r.content)

print("Saved salesforce_research.pptx")
```

***

## 7. Error Handling

The API uses standard HTTP status codes. The submission endpoint returns errors synchronously; processing errors appear as a `"Failed"` status when polling.

| Status                      | Meaning             | Cause & Resolution                                                                                                                          |
| --------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `200 OK`                    | Request accepted    | `report_id` returned. Proceed to polling.                                                                                                   |
| `400 Bad Request`           | Invalid parameters  | Missing `workflow` value, missing both `permalink` and `website`, or an unrecognised `workflow` string. Check the `detail` field.           |
| `401 Unauthorized`          | Auth failed         | The `Authorization` header is missing or contains an invalid token. Verify your key in **Settings → API Keys**.                             |
| `403 Forbidden`             | Insufficient access | Your plan does not include access to this endpoint or to this company. Contact [support@wokelo.ai](mailto:support@wokelo.ai).               |
| `404 Not Found`             | Company not found   | The `permalink` could not be resolved. Use the [Company Search API](/supporting-apis-doc#company-search) to verify, or switch to `website`. |
| `429 Too Many Requests`     | Rate limit exceeded | Implement exponential back-off on submission. The response includes a `Retry-After` header.                                                 |
| `500 Internal Server Error` | Server error        | Retry the submission after a brief delay. If the issue persists, contact [support@wokelo.ai](mailto:support@wokelo.ai).                     |

**Handling a `"Failed"` report status:**

```python theme={"system"}
status_r = requests.get(
    "https://api.wokelo.ai/api/assets/get_notebook_status/",
    headers=HEADERS,
    params={"report_id": report_id}
)
data = status_r.json()

if data.get("status") == "Failed":
    print(f"Report {report_id} failed.")
    # Resubmit with the same parameters
    resubmit = requests.post(
        "https://api.wokelo.ai/api/workflow_manager/start/",
        headers=HEADERS,
        json={"workflow": "company_primer", "permalink": "salesforce"}
    )
    new_report_id = resubmit.json()["report_id"]
    print(f"Resubmitted. New report_id: {new_report_id}")
```

**Retry with exponential back-off on submission:**

```python theme={"system"}
import time, requests

def submit_with_retry(body, api_key, max_retries=3):
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }
    for attempt in range(max_retries):
        try:
            r = requests.post(
                "https://api.wokelo.ai/api/workflow_manager/start/",
                headers=headers,
                json=body,
                timeout=30
            )
            if r.status_code == 429:
                time.sleep(2 ** attempt)
                continue
            r.raise_for_status()
            return r.json()["report_id"]
        except requests.exceptions.Timeout:
            if attempt == max_retries - 1:
                raise
            time.sleep(1)
    raise Exception(f"Submission failed after {max_retries} attempts")
```

***

## 8. Best Practices

**Always use `permalink` over `website` when available**

Permalinks resolve faster and more reliably than website URLs, particularly for companies with complex domain structures or redirects. Use the [Company Search API](/supporting-apis-doc#company-search) to resolve a company name to its permalink before submitting:

```python theme={"system"}
search = requests.get(
    "https://api.wokelo.ai/api/enterprise/company/search",
    headers=HEADERS,
    params={"query": "OpenAI", "search_by": "name"}
)
permalink = search.json()["data"][0]["permalink"]
```

**`workflow` must always be `"company_primer"` — this field is not optional**

The `/api/workflow_manager/start/` endpoint is shared across all Workflow APIs (Company Research, Industry Research, Peer Comparison, Custom). The `workflow` parameter is what distinguishes between them. For Company Research, it must be exactly `"company_primer"`. Omitting it or misspelling it returns a `400` error.

**Store `report_id` immediately and durably**

The submission response contains only `report_id`. If this value is lost before the report is downloaded, there is no API endpoint to list or retrieve past `report_id` values. Store it to a database, log, or queue entry as soon as the submission response is received.

**Use 15–20 second polling intervals — not tight loops**

Reports typically complete in 2–5 minutes. Polling more frequently than every 15 seconds wastes rate limit budget without meaningfully reducing latency. Use a back-off strategy for batch workloads:

```python theme={"system"}
# Recommended polling pattern
for wait in [15, 15, 30, 30, 60, 60, 120]:   # seconds
    time.sleep(wait)
    status = get_status(report_id)
    if status in ("Completed", "Failed"):
        break
```

**Provide `industry` to improve report framing for niche companies**

Wokelo auto-detects industry from its knowledge base, but for newer companies, international companies, or firms in niche verticals, providing the industry string directly improves the accuracy of competitive framing and peer positioning within the Executive Summary and Key Insights:

```python theme={"system"}
json={
    "workflow":   "company_primer",
    "permalink":  "some-niche-startup",
    "industry":   "Climate Technology & Carbon Markets"
}
```

**Use `custom_files` to layer internal data on public synthesis**

The `custom_files` parameter is the most differentiated capability of this API for investment workflows. Uploading a CIM, management presentation, or prior diligence memo alongside the request causes Wokelo to synthesise both the public web research and your internal documents into a unified report. Upload files via the [File Upload API](/supporting-apis-doc#file-upload) first, then reference the returned `fileName` in your request.

**Parse `acquisition_amount` defensively — it can be an empty string or a float**

The `acquisition_amount` field in the M\&A timeline is either a numeric float (raw USD) or an empty string `""` for undisclosed deals. Never assume it is numeric:

```python theme={"system"}
# ❌ Will throw TypeError when amount is ""
formatted = f"${deal['acquisition_amount'] / 1e9:.1f}B"

# ✅ Safe — check type first
amt = deal.get("acquisition_amount")
formatted = f"${amt / 1e9:.1f}B" if isinstance(amt, (int, float)) and amt > 0 else "Undisclosed"
```

**Use `"json"` output for pipelines; `"ppt"` or `"pdf"` for human deliverables**

The JSON output contains every field, source citation, and structured data object. Use it for any downstream processing — CRM ingestion, comparison tools, alerting. The PDF, DOCX, and PPT outputs are rendered for human consumption and strip much of the structured metadata. Request only the format you need — a single `report_id` supports all four formats.

***

## 9. Related APIs

<CardGroup cols={3}>
  <Card title="Company Instant Enrichment" icon="bolt" href="/company-instant-enrichment-doc">
    Synchronous firmographic enrichment — returns structured company data immediately without a report generation step.
  </Card>

  <Card title="Company Deep Intelligence" icon="brain" href="/company-deep-intelligence-doc">
    Deeper async intelligence on strategy, financials, and competitive positioning — more granular than Company Research.
  </Card>

  <Card title="Industry Research" icon="chart-line" href="/industry-research-doc">
    Run the same async workflow pattern against an industry or sector instead of a specific company.
  </Card>

  <Card title="Peer Comparison" icon="scale-balanced" href="/peer-comparison-doc">
    Generate a structured comparison of two or more companies across key dimensions in a single report.
  </Card>

  <Card title="Company News Monitoring" icon="newspaper" href="/company-news-monitoring-doc">
    Fetch real-time, source-cited news articles for any company — synchronous, no polling required.
  </Card>

  <Card title="Supporting APIs" icon="wrench" href="/supporting-apis-doc">
    Company Search, File Upload, Report Status, and Download Report — all used alongside Company Research.
  </Card>
</CardGroup>
