openapi: 3.0.3 info: title: ReachAPI description: > Contact and company data delivered over a REST API. Data-retrieval endpoints follow an asynchronous, credit-metered pattern: 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. Only validated records (valid or catch-all email addresses) are ever returned or billed. version: "2.0.0" contact: email: support@reachstream.com servers: - url: https://api.reachstream.com description: Production security: - ApiKeyAuth: [] tags: - name: Credit Insights - name: Counts - name: Data Access - name: Data Enrichment - name: Filter Value Reference paths: /api/v2/predefined/records/preset-values: get: tags: [Filter Value Reference] summary: Look up predefined values for a filter field description: > Returns the valid, predefined vocabulary (job titles, SIC codes, cities, etc.) usable as inputs to the `filter` object elsewhere in the API. All query parameters are optional; passing more than one narrows results but the exact combination semantics (AND vs OR across parameters) are not specified by this endpoint — pass one parameter at a time for predictable results. parameters: - name: job_title in: query schema: { type: string } description: Filter results by job title. - name: sic_code in: query schema: { type: string } description: Filter results by SIC code. - name: address_zipcode in: query schema: { type: string } description: Filter results by address zip code. - name: address_city in: query schema: { type: string } description: Filter results by address city. - name: address_state in: query schema: { type: string } description: Filter results by address state. - name: address_country in: query schema: { type: string } description: Filter results by address country. - name: company_name in: query schema: { type: string } description: Filter results by company name. - name: website in: query schema: { type: string } description: Filter results by website. - name: tech_keywords in: query schema: { type: string } description: Filter results by technology keywords. - name: job_title_level in: query schema: { type: string } description: Filter results by job title level. - name: job_dept_name in: query schema: { type: string } description: Filter results by job department name. - name: job_function_name in: query schema: { type: string } description: Filter results by job function name. - name: company_type in: query schema: { type: string } description: Filter results by company type. - name: company_industry_categories_list in: query schema: { type: string } description: Filter results by industry categories. - name: company_buzzwords_list in: query schema: { type: string } description: Filter results by company buzzwords. - name: employee_size in: query schema: { type: string } description: Filter results by employee size. - name: annual_revenue_amount in: query schema: { type: string } description: Filter results by annual revenue amount. responses: "200": description: Success content: application/json: schema: allOf: - $ref: "#/components/schemas/Envelope" - type: object properties: data: type: array items: { type: string } example: status: 200 message: Success data: ["Software Engineer", "DevOps Engineer", "Frontend Developer", "Backend Developer"] "400": description: Bad Request — a query parameter was passed as null/empty content: application/json: schema: { $ref: "#/components/schemas/ErrorResponse" } example: { status: 400, message: "Field and value cannot be null or empty", data: "null" } "401": { $ref: "#/components/responses/Unauthorized" } "404": { $ref: "#/components/responses/NotFound" } "500": { $ref: "#/components/responses/ServerError" } /api/v2/retrive/users/active/credits: post: tags: [Credit Insights] summary: Get available credits description: Check the available credits on your account before running a large batch. responses: "200": description: Success content: application/json: schema: allOf: - $ref: "#/components/schemas/Envelope" - type: object properties: data: type: object properties: available_credit: { type: integer } example: status: 200 message: success data: { available_credit: 720 } "401": { $ref: "#/components/responses/Unauthorized" } "404": { $ref: "#/components/responses/NotFound" } "500": { $ref: "#/components/responses/ServerError" } /api/v2/request/records/count: post: tags: [Counts] summary: Get a match count and sample records for a filter description: > Returns 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. requestBody: required: true content: application/json: schema: type: object required: [filter] properties: filter: { $ref: "#/components/schemas/FilterObject" } example: filter: { company_address_state: { "0": "California" } } responses: "200": description: Success content: application/json: schema: allOf: - $ref: "#/components/schemas/Envelope" - type: object properties: data: type: object properties: counts: { type: integer } records: type: array items: { $ref: "#/components/schemas/CompanyContactRecord" } example: status: 200 message: success data: counts: 9697333 records: - id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx naics_code: ["561320"] sic_code: ["8099"] company_company_name: xxxxx company_domain: https://www.xxxxx.com company_type: Private company_founded_year: 2001 company_employee_size: "5000 to 10000" company_annual_revenue_amount: "$1B to $5B" company_address_city: xxxxx company_address_state: California company_address_country: United States company_phone: xxxxx company_industry_categories_list: ["HR & Staffing", "Business Services"] company_tech_keywords_list: ["Salesforce", "Workday", "Amazon Web Services"] company_buzzwords_list: ["Healthcare Staffing", "Travel Nursing", "Allied Health"] contact_name: xxxxx contact_first_name: xxxxx contact_last_name: xxxxx contact_job_title: xxxxx contact_job_title_level: Senior contact_job_dept_name: Healthcare Services contact_job_function_name: Nursing "400": description: Bad Request content: application/json: schema: { $ref: "#/components/schemas/ErrorResponse" } example: { status: 400, message: "Missing parameter filter", data: null } "401": { $ref: "#/components/responses/Unauthorized" } "404": { $ref: "#/components/responses/NotFound" } "500": { $ref: "#/components/responses/ServerError" } /api/v2/async/records/filter/data: post: tags: [Data Access] summary: "Step 1 — Submit a filter (poll-based)" description: > Submits filter criteria and a `fetchCount`. Processing happens asynchronously; the response gives you a Batch Process ID to poll via the Retrieve Data API. `fetchCount` is capped per request based on your plan (see the 403 response below). requestBody: required: true content: application/json: schema: type: object required: [fetchCount, filter] properties: fetchCount: { type: integer, description: "Number of records to fetch. Capped per request based on your plan — see the 403 response below." } filter: { $ref: "#/components/schemas/FilterObject" } example: fetchCount: 200 filter: { company_address_country: { "0": "India" } } responses: "200": description: Records processing initiated content: application/json: schema: allOf: - $ref: "#/components/schemas/Envelope" - type: object properties: data: type: object properties: batch_process_id: { type: integer } example: status: 200 message: Records processing initiated data: { batch_process_id: 31 } "400": description: Bad Request content: application/json: schema: { $ref: "#/components/schemas/ErrorResponse" } example: { status: 400, message: "Required fetchCount and filter", data: null } "402": description: Payment Required — insufficient credit content: application/json: schema: allOf: - $ref: "#/components/schemas/Envelope" - type: object properties: data: type: object properties: available_credit: { type: integer } requested_fetch_count: { type: integer } example: status: 402 message: Insufficient credits data: { available_credit: 720, requested_fetch_count: 2000 } "403": { $ref: "#/components/responses/Forbidden" } "401": { $ref: "#/components/responses/Unauthorized" } "404": { $ref: "#/components/responses/NotFound" } "500": { $ref: "#/components/responses/ServerError" } /api/v2/records/batch-process: get: tags: [Data Access] summary: "Step 2 — Retrieve a batch's validated records" description: Poll with the Batch Process ID from the Data Filter API until status is ready, then read the validated records. parameters: - name: batch_process_id in: query required: true schema: { type: string } responses: "200": description: Success (may return an empty result set if nothing validated) content: application/json: schema: allOf: - $ref: "#/components/schemas/Envelope" - type: object properties: data: type: array items: { $ref: "#/components/schemas/ValidatedRecord" } examples: success: summary: Records returned value: status: 200 message: Success 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"] 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 role: null empty: summary: No valid email addresses were found value: { status: 200, message: "No valid email addresses were found", data: [] } "400": description: Bad Request content: application/json: schema: { $ref: "#/components/schemas/ErrorResponse" } examples: pending: summary: Batch not ready yet value: { status: 400, message: "Records are still being processed", data: null } badId: summary: Malformed or unknown ID value: { status: 400, message: "Provide a valid batch_process_id", data: null } "401": { $ref: "#/components/responses/Unauthorized" } "500": { $ref: "#/components/responses/ServerError" } /api/v2/async/records/batch/list: post: tags: [Data Access] summary: List your batches description: Paginated audit log of every batch you've created via the Filter API — status, record counts, credits used, and the original filter. requestBody: required: false content: application/json: schema: type: object properties: page: { type: integer, description: "Page number, starting at 1." } pageSize: { type: integer, description: "Records per page — commonly 15, 50, 100." } recordStatus: type: string enum: [INITIATED, PROCESSING, READY, INSUFFICIENT_CREDITS] order: { type: string, enum: [asc, desc] } example: { page: 1, pageSize: 15, recordStatus: READY, order: desc } responses: "200": description: Success content: application/json: schema: allOf: - $ref: "#/components/schemas/Envelope" - type: object properties: data: type: object properties: records: type: array items: type: object properties: batch_process_id: { type: integer } request: type: object properties: fetchCount: { type: integer } filters: { $ref: "#/components/schemas/FilterObject" } validRecords: { type: integer } creditPointsUsed: { type: integer } recordStatus: type: string enum: [INITIATED, PROCESSING, READY, INSUFFICIENT_CREDITS] createdAt: { type: string, format: date-time } total_records: { type: integer } total_pagination: { type: integer } current_pagination: { type: integer } example: status: 200 message: Success data: records: - batch_process_id: 31 request: fetchCount: 3 filters: { contact_job_title_1: { "0": "CFO", "1": "CEO" }, company_address_country: { "0": "United Kingdom" } } validRecords: 0 creditPointsUsed: 0 recordStatus: READY createdAt: "2025-10-27 06:31:30.573" total_records: 8 total_pagination: 1 current_pagination: 1 "401": { $ref: "#/components/responses/Unauthorized" } "500": { $ref: "#/components/responses/ServerError" } /api/v2/async/records/filter: post: tags: [Data Access] summary: Submit a filter (webhook-based) description: > Same filter/fetchCount payload as the Data Filter API, 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 — the header is validated against the secret key on file for your account; a missing header returns `400` and a mismatched one returns `401`. `fetchCount` is capped per request based on your plan (see the 403 response below). parameters: - name: webhook-secret-key in: header required: true description: > Your account's Webhook Secret Key (from Account Details → API). Must match exactly, or the request is rejected with `401`. schema: { type: string } requestBody: required: true content: application/json: schema: type: object required: [fetchCount, filter] properties: fetchCount: { type: integer, description: "Number of records to fetch. Capped per request based on your plan — see the 403 response below." } filter: { $ref: "#/components/schemas/FilterObject" } example: fetchCount: 500 filter: { job_title_level: { "0": "C-Suite" } } responses: "200": description: Records processing initiated content: application/json: schema: allOf: - $ref: "#/components/schemas/Envelope" - type: object properties: data: type: object properties: unique_processing_id: { type: integer } example: status: 200 message: Records processing initiated data: { unique_processing_id: 1300 } "400": description: Bad Request content: application/json: schema: { $ref: "#/components/schemas/ErrorResponse" } examples: missing: summary: Missing required fields value: { status: 400, message: "Required fetchCount and filter", data: null } inactive: summary: Webhook not configured/active value: { status: 400, message: "Webhook feature is inactive", data: null } noUrl: summary: Webhook active but no Endpoint URL set value: { status: 400, message: "Webhook URL is required", data: null } missingSecret: summary: webhook-secret-key header not sent value: { status: 400, message: "Missing webhook-secret-key header", data: null } "401": description: Unauthorized — bad X-API-Key, or webhook-secret-key doesn't match the key on file content: application/json: schema: { $ref: "#/components/schemas/ErrorResponse" } examples: badApiKey: summary: Invalid or missing X-API-Key value: { status: 401, message: "Unauthorized", data: null } badSecret: summary: webhook-secret-key doesn't match your account's key value: { status: 401, message: "Invalid webhook-secret-key", data: null } "402": description: Payment Required — insufficient credit content: application/json: schema: allOf: - $ref: "#/components/schemas/Envelope" - type: object properties: data: type: object properties: available_credit: { type: integer } requested_fetch_count: { type: integer } example: status: 402 message: Insufficient credits data: { available_credit: 720, requested_fetch_count: 2000 } "403": { $ref: "#/components/responses/Forbidden" } "404": { $ref: "#/components/responses/NotFound" } "500": { $ref: "#/components/responses/ServerError" } /api/Search/v1/data/enrichment/batch: post: tags: [Data Enrichment] summary: Initiate contact/company enrichment description: > Send partial contact or company records in, get enriched records back. Each object in `data` is validated individually before processing — a failing row returns 400 and rejects the whole batch. `data` is capped per request based on your plan (see the 403 response below). Credits are deducted for every successfully enriched record. requestBody: required: true content: application/json: schema: type: object properties: enrichment_type: type: string enum: [CONTACT, COMPANY] default: CONTACT data: type: array description: "Capped per request based on your plan — see the 403 response below." items: type: object description: > All fields optional — more data improves match accuracy. CONTACT rows require contact_first_name, contact_last_name, and company_company_name. COMPANY rows require company_company_name or company_domain. additionalProperties: true example: enrichment_type: CONTACT data: - contact_first_name: "" contact_last_name: "" company_company_name: "" responses: "200": description: Process initialized content: application/json: schema: allOf: - $ref: "#/components/schemas/Envelope" - type: object properties: data: type: object properties: batch_id: { type: string } example: status: 200 message: Process initialized data: { batch_id: "i2ujxdtw4raNccbL55xdwV_EQUALS__EQUALS_" } "400": description: Bad Request — per-record validation failure content: application/json: schema: { $ref: "#/components/schemas/ErrorResponse" } example: status: 400 message: "Record at index 0 must include contact_first_name, contact_last_name, and company_company_name." data: null "402": description: Payment Required — insufficient credit content: application/json: schema: allOf: - $ref: "#/components/schemas/Envelope" - type: object properties: data: type: object properties: available_credit: { type: integer } requested_fetch_count: { type: integer } example: status: 402 message: Insufficient credits data: { available_credit: 720, requested_fetch_count: 2000 } "403": { $ref: "#/components/responses/Forbidden" } "401": { $ref: "#/components/responses/Unauthorized" } "500": { $ref: "#/components/responses/ServerError" } /api/retrieve/v1/data/enrichment/batch: get: tags: [Data Enrichment] summary: Retrieve enrichment results parameters: - name: id in: query required: true schema: { type: string } description: The batch_id returned by the Initiate Enrichment endpoint. responses: "200": description: Success content: application/json: schema: allOf: - $ref: "#/components/schemas/Envelope" - type: object properties: data: type: array items: { type: object, additionalProperties: true } examples: contact: summary: 'Shape for enrichment_type: "CONTACT"' value: status: 200 message: success data: - id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx naics_code: ["621111"] sic_code: ["8011"] company_company_name: xxxxx company_domain: https://www.xxxxx.com company_type: Private company_employee_size: "5 to 10" company_annual_revenue_amount: "$1M to $5M" company_address_city: xxxxx company_address_state: New York company_address_country: United States company_location: { lat: 0, lon: 0 } company_phone: xxxxx company_industry_categories_list: ["Hospitals & Healthcare"] contact_name: xxxxx contact_first_name: xxxxx contact_last_name: xxxxx contact_job_title: Doctor contact_job_title_level: Entry contact_job_dept_name: Healthcare Services contact_job_function_name: Other Doctors / Physicians contact_email: xxxxx@xxxxx.com contact_email_verified_status: catch-all company: summary: 'Shape for enrichment_type: "COMPANY"' value: status: 200 message: success data: - id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx company_company_name: xxxxx company_domain: https://www.xxxxx.com company_type: Private company_employee_size: "5 to 10" company_annual_revenue_amount: "$1M to $5M" company_address_city: xxxxx company_address_state: New York company_address_country: United States company_phone: xxxxx company_industry_categories_list: ["Hospitals & Healthcare"] sic_code: ["8011"] naics_code: ["621111"] "400": description: Bad Request content: application/json: schema: { $ref: "#/components/schemas/ErrorResponse" } examples: pending: summary: Batch not ready yet value: { status: 400, message: "Records are still being processed", data: null } badId: summary: Malformed or unknown ID value: { status: 400, message: "Provide a valid batch_id", data: null } "401": { $ref: "#/components/responses/Unauthorized" } "500": { $ref: "#/components/responses/ServerError" } components: securitySchemes: ApiKeyAuth: type: apiKey in: header name: X-API-Key responses: Unauthorized: description: API key missing or invalid content: application/json: schema: { $ref: "#/components/schemas/ErrorResponse" } example: { status: 401, message: "Unauthorized", data: null } NotFound: description: Endpoint not found content: application/json: schema: { $ref: "#/components/schemas/ErrorResponse" } example: { status: 404, message: "Not Found", data: null } ServerError: description: Server error content: application/json: schema: { $ref: "#/components/schemas/ErrorResponse" } example: { status: 500, message: "Server Error", data: null } Forbidden: description: > Requested record count exceeds the maximum allowed per request for your plan. Icebreaker plans may request up to 100 records per call; all other plans may request up to 10,000. To fetch more, split the job into multiple requests. content: application/json: schema: { $ref: "#/components/schemas/ErrorResponse" } example: { status: 403, message: "Your plan allows a maximum of 100 records per request. Upgrade your plan to request more.", data: null } schemas: Envelope: type: object properties: status: { type: integer, description: "Status echoed in the response body — not always identical to the HTTP status code; treat the HTTP status code as authoritative." } message: { type: string } required: [status, message] ErrorResponse: allOf: - $ref: "#/components/schemas/Envelope" - type: object properties: data: { nullable: true } FilterField: type: object description: > Object keyed by index ("0", "1", …), one string value per index. Multiple indexed values are combined with OR. Accepts an optional nested "exclude" key (same shape) to remove matching records from this field's results. additionalProperties: type: string example: { "0": "Business Manager", "exclude": { "0": "Business Manager Assistant" } } FilterObject: type: object description: Different fields in the same filter object are combined with AND. properties: job_title: { $ref: "#/components/schemas/FilterField" } job_title_level: { $ref: "#/components/schemas/FilterField" } job_dept_name: { $ref: "#/components/schemas/FilterField" } job_function_name: { $ref: "#/components/schemas/FilterField" } company_industry_categories_list: { $ref: "#/components/schemas/FilterField" } company_buzzwords_list: { $ref: "#/components/schemas/FilterField" } sic_code: { $ref: "#/components/schemas/FilterField" } company_employee_size: { $ref: "#/components/schemas/FilterField" } company_annual_revenue_amount: { $ref: "#/components/schemas/FilterField" } company_address_country: { $ref: "#/components/schemas/FilterField" } company_address_zipcode: { $ref: "#/components/schemas/FilterField" } company_address_state: { $ref: "#/components/schemas/FilterField" } company_address_city: { $ref: "#/components/schemas/FilterField" } company_name: { $ref: "#/components/schemas/FilterField" } company_website: { $ref: "#/components/schemas/FilterField" } company_type: { $ref: "#/components/schemas/FilterField" } tech_keywords: { $ref: "#/components/schemas/FilterField" } additionalProperties: true CompanyContactRecord: type: object description: Shape returned by the Counts API sample records (not billed, not necessarily validated). properties: id: { type: string, format: uuid } naics_code: { type: array, items: { type: string } } sic_code: { type: array, items: { type: string } } company_company_name: { type: string } company_domain: { type: string } company_type: { type: string } company_founded_year: { type: integer } company_employee_size: { type: string } company_annual_revenue_amount: { type: string } company_logo_url: { type: string } company_address_city: { type: string } company_address_state: { type: string } company_address_country: { type: string } company_county: { type: string } company_phone: { type: string } company_industry_categories_list: { type: array, items: { type: string } } company_tech_keywords_list: { type: array, items: { type: string } } company_buzzwords_list: { type: array, items: { type: string } } contact_name: { type: string } contact_first_name: { type: string } contact_last_name: { type: string } contact_job_title: { type: string } contact_job_title_level: { type: string } contact_job_dept_name: { type: string } contact_job_function_name: { type: string } additionalProperties: true ValidatedRecord: description: Shape returned by the Retrieve Data API and the Webhook payload — always includes verified contact email fields, since only validated records are ever delivered. allOf: - $ref: "#/components/schemas/CompanyContactRecord" - type: object properties: contact_email: { type: string, format: email } contact_email_verified_status: type: string enum: [valid, catch-all] description: Only these two values are ever returned — invalid addresses are never billed or delivered.