Skip to content

Client Integration Guide

Sync delivered leads to your CRM in under 5 minutes.


Overview

This guide walks you through integrating OpenProspect's delivered leads into your system. By the end, you'll be able to:

  1. Validate your API credentials
  2. List your prospect searches
  3. Retrieve delivered companies with their prospects
  4. Set up incremental sync using time-based filtering

Prerequisites

Before you begin:

  • API Key: You need a valid API key starting with lnc_live_ (production) or lnc_test_ (sandbox)
  • Base URL: https://api.openprospect.io/api/v1

Getting an API Key

Contact your account manager to obtain API credentials, or create one in the dashboard under Settings > Developer > API Keys.


Step 1: Validate Your API Key

Before making other API calls, verify your API key works correctly.

curl -X GET "https://api.openprospect.io/api/v1/auth/validate" \
  -H "Authorization: Bearer YOUR_API_KEY"
import httpx

API_KEY = "lnc_live_your_api_key_here"
BASE_URL = "https://api.openprospect.io/api/v1"

response = httpx.get(
    f"{BASE_URL}/auth/validate",
    headers={"Authorization": f"Bearer {API_KEY}"}
)

if response.status_code == 200:
    data = response.json()
    print(f"API Key valid for organization: {data['organization_name']}")
    print(f"Available scopes: {data['scopes']}")
else:
    print(f"Error: {response.status_code}")
    print(response.json())
const API_KEY = "lnc_live_your_api_key_here";
const BASE_URL = "https://api.openprospect.io/api/v1";

const response = await fetch(`${BASE_URL}/auth/validate`, {
  headers: { "Authorization": `Bearer ${API_KEY}` }
});

if (response.ok) {
  const data = await response.json();
  console.log(`API Key valid for organization: ${data.organization_name}`);
  console.log(`Available scopes: ${data.scopes}`);
} else {
  console.error(`Error: ${response.status}`);
}
const API_KEY = "lnc_live_your_api_key_here";
const BASE_URL = "https://api.openprospect.io/api/v1";

interface ValidateResponse {
  valid: boolean;
  organization_id: string;
  organization_name: string;
  scopes: string[];
}

const response = await fetch(`${BASE_URL}/auth/validate`, {
  headers: { "Authorization": `Bearer ${API_KEY}` }
});

if (response.ok) {
  const data: ValidateResponse = await response.json();
  console.log(`API Key valid for organization: ${data.organization_name}`);
  console.log(`Available scopes: ${data.scopes}`);
} else {
  console.error(`Error: ${response.status}`);
}
using System.Net.Http.Headers;

var apiKey = "lnc_live_your_api_key_here";
var baseUrl = "https://api.openprospect.io/api/v1";

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

var response = await client.GetAsync($"{baseUrl}/auth/validate");

if (response.IsSuccessStatusCode)
{
    var json = await response.Content.ReadAsStringAsync();
    Console.WriteLine($"Response: {json}");
}
else
{
    Console.WriteLine($"Error: {response.StatusCode}");
}

Expected Response (200 OK):

{
  "valid": true,
  "organization_id": "8cc9e860-162c-4790-b79c-68d042fbee4d",
  "organization_name": "Your Organization",
  "scopes": [
    "companies:read",
    "prospects:read",
    "job_search:read"
  ]
}

Checkpoint

If you see "valid": true, your API key is working. Note the scopes array—you'll need companies:read and prospects:read to retrieve delivered leads.


Step 2: List Your Prospect Searches

Prospect searches define your Ideal Customer Profile (ICP). Each search has an ID you'll use to retrieve delivered companies.

curl -X GET "https://api.openprospect.io/api/v1/prospect-searches/?organization_mode=true&limit=10" \
  -H "Authorization: Bearer YOUR_API_KEY"
response = httpx.get(
    f"{BASE_URL}/prospect-searches/",
    params={"organization_mode": "true", "limit": 10},
    headers={"Authorization": f"Bearer {API_KEY}"}
)

searches = response.json()
for search in searches["items"]:
    print(f"ID: {search['id']}")
    print(f"Name: {search['name']}")
    print(f"Status: {search['status']}")
    print("---")
const response = await fetch(
  `${BASE_URL}/prospect-searches/?organization_mode=true&limit=10`,
  { headers: { "Authorization": `Bearer ${API_KEY}` } }
);

const searches = await response.json();
for (const search of searches.items) {
  console.log(`ID: ${search.id}`);
  console.log(`Name: ${search.name}`);
  console.log(`Status: ${search.status}`);
  console.log("---");
}
interface ProspectSearch {
  id: string;
  name: string;
  status: string;
  created_at: string;
}

interface SearchListResponse {
  items: ProspectSearch[];
  total: number;
  limit: number;
  offset: number;
}

const response = await fetch(
  `${BASE_URL}/prospect-searches/?organization_mode=true&limit=10`,
  { headers: { "Authorization": `Bearer ${API_KEY}` } }
);

const searches: SearchListResponse = await response.json();
for (const search of searches.items) {
  console.log(`ID: ${search.id}`);
  console.log(`Name: ${search.name}`);
  console.log(`Status: ${search.status}`);
}
var response = await client.GetAsync(
    $"{baseUrl}/prospect-searches/?organization_mode=true&limit=10");

if (response.IsSuccessStatusCode)
{
    var json = await response.Content.ReadAsStringAsync();
    var searches = JsonSerializer.Deserialize<SearchListResponse>(json);

    foreach (var search in searches.Items)
    {
        Console.WriteLine($"ID: {search.Id}");
        Console.WriteLine($"Name: {search.Name}");
        Console.WriteLine($"Status: {search.Status}");
        Console.WriteLine("---");
    }
}

// Response classes
public record SearchListResponse(
    List<ProspectSearch> Items,
    int Total,
    int Limit,
    int Offset
);

public record ProspectSearch(
    string Id,
    string Name,
    string Status,
    DateTime CreatedAt
);

Expected Response:

{
  "items": [
    {
      "id": "b7146435-6b29-432e-9719-f5ec7b8255d6",
      "name": "Enterprise SaaS Companies - DACH Region",
      "status": "active",
      "created_at": "2025-10-19T10:58:39.071477Z"
    }
  ],
  "total": 1,
  "limit": 10,
  "offset": 0
}

Note the ID

Save the id of the prospect search you want to sync. You'll use it in the next step.


Step 3: Retrieve Delivered Companies

This is the core integration endpoint. It returns companies that have been qualified and delivered, along with their prospects (contacts).

# Replace {prospect_search_id} with your actual ID
curl -X GET "https://api.openprospect.io/api/v1/deliveries/{prospect_search_id}/companies?limit=50" \
  -H "Authorization: Bearer YOUR_API_KEY"
prospect_search_id = "b7146435-6b29-432e-9719-f5ec7b8255d6"

response = httpx.get(
    f"{BASE_URL}/deliveries/{prospect_search_id}/companies",
    params={"limit": 50},
    headers={"Authorization": f"Bearer {API_KEY}"}
)

data = response.json()
print(f"Total companies: {data['total']}")
print(f"Has more pages: {data['has_more']}")

for company in data["items"]:
    print(f"\nCompany: {company['name']}")
    print(f"Website: {company['website_url']}")
    print(f"Employees: {company.get('employee_count', 'N/A')}")

    # Prospects (contacts) are embedded in the company
    for prospect in company.get("prospects", []):
        print(f"  - {prospect['first_name']} {prospect['last_name']}")
        print(f"    Title: {prospect['job_title']}")
        print(f"    Email: {prospect.get('email', 'N/A')}")
const prospectSearchId = "b7146435-6b29-432e-9719-f5ec7b8255d6";

const response = await fetch(
  `${BASE_URL}/deliveries/${prospectSearchId}/companies?limit=50`,
  { headers: { "Authorization": `Bearer ${API_KEY}` } }
);

const data = await response.json();
console.log(`Total companies: ${data.total}`);
console.log(`Has more pages: ${data.has_more}`);

for (const company of data.items) {
  console.log(`\nCompany: ${company.name}`);
  console.log(`Website: ${company.website_url}`);
  console.log(`Employees: ${company.employee_count ?? "N/A"}`);

  for (const prospect of company.prospects ?? []) {
    console.log(`  - ${prospect.first_name} ${prospect.last_name}`);
    console.log(`    Title: ${prospect.job_title}`);
    console.log(`    Email: ${prospect.email ?? "N/A"}`);
  }
}
interface LegalRegistrationInfo {
  company_name: string;
  legal_form: string;
  legal_form_code?: string;
  register_type: string;
  registration_number: string;
  registration_court: string;
  full_address?: string;
  business_purpose?: string;
  founding_date?: string;
  share_capital_amount?: string;
  share_capital_currency?: string;
  status: string;
  is_dissolved: boolean;
  dissolution_date?: string;
  dissolution_reason?: string;
}

interface Prospect {
  id: string;
  company_id: string;
  first_name: string;
  last_name?: string;
  job_title?: string;
  biography?: string;
  email?: string;
  phone_number?: string;
  linkedin_url?: string;
  social_media_profiles?: { url: string; platform: string }[];
  qualification_score?: number;
  qualification_reason?: string;
  email_type?: string;
  validation_confidence?: number;
  bounce_risk_score?: number;
  created_at?: string;
  updated_at?: string;
}

interface Company {
  id: string;
  name: string;
  website_url?: string;
  normalized_url?: string;
  business_type?: string;
  street?: string;
  city?: string;
  postal_code?: string;
  state?: string;
  country?: string;
  latitude?: number;
  longitude?: number;
  description?: string;
  mission_statement?: string;
  employee_count?: number;
  phone_numbers?: string[];
  additional_phone_numbers?: { number: string; type: string }[];
  social_media_links?: { url: string; platform: string }[];
  match_score?: number;
  match_reasons?: string[];
  match_reasoning?: string;
  review_rating?: number;
  review_count?: number;
  web_technologies?: string[];
  web_technologies_analyzed_at?: string;
  email_antispam_protection: boolean;
  review_status?: string;
  reviewed_at?: string;
  created_at?: string;
  updated_at?: string;
  legal_registration_info?: LegalRegistrationInfo;
  prospects: Prospect[];
}

interface DeliveredCompaniesResponse {
  items: Company[];
  total: number;
  limit: number;
  offset: number;
  has_more: boolean;
}

const prospectSearchId = "b7146435-6b29-432e-9719-f5ec7b8255d6";

const response = await fetch(
  `${BASE_URL}/deliveries/${prospectSearchId}/companies?limit=50`,
  { headers: { "Authorization": `Bearer ${API_KEY}` } }
);

const data: DeliveredCompaniesResponse = await response.json();
console.log(`Total companies: ${data.total}`);

for (const company of data.items) {
  console.log(`\nCompany: ${company.name}`);
  console.log(`Match Score: ${company.match_score}/100`);
  console.log(`Technologies: ${company.web_technologies?.join(", ")}`);

  for (const prospect of company.prospects) {
    console.log(`  - ${prospect.first_name} ${prospect.last_name}`);
    console.log(`    Email: ${prospect.email} (${prospect.email_type})`);
    console.log(`    Qualification: ${prospect.qualification_score}/100`);
  }
}
var prospectSearchId = "b7146435-6b29-432e-9719-f5ec7b8255d6";

var response = await client.GetAsync(
    $"{baseUrl}/deliveries/{prospectSearchId}/companies?limit=50");

if (response.IsSuccessStatusCode)
{
    var json = await response.Content.ReadAsStringAsync();
    var options = new JsonSerializerOptions
    {
        PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
        PropertyNameCaseInsensitive = true
    };
    var data = JsonSerializer.Deserialize<DeliveredCompaniesResponse>(json, options);

    Console.WriteLine($"Total companies: {data.Total}");
    Console.WriteLine($"Has more pages: {data.HasMore}");

    foreach (var company in data.Items)
    {
        Console.WriteLine($"\nCompany: {company.Name}");
        Console.WriteLine($"Website: {company.WebsiteUrl}");
        Console.WriteLine($"Match Score: {company.MatchScore}/100");
        Console.WriteLine($"Technologies: {string.Join(", ", company.WebTechnologies ?? [])}");

        foreach (var prospect in company.Prospects ?? [])
        {
            Console.WriteLine($"  - {prospect.FirstName} {prospect.LastName}");
            Console.WriteLine($"    Title: {prospect.JobTitle}");
            Console.WriteLine($"    Email: {prospect.Email} ({prospect.EmailType})");
            Console.WriteLine($"    Qualification: {prospect.QualificationScore}/100");
        }
    }
}

// Response classes with full schema
public record DeliveredCompaniesResponse(
    List<Company> Items,
    int Total,
    int Limit,
    int Offset,
    bool HasMore
);

public record LegalRegistrationInfo(
    string CompanyName,
    string LegalForm,
    string? LegalFormCode,
    string RegisterType,
    string RegistrationNumber,
    string RegistrationCourt,
    string? FullAddress,
    string? BusinessPurpose,
    string? FoundingDate,
    string? ShareCapitalAmount,
    string? ShareCapitalCurrency,
    string Status,
    bool IsDissolved,
    string? DissolutionDate,
    string? DissolutionReason
);

public record Company(
    string Id,
    string Name,
    string? WebsiteUrl,
    string? NormalizedUrl,
    string? BusinessType,
    string? Street,
    string? City,
    string? PostalCode,
    string? State,
    string? Country,
    double? Latitude,
    double? Longitude,
    string? Description,
    string? MissionStatement,
    int? EmployeeCount,
    List<string>? PhoneNumbers,
    List<Dictionary<string, string>>? AdditionalPhoneNumbers,
    List<Dictionary<string, string>>? SocialMediaLinks,
    int? MatchScore,
    List<string>? MatchReasons,
    string? MatchReasoning,
    double? ReviewRating,
    int? ReviewCount,
    List<string>? WebTechnologies,
    DateTime? WebTechnologiesAnalyzedAt,
    bool EmailAntispamProtection,
    string? ReviewStatus,
    DateTime? ReviewedAt,
    DateTime? CreatedAt,
    DateTime? UpdatedAt,
    LegalRegistrationInfo? LegalRegistrationInfo,
    List<Prospect>? Prospects
);

public record Prospect(
    string Id,
    string CompanyId,
    string FirstName,
    string? LastName,
    string? JobTitle,
    string? Biography,
    string? Email,
    string? PhoneNumber,
    string? LinkedinUrl,
    List<Dictionary<string, string>>? SocialMediaProfiles,
    int? QualificationScore,
    string? QualificationReason,
    string? EmailType,
    int? ValidationConfidence,
    int? BounceRiskScore,
    DateTime? CreatedAt,
    DateTime? UpdatedAt
);

Example Response:

{
  "items": [
    {
      "id": "a45e6452-496e-4bb3-86a0-3c99475c0fc3",
      "name": "Acme Technologies GmbH",
      "website_url": "https://www.acme-tech.de/",
      "normalized_url": "acme-tech.de",
      "business_type": "Software Development",
      "street": "MaximilianstraĂźe 35",
      "city": "Munich",
      "postal_code": "80539",
      "state": "Bayern",
      "country": "Germany",
      "latitude": 48.1371,
      "longitude": 11.5754,
      "description": "Acme Technologies is a leading provider of enterprise software solutions, specializing in cloud-native applications and digital transformation services.",
      "mission_statement": "Empowering businesses through innovative technology",
      "employee_count": 115,
      "phone_numbers": ["+49 89 12345678"],
      "additional_phone_numbers": [
        {"number": "+49 89 12345680", "type": "Sales"},
        {"number": "+49 89 12345681", "type": "Support"}
      ],
      "social_media_links": [
        {"url": "https://linkedin.com/company/acme-tech", "platform": "linkedin"},
        {"url": "https://twitter.com/acmetech", "platform": "twitter"}
      ],
      "match_score": 85,
      "match_reasons": [
        "Industry: Software Development",
        "Company size: 100-200 employees",
        "Location: DACH region",
        "Technology stack includes target technologies"
      ],
      "match_reasoning": "Strong ICP fit based on industry vertical, company size, and geographic location. Uses modern tech stack with React and AWS.",
      "review_rating": 4.5,
      "review_count": 127,
      "web_technologies": ["React", "Next.js", "AWS", "PostgreSQL", "Stripe", "HubSpot"],
      "web_technologies_analyzed_at": "2025-11-01T14:30:00Z",
      "email_antispam_protection": false,
      "review_status": "accepted",
      "reviewed_at": "2025-11-02T10:15:00Z",
      "legal_registration_info": {
        "company_name": "Acme Technologies GmbH",
        "legal_form": "GmbH",
        "legal_form_code": "GmbH",
        "register_type": "HRB",
        "registration_number": "123456",
        "registration_court": "MĂĽnchen",
        "full_address": "MaximilianstraĂźe 35, 80539 MĂĽnchen",
        "business_purpose": "Development, sale and distribution of software solutions and related consulting services",
        "founding_date": "2015-03-15",
        "share_capital_amount": "100000.00",
        "share_capital_currency": "EUR",
        "status": "active",
        "is_dissolved": false,
        "dissolution_date": null,
        "dissolution_reason": null
      },
      "prospects": [
        {
          "id": "e5fd4873-02a1-4ed7-aa75-6a2daa04ccf2",
          "company_id": "a45e6452-496e-4bb3-86a0-3c99475c0fc3",
          "first_name": "Max",
          "last_name": "Mustermann",
          "job_title": "Chief Executive Officer",
          "biography": "Experienced tech entrepreneur with 15+ years in enterprise software. Previously founded two successful SaaS startups.",
          "email": "max.mustermann@acme-tech.de",
          "phone_number": "+49 89 12345679",
          "linkedin_url": "https://linkedin.com/in/maxmustermann",
          "social_media_profiles": [
            {"url": "https://twitter.com/maxmustermann", "platform": "twitter"}
          ],
          "qualification_score": 92,
          "qualification_reason": "C-level executive with decision-making authority. Direct budget control for software purchases.",
          "email_type": "PERSONAL",
          "validation_confidence": 98,
          "bounce_risk_score": 2,
          "created_at": "2025-11-02T15:39:01.194907Z",
          "updated_at": "2025-11-02T20:31:43.088315Z"
        },
        {
          "id": "f8a12345-6789-4abc-def0-123456789abc",
          "company_id": "a45e6452-496e-4bb3-86a0-3c99475c0fc3",
          "first_name": "Anna",
          "last_name": "Schmidt",
          "job_title": "Chief Technology Officer",
          "biography": "Technical leader with deep expertise in cloud architecture and distributed systems.",
          "email": "anna.schmidt@acme-tech.de",
          "phone_number": "+49 89 12345682",
          "linkedin_url": "https://linkedin.com/in/annaschmidt",
          "social_media_profiles": null,
          "qualification_score": 88,
          "qualification_reason": "Technical decision maker. Directly involved in technology vendor selection.",
          "email_type": "PERSONAL",
          "validation_confidence": 95,
          "bounce_risk_score": 5,
          "created_at": "2025-11-02T15:40:15.123456Z",
          "updated_at": "2025-11-02T20:31:43.088315Z"
        }
      ],
      "created_at": "2025-11-02T15:39:01.194907Z",
      "updated_at": "2025-11-02T20:31:43.088315Z"
    }
  ],
  "total": 50,
  "limit": 50,
  "offset": 0,
  "has_more": false
}

Step 4: Incremental Sync with delivered_since

For ongoing synchronization, use the delivered_since parameter to fetch only new companies since your last sync.

# Fetch companies delivered after November 1, 2025
curl -X GET "https://api.openprospect.io/api/v1/deliveries/{prospect_search_id}/companies?delivered_since=2025-11-01T00:00:00Z&limit=100" \
  -H "Authorization: Bearer YOUR_API_KEY"
from datetime import datetime, timedelta, UTC

# Get companies delivered in the last 24 hours
since = (datetime.now(UTC) - timedelta(days=1)).isoformat()

response = httpx.get(
    f"{BASE_URL}/deliveries/{prospect_search_id}/companies",
    params={
        "delivered_since": since,
        "limit": 100
    },
    headers={"Authorization": f"Bearer {API_KEY}"}
)

data = response.json()
print(f"New companies since {since}: {data['total']}")
// Get companies delivered in the last 24 hours
const since = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();

const response = await fetch(
  `${BASE_URL}/deliveries/${prospectSearchId}/companies?delivered_since=${since}&limit=100`,
  { headers: { "Authorization": `Bearer ${API_KEY}` } }
);

const data = await response.json();
console.log(`New companies since ${since}: ${data.total}`);
// Get companies delivered in the last 24 hours
const since = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();

const response = await fetch(
  `${BASE_URL}/deliveries/${prospectSearchId}/companies?delivered_since=${since}&limit=100`,
  { headers: { "Authorization": `Bearer ${API_KEY}` } }
);

const data: DeliveredCompaniesResponse = await response.json();
console.log(`New companies since ${since}: ${data.total}`);
// Get companies delivered in the last 24 hours
var since = DateTime.UtcNow.AddDays(-1).ToString("o");

var response = await client.GetAsync(
    $"{baseUrl}/deliveries/{prospectSearchId}/companies?delivered_since={since}&limit=100");

if (response.IsSuccessStatusCode)
{
    var json = await response.Content.ReadAsStringAsync();
    var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
    var data = JsonSerializer.Deserialize<DeliveredCompaniesResponse>(json, options);

    Console.WriteLine($"New companies since {since}: {data.Total}");
}

Sync Strategy

Store the timestamp of your last successful sync. On subsequent runs, use that timestamp as delivered_since to fetch only new data.


Pagination

For large result sets, use limit and offset parameters:

def fetch_all_companies(prospect_search_id: str, delivered_since: str = None):
    """Fetch all companies with pagination."""
    all_companies = []
    offset = 0
    limit = 100

    while True:
        params = {"limit": limit, "offset": offset}
        if delivered_since:
            params["delivered_since"] = delivered_since

        response = httpx.get(
            f"{BASE_URL}/deliveries/{prospect_search_id}/companies",
            params=params,
            headers={"Authorization": f"Bearer {API_KEY}"}
        )

        data = response.json()
        all_companies.extend(data["items"])

        if not data["has_more"]:
            break

        offset += limit

    return all_companies

Error Handling

All API responses include an X-Request-Id header for debugging.

Common Error Codes

Status Code Description
401 UNAUTHORIZED Invalid or missing API key
403 FORBIDDEN API key lacks required scopes
404 NOT_FOUND Prospect search not found
422 VALIDATION_ERROR Invalid request parameters
429 RATE_LIMITED Too many requests

Error Response Format

{
  "error": "UNAUTHORIZED",
  "message": "Invalid API key",
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}

Python Error Handling Example

def handle_api_error(response: httpx.Response) -> None:
    """Handle API errors with proper error messages."""
    if response.status_code == 401:
        raise Exception("Invalid API key. Check your credentials.")
    elif response.status_code == 403:
        raise Exception("Insufficient permissions. Check your API key scopes.")
    elif response.status_code == 404:
        raise Exception("Resource not found. Check the prospect search ID.")
    elif response.status_code == 429:
        raise Exception("Rate limited. Wait and retry.")
    elif response.status_code >= 400:
        error = response.json()
        request_id = response.headers.get("x-request-id", "unknown")
        raise Exception(
            f"API Error: {error.get('message')} "
            f"(Request ID: {request_id})"
        )

# Usage
response = httpx.get(...)
if response.status_code >= 400:
    handle_api_error(response)

Complete Integration Example

Here's a complete script for syncing delivered leads to your system:

"""
OpenProspect API Integration Example
Syncs delivered companies and prospects to your CRM.
"""
import httpx
from datetime import datetime, UTC

# Configuration
API_KEY = "lnc_live_your_api_key_here"
BASE_URL = "https://api.openprospect.io/api/v1"
PROSPECT_SEARCH_ID = "your-prospect-search-id"

def get_headers():
    return {"Authorization": f"Bearer {API_KEY}"}

def validate_credentials():
    """Validate API credentials before starting sync."""
    response = httpx.get(
        f"{BASE_URL}/auth/validate",
        headers=get_headers()
    )

    if response.status_code != 200:
        raise Exception(f"Authentication failed: {response.json()}")

    data = response.json()
    print(f"Authenticated as: {data['organization_name']}")
    return data

def fetch_delivered_companies(delivered_since: str = None):
    """Fetch all delivered companies with pagination."""
    all_companies = []
    offset = 0
    limit = 100

    while True:
        params = {"limit": limit, "offset": offset}
        if delivered_since:
            params["delivered_since"] = delivered_since

        response = httpx.get(
            f"{BASE_URL}/deliveries/{PROSPECT_SEARCH_ID}/companies",
            params=params,
            headers=get_headers()
        )

        if response.status_code != 200:
            raise Exception(f"API Error: {response.json()}")

        data = response.json()
        all_companies.extend(data["items"])

        print(f"Fetched {len(all_companies)}/{data['total']} companies")

        if not data["has_more"]:
            break

        offset += limit

    return all_companies

def sync_to_crm(company: dict):
    """
    Replace this with your actual CRM integration.
    Example: HubSpot, Salesforce, Pipedrive, etc.
    """
    print(f"Syncing: {company['name']}")
    for prospect in company.get("prospects", []):
        print(f"  - {prospect['first_name']} {prospect['last_name']} ({prospect.get('email', 'No email')})")

def main():
    # Step 1: Validate credentials
    validate_credentials()

    # Step 2: Fetch companies (use delivered_since for incremental sync)
    # Example: Fetch companies delivered in the last 7 days
    # since = (datetime.now(UTC) - timedelta(days=7)).isoformat()
    companies = fetch_delivered_companies()

    # Step 3: Sync to your CRM
    for company in companies:
        sync_to_crm(company)

    print(f"\nSync complete! Processed {len(companies)} companies.")

if __name__ == "__main__":
    main()
using System.Net.Http.Headers;
using System.Text.Json;
using System.Text.Json.Serialization;

/// <summary>
/// OpenProspect API Integration Example
/// Syncs delivered companies and prospects to your CRM.
/// </summary>
public class OpenProspectSync
{
    private const string ApiKey = "lnc_live_your_api_key_here";
    private const string BaseUrl = "https://api.openprospect.io/api/v1";
    private const string ProspectSearchId = "your-prospect-search-id";

    private readonly HttpClient _client;
    private readonly JsonSerializerOptions _jsonOptions;

    public OpenProspectSync()
    {
        _client = new HttpClient();
        _client.DefaultRequestHeaders.Authorization =
            new AuthenticationHeaderValue("Bearer", ApiKey);

        _jsonOptions = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
            PropertyNameCaseInsensitive = true
        };
    }

    public async Task<bool> ValidateCredentialsAsync()
    {
        var response = await _client.GetAsync($"{BaseUrl}/auth/validate");

        if (!response.IsSuccessStatusCode)
        {
            Console.WriteLine($"Authentication failed: {response.StatusCode}");
            return false;
        }

        var json = await response.Content.ReadAsStringAsync();
        var data = JsonSerializer.Deserialize<ValidateResponse>(json, _jsonOptions);

        Console.WriteLine($"Authenticated as: {data?.OrganizationName}");
        return true;
    }

    public async Task<List<Company>> FetchDeliveredCompaniesAsync(DateTime? deliveredSince = null)
    {
        var allCompanies = new List<Company>();
        var offset = 0;
        const int limit = 100;

        while (true)
        {
            var url = $"{BaseUrl}/deliveries/{ProspectSearchId}/companies?limit={limit}&offset={offset}";
            if (deliveredSince.HasValue)
            {
                url += $"&delivered_since={deliveredSince.Value:o}";
            }

            var response = await _client.GetAsync(url);

            if (!response.IsSuccessStatusCode)
            {
                throw new Exception($"API Error: {response.StatusCode}");
            }

            var json = await response.Content.ReadAsStringAsync();
            var data = JsonSerializer.Deserialize<DeliveredCompaniesResponse>(json, _jsonOptions);

            if (data?.Items != null)
            {
                allCompanies.AddRange(data.Items);
            }

            Console.WriteLine($"Fetched {allCompanies.Count}/{data?.Total} companies");

            if (data?.HasMore != true)
            {
                break;
            }

            offset += limit;
        }

        return allCompanies;
    }

    public void SyncToCrm(Company company)
    {
        // Replace this with your actual CRM integration
        // Example: HubSpot, Salesforce, Pipedrive, etc.
        Console.WriteLine($"Syncing: {company.Name}");

        foreach (var prospect in company.Prospects ?? new List<Prospect>())
        {
            Console.WriteLine($"  - {prospect.FirstName} {prospect.LastName} ({prospect.Email ?? "No email"})");
        }
    }

    public async Task RunAsync()
    {
        // Step 1: Validate credentials
        if (!await ValidateCredentialsAsync())
        {
            return;
        }

        // Step 2: Fetch companies (use deliveredSince for incremental sync)
        // Example: Fetch companies delivered in the last 7 days
        // var since = DateTime.UtcNow.AddDays(-7);
        var companies = await FetchDeliveredCompaniesAsync();

        // Step 3: Sync to your CRM
        foreach (var company in companies)
        {
            SyncToCrm(company);
        }

        Console.WriteLine($"\nSync complete! Processed {companies.Count} companies.");
    }

    public static async Task Main(string[] args)
    {
        var sync = new OpenProspectSync();
        await sync.RunAsync();
    }
}

// Response classes with full schema
public record ValidateResponse(
    bool Valid,
    string OrganizationId,
    string OrganizationName,
    List<string> Scopes
);

public record DeliveredCompaniesResponse(
    List<Company> Items,
    int Total,
    int Limit,
    int Offset,
    bool HasMore
);

public record LegalRegistrationInfo(
    string CompanyName,
    string LegalForm,
    string? LegalFormCode,
    string RegisterType,
    string RegistrationNumber,
    string RegistrationCourt,
    string? FullAddress,
    string? BusinessPurpose,
    string? FoundingDate,
    string? ShareCapitalAmount,
    string? ShareCapitalCurrency,
    string Status,
    bool IsDissolved,
    string? DissolutionDate,
    string? DissolutionReason
);

public record Company(
    string Id,
    string Name,
    string? WebsiteUrl,
    string? NormalizedUrl,
    string? BusinessType,
    string? Street,
    string? City,
    string? PostalCode,
    string? State,
    string? Country,
    double? Latitude,
    double? Longitude,
    string? Description,
    string? MissionStatement,
    int? EmployeeCount,
    List<string>? PhoneNumbers,
    List<Dictionary<string, string>>? AdditionalPhoneNumbers,
    List<Dictionary<string, string>>? SocialMediaLinks,
    int? MatchScore,
    List<string>? MatchReasons,
    string? MatchReasoning,
    double? ReviewRating,
    int? ReviewCount,
    List<string>? WebTechnologies,
    DateTime? WebTechnologiesAnalyzedAt,
    bool EmailAntispamProtection,
    string? ReviewStatus,
    DateTime? ReviewedAt,
    DateTime? CreatedAt,
    DateTime? UpdatedAt,
    LegalRegistrationInfo? LegalRegistrationInfo,
    List<Prospect>? Prospects
);

public record Prospect(
    string Id,
    string CompanyId,
    string FirstName,
    string? LastName,
    string? JobTitle,
    string? Biography,
    string? Email,
    string? PhoneNumber,
    string? LinkedinUrl,
    List<Dictionary<string, string>>? SocialMediaProfiles,
    int? QualificationScore,
    string? QualificationReason,
    string? EmailType,
    int? ValidationConfidence,
    int? BounceRiskScore,
    DateTime? CreatedAt,
    DateTime? UpdatedAt
);
/**
 * OpenProspect API Integration Example
 * Syncs delivered companies and prospects to your CRM.
 */

const API_KEY = "lnc_live_your_api_key_here";
const BASE_URL = "https://api.openprospect.io/api/v1";
const PROSPECT_SEARCH_ID = "your-prospect-search-id";

// Full schema interfaces
interface ValidateResponse {
  valid: boolean;
  organization_id: string;
  organization_name: string;
  scopes: string[];
}

interface LegalRegistrationInfo {
  company_name: string;
  legal_form: string;
  legal_form_code?: string;
  register_type: string;
  registration_number: string;
  registration_court: string;
  full_address?: string;
  business_purpose?: string;
  founding_date?: string;
  share_capital_amount?: string;
  share_capital_currency?: string;
  status: string;
  is_dissolved: boolean;
  dissolution_date?: string;
  dissolution_reason?: string;
}

interface Prospect {
  id: string;
  company_id: string;
  first_name: string;
  last_name?: string;
  job_title?: string;
  biography?: string;
  email?: string;
  phone_number?: string;
  linkedin_url?: string;
  social_media_profiles?: { url: string; platform: string }[];
  qualification_score?: number;
  qualification_reason?: string;
  email_type?: string;
  validation_confidence?: number;
  bounce_risk_score?: number;
  created_at?: string;
  updated_at?: string;
}

interface Company {
  id: string;
  name: string;
  website_url?: string;
  normalized_url?: string;
  business_type?: string;
  street?: string;
  city?: string;
  postal_code?: string;
  state?: string;
  country?: string;
  latitude?: number;
  longitude?: number;
  description?: string;
  mission_statement?: string;
  employee_count?: number;
  phone_numbers?: string[];
  additional_phone_numbers?: { number: string; type: string }[];
  social_media_links?: { url: string; platform: string }[];
  match_score?: number;
  match_reasons?: string[];
  match_reasoning?: string;
  review_rating?: number;
  review_count?: number;
  web_technologies?: string[];
  web_technologies_analyzed_at?: string;
  email_antispam_protection: boolean;
  review_status?: string;
  reviewed_at?: string;
  created_at?: string;
  updated_at?: string;
  legal_registration_info?: LegalRegistrationInfo;
  prospects: Prospect[];
}

interface DeliveredCompaniesResponse {
  items: Company[];
  total: number;
  limit: number;
  offset: number;
  has_more: boolean;
}

async function validateCredentials(): Promise<boolean> {
  const response = await fetch(`${BASE_URL}/auth/validate`, {
    headers: { "Authorization": `Bearer ${API_KEY}` }
  });

  if (!response.ok) {
    console.error(`Authentication failed: ${response.status}`);
    return false;
  }

  const data: ValidateResponse = await response.json();
  console.log(`Authenticated as: ${data.organization_name}`);
  return true;
}

async function fetchDeliveredCompanies(deliveredSince?: string): Promise<Company[]> {
  const allCompanies: Company[] = [];
  let offset = 0;
  const limit = 100;

  while (true) {
    let url = `${BASE_URL}/deliveries/${PROSPECT_SEARCH_ID}/companies?limit=${limit}&offset=${offset}`;
    if (deliveredSince) {
      url += `&delivered_since=${deliveredSince}`;
    }

    const response = await fetch(url, {
      headers: { "Authorization": `Bearer ${API_KEY}` }
    });

    if (!response.ok) {
      throw new Error(`API Error: ${response.status}`);
    }

    const data: DeliveredCompaniesResponse = await response.json();
    allCompanies.push(...data.items);

    console.log(`Fetched ${allCompanies.length}/${data.total} companies`);

    if (!data.has_more) {
      break;
    }

    offset += limit;
  }

  return allCompanies;
}

function syncToCrm(company: Company): void {
  // Replace this with your actual CRM integration
  // Example: HubSpot, Salesforce, Pipedrive, etc.
  console.log(`Syncing: ${company.name}`);
  console.log(`  Match Score: ${company.match_score}/100`);
  console.log(`  Technologies: ${company.web_technologies?.join(", ") ?? "N/A"}`);

  for (const prospect of company.prospects ?? []) {
    console.log(`  - ${prospect.first_name} ${prospect.last_name}`);
    console.log(`    Email: ${prospect.email ?? "N/A"} (${prospect.email_type ?? "unknown"})`);
    console.log(`    Qualification: ${prospect.qualification_score ?? "N/A"}/100`);
  }
}

async function main(): Promise<void> {
  // Step 1: Validate credentials
  if (!await validateCredentials()) {
    return;
  }

  // Step 2: Fetch companies (use deliveredSince for incremental sync)
  // Example: Fetch companies delivered in the last 7 days
  // const since = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();
  const companies = await fetchDeliveredCompanies();

  // Step 3: Sync to your CRM
  for (const company of companies) {
    syncToCrm(company);
  }

  console.log(`\nSync complete! Processed ${companies.length} companies.`);
}

main().catch(console.error);

Next Steps


Support

If you encounter issues:

  1. Check the X-Request-Id header in the response
  2. Include this ID when contacting support
  3. Email: support@openprospect.io