Skip to content

Client Integration Guide

This guide shows the stable pull-based integration for CRMs, data warehouses, and internal reporting systems.

Integration Flow

  1. Validate the API key.
  2. List visible prospect searches.
  3. Pull delivered companies for each prospect search.
  4. Store the latest successful delivery timestamp.
  5. Repeat with delivered_since for incremental sync.

Required Scopes

Operation Scopes
Validate key Any active API key
List prospect searches prospect_searches:read
Pull delivered companies companies:read, prospects:read

Validate the Key

GET /api/v1/auth/validate

curl -sS https://api.openprospect.io/api/v1/auth/validate \
  -H "Authorization: Bearer ${OPENPROSPECT_API_KEY}"

Expected response:

{
  "valid": true,
  "scopes": ["prospect_searches:read", "companies:read", "prospects:read"]
}

List Prospect Searches

GET /api/v1/prospect-searches

curl -sS "https://api.openprospect.io/api/v1/prospect-searches?limit=10" \
  -H "Authorization: Bearer ${OPENPROSPECT_API_KEY}"
import os

import httpx

api_key = os.environ["OPENPROSPECT_API_KEY"]

response = httpx.get(
    "https://api.openprospect.io/api/v1/prospect-searches",
    headers={"Authorization": f"Bearer {api_key}"},
    params={"limit": 10},
    timeout=30.0,
)
response.raise_for_status()
print(response.json()["items"])
const url = new URL("https://api.openprospect.io/api/v1/prospect-searches");
url.searchParams.set("limit", "10");

const response = await fetch(url, {
  headers: { Authorization: `Bearer ${process.env.OPENPROSPECT_API_KEY}` },
});

if (!response.ok) {
  throw new Error(`Prospect search list failed: ${response.status}`);
}

console.log((await response.json()).items);
interface ProspectSearchList {
  items: Array<{ id: string; name: string; status: string }>;
  total: number;
  limit: number;
  offset: number;
}

const url = new URL("https://api.openprospect.io/api/v1/prospect-searches");
url.searchParams.set("limit", "10");

const response = await fetch(url, {
  headers: { Authorization: `Bearer ${process.env.OPENPROSPECT_API_KEY}` },
});

if (!response.ok) {
  throw new Error(`Prospect search list failed: ${response.status}`);
}

const searches = (await response.json()) as ProspectSearchList;
console.log(searches.items);
using System.Net.Http.Headers;

var apiKey = Environment.GetEnvironmentVariable("OPENPROSPECT_API_KEY")
    ?? throw new InvalidOperationException("OPENPROSPECT_API_KEY is not set.");

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);

var response = await client.GetAsync("https://api.openprospect.io/api/v1/prospect-searches?limit=10");
response.EnsureSuccessStatusCode();
Console.WriteLine(await response.Content.ReadAsStringAsync());

Pull Delivered Companies

GET /api/v1/deliveries/{prospect_search_id}/companies

Use this endpoint for CRM sync. It returns companies with embedded prospects.

curl -sS \
  "https://api.openprospect.io/api/v1/deliveries/${PROSPECT_SEARCH_ID}/companies?limit=100" \
  -H "Authorization: Bearer ${OPENPROSPECT_API_KEY}"

Incremental Sync

After each successful run, store the newest delivered timestamp from your own sync state. On the next run, send it as delivered_since.

curl -sS \
  "https://api.openprospect.io/api/v1/deliveries/${PROSPECT_SEARCH_ID}/companies?delivered_since=2026-02-25T12:00:00Z&limit=100" \
  -H "Authorization: Bearer ${OPENPROSPECT_API_KEY}"

Process pages until has_more is false.

Minimal Python Sync

import os
from collections.abc import Iterator
from typing import Any

import httpx

api_key = os.environ["OPENPROSPECT_API_KEY"]
prospect_search_id = os.environ["PROSPECT_SEARCH_ID"]


def iter_delivered_companies(delivered_since: str | None = None) -> Iterator[dict[str, Any]]:
    offset = 0
    headers = {"Authorization": f"Bearer {api_key}"}

    while True:
        response = httpx.get(
            f"https://api.openprospect.io/api/v1/deliveries/{prospect_search_id}/companies",
            headers=headers,
            params={"limit": 100, "offset": offset, "delivered_since": delivered_since},
            timeout=30.0,
        )
        response.raise_for_status()
        page = response.json()

        yield from page["items"]

        if not page["has_more"]:
            break

        offset += page["limit"]


for company in iter_delivered_companies():
    print(company["id"], company["name"])