# Enrich a contact list with email and phone

You have access to two enrichment tools: a primary one and a
LinkedIn-based fallback. Run this against **[a list of 1–250 contacts,
each with at least an email, a LinkedIn identifier, or a name and
company]**.

## 0. Set up (skip if you're already connected)

If you don't already have live tool access for this, connect it first
— this prompt is only as real as the tools behind it:

1. Get a Tulina account: book a demo at https://tulina.ai/book.
2. Add Tulina's MCP server to your assistant: https://mcp.tulina.ai/mcp
3. In Tulina, connect your own API keys for the tools this prompt uses
   — your primary enrichment provider and a LinkedIn-based fallback.

Once connected, your assistant has real tool access and the rest of
this prompt runs as written.

## 0b. Already on Tulina? Three things around the run

An account and the MCP server are not the whole setup. Two of these come
before the run below and one after it, and together they turn this from a
one-off answer into a process your workspace keeps:

1. **Activate this process's connectors first.** Call
   `oto_connector(op="list")`, match it against the tools named in step 3
   above, and `oto_connector(op="select", name="...")` every one that
   isn't active yet. Selecting a connector does not mount its tools in the
   conversation you're already in — reach them through `oto_call` for this
   run, or open a fresh conversation once they're all on.
2. **Attach the work to an existing project.** `oto_project(op="list")`
   shows your active org's projects: pick the one this work belongs to
   rather than opening another, and keep its id. The project is where this
   process, the tables it writes to and the connectors it uses hang
   together.
3. **When the run is done, save it as a process — with its graph.** Write
   the body with `oto_procedure(op="set", ...)`, then attach it with
   `oto_project(op="link", project_id=..., target_type="procedure",
   target_ref="<your slug>")`. The body has to carry a drawing: read
   `oto_guide(op="read", slug="procedure-flowchart")` and follow it
   exactly — ONE untagged fenced block in that grammar, opening with the
   trigger and a quoted example of what you'd type to start a run. Tulina
   parses that drawing back into the graph it renders as the process's
   default view, which is what makes it come out in the same style as
   every other process in the app; a drawing the grammar can't read falls
   back to raw characters instead. Saving a process needs org-admin
   rights — without them, hand the finished body to someone who has them.

## 1. Gather every identifiable contact

Each contact needs at least one identifying combination: an email, a
LinkedIn URL or slug, or a first name + last name + company. Attach a
reference ID to every contact (your own row id) so results can be
mapped back cleanly — a batch call doesn't guarantee it returns rows in
the order you sent them. If a contact might need the LinkedIn fallback
later, keep its LinkedIn identifier on hand from this step; the
fallback tool requires it.

An under-specified contact doesn't fail the whole batch — the
enrichment tool processes what it can and reports an error or warning
for that one row.

## 2. Enrich the whole batch at once

Submit the whole batch in one call, not one request per contact — batch
size and per-item size limits apply, so split into chunks if you're
over them. The call returns immediately with a request id; the
enrichment runs asynchronously. Poll for the result starting around 30
seconds after submission, then every 20–30 seconds until it's done.

When results come back, treat email quality labels literally: a
personal, verified email at the company's own domain is the best
outcome; a generic mailbox is usable but weaker; anything marked
invalid counts as no email at all, not a low-confidence one.

## 3. Backfill missing emails through the fallback

For every contact still without a usable email, and that has a LinkedIn
identifier: call the fallback tool for email only — don't spend extra
credits pulling phone here, that's a separate concern. If it finds an
email, use it and mark its source as the fallback provider so the final
table shows where each field came from. If it finds nothing, or the
contact has no LinkedIn identifier to fall back on, leave it blank and
flag it in the final step — never drop the row.

## 4. Return one table, flag every gap

Return one clean table: name, best-qualified email with its source,
phone/mobile if found, and any relevant company data the enrichment
returned. Flag every contact where neither provider found a usable
email — don't drop them silently, since a flagged gap tells a human
exactly who still needs manual work.

This is a standalone enrichment step — it doesn't write anything back
to a CRM. If you want the results pushed somewhere, do that as an
explicit next step, not automatically.

## Output

Report: total contacts submitted, how many resolved on the first
provider, how many needed the fallback and how many of those resolved,
and the final list of contacts still missing an email.
