Skip to content
HappyFetch

Enrich every signup with company data

Turn the domain in a signup's email address into company size, industry and headquarters, and route each lead before anyone reads it.

How it works#

  1. Take the domain from the signup's email address: jane@acme.com becomes acme.com.
  2. Skip free email providers like gmail.com. A lookup would return the email provider, not your user's company.
  3. Look the domain up. The company's profile comes back as JSON.
  4. Route on what you get: company size, industry, country.
curl https://api.happyfetch.net/v1/domain --max-time 120 \
  -H "Authorization: Bearer $HAPPYFETCH_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"domain":"stripe.com"}'

The complete answer for stripe.com:

200 OK
{
  "data": {
    "name": "Stripe",
    "tagline": "Help increase the GDP of the internet.",
    "description": "Stripe builds programmable financial services. Millions of companies—from the world’s largest enterprises to the most ambitious startups—use Stripe to accept payments, grow their revenue, and accelerate new business opportunities. Headquartered in San Francisco and Dublin, the company aims to increase the GDP of the internet.",
    "industry": "Technology, Information and Internet",
    "websiteUrl": "https://stripe.com",
    "phone": null,
    "logo": "https://media.licdn.com/dms/image/v2/D560BAQE2ZfJyfn-VCg/company-logo_200_200/B56ZlyKwpUKIAI-/0/1758557047806/stripe_logo?e=2147483647&v=beta&t=En4Hm6NDGbDTYCoOQ0Ko5Ne2gylx0WRb0yL2GlOeXBQ",
    "backgroundUrl": "https://media.licdn.com/dms/image/v2/D563DAQFt98MykXcktg/image-scale_191_1128/B56Z352EMMKIAY-/0/1778013193531/stripe_cover?e=2147483647&v=beta&t=UwiZWbPrYkD77DpQmZIjVuuqKMCfyZ-e-YcHE336MlY",
    "followerCount": 1721407,
    "employeeCount": 16594,
    "employeeCountRange": {
      "start": 5001,
      "end": 10000
    },
    "foundedOn": {
      "year": 2010
    },
    "headquarter": {
      "city": "South San Francisco",
      "country": "US",
      "geographicArea": "California",
      "postalCode": "94080",
      "street1": "354 Oyster Point Blvd",
      "street2": null
    },
    "locations": [
      {
        "city": "South San Francisco",
        "country": "US",
        "postalCode": "94080",
        "state": "California",
        "street1": "354 Oyster Point Blvd",
        "street2": null
      }
    ],
    "specialities": [],
    "universalName": "stripe",
    "linkedInUrl": "https://www.linkedin.com/company/stripe",
    "linkedInId": "2135371"
  },
  "meta": {
    "request_id": "c41d7e02-5b8a-4f3c-9e61-7a2d0b95f4e8",
    "endpoint": "domain",
    "credits_charged": 4,
    "credits_remaining": 196,
    "cache": {
      "status": "miss",
      "age_seconds": 0,
      "fetched_at": "2026-09-22T17:40:00.000Z",
      "max_age_seconds": 604800
    },
    "content_hash": "sha256:5da96e23d8f77cc3b21e33ef47ed3f0086328e61fdf427f2941e351f56af9554",
    "canonical": {
      "slug": "stripe",
      "id": "2135371"
    },
    "resolved": {
      "domain": "stripe.com",
      "verified": true
    }
  }
}

Route by company size#

Python
import os

import requests

API = "https://api.happyfetch.net"
FREE_MAIL = {
    "gmail.com", "googlemail.com", "outlook.com", "hotmail.com", "live.com",
    "yahoo.com", "icloud.com", "me.com", "aol.com", "gmx.com", "proton.me", "protonmail.com",
}


def company_for_signup(email: str) -> dict | None:
    domain = email.rsplit("@", 1)[-1].strip().lower()
    if domain in FREE_MAIL:
        return None
    res = requests.post(
        f"{API}/v1/domain",
        headers={"Authorization": f"Bearer {os.environ['HAPPYFETCH_API_KEY']}"},
        json={"domain": domain},
        timeout=120,
    )
    if res.status_code == 404:  # a confirmed answer: no company at this domain
        return None
    res.raise_for_status()
    return res.json()["data"]


def route(email: str) -> str:
    company = company_for_signup(email)
    if company is None:
        return "self-serve"  # free email, or no company at the domain
    size = company["employeeCountRange"] or {}
    if (size.get("start") or 0) >= 201:
        return "sales"  # 201 employees or more: a person follows up
    return "nurture"

Run it in a background job after the signup is saved, so a lookup never holds up your signup form.

What it costs#

Lookups a month Smallest pack (Starter) Biggest pack (Business)
1,000 lookups by website domain $2.00 $1.00
10,000 lookups by website domain $20.00 $10.00
100,000 lookups by website domain $200.00 $100.00

Every lookup fetched fresh, at 4 credits each. Lookups our cache answers cost half. A confirmed not-found costs the same, and nothing from our cache. Starter: $10 for 20,000 credits. Business: $500 for 2,000,000 credits. Credits never expire.

A signup from a company that's already in our cache costs half: $0.50 per 1,000 domain lookups on our biggest pack.

Good to know#

  • No company at the domain. You get a clear answer that there's none, and why: nothing answers at the domain, or the site has no LinkedIn company page. It costs 4 credits, and asking again while that answer is in our cache is free.
  • Check the match. Every answer says whether the company's own website is on that domain. If it isn't, we matched the domain to a company that lists another website, such as a parent company's. Treat that as a strong hint, not a fact.
  • Retries are safe. Give each call a retry key (see idempotency), and a retry after a timeout gets the stored answer instead of paying twice.
  • One key per company. Every answer carries the company's numeric id, which stays the same when a company renames. Signups from acme.com and eu.acme.com land on the same record.

Try it on your own companies

200 credits free when you verify your email. No card needed, no subscription.