01 Overview
ReachAPI is a REST‑oriented service suite for embedding contact and company data into applications. It returns structured JSON, and the data‑retrieval endpoints follow an asynchronous, credit‑metered pattern: you submit filter criteria, the server validates and processes matching records in the background, and you either poll for a batch ID or receive a webhook when the batch is ready.
Every endpoint on this page is also described machine‑readably in an OpenAPI 3.0 spec — import it into Postman/Insomnia, feed it to a codegen tool, or point an LLM agent at it directly.
02 Authentication
API Key
Every request (except the webhook receiver on your own server) is authenticated with an X-API-Key header.
| Step | Action |
|---|---|
| 1 | Log in to your ReachStream account. |
| 2 | Open settings icon (bottom left) → Account Details → API. |
| 3 | Click Generate API Key. |
| 4 | Copy and store the key securely. |
Webhook Secret
For the webhook‑based data request flow, generate a Webhook Secret Key from the same Account Details page and set an active Endpoint URL that accepts POST requests.
03 Credit Insights API
Check the available credit balance on your account before running a large batch.
04 Counts API
Get a total match count and a small sample of records for a given filter, without spending download credits — useful for sizing a request before committing to it.
05 Data Access API
Data can be retrieved two ways: API Query (poll for results using a Batch Process ID) or Webhook (ReachStream pushes the result to your endpoint when ready). Only validated records are returned and billed — this includes both valid and catch‑all email addresses; if 99 of 100 requested contacts come back valid or catch‑all, you receive and are charged for 99.
Step 1 — Data Filter API
Submits filter criteria and a fetchCount. Processing happens asynchronously; the response gives you a Batch Process ID to poll.
| Field | Type | Required | Description |
|---|---|---|---|
| fetchCount | Integer | Yes | Number of records to fetch. |
| filter | Object | Yes | Filtering criteria — see Filter Property. |
Step 2 — Retrieve Data API
Poll with the Batch Process ID from step 1 until status is ready, then read the validated records.
| Status | Message | Meaning |
|---|---|---|
| 200 | Success | Records returned. |
| 200 | No valid email addresses were found | Widen filters or raise fetchCount. |
| 400 | Records are still being processed | Not ready yet — poll again shortly. |
| 400 | Provide a valid batch_process_id | ID malformed or unknown. |
Batch List API
Paginated audit log of every batch you've created via the Filter API — status, record counts, credits used, and the original filter.
| Field | Required | Description |
|---|---|---|
| page | No | Page number, starting at 1. |
| pageSize | No | Records per page — commonly 15, 50, 100. |
| recordStatus | No | INITIATED · PROCESSING · READY · INSUFFICIENT_CREDITS |
| order | No | asc or desc. |
Webhook‑based Request
Same filter/fetchCount payload, but instead of polling, ReachStream pushes the validated batch to your Webhook URL once ready. Requires an active webhook and its secret key in the webhook_secret_key header.
06 Data Enrichment APIs
Send partial contact or company records in, get enriched records back — also processed asynchronously in two steps.
Initiate Enrichment
| Field | Description |
|---|---|
| enrichment_type | "CONTACT" or "COMPANY". |
| data | Array of partial contact or company objects — all fields optional, more data improves match accuracy. |
Each object in data is validated individually before processing — a failing row returns 400 and rejects the whole batch.
| Applies to | Requirement | Error (400) if missing |
|---|---|---|
| Every row | Must be a JSON object. | "Record at index X must be an object." |
enrichment_type: "COMPANY" | company_company_name OR company_domain. | "Record at index X must include company_company_name or company_domain." |
enrichment_type: "CONTACT" (default) | contact_first_name AND contact_last_name AND company_company_name. | "Record at index X must include contact_first_name, contact_last_name, and company_company_name." |
Retrieve Enrichment Results
07 Predefined Values
Look up valid, predefined values (job titles, SIC codes, cities, etc.) to use as filter inputs elsewhere in the API.
| Parameter | Description |
|---|---|
| job_title | Filter results by job title. |
| sic_code | Filter results by SIC code. |
| address_zipcode | Filter results by address zip code. |
| address_city | Filter results by address city. |
| address_state | Filter results by address state. |
| address_country | Filter results by address country. |
| company_name | Filter results by company name. |
| website | Filter results by website. |
| tech_keywords | Filter results by technology keywords. |
| job_title_level | Filter results by job title level. |
| job_dept_name | Filter results by job department name. |
| job_function_name | Filter results by job function name. |
| company_type | Filter results by company type. |
| company_industry_categories_list | Filter results by industry categories. |
| company_buzzwords_list | Filter results by company buzzwords. |
| employee_size | Filter results by employee size. |
| annual_revenue_amount | Filter results by annual revenue amount. |
Predefined value lists (the full valid vocabulary for each field) are also published as an SDK on GitHub.
08 Filter Property
The filter object is the shared search payload used by the Counts, Data Access, and Data Enrichment endpoints. Every field takes an object keyed by index ("0", "1", …) so you can pass multiple values per criterion.
job_title: {"0":"CEO","1":"CFO"} matches a record whose title is CEO or CFO, so the result set can contain both CEOs and CFOs together. Different fields in the same filter object are combined with AND — e.g. a job_title filter plus a company_address_country filter matches only records satisfying both.
| Field | Type | Description |
|---|---|---|
| job_title | String | One or more job titles, e.g. "Business Manager". |
| job_title_level | String | Seniority tier, e.g. "Manager", "C-Suite". |
| job_dept_name | String | Department name, e.g. "Marketing". |
| job_function_name | String | Job function, e.g. "Engineering". |
| company_industry_categories_list | String | Industry category, e.g. "Information Technology". |
| company_buzzwords_list | String | Company buzzword, e.g. "Railway Engineering". |
| sic_code | String (numeric code) | One or more SIC codes. |
| company_employee_size | String (range) | Range string, e.g. "10 to 50". |
| company_annual_revenue_amount | String (range) | Range string, e.g. "$1M to $5M". |
| company_address_country | String | Country name. |
| company_address_zipcode | String | Zip / postal code. |
| company_address_state | String | State / province. |
| company_address_city | String | City. |
| company_name | String | Company name. |
| company_website | String | Company website. |
| company_type | String | e.g. "Public Company", "Non-Profit". |
| tech_keywords | String | Technology keyword, e.g. "amazon ec2". |
{
"filter": {
"job_title": { "0": "Business Manager" },
"job_title_level": { "0": "Manager" },
"company_address_country": { "0": "United States" },
"company_address_state": { "0": "California" },
"sic_code": { "0": "111", "1": "112" },
"company_employee_size": { "0": "10 to 20" }
}
}
Excluding values from a field
Any field in the filter object accepts a nested exclude object, keyed by index the same way as the field itself. It removes matching records from that field's results — combine it with the field's own indexed values to include a broad match while excluding specific values.
{
"filter": {
"job_title": {
"0": "Software",
"exclude": {
"0": "Software Developer"
}
}
}
}
Here, records matching "Software" are included, except those matching "Software Developer".
/api/v2/async/records/filter/data), and the Webhook‑based Filter API (/api/v2/async/records/filter).09 Webhook
Once configured and active, ReachStream POSTs a JSON payload to your endpoint as soon as a batch is validated, instead of you polling for it.
Payload shape
{
"unique_processing_id": 1300,
"event": "data_notification",
"data": [
{
"id": "xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"naics_code": [
"541330"
],
"sic_code": [
"8711"
],
"company_company_name": "xxxxx",
"company_domain": "xxxxx.com",
"company_type": "Private",
"company_employee_size": "100 to 250",
"company_annual_revenue_amount": "$10M to $25M",
"company_address_city": "xxxxx",
"company_address_state": "xxxxx",
"company_address_country": "Switzerland",
"company_phone": "xxxxx",
"company_industry_categories_list": [
"Engineering Services"
],
"company_tech_keywords_list": [
"Aws",
"Abacus",
"Azure",
"Google analytics",
"Director",
"Compliance",
"Continuous improvement",
"Financial",
"Infrastructure"
],
"company_buzzwords_list": [
"Railway Engineering",
"Power Supply",
"Rolling Stock",
"Traction Systems",
"Infrastructure"
],
"contact_name": "xxxxx",
"contact_first_name": "xxxxx",
"contact_last_name": "xxxxx",
"contact_job_title": "xxxxx",
"contact_job_title_level": "C-Suite",
"contact_job_dept_name": "C-Suite",
"contact_job_function_name": "Executive",
"contact_email": "xxxxx@xxxxx.com",
"contact_email_verified_status": "valid"
}
]
}
Handling incoming requests
| Step | Action |
|---|---|
| 1 | Accept POST requests at your configured endpoint URL. |
| 2 | Parse the JSON payload. |
| 3 | Process the data (e.g. write to your database). |
| 4 | Respond with 200 OK to acknowledge receipt — anything else triggers a retry. |
Security
Verify each request using your shared webhook secret key, serve the endpoint over HTTPS only, and consider IP‑whitelisting ReachStream's outbound addresses.
Testing & troubleshooting
Use Postman or ngrok to simulate deliveries locally. If deliveries seem to fail, check your server logs, confirm the payload shape matches what's above, and confirm your endpoint truly returns 200.
10 HTTP Return Codes
11 Rate Limitations
HTTP 429. Build in backoff and avoid tight polling loops when waiting on batch status.