# Find leads with Looot

> Find people at the companies you name, verify their addresses, and add only the deliverable ones to your contacts or a campaign, inside a budget you set.

Source: https://docs.ayinbox.com/guides/looot-leads/

A lead job takes a list of company domains and, optionally, job titles. For each domain it looks up the people [Looot](https://looot.ai/) can find there, keeps the ones whose title matches, verifies each address, and adds the deliverable ones to your contacts. You can send them straight into a campaign or a category.

Lead jobs run on the instance's Looot balance, so the operator has to turn them on first (`AYINBOX_LOOOT_LEADS`, see [configuration](/development/configuration/)). On an instance that bills with credits, the workspace pays for what each job spends in [credits](/guides/ai-credits/).

Find leads from the dashboard [#find-leads-from-the-dashboard]

On the [Contacts](/guides/contacts-crm/) page, **Find leads** opens the lead search. It only appears when the instance has lead jobs turned on. Starting one takes the **Use integrations** and **Manage contacts** permissions and, on a hosted workspace, a paid plan that includes integrations (the [Warmup plan](/guides/billing/#the-warmup-plan) does not; an instance without billing has no plan check). Seeing the list of jobs takes **Use integrations** or **Manage settings**.

1. **Company domains.** Paste them one per line or comma separated. Websites and addresses work too: `https://www.acme.io/about` and `ana@acme.io` both become `acme.io`. The dialog shows how many domains it read, drops repeats, and lists anything that is not a domain so you can fix it before starting. A job takes up to 100 domains.
2. **Job titles** (optional). Type a title and press Enter or a comma to add it. A person is kept when their title contains any of them. Leave it empty to keep anyone named at the domain.
3. **People per domain.** From 1 to 25, 3 by default.
4. **Budget.** From $0.05 to $50, $5 by default, in steps of $0.50 or typed to the cent. The job never spends more than this.
5. **Campaign and labels** (optional). Imported people are added to the campaign and get the labels you pick. A campaign that is already sending mails them as they arrive, so choosing one also takes the **Send campaigns** permission (see [sending campaigns](#sending-campaigns)). Without it, the picker marks those campaigns **Needs Send campaigns** and they cannot be chosen; a draft or paused one can.

As you type, the dialog shows the most the job can spend. Each domain can cost at most one search plus one check per person: the search asks for three times the people you want (at least 5, at most 50) and costs up to $0.0025 per person asked for plus $0.01, and each check costs up to $0.005. Three people per domain is at most $0.0475 a domain. When the worst case for every domain is more than the budget, the dialog says how many domains the budget is sure to cover. Lookups that find nobody cost nothing, so a job usually spends less.

On an instance that bills with credits, the dialog also shows the most the job can charge the workspace, in credits. Each domain is charged its settled spend rounded up to a whole credit on its own (see [credits](#credits)), so the figure is each domain's worst case in credits, and never more than the budget in credits plus one credit per domain. At the default price, three people per domain is at most 5 credits a domain, and ten domains with a $5 budget are at most 50 credits. If the dialog cannot load how the instance bills, it says the cost in credits could not be loaded instead of showing no figure; reopening the dialog tries again.

If the server refuses the request, its reason shows in the dialog and nothing is started. Submitting the same dialog again with the same details after a lost answer returns the job the first attempt started rather than starting a second one; changing any detail sends it as a new request.

Once the workspace has a job, a **Lead jobs** button in the page header opens the list, and it opens on its own after you start one. Each job shows its status, how many domains it has searched out of the total, how many people it found, verified, imported and skipped, and what it has spent so far, including charges Looot is still settling. A job that stopped at its budget is marked **Budget reached**, and a failed one shows why. Click a job to see every domain and title. The list refreshes on its own while a job is queued or running, the refresh button in the header reloads every job at once, and the contact list picks up imported people as they arrive.

Start a lead job with the API [#start-a-lead-job-with-the-api]

Send the domains, and optionally titles, people per domain, a budget and where the contacts should go:

```json
POST /v1/integrations/looot/lead-jobs
{
  "domains": ["acme.io", "https://www.example.com/about"],
  "titles": ["head of sales", "founder"],
  "per_domain": 3,
  "max_cost_usd": 5,
  "campaign_id": "6f0c...",
  "category_ids": []
}
```

Domains can be pasted as websites or addresses; each is reduced to its bare domain and repeats are dropped. Send an `Idempotency-Key` header to make a retry return the same job instead of starting a second one. Reusing a key with a different body is refused with `409`, so use a new key for changed details.

The answer is `202` with the job and `estimated_max_usd`, the most the job could spend before its own budget stops it. On an instance that bills with credits it also carries `estimated_max_credits`, the most the job can charge the workspace; the field is absent otherwise. On a hosted workspace without a paid plan that includes integrations, the answer is `403`.

Sending campaigns [#sending-campaigns]

Adding found people to a campaign that is sending is the same as sending to them, so it takes the right to send campaigns as well as the lead job's own: `SEND_CAMPAIGNS` for an API key or app, and **Send campaigns** (`send_campaigns`) for a member, including the member behind an app or the member who created the API key. A key keeps only the rights its creator still holds, so a key with `SEND_CAMPAIGNS` from a member who has since lost **Send campaigns** is refused too. A campaign is sending when it is active, when it finished (it restarts for new leads), or when it was parked because its leads were undeliverable (it resumes on its own once they verify). Without the right the request is refused with `403` [`looot_campaign_send_required`](/api/error-codes/#looot_campaign_send_required) and nothing is started. A retry with the same `Idempotency-Key` as a request that did start a job still returns that job, even if its campaign has started sending since.

A draft or paused campaign needs nothing more than the lead job's own permissions. The people land in it as leads, and a member with **Send campaigns** starts it when they are ready.

What a job does [#what-a-job-does]

* **People at the domain only.** Each search asks for people at one domain, and any result at a different domain is dropped, even when a provider returns it.
* **Named people, matching titles.** Generic addresses such as `info@` are skipped. With titles set, a person is kept when their title contains any of them, ignoring case. The most confident matches come first, up to `per_domain`.
* **Verified before import.** Every address is checked through Looot first. Only addresses that come back valid are imported; the rest count as skipped. Imported contacts carry the verification result, so they are not checked again.
* **Country, when reported.** A provider that reports a country fills the contact's `country` field, the person's own or else their company's, which the [prior consent](/guides/contacts-crm/#prior-consent) list reads. Most domain searches report none, and a contact with no country is not held, so check the country of leads you find in a country on your list.
* **Inside the budget.** Before each domain the job reserves the most that domain could cost (the search plus one check per person). When the budget cannot cover that, the job stops and reports `budget_reached`. A charge Looot has not settled yet is counted at its cap until it settles.
* **Safe to interrupt.** A job saves its progress after every domain. If the instance restarts or Looot does not answer in time, the job picks up where it stopped, and repeated lookups are replayed rather than charged again.

Credits [#credits]

On an instance that bills with credits, each domain is charged to the workspace once its lookups have settled: the domain's settled Looot spend (the search and every check) divided by the operator's price per credit, rounded up. The default is one credit per $0.01, so a domain that cost $0.0103 is 2 credits and a domain that cost nothing is free.

* **Only settled spend.** A charge Looot has not settled yet is not billed. When a lookup is still running, its answer was lost, or Looot asked to slow down, the job retries that domain later, and the replayed lookups bring their settled cost, which is charged then. A lookup Looot answered without any cost stays in `held_micros` and is not billed.
* **Once per domain.** Each domain's charge is recorded under the job and the domain, so a job that resumes after an interruption never pays for a domain twice.
* **Checked before each domain.** The job only starts a domain the workspace could pay for at its most (the same worst case the budget reserves): the balance has to cover it, and so do the workspace's [spend limits](/guides/ai-credits/#usage-and-spend-controls) and the limit of the member who started the job. The check runs before any lookup, so Looot is never paid for a domain the workspace could not be charged for. A domain the job already paid for before an interruption is finished without that check.
* **Out of credits.** When the workspace cannot cover the next domain, runs out, or reaches its [spend limit](/guides/ai-credits/#usage-and-spend-controls), or the member who started the job reaches their own limit, the job stops with status `error` and a `last_error` saying why. People found at a domain that could not be paid for are not imported. Add credits, then start a new job.

Charges appear in the transaction log under **Settings > Billing** as **Looot lead search**, naming the domain and the member who started the job, and count toward that member's limits. The addresses a job checks are part of its domain's charge, never billed again as email verification.

Follow a job [#follow-a-job]

`GET /v1/integrations/looot/lead-jobs` lists the latest jobs, and `GET /v1/integrations/looot/lead-jobs/:jobId` returns one with its progress: `domains_done`, `found`, `verified`, `imported`, `skipped`, `spent_micros` (settled spend in millionths of a dollar), `held_micros` (spend still being settled), `budget_reached` and `last_error`.

The list also says how the instance bills jobs, so a client can price one in credits before starting it:

```json
{
  "data": [],
  "credits": { "metered": true, "micros_per_credit": 10000 }
}
```

`metered` is `false` on an instance that does not bill with credits, and `micros_per_credit` (the settled spend one credit pays for, in millionths of a dollar) is then left out.

From an agent [#from-an-agent]

Agents in Claude Code, Cursor and other MCP clients, the [REST agent tools](/api/agent-tools/) and the in-product assistant can run lead jobs too: `find_leads` starts one, `get_lead_job` and `list_lead_jobs` follow it, and `verify_email` checks a single address through the workspace's verifier. Starting a job takes the same permissions as `POST`. Naming a campaign also takes `WRITE_CAMPAIGNS`, and `manage_campaigns` for the member, and a campaign that is [sending](#sending-campaigns) takes `SEND_CAMPAIGNS` and `send_campaigns` as well, because an agent should not enrol people in a live sequence without the right to send. A self-registered MCP client is never granted `SEND_CAMPAIGNS`, so it can only add leads to a draft or paused campaign. Reading jobs takes the same permissions as the `GET` endpoints, and `verify_email` takes `WRITE_CONTACTS`, and `manage_contacts` for the member. `find_leads` always needs a budget (`max_cost_usd`), because an MCP client runs it without asking anyone first; in the assistant it always asks before it runs. See [Find and verify leads](/api/mcp/#find-and-verify-leads).

Good to know [#good-to-know]

* Contacts a job adds show **Looot** as their source, with the domain as the detail.
* An existing contact with the same address is updated, not duplicated.
* Lead jobs are not part of a [workspace export](/guides/workspace-export-import/); the contacts they found are.
