IntelBase
API Reference

IntelBase API

Turn an email address into a full intelligence profile — registered accounts, profile data, data breaches and infostealer logs — or find every site a username is registered on and which of those accounts belong to the same person. All requests are made against the base URL below and authenticated with your API key.

Base URL

Base URL
https://api.intelbase.is
POST /lookup/email Email lookup
POST /lookup/username Username lookup
GET /lookup/modules List modules
GET /account/ip Your IP (debug)

Your API key lives in your dashboard. A paid plan with API access is required — the API is not available on the free plan.

Authentication

Authenticate every request by sending your API key in the x-api-key header. Keep your key secret — treat it like a password. If it leaks, regenerate it from the dashboard.

Header
x-api-key: YOUR_API_KEY

Requests without a valid key return 401 Unauthorized. Requests from a free plan, or a plan without API access, also return 401.

IP whitelisting & debugging

For security, lookup requests must originate from an IP address you've whitelisted (configurable in your dashboard, or per-team). If the IP a request comes from isn't on the list, the API returns 401 Unauthorized with "Your IP is not whitelisted."

Trouble authorizing your IP?

The IP you think you're calling from is often not the IP the server actually sees — proxies, NAT, load balancers and IPv6 vs IPv4 all get in the way. To debug, call GET /account/ip from the exact same machine/network that makes your API calls and make sure the IP it returns is the one you've whitelisted.

cURL
curl https://api.intelbase.is/account/ip
Response
{ "ip": "203.0.113.24" }

Whatever value comes back here is what needs to be in your whitelist. If it doesn't match, add that exact IP (or fix your egress so it resolves to a whitelisted one).

POST /lookup/email

Email lookup

Runs a full lookup against a single email address: account modules that return profile data, registration checks, data breaches, infostealer logs and stealer-log enrichment, all in parallel. The response is returned once everything finishes or timeout_ms expires. Send a JSON body with the parameters below, the x-api-key header and Content-Type: application/json.

Body parameters

Field Type Default Description
email req string — The target email address to investigate.
timeout_ms integer 10000 Max time to wait for the lookup, in milliseconds (100–120000). Modules still running when it expires are dropped from the result. Values under 5000 automatically skip slower modules (dropbox, google, gravatar).
include_data_breaches boolean true Search data breaches and stealer logs. Set to false to only check accounts. Breach visibility also depends on your plan.
include_stealer_logs boolean true Include infostealer log results and enrichment. Set to false to search breaches only. Has no effect when include_data_breaches is false. Access also depends on your plan.
include_ai boolean false Run the AI steps: the `identity` ownership check, profile-picture matching and AI-ranked `suggestions`. They add time to the lookup, so they are off unless you ask for them. Requires a plan with AI features; ignored otherwise.
exclude_modules string[] [] Module names to skip (see GET /lookup/modules). Mutually exclusive with include_modules.
include_modules string[] [] Run only these module names (see GET /lookup/modules). Mutually exclusive with exclude_modules.

Example request

cURL
curl -X POST https://api.intelbase.is/lookup/email \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "timeout_ms": 10000,
    "include_data_breaches": true
  }'

Email response

A successful lookup returns 200 OK with the following top-level structure. Each lookup counts once against your daily quota.

Field Type Description
identifier.accounts object[] Accounts found for the email with profile data. Each item has a `module` (id, name, name_formatted, domain, type) and a flat `data` map of the harvested fields (username, full_name, avatar_url, creation_date, …). Fields vary per module.
validator.registered module[] Every service the email is confirmed registered on — including the ones in identifier.accounts.
validator.unregistered module[] Services that were checked and where the email is not registered. Modules filtered out by include_modules / exclude_modules are not listed.
data_breaches object `{ amount, sources, results, redacted, partially_redacted }`. Each result includes email, password, username, full_name, ip_address, phone_number, hash, and a `source` (name, date). Results are redacted when your plan can't view breach data.
stealer_logs object `{ count, results, has_stealer_log_type, redacted, compromised }`. Each result includes data_type (combo | stealerlog), origin, login, password.
stealer_enrichment object | null Aggregated infostealer intelligence (autofill, accounts, user_info, card_holders, scanned_files, posted_at) when available and permitted by your plan. `null` otherwise.
suggestions object `{ ranked_by, items }`. Emails and usernames found in the results that are worth searching next; nothing is searched for you. Each item is `{ value, kind, sources, weight, likelihood?, confidence? }`. `sources` lists where it was found (`site`, and `kind`: profile, stealer, people_search or email_handle). `likelihood` (likely, possible, unlikely) says whether it belongs to the person you searched; `ranked_by` says how that was judged (jev, identity or sources); without `include_ai` it is always sources.
insights.score object `{ version, authenticity, exposure }`. Two 0–100 scores, each `{ score, band, label, reasons, cap?, missing? }`. **authenticity** is how established the address looks (high = a real, long-used mailbox; bands very_low, low, moderate, high). **exposure** is how exposed its credentials are (high = worse; bands none, low, moderate, high, critical), and is `null` when breach data wasn't included. `reasons` lists each signal with its points; `cap` is set when a disposable or mail-less domain limited authenticity; `missing` names signals that couldn't be checked.
insights.password_reuse object | absent `{ credentials, distinct, max_sources, reused }`. Whether the same password appears across the breach and stealer-log results, compared in memory. `reused` lists the sources sharing each repeated password. Passwords themselves are never returned here. Absent when no leaked record carried a password or hash.
insights.domain object `{ domain, checked, accepts_mail, mx_provider, spf, dmarc, disposable, free_provider, role_address }`, from public DNS and bundled lists. When `checked` is false DNS didn't answer and the DNS fields are unknown, not negative.
identity object | absent Whether the accounts on this address fit one person, in the same shape as the username lookup's `identity` object (see the username endpoint). The main group (`groups[0]`) is the address's likely owner; accounts in other groups or marked different suggest someone mistyped the address at sign-up, or that it was reused. Only present when `include_ai` is true and your plan has AI features. Absent when fewer than two accounts returned profile data, or on cloaked lookups.
meta object `{ email, first_seen, last_seen, cloaked, timeline }`. first_seen / last_seen come from account dates and may be null. The `timeline` array (source, name, date) is only present when at least two dated events exist.

Example response

200 OK
{
  "identifier": {
    "accounts": [
      {
        "module": {
          "id": "5f9a...",
          "name": "google",
          "name_formatted": "Google",
          "domain": "google.com",
          "type": 0
        },
        "data": {
          "id": "1178...",
          "username": "targetuser",
          "full_name": "Target User",
          "avatar_url": "https://.../photo.jpg",
          "creation_date": "2016-04-12T00:00:00Z"
        }
      }
    ]
  },
  "validator": {
    "registered": [
      { "id": "…", "name": "google", "name_formatted": "Google", "domain": "google.com", "type": 0 },
      { "id": "…", "name": "spotify", "name_formatted": "Spotify", "domain": "spotify.com", "type": 1 }
    ],
    "unregistered": [
      { "id": "…", "name": "duolingo", "name_formatted": "Duolingo", "domain": "duolingo.com", "type": 1 }
    ]
  },
  "data_breaches": {
    "amount": 3,
    "sources": 2,
    "results": [
      {
        "email": "[email protected]",
        "password": "hunter2",
        "username": "targetuser",
        "full_name": "Target User",
        "ip_address": "203.0.113.9",
        "phone_number": "",
        "hash": "",
        "source": { "name": "ExampleBreach", "date": "2021-06" }
      }
    ],
    "redacted": false,
    "partially_redacted": false
  },
  "stealer_logs": {
    "count": 1,
    "results": [
      { "data_type": "stealerlog", "origin": "https://accounts.google.com", "login": "[email protected]", "password": "hunter2" }
    ],
    "has_stealer_log_type": true,
    "redacted": false,
    "compromised": true
  },
  "stealer_enrichment": {
    "autofill": [
      {
        "tag": "email",
        "label": "Email",
        "total": 4,
        "unique": 2,
        "values": [
          { "value": "[email protected]", "count": 3 },
          { "value": "[email protected]", "count": 1 }
        ]
      }
    ],
    "accounts": [
      {
        "platform": "instagram.com",
        "value": "[email protected]",
        "kind": "username",
        "source": "credential",
        "id_link": "https://instagram.com/username"
      }
    ],
    "user_info": {
      "username": "targetuser",
      "ip_address": "203.0.113.9",
      "country": "US",
      "location": "New York, NY",
      "zip_code": "10001"
    },
    "scanned_files": 128,
    "posted_at": "2025-02-14T00:00:00Z",
    "realtime": false,
    "redacted": false
  },
  "meta": {
    "email": "[email protected]",
    "first_seen": "2016-04-12T00:00:00Z",
    "last_seen": "2023-09-01T00:00:00Z",
    "cloaked": false,
    "timeline": [
      { "source": "creation_date", "name": "Google", "date": "2016-04-12T00:00:00Z" },
      { "source": "data_breach", "name": "ExampleBreach", "date": "2021-06-01T00:00:00Z" }
    ]
  }
}
POST /lookup/username

Username lookup

Checks a username across hundreds of sites and returns every profile it exists on, with the profile data each site exposes. Because different people often register the same handle, you can set include_ai to also get an identity section that groups the found accounts into probable people, using their profile details and profile pictures. Send a JSON body with the parameters below, the x-api-key header and Content-Type: application/json.

Body parameters

Field Type Default Description
username req string — The username to search for, without a leading @. Letters, digits, dot, underscore and hyphen; must start with a letter or digit; up to 65 characters.
timeout_ms integer 15000 Max time to wait for the site checks, in milliseconds (100–120000). Sites still running when it expires are dropped from the result.
exclude_modules string[] [] Site module names to skip, e.g. ["github", "reddit"]. Mutually exclusive with include_modules.
include_modules string[] [] Check only these site module names. Mutually exclusive with exclude_modules.
include_ai boolean false Run the AI identity grouping and profile-picture matching that fill the `identity` section. They run after the site checks, so they are off unless you ask for them. Requires a plan with AI features; ignored otherwise.

Example request

cURL
curl -X POST https://api.intelbase.is/lookup/username \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "targetuser",
    "timeout_ms": 15000,
    "include_ai": true
  }'

Username lookups query many more sites than an email lookup, and with include_ai the identity grouping runs after the site checks finish, so a full lookup can take noticeably longer than timeout_ms. Set your HTTP client's timeout generously (60s+).

Username response

A successful lookup returns 200 OK. The identifier and validator sections use the same shapes as the email lookup, so the same parsing code works for both. There are no breach or stealer-log sections. Each lookup counts once against your daily quota.

Field Type Description
identifier.accounts object[] Profiles found under the username that returned data. Same shape as the email lookup: a `module` and a flat `data` map (username, full_name, bio, avatar_url, profile_url, followers, creation_date, …). Fields vary per site.
validator.registered module[] Every site where the username exists — including sites that only confirmed existence without profile data.
validator.unregistered module[] Sites that were checked where the username was not found (or did not answer before the timeout).
identity object Optional. Groups the found accounts into probable people, since different people often register the same username. Only present when `include_ai` is true, your plan has AI features, and at least two accounts returned profile data. See the identity fields below.
meta object `{ username, cloaked }`.

The identity object

Field Type Description
verdict string one_person, mostly_one_person, multiple_people, unlinked (no accounts could be tied together) or insufficient (too little profile data to compare).
summary string A one-sentence, human-readable explanation of the verdict.
groups object[] Probable people, largest first. Each has an `id`, `sites` (domains), and optionally a `name` and `avatar` URL (`avatar_face` is true when the avatar is a photo of a face). `matches` explains each link in the group: the two sites `a` and `b`, `via` (details | email | name | picture | gravatar — what decided it; name is the same full name on an email lookup), `confidence` (0–1, for details links) and `signals`, the details both accounts share, each a `kind` (name, similar_name, link, website, links_to, username, location, work, email, picture, gravatar) and usually a `value`.
accounts object[] Where each compared account landed: `module`, `status` (main = the largest group, group = another person, different = contradicts the main group, unlinked = too little to tell), `group` (index into groups, or -1), `via` (profile | picture — how it was tied in) and `name` (the first name the account shows, if any).

Accounts that had nothing to compare besides the username itself are left out of identity.accounts. Treat the grouping as a strong hint, not proof.

Example response

200 OK
{
  "identifier": {
    "accounts": [
      {
        "module": {
          "id": "66c1...",
          "name": "github",
          "name_formatted": "GitHub",
          "domain": "github.com",
          "type": 2
        },
        "data": {
          "id": "583231",
          "username": "targetuser",
          "profile_url": "https://github.com/targetuser",
          "avatar_url": "https://avatars.githubusercontent.com/u/583231",
          "full_name": "Target User",
          "location": "New York, NY",
          "followers": 120,
          "following": 8,
          "creation_date": "2014-02-03T18:22:11Z"
        }
      },
      {
        "module": {
          "id": "66c1...",
          "name": "reddit",
          "name_formatted": "Reddit",
          "domain": "reddit.com",
          "type": 2
        },
        "data": {
          "username": "targetuser",
          "profile_url": "https://www.reddit.com/user/targetuser",
          "avatar_url": "https://styles.redditmedia.com/.../avatar.png",
          "creation_date": "2015-07-19T10:04:52Z"
        }
      }
    ]
  },
  "validator": {
    "registered": [
      { "id": "…", "name": "github", "name_formatted": "GitHub", "domain": "github.com", "type": 2 },
      { "id": "…", "name": "reddit", "name_formatted": "Reddit", "domain": "reddit.com", "type": 2 },
      { "id": "…", "name": "twitch", "name_formatted": "Twitch", "domain": "twitch.tv", "type": 2 }
    ],
    "unregistered": [
      { "id": "…", "name": "steam", "name_formatted": "Steam", "domain": "steamcommunity.com", "type": 2 }
    ]
  },
  "identity": {
    "verdict": "one_person",
    "summary": "All 2 accounts with details or a profile picture look like the same person.",
    "groups": [
      {
        "id": 0,
        "name": "Target User",
        "sites": ["github.com", "reddit.com"],
        "avatar": "https://avatars.githubusercontent.com/u/583231",
        "avatar_face": true,
        "matches": [
          {
            "a": "github.com",
            "b": "reddit.com",
            "via": "picture",
            "signals": [{ "kind": "picture" }]
          }
        ]
      }
    ],
    "accounts": [
      { "module": "github", "via": "profile", "status": "main", "group": 0 },
      { "module": "reddit", "via": "picture", "status": "main", "group": 0 }
    ]
  },
  "meta": {
    "username": "targetuser",
    "cloaked": false
  }
}
GET /lookup/modules

Modules

Lists the modules available to email lookups. Use the name values in include_modules / exclude_modules. Username site modules are named after the site in lowercase (github, reddit, instagram, …). This endpoint requires your API key but does not count against your quota.

cURL
curl https://api.intelbase.is/lookup/modules \
  -H "x-api-key: YOUR_API_KEY"
200 OK
{
  "identifier": [
    { "id": "…", "name": "google", "name_formatted": "Google", "domain": "google.com", "type": 0 }
  ],
  "validator": [
    { "id": "…", "name": "spotify", "name_formatted": "Spotify", "domain": "spotify.com", "type": 1 }
  ],
  "phone": [
    { "id": "…", "name": "doordash", "name_formatted": "DoorDash", "domain": "doordash.com", "type": 3 }
  ],
  "count": 3
}

Module type

0 Account — email lookup, returns profile data
1 Registration check — email lookup, registered or not
2 Username — username lookup
3 Phone

Errors

Errors are returned with the appropriate HTTP status and, where applicable, a JSON body of the form { "error": "message" }.

400

Bad Request

Malformed JSON, an invalid email or username, or both exclude_modules and include_modules supplied.

401

Unauthorized

Missing/invalid API key, a free plan, a plan without API access, an IP that is not whitelisted, or your daily lookup limit was reached.

403

Forbidden

Email lookups only: the address has asked to be blacklisted and cannot be looked up.

429

Too Many Requests

You exceeded your plan's per-minute API rate limit.

500

Server Error

An unexpected error occurred while running the lookup.

GET /account/ip

Your IP (debug)

A public, unauthenticated helper that echoes back the IP address the server sees your request coming from. Use it to verify what to add to your IP whitelist (see IP whitelisting & debugging).

cURL
curl https://api.intelbase.is/account/ip
200 OK
{ "ip": "203.0.113.24" }

Rate limits & quotas

Two limits apply to API usage, both determined by your plan and shared across email and username lookups:

  • Per-minute rate limit. Exceeding it returns 429 Too Many Requests.

  • Daily lookup quota. Every completed email or username lookup counts as one. Once reached, further lookups return 401 Unauthorized until the counter resets. On teams, the quota is shared across members.

Need higher limits?

Compare plans or reach out about enterprise volume.