Contact Endpoints

All three contact operations are part of All tools. A start needs the relevant scope and enough credits, and the tool must be available in /v1/health. Free credits also follow the free limits. Accepted starts return 202 Accepted.

All contact endpoints are preview. Preview means the contract may still evolve before stable release; returned data is live contact data, not sample output.

Contact operations do not accept operation callback fields, dry_run, offset, artifact controls, or raw provider options. Unknown request fields are rejected.

All three contact operations are also available to verified free accounts and guest trial API credentials while free use is available. Free credits are one-off grants and do not refresh monthly.

See Contact Pricing for fixed prices, plan access, no-result settlement, and no-cost failure behavior.

POST/v1/contacts/domain-search

Finds public contacts associated with a company domain.

Required Access

  • Access: Paid plans that include this family, or free credits (guest trial or verified account) within the free limits.
  • Operation family: Contacts
  • Scope: api:contact:write
  • Credits: 80 credits reserved on acceptance
  • Idempotency: Idempotency-Key header required

Request

{
  "domain": "example.com",
  "limit": 10,
  "departments": ["sales"],
  "seniorities": ["director", "manager"],
  "include_generic": false
}

Fields:

  • domain: required hostname only, such as example.com. Chab lowercases the hostname and removes one trailing dot. URLs, paths, query strings, and schemes are rejected.
  • limit: optional integer from 1 to 25; defaults to 10.
  • departments: optional array of up to 5 unique values. Supported values are executive, sales, marketing, engineering, support, finance, hr, legal, operations, other, and unknown.
  • seniorities: optional array of up to 5 unique values. Supported values are owner, founder, c_level, vp, director, manager, individual, and unknown.
  • include_generic: optional boolean; defaults to true. Set false to exclude role or shared addresses such as sales@ or info@.

Chab matches related filters through coarse groups. For seniority, owner, founder, and c_level share one executive group, while vp, director, and manager share one senior group. For departments, operations spans management and operations roles, while marketing spans marketing and communication roles. If a selection includes other or unknown, Chab avoids a provider-side filter that would exclude those values and enforces the complete selection after results are normalized. The requested limit is applied after normalization, filtering, and deduplication, so an earlier nonmatching or duplicate candidate does not consume a returned-result slot.

Example

curl -X POST https://www.chab.ai/v1/contacts/domain-search \
  -H "Authorization: Bearer CHAB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: contacts-domain-search-001" \
  -d '{"domain":"example.com","limit":10,"departments":["sales","marketing"],"seniorities":["manager","director"],"include_generic":false}'

Async Response

{
  "operation": {
    "id": "op_01JZ7H0A1B2C3D4E5F6G7H8J9K",
    "status": "queued",
    "operation_key": "contacts.domain_search",
    "family": "contacts",
    "status_url": "/v1/operations/op_01JZ7H0A1B2C3D4E5F6G7H8J9K",
    "result_url": "/v1/operations/op_01JZ7H0A1B2C3D4E5F6G7H8J9K/result",
    "estimated_credits": 8,
    "result_available": false,
    "warnings": []
  },
  "meta": {
    "request_id": "req_123",
    "credits": {
      "estimated": 8,
      "reserved": 8,
      "currency": "credit"
    }
  }
}

Credit estimates and reservations are reported on the operation envelope and response metadata. After the operation becomes terminal, operation.settlement.final_credits is the authoritative final charge. Result payloads do not include a separate usage or credit object.

Result

{
  "data": {
    "result": {
      "domain": "example.com",
      "contacts": [
        {
          "email": "[email protected]",
          "first_name": "Jane",
          "last_name": "Doe",
          "full_name": "Jane Doe",
          "title": "Sales Director",
          "department": "sales",
          "seniority": "director",
          "organization": {
            "name": "Example Inc.",
            "domain": "example.com"
          },
          "confidence": 0.92,
          "source_category": "website",
          "is_role_address": false,
          "is_generic_address": false,
          "verification": {
            "status": "valid",
            "mx_records_found": true,
            "smtp_check": true,
            "accepts_all": false,
            "disposable": false,
            "blocked_domain": false
          },
          "evidence": {
            "matched_pattern": true,
            "public_profile_seen": false,
            "domain_match": true,
            "verification_observed": true
          },
          "warnings": []
        }
      ],
      "summary": {
        "requested_limit": 10,
        "returned": 1,
        "deduplicated": 0,
        "no_result": false
      }
    },
    "artifacts": [],
    "warnings": [],
    "result_expires_at": "2026-07-17T09:30:05+00:00"
  },
  "meta": {
    "request_id": "req_123"
  }
}

If no matching contacts are found, the operation still succeeds and charges the fixed price because provider work started. The result contains an empty contacts array and summary.no_result: true.

When the lookup returns company-wide organization or email-pattern facts, Chab uses those facts while normalizing each contact. Organization values can remain populated when an individual contact record does not repeat them. Pattern evidence is evaluated against each normalized address, so evidence.matched_pattern is true only when that address follows the known company pattern.

POST/v1/contacts/email-finder

Finds a likely work email address for one person at a company.

Required Access

  • Access: Paid plans that include this family, or free credits (guest trial or verified account) within the free limits.
  • Operation family: Contacts
  • Scope: api:contact:write
  • Credits: 8 credits reserved on acceptance
  • Idempotency: Idempotency-Key header required

Request

Lookup by full name:

{
  "full_name": "Jane Doe",
  "domain": "example.com"
}

Lookup by split name and company:

{
  "first_name": "Jane",
  "last_name": "Doe",
  "company": "Example Inc."
}

Fields:

  • Provide either full_name or both first_name and last_name.
  • Do not send full_name together with first_name or last_name.
  • full_name can be up to 160 characters.
  • first_name and last_name can each be up to 80 characters.
  • Chab trims name and company values and collapses repeated whitespace. Whitespace-only values are rejected.
  • Split names remain a split-name lookup; Chab also derives the normalized full_name shown in the operation summary and result lookup.
  • Provide at least one company selector: domain or company.
  • domain must be a hostname only. URLs, paths, query strings, and schemes are rejected.
  • company is optional when domain is present and can help when a hostname is not known. It can be up to 160 characters.

Example

curl -X POST https://www.chab.ai/v1/contacts/email-finder \
  -H "Authorization: Bearer CHAB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: contacts-email-finder-001" \
  -d '{"full_name":"Ada Lovelace","domain":"example.com"}'

Async Response

The create response has the same operation envelope shape as domain search, with operation_key: "contacts.email_finder" and an 8 credit estimate/reservation.

Result

{
  "data": {
    "result": {
      "lookup": {
        "full_name": "Jane Doe",
        "first_name": null,
        "last_name": null,
        "domain": "example.com",
        "company": null
      },
      "contact": {
        "email": "[email protected]",
        "first_name": "Jane",
        "last_name": "Doe",
        "full_name": "Jane Doe",
        "title": "Sales Director",
        "department": "sales",
        "seniority": "director",
        "organization": {
          "name": "Example Inc.",
          "domain": "example.com"
        },
        "confidence": 0.9,
        "source_category": "company_pattern",
        "is_role_address": false,
        "is_generic_address": false,
        "verification": {
          "status": "valid",
          "mx_records_found": true,
          "smtp_check": true,
          "accepts_all": false,
          "disposable": false,
          "blocked_domain": false
        },
        "evidence": {
          "matched_pattern": true,
          "public_profile_seen": false,
          "domain_match": true,
          "verification_observed": true
        },
        "warnings": []
      },
      "summary": {
        "no_result": false
      }
    },
    "artifacts": [],
    "warnings": [],
    "result_expires_at": "2026-07-17T09:30:05+00:00"
  },
  "meta": {
    "request_id": "req_123"
  }
}

If no likely email is found, the operation succeeds, contact is null, and summary.no_result is true.

POST/v1/contacts/email-verify

Checks one email address, or a list of up to 100, and returns normalized verification facts for each address.

Required Access

  • Plan: Pro or Scale. Verified free accounts and guest trial API credentials can start contacts.email_verify with free credits while free use is available.
  • Operation family: Contacts
  • Scope: api:contact:write
  • Credits: 2 credits per address, reserved on acceptance (200 credits for 100 addresses). Addresses that could not be checked are not charged. Free credits are one-off grants and do not refresh monthly.
  • Idempotency: Idempotency-Key header required

Request

{
  "email": "[email protected]"
}

Or a list:

Fields (send exactly one of the two):

  • email: an RFC email address, up to 254 characters. Chab trims and lowercases the address before verification.
  • emails: 1 to 100 RFC email addresses, no duplicates. Chab trims and lowercases each one. To check a long list, such as a CSV of 400 leads, send it in requests of 100.

Example

curl -X POST https://www.chab.ai/v1/contacts/email-verify \
  -H "Authorization: Bearer CHAB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: contacts-email-verify-001" \
  -d '{"email":"[email protected]"}'

Async Response

The create response has the same operation envelope shape as domain search, with operation_key: "contacts.email_verify" and an estimate and reservation of 2 credits per address.

Result

{
  "data": {
    "result": {
      "email": "[email protected]",
      "verification": {
        "status": "valid",
        "mx_records_found": true,
        "smtp_check": true,
        "accepts_all": false,
        "disposable": false,
        "blocked_domain": false
      },
      "confidence": 0.95,
      "source_category": "verification_check",
      "evidence": {
        "matched_pattern": false,
        "public_profile_seen": false,
        "domain_match": true,
        "verification_observed": true
      },
      "warnings": [],
      "summary": {
        "no_result": false
      }
    },
    "artifacts": [],
    "warnings": [],
    "result_expires_at": "2026-07-17T09:30:05+00:00"
  },
  "meta": {
    "request_id": "req_123"
  }
}

A request with emails returns one row per address, in the order sent, and a count per verdict:

{
  "data": {
    "result": {
      "results": [
        {
          "email": "[email protected]",
          "checked": true,
          "verification": {
            "status": "valid",
            "mx_records_found": true,
            "smtp_check": true,
            "accepts_all": false,
            "disposable": false,
            "blocked_domain": null
          }
        },
        {
          "email": "[email protected]",
          "checked": true,
          "verification": {
            "status": "invalid",
            "mx_records_found": null,
            "smtp_check": false,
            "accepts_all": false,
            "disposable": false,
            "blocked_domain": null
          }
        }
      ],
      "summary": {
        "total": 2,
        "valid": 1,
        "invalid": 1,
        "risky": 0,
        "unverifiable": 0,
        "not_checked": 0,
        "no_result": false
      },
      "source_category": "verification_check",
      "warnings": []
    }
  }
}

Chab checks a batch several addresses at a time and stops after about 45 seconds. Addresses it could not check come back with checked: false and status unverifiable, are not charged, and a warning names how many there were. Send those again.

Before the mailbox check, Chab looks up the domain in DNS. When the domain does not exist or has no mail server (no MX, A or AAAA record), or it publishes a "null MX" record that says it accepts no email, the address is invalid right away. Its verification then has mx_records_found: false and a reason of no_mail_server or domain_accepts_no_mail. These addresses are charged like any checked address. When the DNS lookup itself fails, Chab runs the mailbox check as usual.

Verification status values are:

  • valid: the address appears deliverable.
  • invalid: the address appears undeliverable.
  • risky: the address may deliver but has risk signals such as accept-all behavior.
  • unknown: Chab could not determine a stronger status.
  • unverifiable: verification could not be completed for the address.

Email verification always returns one of these statuses, including unverifiable, so it does not have a no-result outcome.

When a verification response contains both a detailed status and a legacy coarse result, Chab uses the detailed status.

blocked_domain: true means the remote SMTP server prevented the verification check. It does not by itself mean the address is invalid; the normalized verification status remains authoritative.

unverifiable, low-confidence, missing-field, and duplicate-candidate conditions are returned as structured warnings. Warnings are advisory and do not change the operation's terminal success status.

Contact Result Fields

Contact records use these normalized enum values:

  • department: executive, sales, marketing, engineering, support, finance, hr, legal, operations, other, or unknown.
  • seniority: owner, founder, c_level, vp, director, manager, individual, or unknown.
  • source_category: website, public_profile, company_pattern, verification_check, or unknown.
  • evidence.matched_pattern: true only when the normalized address matches a known company email pattern; the presence of a company pattern alone does not make this true.

Boolean flags distinguish shared and role addresses:

  • is_role_address: true for addresses whose local part is a role or mailbox name, such as support@.
  • is_generic_address: true for addresses that are generic, shared, or not clearly tied to one person.

Sparse fields are returned as null rather than omitted. When missing data is important to interpretation, Chab includes a structured field_unavailable warning.

Domain-search candidates are deduplicated by normalized email address, or by full name plus organization domain when no email is available. Chab keeps the highest-ranked candidate, fills only missing fields from duplicates, and emits one duplicate_candidate warning for each conflicting field whose higher-ranked value was retained.

Billing and No-Result Behavior

Validation failures, authentication failures, missing scope, missing paid-plan access, insufficient credits, and readiness failures before work starts are not charged. A contact operation that ends in a provider error instead of a result also releases its full hold. Once provider work returns a successful result, the operation settles at the fixed price even when no contact is found.

Idempotent retries with the same Idempotency-Key and byte-identical request body return the original operation and do not create a second hold.

Errors

Common errors include:

  • validation_failed: the JSON body is malformed, missing required fields, or contains unsupported fields.
  • api_scope_missing: the key does not include api:contact:write.
  • paid_plan_required or operation_family_not_included: the team plan cannot call contact endpoints.
  • insufficient_credits: the team or token budget cannot cover the fixed estimate.
  • provider_unavailable: contact lookup is temporarily unavailable.
  • provider_temporarily_rate_limited: retry after the indicated delay.
  • provider_error or provider_response_invalid: the operation could not safely produce a normalized result. For email verification, Chab rejects an provider result that omits the verified address or names a different one; it never presents that result as verification of your requested address.

Temporary provider rate caps use provider_temporarily_rate_limited. Provider usage or readiness exhaustion uses provider_unavailable and is not treated as an immediately retryable rate cap.

See Errors, Rate Limits, and Pagination for the shared error envelope and retry guidance.