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

# Enrich a list of companies

> Turn a column of domains into company records with names, descriptions, logos, colours, and social links.

<Note>
  **Have an agent build it.** Copy the brief below into Claude Code, Cursor, or any coding agent with access to your project. It states the calls, the questions worth asking you first, and the mistakes to avoid.
</Note>

<Accordion title="Agent brief">
  ```text theme={null}
  Implement this blueprint in my project:
  https://docs.hydrafetch.com/blueprints/lead-enrichment

  Read that page, inspect this project's stack, then build the flow end to end.

  Build a company enrichment function over a list of domains using the Hydrafetch API.

  Per domain: GET /v1/web/brand?domain={domain} returns the full record (name, description, tagline, industry classification, colours, fonts, socials, logos). GET /v1/web/brand/logo?domain={domain}&theme=light|dark&type=icon|wordmark returns one asset. GET /v1/web/brand/search?query={name} finds a domain from a company name.

  Ask me before writing code:
  - Where does the list come from and how many domains, so we can decide on concurrency and cost up front?
  - Which fields does the product actually render today, and should we store the whole record anyway?
  - Are inputs domains or company names? Names need the brand search step first, and names are ambiguous in a way domains are not.
  - What should the UI show for a domain with no resolvable brand?
  - How often should records refresh, and should a failed refresh keep the previous record?

  The response shape: data with name, domain, description, tagline, naics, colors[], fonts, socials[], and logos with format, variant and dimensions. data is null when nothing resolves.

  Clean the input before spending: normalise each domain (lowercase, strip scheme, www, path and trailing slash), deduplicate after normalising, and drop free email provider domains, since enriching gmail.com returns the email provider rather than a company. Refresh on a long cycle of six to twelve months rather than nightly, because brands change slowly, and keep the existing record when a refresh fails rather than overwriting it with an empty one. Track the share of the list that resolved, and sample successes as well as failures, since a confidently wrong company is worse than a blank.

  Notes: authenticate with the X-API-Key header. A full record is 5 credits, a single logo is 1 and a brand search is 1, so do not resolve a record when only a mark is needed. Failed calls are free. Keep the API key on the server and never ship it in client code.
  ```
</Accordion>

You have domains, from a signup form, a CRM export, or a conference list, and you need them to become companies: a real name, what they do, an industry code, a logo you can render, and the social accounts to follow.

One call per domain does it. `brand` resolves the whole record.

## The pipeline

### 1. Resolve a domain into a brand record

```bash theme={null}
curl -X GET "https://api.hydrafetch.com/v1/web/brand?domain=stripe.com" \
  -H "X-API-Key: $HYDRAFETCH_API_KEY"
```

You get back the company name, description, tagline, an industry classification, a colour palette, the fonts the site uses, social profiles, and logos already processed into several formats and background variants.

### 2. Take only the logo when that is all you need

If you are rendering an avatar in a list and nothing else, resolving the whole record and throwing most of it away is five times the price.

```bash theme={null}
curl -X GET "https://api.hydrafetch.com/v1/web/brand/logo?domain=stripe.com&theme=light&type=icon" \
  -H "X-API-Key: $HYDRAFETCH_API_KEY"
```

### 3. Resolve a name you do not have a domain for

`GET /v1/web/brand/search?query=stripe` finds candidate companies by name, so a messy list of company names can be turned into domains before enrichment.

### 4. Store the record, not just the fields you use today

The full record is one call whether you read three fields or thirty. Store it, and adding a field to your UI later becomes a database change rather than a re-enrichment of your whole list.

## Clean the input first

Most of the money wasted on enrichment is spent before any call is made, on inputs that were never going to resolve.

Normalise every domain to one form: strip the scheme, strip `www`, drop the path and any trailing slash, lowercase it. `www.stripe.com`, `stripe.com/pricing` and `https://Stripe.com` are one company, and sending all three spends three times for one answer.

Deduplicate after normalising, not before. A list of 5,000 rows from a CRM is routinely 3,000 companies.

Drop the addresses that are not companies. A list built from signup emails is full of `gmail.com`, `outlook.com` and the rest, and enriching a free email provider returns the email provider. Filter those out before spending, and treat the row as a person without a company rather than a company.

Watch for the subsidiary problem. Enriching `youtube.com` gives you YouTube, which is correct and may not be what a sales team means when the parent is the account. Decide which you want before the data lands somewhere it will be trusted.

## Resolving a name instead of a domain

When the list is company names, add a step. `GET /v1/web/brand/search?query=...` returns candidates, and 1 credit per lookup makes it cheap to run across the whole list.

Names are ambiguous in a way domains are not. Several real companies share a name across countries and industries, so keep the match confidence and any other signal you have, like a country or an industry, and hold anything ambiguous for review rather than guessing.

Store the resolved domain back onto your record. That turns a fuzzy name match into a stable key you never have to resolve again.

## Refreshing without re-spending

Brands move slowly. A company changes its logo or its palette every few years, not every quarter, so a nightly refresh spends real money to discover that nothing happened.

Refresh on a long cycle, six or twelve months, and stagger it so the whole list does not re-resolve on one day.

Refresh on a signal instead when you have one. A domain that starts returning something different, a customer who mentions a rebrand, a record that fails to render in your UI: those are worth a targeted refresh in a way that a calendar is not.

Keep what you had until the new answer arrives. Replacing a good record with an empty one because a refresh failed is worse than serving a slightly old logo.

## Measuring the match rate

Track the share of your list that resolved to a real record, and look at the failures rather than only the total.

A low rate on a list of large companies means something is wrong with the input, usually formatting. A low rate on a list of small local businesses is simply the shape of the world, since plenty of them have no real web presence to read.

Sample the successes too. A record that resolved to the wrong company is more damaging than one that did not resolve at all, because it is confidently wrong on a sales call.

## What it costs

A full brand record is 5 credits. A single logo is 1. A brand search is 1.

The price is flat whether the record was already held or resolved fresh, so a list with repeats does not cost more per unique company than a list without them.

## What to watch for

Normalise domains before you send them. `www.stripe.com`, `stripe.com/`, and `https://stripe.com` are one company, and sending all three spends three times.

Handle the empty answer. Some domains have no resolvable brand: a parked domain, a personal site, a company that no longer exists. Decide what your UI shows for that case before you meet it in production.

A logo has a variant for a reason. Ask for the one that suits the background you are drawing on, rather than picking one and hoping. A dark wordmark on a dark card is invisible.
