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

# Reach buying committees at newly funded companies

> Watch for funding announcements with a Fuse signal agent, find the leaders you sell to at each newly funded company, and enroll them in an always-on campaign.

A company that has just raised money has fresh budget and pressure to grow, which makes a funding announcement one of the clearest buying signals in B2B sales. This workflow sets up a [signal agent](/signals/agents) that delivers newly funded companies into a list, finds the leaders you sell to at each one, adds their work emails and enrolls them in a dynamic campaign. A daily job keeps it running as new rounds are announced.

The agent delivers companies, not people, so this is also the full pattern for any company signal: take the domains, then search for the people who work there.

```mermaid theme={null}
%%{init: {"flowchart": {"rankSpacing": 20, "nodeSpacing": 20}}}%%
flowchart TD
  A[Funding agent] -->|listId| B[Funded companies]
  B -->|domains| C[People search]
  C -->|listId| D[Decision makers]
  D -->|isDynamic| E[AI campaign]
```

## Before you start

| You need | Why |
| - | - |
| An API key with the `agents`, `lists`, `search` and `campaigns` [scopes](/concepts/scopes) | The agent, the company list, the people search and the campaign each sit on a different surface. |
| A connected mailbox | The campaign cannot be approved without one. |
| Credits | The agent charges 100 credits per company it delivers, and saving people costs 20 to 50 per work email found. Starting the agent is free. |

## Step by step

<Steps>
  <Step title="Find the exact values the agent matches on">
    Industries must be exact strings, so resolve them first:

    ```bash theme={null}
    curl -G https://api.tryfuse.ai/api/v1/business/agents/autocomplete \
      -u "$FUSE_API_KEY:" \
      --data-urlencode "field=industry" \
      --data-urlencode "q=software"
    ```

    ```json theme={null}
    { "field": "industry", "suggestions": ["Software Development", "IT Services and IT Consulting"] }
    ```

    Round types come from a fixed list: `pre_seed`, `seed`, `series_a`, `series_b`, `series_c` and so on through `series_j`, plus `private_equity`, `debt_financing`, `grant` and others listed in the API reference. Countries are full English names such as `"United Kingdom"`, and headcount uses exact bands such as `11-50` and `51-200`. A value outside these lists is still accepted with `201`, and the agent then quietly finds nothing. See [Finding accepted values](/concepts/field-values).
  </Step>

  <Step title="Create and start the funding agent">
    ```bash theme={null}
    curl -X POST https://api.tryfuse.ai/api/v1/business/agents/funding-announcements \
      -u "$FUSE_API_KEY:" \
      -H "Content-Type: application/json" \
      -d '{
        "listName": "Funded - Series A and B software",
        "fundingRoundTypes": ["series_a", "series_b"],
        "industries": ["Software Development"],
        "companyCountries": ["United States", "United Kingdom"],
        "companyHeadcount": ["11-50", "51-200"],
        "maxCreditSpend": 5000,
        "expirationDate": null,
        "start": true
      }'
    ```

    ```json theme={null}
    {
      "agent": {
        "id": "6a8dd1209c41d20014b44201",
        "type": "funding-announcements",
        "name": "Funded - Series A and B software",
        "status": "processing",
        "started": true
      }
    }
    ```

    At least one of `industries`, `companyCountries` or `companyHeadcount` is required, and each takes several values. `start: true` creates the agent and starts it in one call, which also reports any configuration problem straight away. To review a draft first, leave `start` out and activate it later, as in [Job change outreach](/workflows/job-change-outreach).
  </Step>

  <Step title="Find the agent's company list">
    `GET /business/agents` returns the agent's results list:

    ```bash theme={null}
    curl "https://api.tryfuse.ai/api/v1/business/agents?limit=25" -u "$FUSE_API_KEY:"
    ```

    ```json theme={null}
    {
      "agents": [
        {
          "id": "6a8dd1209c41d20014b44201",
          "type": "funding-announcements",
          "status": "active",
          "entityType": "company",
          "listId": "6a8dd1a5c5017e82fb60a311",
          "contactsFound": 27
        }
      ],
      "pagination": { "pageNum": 1, "totalPages": 1, "totalRecords": 1 }
    }
    ```

    `contactsFound` counts the companies delivered so far.
  </Step>

  <Step title="Read the funded companies' domains">
    ```bash theme={null}
    curl "https://api.tryfuse.ai/api/v1/business/lists/6a8dd1a5c5017e82fb60a311/filter-values?field=domain" \
      -u "$FUSE_API_KEY:"
    ```

    ```json theme={null}
    { "field": "domain", "values": ["northwindpay.com", "ledgerline.io", "tallyforge.com"], "total": 27 }
    ```

    Each call reads up to 1,000 rows of the list, and `total` is how many company rows it has. Once the list grows past 1,000, page through it with `start` (1, 1001, 2001 and so on). The agent keeps adding companies, so keep a record of the domains you have already searched and only search the new ones each time. `GET /business/lists/{listId}/rows` returns each company's name, industry, headcount and country if you want to filter further. The agent records the company itself; the round, amount and investors are not written to the list.
  </Step>

  <Step title="Find the people you sell to at those companies">
    Pass the domains as `job_company_website`, up to 1,000 per search, with the roles and seniority you sell to. Preview the count first:

    ```bash theme={null}
    curl -X POST https://api.tryfuse.ai/api/v1/business/prospects/search \
      -u "$FUSE_API_KEY:" \
      -H "Content-Type: application/json" \
      -d '{
        "filters": {
          "job_company_website": ["northwindpay.com", "ledgerline.io", "tallyforge.com"],
          "job_title_role": [{ "status": "include", "value": "finance" }, { "status": "include", "value": "operations" }],
          "job_title_levels": [{ "status": "include", "value": "cxo" }, { "status": "include", "value": "vp" }, { "status": "include", "value": "director" }]
        },
        "size": 5
      }'
    ```

    Then save them with work emails into one list that every run appends to:

    ```bash theme={null}
    curl -X POST https://api.tryfuse.ai/api/v1/business/prospects/search/save-to-list \
      -u "$FUSE_API_KEY:" \
      -H "Content-Type: application/json" \
      -d '{
        "filters": {
          "job_company_website": ["northwindpay.com", "ledgerline.io", "tallyforge.com"],
          "job_title_role": [{ "status": "include", "value": "finance" }, { "status": "include", "value": "operations" }],
          "job_title_levels": [{ "status": "include", "value": "cxo" }, { "status": "include", "value": "vp" }, { "status": "include", "value": "director" }]
        },
        "listName": "Funded - buying committee",
        "limit": 200,
        "enrich": "email"
      }'
    ```

    ```json theme={null}
    { "listIds": ["68b5c0119c41d20014b45001"], "enrich": "email", "totalContacts": 41, "estimatedMinutes": 3, "jobId": "68b5c0129c41d20014b45009", "status": "pending" }
    ```

    Poll `GET /business/jobs/{jobId}` with the `jobId` from the `202` until `status` is `completed`, then read `metrics` on `GET /business/lists/{listId}`. Very new or very small companies may not be in the people database yet. A [Deep Research run](/workflows/deep-research-to-campaign) can find their leaders instead.
  </Step>

  <Step title="Point a dynamic campaign at the people list">
    Do this once, after the first save has filled the list:

    ```bash theme={null}
    curl -X POST https://api.tryfuse.ai/api/v1/business/campaigns \
      -u "$FUSE_API_KEY:" \
      -H "Content-Type: application/json" \
      -d '{
        "campaignName": "Funded - buying committee",
        "campaignType": "ai-generated",
        "listId": "68b5c0119c41d20014b45001",
        "isDynamic": true,
        "channels": ["email", "email"],
        "ctaLink": "https://example.com/demo",
        "userPrompt": "Their company just raised a funding round. Congratulate them in one line, then offer help scaling finance operations as the team grows. No hard sell.",
        "excludeContacted": "last_6_months"
      }'
    ```

    Wait for initialization, preview and approve as in steps 7 to 9 of [Build an AI outbound campaign from a prompt](/workflows/ai-campaign-from-a-prompt). The agent records the company, not the details of the round. To name the round and lead investor in the email, write that line with a smart column and merge it in with a column token. Add each day's people in batches, as described in [Personalize every email with AI research](/workflows/personalize-emails-with-ai-research#add-new-prospects-in-batches), so nobody is enrolled before their line exists.
  </Step>
</Steps>

## Run it every day

The agent delivers on its own schedule. Once a day, repeat steps 4 and 5 for domains you have not searched yet. Saving with the same `listName` appends to the people list, and the dynamic campaign enrolls the new contacts within about 30 minutes, up to 200 at a time.

## What it costs

| Step | Credits |
| - | - |
| The funding agent | 100 per company delivered. Starting it is free, and `maxCreditSpend` caps any single run. |
| Previewing the people search | 2 per profile returned |
| Saving people with `enrich: "email"` | 20 to 50 per work email found, nothing when none is found |
| Reading agents, domains and lists | Free |

## Troubleshooting

| Symptom | Cause | Fix |
| - | - | - |
| The agent is `active` but delivers nothing | A round type, country or headcount band is outside the vocabulary, so nothing matches. | Check each value, then duplicate the agent, correct the copy and start it. |
| `422 VALIDATION_FAILED` creating the agent | None of `industries`, `companyCountries` or `companyHeadcount` was sent, or a value broke a rule. | `param` names the field; send at least one of the three. |
| `filter-values` returns no domains | Nothing has been delivered yet, or the id is not the agent's company list. | Wait for `contactsFound` to rise, and take `listId` from `GET /business/agents`. |
| The people search finds few or no people | The companies are too new for the people database, or the filters are too narrow. | Widen the roles and levels, or research the companies with Deep Research. |
| `422 LIST_INCOMPATIBLE_WITH_CHANNELS` creating the campaign | The people list is empty, or its reachability stats have not caught up. | Wait for the first save's enrichment job to reach `completed`, then retry after a minute or two. |

## Run the whole workflow

<Accordion title="Python script: daily funding sync">
  ```python theme={null}
  """Daily job: find the buying committee at newly funded companies and add them to a campaign list."""
  import json
  import os
  import time

  import requests

  BASE = "https://api.tryfuse.ai/api/v1/business"
  AUTH = (os.environ["FUSE_API_KEY"], "")
  AGENT_ID = os.environ["FUSE_FUNDING_AGENT_ID"]  # created once in step 2
  PEOPLE_LIST_NAME = "Funded - buying committee"
  STATE_FILE = "searched_domains.json"
  FILTERS = {
      "job_title_role": [{"status": "include", "value": role} for role in ("finance", "operations")],
      "job_title_levels": [{"status": "include", "value": level} for level in ("cxo", "vp", "director")],
  }


  class FuseError(Exception):
      def __init__(self, status, code, message):
          super().__init__(f"{status} {code}: {message}")
          self.code = code


  def call(method, path, **kwargs):
      """Send one request, wait out 429s, and raise FuseError on any other failure."""
      while True:
          response = requests.request(method, BASE + path, auth=AUTH, timeout=60, **kwargs)
          if response.status_code == 429:
              time.sleep(int(response.headers.get("Retry-After", 5)))
              continue
          if response.status_code >= 400:
              try:
                  error = response.json().get("error", {})
              except ValueError:
                  error = {}
              raise FuseError(response.status_code, error.get("code"), error.get("message"))
          return response.json() if response.content else None


  def find_agent(agent_id):
      """GET /agents is the only read that returns an agent's results listId."""
      page = 1
      while True:
          body = call("GET", "/agents", params={"limit": 100, "pageNum": page})
          for agent in body["agents"]:
              if agent["id"] == agent_id:
                  return agent
          if page >= body["pagination"]["totalPages"]:
              raise SystemExit(f"Agent {agent_id} not found")
          page += 1


  def read_domains(list_id):
      """filter-values reads up to 1,000 rows at a time, so page through a longer list with start."""
      domains, start = set(), 1
      while True:
          page = call("GET", f"/lists/{list_id}/filter-values",
                      params={"field": "domain", "start": start, "amount": 1000})
          domains.update(page["values"])
          start += 1000
          if start > page["total"]:
              return domains


  def wait_for_enrichment(job_id, delay=10, max_delay=60):
      """Poll an enrichment job until it ends. A stopped job waits for a top-up and a resume in the app."""
      while True:
          time.sleep(delay)
          job = call("GET", f"/jobs/{job_id}")["job"]
          if job["status"] in ("completed", "cancelled", "failed", "stopped"):
              return job
          delay = min(delay * 1.5, max_delay)


  searched = set(json.load(open(STATE_FILE))) if os.path.exists(STATE_FILE) else set()

  # 3-4. The funded companies the agent has delivered that we have not searched yet
  agent = find_agent(AGENT_ID)
  if agent["status"] in ("paused", "expired", "failed"):
      print(f"Warning: the agent is {agent['status']} and has stopped delivering.")
  new_domains = sorted(read_domains(agent["listId"]) - searched)[:1000]
  if not new_domains:
      raise SystemExit("No newly funded companies since the last run.")

  # 5. Find the buying committee at those companies and save them with work emails
  filters = {**FILTERS, "job_company_website": new_domains}
  total = call("POST", "/prospects/search", json={"filters": filters, "size": 1})["total"]
  print(f"{len(new_domains)} new companies, {total} matching people")
  if total:
      saved = call("POST", "/prospects/search/save-to-list", json={
          "filters": filters, "listName": PEOPLE_LIST_NAME, "limit": min(total, 1000), "enrich": "email",
      })
      print("Enrichment", wait_for_enrichment(saved["jobId"])["status"])
      people = call("GET", f"/lists/{saved['listIds'][0]}")["list"]
      print("Contacts with a work email:", people["metrics"]["totalWithProfessionalEmail"])

  json.dump(sorted(searched | set(new_domains)), open(STATE_FILE, "w"))
  ```
</Accordion>

## Do it from Claude

With the [Fuse MCP server](/mcp/connect) connected:

> Set up a signal agent for software companies in the US and UK with 11 to 200 employees that announce a Series A or Series B. Then find the finance and operations leaders at the companies it has delivered so far, save them with work emails to "Funded - buying committee", and draft an AI campaign on that list that enrolls new people automatically. Don't launch it.

The assistant sets up the signal agent and reads the companies it has delivered, then searches for the people, saves them and drafts the campaign. Creating a campaign never launches it.

## Related

<CardGroup cols={2}>
  <Card title="Create an agent" icon="robot" href="/guides/create-an-agent">
    Every agent kind and its configuration fields.
  </Card>

  <Card title="Build a list from search" icon="magnifying-glass" href="/guides/build-a-list-from-search">
    People search filters and the accepted vocabularies.
  </Card>

  <Card title="Job change outreach" icon="briefcase" href="/workflows/job-change-outreach">
    The same always-on pattern with an agent that delivers people.
  </Card>

  <Card title="Website visitor outreach" icon="globe" href="/workflows/website-visitor-outreach">
    The same domain-to-people step, driven by who visits your site.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.