ReachStream ReachStream

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.

Base URL

All endpoints below are relative to this base URL.

https://api.reachstream.com

Every endpoint on this page is also described machine‑readably in an OpenAPI 3.0 spec — YAML or JSON — import it into Postman/Insomnia, feed it to a codegen tool, or point an LLM agent at it directly.

02 Quickstart

The full request cycle in four calls: check your credit balance, size a search with Counts, submit a Data Filter request, then poll for the results. Grab an API key from Authentication first — every call below expects it in the X-API-Key header.

Step 1 — Check your credit balance

Confirms your key works and shows how much credit you have before spending any of it.

curl --location 'https://api.reachstream.com/api/v2/retrive/users/active/credits' \
  --request POST \
  --header 'X-API-Key: your-api-key-here'

Full reference →

Step 2 — Size your search with Counts

Try a filter and see how many records match — this doesn't spend download credits.

curl --location 'https://api.reachstream.com/api/v2/request/records/count' \
  --request POST \
  --header 'X-API-Key: your-api-key-here' \
  --header 'Content-Type: application/json' \
  --data '{
  "filter": {
    "company_address_state": { "0": "California" }
  }
}'

See Filter Property for the full set of filterable fields. Full reference →

Step 3 — Submit a Data Filter request

Once the filter looks right, submit it with a fetchCount to start processing. This returns a batch_process_id — it doesn't return records yet.

curl --location 'https://api.reachstream.com/api/v2/async/records/filter/data' \
  --request POST \
  --header 'X-API-Key: your-api-key-here' \
  --header 'Content-Type: application/json' \
  --data '{
  "fetchCount": 50,
  "filter": {
    "company_address_state": { "0": "California" }
  }
}'

Full reference →

Step 4 — Poll for the results

Poll with the batch_process_id from Step 3 until it stops returning "still being processed" — then the validated records are in the response.

curl --location 'https://api.reachstream.com/api/v2/records/batch-process?batch_process_id=31' \
  --header 'X-API-Key: your-api-key-here'
Don't poll in a tight loop — see Rate Limitations. Prefer Webhook‑based Request instead if you'd rather be notified than poll.

Full reference →

03 Authentication

API Key

Every request (except the webhook receiver on your own server) is authenticated with an X-API-Key header.

StepAction
1Log in to your ReachStream account.
2Open settings icon (bottom left) → Account Details → API.
3Click Generate API Key.
4Copy and store the key securely.
Your key stays local. The key you paste in the top bar is held only in this page's memory for the current session — it is never written to a file, sent anywhere besides the ReachStream API, or stored after you close the tab.

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.

04 Credit Insights API

Check the available credits on your account before running a large batch.

POST/api/v2/retrive/users/active/credits

05 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.

POST/api/v2/request/records/count

06 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.

Record limits. Every record-fetching request below (Data Filter API, Webhook-based Request, and Enrichment) is capped per request based on your plan: Icebreaker plans may request up to 100 records, all other plans up to 10,000. Requests over the cap return 403 Forbidden; paid plans needing more should split the job into multiple requests.

Step 1 — Data Filter API

Submits filter criteria and a fetchCount. Processing happens asynchronously; the response gives you a Batch Process ID to poll.

POST/api/v2/async/records/filter/data
FieldTypeRequiredDescription
fetchCountIntegerYesNumber of records to fetch. Capped per plan — see Record Limits.
filterObjectYesFiltering 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.

GET/api/v2/records/batch-process
StatusMessageMeaning
200SuccessRecords returned.
200No valid email addresses were foundWiden filters or raise fetchCount.
400Records are still being processedNot ready yet — poll again shortly.
400Provide a valid batch_process_idID 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.

POST/api/v2/async/records/batch/list
FieldRequiredDescription
pageNoPage number, starting at 1.
pageSizeNoRecords per page — commonly 15, 50, 100.
recordStatusNoINITIATED · PROCESSING · READY · INSUFFICIENT_CREDITS
orderNoasc 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 — this header is validated against the secret key on file for your account: omit it and you get 400, send the wrong value and you get 401.

POST/api/v2/async/records/filter

fetchCount is capped per plan — see Record Limits.

07 Data Enrichment APIs

Send partial contact or company records in, get enriched records back — also processed asynchronously in two steps.

Initiate Enrichment

POST/api/Search/v1/data/enrichment/batch
FieldDescription
enrichment_type"CONTACT" or "COMPANY".
dataArray of partial contact or company objects — all fields optional, more data improves match accuracy. Capped per plan — see Record Limits.

Each object in data is validated individually before processing — a failing row returns 400 and rejects the whole batch.

Applies toRequirementError (400) if missing
Every rowMust 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."
Credits are deducted for every successfully enriched record — for CONTACT enrichment this includes both valid and catch‑all email matches, and for COMPANY enrichment every matched company record is billed.

Retrieve Enrichment Results

GET/api/retrieve/v1/data/enrichment/batch

08 Filter Value Reference

Use this endpoint to retrieve the supported values available for ReachAPI filters, including job titles, locations, industries, company types, technologies, employee sizes, revenue ranges, and other searchable attributes. These values can be used when building filter requests across the Counts API and Data Access APIs, helping ensure your queries use recognized filter inputs.

GET/api/v2/predefined/records/preset-values
ParameterDescription
job_titleFilter results by job title.
sic_codeFilter results by SIC code.
address_zipcodeFilter results by address zip code.
address_cityFilter results by address city.
address_stateFilter results by address state.
address_countryFilter results by address country.
company_nameFilter results by company name.
websiteFilter results by website.
tech_keywordsFilter results by technology keywords.
job_title_levelFilter results by job title level.
job_dept_nameFilter results by job department name.
job_function_nameFilter results by job function name.
company_typeFilter results by company type.
company_industry_categories_listFilter results by industry categories.
company_buzzwords_listFilter results by company buzzwords.
employee_sizeFilter results by employee size.
annual_revenue_amountFilter results by annual revenue amount.

Filter value reference lists (the full valid vocabulary for each field) are also published as an SDK on GitHub.

09 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.

Combining values. Multiple indexed values within the same field are combined with OR — e.g. 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.
FieldTypeDescription
job_titleStringOne or more job titles, e.g. "Business Manager".
job_title_levelStringSeniority tier, e.g. "Manager", "C-Suite".
job_dept_nameStringDepartment name, e.g. "Marketing".
job_function_nameStringJob function, e.g. "Engineering".
company_industry_categories_listStringIndustry category, e.g. "Information Technology".
company_buzzwords_listStringCompany buzzword, e.g. "Railway Engineering".
sic_codeString (numeric code)One or more SIC codes.
company_employee_sizeString (range)Range string, e.g. "10 to 50".
company_annual_revenue_amountString (range)Range string, e.g. "$1M to $5M".
company_address_countryStringCountry name.
company_address_zipcodeStringZip / postal code.
company_address_stateStringState / province.
company_address_cityStringCity.
company_nameStringCompany name.
company_websiteStringCompany website.
company_typeStringe.g. "Government Agency", "Nonprofit", "Partnership", "Public", "Educational", "Private", "Self-Owned", "Self-Employed".
tech_keywordsStringTechnology 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".

Supported on the Counts API, the Data Filter API (/api/v2/async/records/filter/data), and the Webhook‑based Filter API (/api/v2/async/records/filter).

The job_title field accepts an optional matchRelatedTitles boolean, keyed alongside the field's own indexed values (not nested inside exclude). Set it to false to match only the exact title(s) supplied. Set it to true — or omit it — to also match titles ReachStream considers related to the ones supplied.

{
  "filter": {
    "job_title": {
      "0": "Hr manager",
      "1": "Project manager",
      "exclude": {
        "0": "Business Manager and HR",
        "1": "HR Manager and Accounting Supervisor"
      },
      "matchRelatedTitles": false
    }
  }
}
Default: true. If matchRelatedTitles is omitted, related titles are matched by default. Set it to false for an exact‑title‑only match. Supported on the Counts API and the Data Access API.

10 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"
    }
  ]
}

Delivery headers

Every delivery POST to your Webhook URL carries these headers, in addition to the JSON body above:

HeaderValue
Content-Typeapplication/json
p_idThe batch's unique_processing_id — same value as in the body, provided as a header too so you can route/log without parsing the payload.
webhook-secret-keyYour account's Webhook Secret Key — use this to verify the delivery actually came from ReachStream. See Security.

Handling incoming requests

StepAction
1Accept POST requests at your configured endpoint URL.
2Parse the JSON payload.
3Process the data (e.g. write to your database).
4Respond with 200 OK to acknowledge receipt — anything else triggers a retry.

Retry policy

A delivery only counts as successful when your endpoint returns 200 (or a JSON body containing "status": 200). Anything else — a non‑200 status, a timeout, or an unparseable response — is logged as a failed attempt and retried on ReachStream's next delivery pass.

LimitValue
Max total attempts21 per batch.
Max attempts per day3 per batch, on a rolling 24‑hour window.
Retry window7 days from when the batch first became ready — attempts stop after this even if the 21‑try limit hasn't been reached.

Each failed attempt triggers a notification email to your account with the error status and reason. If a batch exhausts its retries or its 7‑day window without a successful delivery, it's marked dormant, a final "try limit exceeded" email is sent, and no further attempts are made — check the Batch List API or your inbox if you suspect a delivery was missed.

Security

Every delivery includes your Webhook Secret Key in the webhook-secret-key header — before trusting a request, compare that header's value against the secret key stored in your own systems (from Account Details → API) using a constant‑time comparison, and reject anything that doesn't match. Also 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, confirm your endpoint truly returns 200, and check for a retry‑failure email — see Retry policy.

11 HTTP Return Codes

200
Success.
400
Malformed request or missing parameters.
401
API key missing or invalid.
402
Insufficient credit to perform the request.
403
Forbidden — request not permitted, often a bad key.
404
Endpoint not found — check the URL.
429
Rate limit exceeded.
500
Server error — contact support@reachstream.com.

12 Rate Limitations

10 RPS
Exceeding 10 requests per second returns an HTTP 429. Build in backoff and avoid tight polling loops when waiting on batch status.