Skip to content

Enrichment Order Guide

Submit your company list, get back enriched data with contacts, technologies, and more.


Overview

Enrichment orders let you submit a list of companies you already know and get back structured data: company profiles, decision-maker contacts, technology stacks, legal registration data, and AI-powered match scoring.

The workflow is simple:

  1. Create an order with your company list
  2. Track the order status (polling or webhook)
  3. Retrieve enriched results via the order endpoint

Order Lifecycle

stateDiagram-v2
    [*] --> RECEIVED: Create order
    RECEIVED --> ACCEPTED: Admin review
    RECEIVED --> CANCELLED: Cancel
    ACCEPTED --> IN_PROGRESS: Enrichment starts
    ACCEPTED --> CANCELLED: Cancel
    IN_PROGRESS --> COMPLETED: All enrichment finished
    IN_PROGRESS --> CANCELLED: Cancel
    COMPLETED --> [*]
    CANCELLED --> [*]
Status What It Means
RECEIVED Your order is queued for admin review
ACCEPTED Approved and enrichment pipeline is starting
IN_PROGRESS Enrichment is actively running
COMPLETED All data is ready — retrieve your results
CANCELLED Order was cancelled

Prerequisites

Before you begin:

  • API Key with orders:read and orders:write scopes. Create one in the OpenProspect dashboard under Settings > Developer > API Keys.
  • Base URL: https://api.openprospect.io/api/v1

Scopes

Enrichment orders only need two scopes: orders:read and orders:write. No other scopes are required.


Step 1: Create an Order

Submit your company list with the enrichment features you want.

Request

POST /api/v1/orders/

curl -X POST "https://api.openprospect.io/api/v1/orders/" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Q1 2026 Hotel Prospects",
    "features": ["COMPANY_DATA", "CONTACTS", "TECHNOLOGIES"],
    "profile_name": "Hotel Enrichment Q1",
    "companies": [
      {
        "company_name": "Grand Hotel Berlin",
        "external_id": "CRM-1001",
        "website_url": "https://www.grandhotel-berlin.de",
        "city": "Berlin",
        "country": "Germany"
      },
      {
        "company_name": "Alpine Resort Innsbruck",
        "external_id": "CRM-1002",
        "city": "Innsbruck",
        "country": "Austria"
      }
    ]
  }'
import httpx

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

order = {
    "title": "Q1 2026 Hotel Prospects",
    "features": ["COMPANY_DATA", "CONTACTS", "TECHNOLOGIES"],
    "profile_name": "Hotel Enrichment Q1",
    "companies": [
        {
            "company_name": "Grand Hotel Berlin",
            "external_id": "CRM-1001",
            "website_url": "https://www.grandhotel-berlin.de",
            "city": "Berlin",
            "country": "Germany",
        },
        {
            "company_name": "Alpine Resort Innsbruck",
            "external_id": "CRM-1002",
            "city": "Innsbruck",
            "country": "Austria",
        },
    ],
}

response = httpx.post(
    f"{BASE_URL}/orders/",
    json=order,
    headers={"Authorization": f"Bearer {API_KEY}"},
)

if response.status_code == 202:
    data = response.json()
    print(f"Order created: {data['order_id']}")
    print(f"Status: {data['status']}")
else:
    print(f"Error {response.status_code}: {response.json()}")
const API_KEY = "lnc_live_your_api_key_here";
const BASE_URL = "https://api.openprospect.io/api/v1";

const order = {
  title: "Q1 2026 Hotel Prospects",
  features: ["COMPANY_DATA", "CONTACTS", "TECHNOLOGIES"],
  profile_name: "Hotel Enrichment Q1",
  companies: [
    {
      company_name: "Grand Hotel Berlin",
      external_id: "CRM-1001",
      website_url: "https://www.grandhotel-berlin.de",
      city: "Berlin",
      country: "Germany",
    },
    {
      company_name: "Alpine Resort Innsbruck",
      external_id: "CRM-1002",
      city: "Innsbruck",
      country: "Austria",
    },
  ],
};

const response = await fetch(`${BASE_URL}/orders/`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(order),
});

if (response.status === 202) {
  const data = await response.json();
  console.log(`Order created: ${data.order_id}`);
  console.log(`Status: ${data.status}`);
} else {
  console.error(`Error ${response.status}:`, await response.json());
}
const API_KEY = "lnc_live_your_api_key_here";
const BASE_URL = "https://api.openprospect.io/api/v1";

interface CreateOrderResponse {
  order_id: string;
  status: string;
  company_count: number;
  estimated_cost: { total: number; currency: string } | null;
  message: string;
}

const order = {
  title: "Q1 2026 Hotel Prospects",
  features: ["COMPANY_DATA", "CONTACTS", "TECHNOLOGIES"],
  profile_name: "Hotel Enrichment Q1",
  companies: [
    {
      company_name: "Grand Hotel Berlin",
      external_id: "CRM-1001",
      website_url: "https://www.grandhotel-berlin.de",
      city: "Berlin",
      country: "Germany",
    },
    {
      company_name: "Alpine Resort Innsbruck",
      external_id: "CRM-1002",
      city: "Innsbruck",
      country: "Austria",
    },
  ],
};

const response = await fetch(`${BASE_URL}/orders/`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(order),
});

if (response.status === 202) {
  const data: CreateOrderResponse = await response.json();
  console.log(`Order created: ${data.order_id}`);
  console.log(`Status: ${data.status}`);
} else {
  console.error(`Error ${response.status}:`, await response.json());
}
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;

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

var order = new
{
    title = "Q1 2026 Hotel Prospects",
    features = new[] { "COMPANY_DATA", "CONTACTS", "TECHNOLOGIES" },
    profile_name = "Hotel Enrichment Q1",
    companies = new[]
    {
        new
        {
            company_name = "Grand Hotel Berlin",
            external_id = "CRM-1001",
            website_url = "https://www.grandhotel-berlin.de",
            city = "Berlin",
            country = "Germany"
        },
        new
        {
            company_name = "Alpine Resort Innsbruck",
            external_id = "CRM-1002",
            city = (string?)null,
            website_url = (string?)null,
            // city and country can be provided without a URL
        }
    }
};

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

var json = JsonSerializer.Serialize(order);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync($"{baseUrl}/orders/", content);

if ((int)response.StatusCode == 202)
{
    var body = await response.Content.ReadAsStringAsync();
    Console.WriteLine($"Order created: {body}");
}
else
{
    Console.WriteLine($"Error {(int)response.StatusCode}");
    Console.WriteLine(await response.Content.ReadAsStringAsync());
}

Response (202 Accepted)

{
  "order_id": "4f767705-03a2-4e91-a3e8-1ec3f9dea865",
  "status": "RECEIVED",
  "company_count": 2,
  "estimated_cost": null,
  "message": "Order received. Awaiting admin review."
}

Checkpoint

Save the order_id from the response. You need it for all subsequent calls.

Company Fields

Each company in the companies array accepts these fields:

Field Type Required Description
company_name string Yes Company name (max 500 chars)
external_id string No Your CRM ID for this company. Returned as source_id in results. Auto-generated if omitted.
website_url string No Company website. If missing, we attempt to discover it automatically.
postal_code string No Postal/ZIP code
city string No City name
street string No Street address
country string No Country name or ISO code
email string No Contact email
phone string No Contact phone number
employee_count integer No Number of employees
industry_code string No SIC or industry code
industry_description string No Industry description

Providing website_url

If you have the company's website URL, always include it. It significantly improves enrichment quality and speed. Without it, we use automated search to discover the URL, which can occasionally find the wrong site for companies with ambiguous names.

Request Parameters

Parameter Type Required Description
title string Yes A descriptive name for your order
features string[] Yes Enrichment features to apply (see Features Reference)
profile_name string No Name for a new enrichment profile (auto-created). Mutually exclusive with profile_id. If neither is provided, a profile is auto-created from the order title.
profile_id UUID No ID of an existing enrichment profile. Mutually exclusive with profile_name.
priority string No NORMAL (default) or EXPRESS
webhook_url string No URL for status change notifications (see Webhooks)
ideal_customer_profile string No ICP description for targeting (improves match scoring)
contact_roles string[] No Target contact roles (e.g., ["CEO", "CTO", "Head of Sales"])
companies object[] Yes 1 to 10,000 companies

Step 2: Track Order Status

After creating an order, poll the status endpoint to know when results are ready.

Request

GET /api/v1/orders/{order_id}

curl -X GET "https://api.openprospect.io/api/v1/orders/4f767705-03a2-4e91-a3e8-1ec3f9dea865" \
  -H "Authorization: Bearer YOUR_API_KEY"
import time

order_id = "4f767705-03a2-4e91-a3e8-1ec3f9dea865"

while True:
    response = httpx.get(
        f"{BASE_URL}/orders/{order_id}",
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    data = response.json()
    status = data["status"]
    print(f"Order status: {status}")

    if status == "COMPLETED":
        print("Results are ready!")
        break
    elif status == "CANCELLED":
        print("Order was cancelled.")
        break

    time.sleep(60)  # Check every minute
const orderId = "4f767705-03a2-4e91-a3e8-1ec3f9dea865";

async function pollOrderStatus() {
  while (true) {
    const response = await fetch(`${BASE_URL}/orders/${orderId}`, {
      headers: { Authorization: `Bearer ${API_KEY}` },
    });
    const data = await response.json();
    console.log(`Order status: ${data.status}`);

    if (data.status === "COMPLETED") {
      console.log("Results are ready!");
      return data;
    }
    if (data.status === "CANCELLED") {
      console.log("Order was cancelled.");
      return data;
    }

    await new Promise((resolve) => setTimeout(resolve, 60000));
  }
}

await pollOrderStatus();
interface OrderStatusResponse {
  order_id: string;
  title: string;
  status: "RECEIVED" | "ACCEPTED" | "IN_PROGRESS" | "COMPLETED" | "CANCELLED";
  priority: string;
  company_count: number;
  features: string[];
  estimated_cost: { total: number; currency: string } | null;
  prospect_search_id: string | null;
  admin_notes: string | null;
  webhook_url: string | null;
  created_at: string;
  accepted_at: string | null;
  completed_at: string | null;
  cancelled_at: string | null;
}

const orderId = "4f767705-03a2-4e91-a3e8-1ec3f9dea865";

async function pollOrderStatus(): Promise<OrderStatusResponse> {
  while (true) {
    const response = await fetch(`${BASE_URL}/orders/${orderId}`, {
      headers: { Authorization: `Bearer ${API_KEY}` },
    });
    const data: OrderStatusResponse = await response.json();
    console.log(`Order status: ${data.status}`);

    if (data.status === "COMPLETED" || data.status === "CANCELLED") {
      return data;
    }

    await new Promise((resolve) => setTimeout(resolve, 60000));
  }
}

const result = await pollOrderStatus();
var orderId = "4f767705-03a2-4e91-a3e8-1ec3f9dea865";

while (true)
{
    var response = await client.GetAsync($"{baseUrl}/orders/{orderId}");
    var body = await response.Content.ReadAsStringAsync();
    var data = JsonSerializer.Deserialize<JsonElement>(body);
    var status = data.GetProperty("status").GetString();

    Console.WriteLine($"Order status: {status}");

    if (status == "COMPLETED")
    {
        Console.WriteLine("Results are ready!");
        break;
    }
    if (status == "CANCELLED")
    {
        Console.WriteLine("Order was cancelled.");
        break;
    }

    await Task.Delay(60000); // Check every minute
}

Response (200 OK)

{
  "order_id": "4f767705-03a2-4e91-a3e8-1ec3f9dea865",
  "title": "Q1 2026 Hotel Prospects",
  "status": "COMPLETED",
  "priority": "NORMAL",
  "company_count": 2,
  "features": ["COMPANY_DATA", "CONTACTS", "TECHNOLOGIES"],
  "estimated_cost": null,
  "prospect_search_id": "42665897-b189-4e0f-8841-499351a30aff",
  "admin_notes": null,
  "webhook_url": null,
  "created_at": "2026-02-25T10:30:00.000000Z",
  "accepted_at": "2026-02-25T10:45:00.000000Z",
  "completed_at": "2026-02-25T12:00:00.000000Z",
  "cancelled_at": null
}

Checkpoint

When status is COMPLETED, proceed to Step 3 to retrieve your enriched data.

List All Orders

You can also list all your orders with optional status filtering:

curl -X GET "https://api.openprospect.io/api/v1/orders/?status=COMPLETED&limit=10" \
  -H "Authorization: Bearer YOUR_API_KEY"

Step 3: Retrieve Results

Once the order is COMPLETED, retrieve your enriched companies with all their data.

Request

GET /api/v1/orders/{order_id}/results

curl -X GET "https://api.openprospect.io/api/v1/orders/4f767705-03a2-4e91-a3e8-1ec3f9dea865/results?limit=50" \
  -H "Authorization: Bearer YOUR_API_KEY"
order_id = "4f767705-03a2-4e91-a3e8-1ec3f9dea865"
all_companies = []
offset = 0
limit = 50

while True:
    response = httpx.get(
        f"{BASE_URL}/orders/{order_id}/results",
        params={"limit": limit, "offset": offset},
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    data = response.json()

    for company in data["items"]:
        print(f"Company: {company['name']}")
        print(f"  Source ID: {company['source_id']}")
        print(f"  Match Score: {company['match_score']}")
        print(f"  Prospects: {len(company['prospects'])}")
        all_companies.append(company)

    if not data["has_more"]:
        break
    offset += limit

print(f"\nTotal companies retrieved: {len(all_companies)}")
const orderId = "4f767705-03a2-4e91-a3e8-1ec3f9dea865";
const allCompanies = [];
let offset = 0;
const limit = 50;

while (true) {
  const response = await fetch(
    `${BASE_URL}/orders/${orderId}/results?limit=${limit}&offset=${offset}`,
    { headers: { Authorization: `Bearer ${API_KEY}` } }
  );
  const data = await response.json();

  for (const company of data.items) {
    console.log(`Company: ${company.name}`);
    console.log(`  Source ID: ${company.source_id}`);
    console.log(`  Match Score: ${company.match_score}`);
    console.log(`  Prospects: ${company.prospects.length}`);
    allCompanies.push(company);
  }

  if (!data.has_more) break;
  offset += limit;
}

console.log(`\nTotal companies retrieved: ${allCompanies.length}`);
interface Prospect {
  id: string;
  company_id: string;
  first_name: string;
  last_name: string | null;
  job_title: string | null;
  email: string | null;
  phone_number: string | null;
  linkedin_url: string | null;
  qualification_score: number | null;
  qualification_reason: string | null;
  email_type: string | null;
  validation_confidence: number | null;
  bounce_risk_score: number | null;
}

interface Company {
  id: string;
  name: string;
  website_url: string | null;
  business_type: string | null;
  city: string | null;
  country: string | null;
  description: string | null;
  employee_count: number | null;
  phone_numbers: string[] | null;
  social_media_links: { platform: string; url: string }[] | null;
  match_score: number | null;
  match_reasons: string[] | null;
  web_technologies: string[] | null;
  source_id: string | null;
  delivered_at: string | null;
  legal_registration_info: Record<string, unknown> | null;
  prospects: Prospect[];
}

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

const orderId = "4f767705-03a2-4e91-a3e8-1ec3f9dea865";
const allCompanies: Company[] = [];
let offset = 0;
const limit = 50;

while (true) {
  const response = await fetch(
    `${BASE_URL}/orders/${orderId}/results?limit=${limit}&offset=${offset}`,
    { headers: { Authorization: `Bearer ${API_KEY}` } }
  );
  const data: ResultsResponse = await response.json();
  allCompanies.push(...data.items);

  if (!data.has_more) break;
  offset += limit;
}

console.log(`Total companies: ${allCompanies.length}`);
var orderId = "4f767705-03a2-4e91-a3e8-1ec3f9dea865";
var offset = 0;
var limit = 50;
var allCompanies = new List<JsonElement>();

while (true)
{
    var response = await client.GetAsync(
        $"{baseUrl}/orders/{orderId}/results?limit={limit}&offset={offset}");
    var body = await response.Content.ReadAsStringAsync();
    var data = JsonSerializer.Deserialize<JsonElement>(body);

    foreach (var company in data.GetProperty("items").EnumerateArray())
    {
        Console.WriteLine($"Company: {company.GetProperty("name")}");
        Console.WriteLine($"  Source ID: {company.GetProperty("source_id")}");
        allCompanies.Add(company);
    }

    if (!data.GetProperty("has_more").GetBoolean()) break;
    offset += limit;
}

Console.WriteLine($"\nTotal companies: {allCompanies.Count}");

Response (200 OK)

{
  "items": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "name": "Grand Hotel Berlin",
      "website_url": "https://www.grandhotel-berlin.de",
      "normalized_url": "grandhotel-berlin.de",
      "business_type": "Hotel",
      "city": "Berlin",
      "country": "Germany",
      "description": "A luxury 5-star hotel in the heart of Berlin...",
      "employee_count": 120,
      "phone_numbers": ["+49 30 12345678"],
      "social_media_links": [
        {"platform": "facebook", "url": "https://facebook.com/grandhotelberlin"},
        {"platform": "instagram", "url": "https://instagram.com/grandhotelberlin"}
      ],
      "match_score": 8,
      "match_reasons": ["Industry match", "Size match", "Location match"],
      "match_reasoning": "The company operates a luxury hotel in Berlin...",
      "web_technologies": ["WordPress", "Google Analytics", "Cloudflare"],
      "web_technologies_analyzed_at": "2026-02-25T11:30:00.000000Z",
      "source_id": "CRM-1001",
      "delivered_at": "2026-02-25T11:45:00.000000Z",
      "legal_registration_info": null,
      "prospects": [
        {
          "id": "e5f6a7b8-c9d0-1234-e5f6-a7b8c9d01234",
          "company_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
          "first_name": "Maria",
          "last_name": "Schmidt",
          "job_title": "General Manager",
          "email": "m.schmidt@grandhotel-berlin.de",
          "phone_number": null,
          "linkedin_url": "https://linkedin.com/in/mariaschmidt",
          "qualification_score": 9,
          "qualification_reason": "Senior decision maker in hotel management",
          "email_type": "PERSONAL",
          "validation_confidence": 95,
          "bounce_risk_score": 5
        }
      ]
    }
  ],
  "total": 2,
  "limit": 50,
  "offset": 0,
  "has_more": false
}

Checkpoint

You should see your companies with enriched data. Each company's source_id matches the external_id you submitted — use this to sync results back to your CRM.

Correlating Results to Your CRM

The external_id you submit with each company is returned as source_id in the results. This is your correlation key:

You Submit You Get Back Use For
"external_id": "CRM-1001" "source_id": "CRM-1001" Match enriched data to your CRM record

Incremental Sync

For large orders or ongoing syncs, use the delivered_since parameter to fetch only new results:

curl -X GET "https://api.openprospect.io/api/v1/orders/{order_id}/results?delivered_since=2026-02-25T12:00:00Z" \
  -H "Authorization: Bearer YOUR_API_KEY"

Pagination

Results are paginated. Use limit and offset to page through large result sets:

Parameter Default Range Description
limit 50 1-100 Companies per page
offset 0 0+ Number of companies to skip
delivered_since - ISO 8601 Only companies delivered after this timestamp

The response includes has_more: true when there are additional pages.


Webhook Notifications

Instead of polling, you can receive status change notifications via webhook.

Setup

Include a webhook_url when creating your order:

{
  "title": "Q1 2026 Hotel Prospects",
  "features": ["COMPANY_DATA", "CONTACTS"],
  "profile_name": "Hotel Enrichment Q1",
  "webhook_url": "https://your-api.com/webhooks/openprospect",
  "companies": [...]
}

Webhook Payload

When the order status changes, we send a POST request to your URL:

{
  "event": "order.status_changed",
  "order_id": "4f767705-03a2-4e91-a3e8-1ec3f9dea865",
  "status": "COMPLETED",
  "previous_status": "IN_PROGRESS",
  "timestamp": "2026-02-25T12:00:00.000000+00:00"
}

You receive a notification for every status transition:

Transition When
RECEIVEDACCEPTED Admin approves your order
ACCEPTEDIN_PROGRESS Enrichment starts
IN_PROGRESSCOMPLETED All enrichment finished — retrieve your results

Retry Policy

If your endpoint returns a 5xx error or is unreachable, we retry up to 3 times. Design your webhook handler to be idempotent.

Testing Webhooks

Use webhook.site to generate a temporary URL for testing. You can inspect every payload we send.

Webhook Security

For production use, verify webhook authenticity using one of these approaches:

Option 1: URL token — Include a secret token as a query parameter:

https://your-api.com/webhooks/openprospect?token=your_secret_token

Verify this token on your server before processing the payload.

Option 2: Organization-level Authorization header — Configure a default webhook URL and Authorization header for your organization via the notification settings endpoints. This header is sent with every webhook delivery.

Organization Notification Settings

You can configure organization-wide webhook settings (URL, auth header, email notifications) through the OpenProspect dashboard. When set, these apply to all orders unless overridden by an order-level webhook_url.


Enrichment Features

Choose which data you want by including features in the features array.

Available Features

Feature What You Get
COMPANY_DATA Company profile: description, employee count, phone numbers, social media, reviews, favicon
CONTACTS Decision-maker contacts: names, job titles, LinkedIn profiles, qualification scores
TECHNOLOGIES Web technology stack: CMS, analytics tools, frameworks, marketing platforms
JOBS Active job postings from the company (used for hiring signal analysis)
HANDELSREGISTER German commercial register data: legal form, registration, capital, founding date
ANALYSIS AI match scoring: how well the company fits your ICP, with detailed reasoning
EMAIL_DISCOVERY Validated email addresses for discovered contacts
EMAIL_GENERATION AI-generated personalized outreach emails for contacts

Feature Dependencies

Some features build on others for best results:

COMPANY_DATA ──> CONTACTS ──> EMAIL_DISCOVERY
     |                |              |
     |                └──> EMAIL_GENERATION
     |
     ├──> TECHNOLOGIES
     ├──> JOBS
     ├──> HANDELSREGISTER (German companies only)
     └──> ANALYSIS (benefits from all other data)

COMPANY_DATA is the foundation — it crawls the company website and extracts structured data. Most other features depend on this data being available.

Recommended Combinations

For a standard enrichment order, use ["COMPANY_DATA", "CONTACTS", "ANALYSIS"]. Add "TECHNOLOGIES" if you need technology stack data, or "EMAIL_DISCOVERY" if you need verified email addresses.

What Each Feature Returns

COMPANY_DATA

Populates the company profile fields in the response:

  • description, business_type, employee_count
  • phone_numbers, social_media_links
  • review_rating, review_count
  • street, city, postal_code, country
  • favicon_url

CONTACTS

Populates the prospects array on each company:

  • first_name, last_name, job_title
  • linkedin_url, phone_number
  • qualification_score (0-10), qualification_reason

TECHNOLOGIES

Populates the technology fields:

  • web_technologies (e.g., ["WordPress", "Google Analytics", "React"])
  • web_technologies_analyzed_at

HANDELSREGISTER

Populates legal_registration_info (German companies only):

  • company_name, legal_form, registration_number, registration_court
  • founding_date, share_capital_amount, business_purpose
  • status, is_dissolved

ANALYSIS

Populates the match scoring fields:

  • match_score (0-10)
  • match_reasons (e.g., ["Industry match", "Size match"])
  • match_reasoning (detailed AI explanation)

EMAIL_DISCOVERY

Populates email fields on each prospect:

  • email, email_type (PERSONAL, GENERAL, ROLE)
  • validation_confidence (0-100), bounce_risk_score (0-100)

Error Handling

Error Response Formats

The API uses consistent error formats per status code:

Authentication Error (401)

{
  "error": "UNAUTHORIZED",
  "message": "Invalid or expired API key",
  "request_id": "abc123-def456"
}

Cause: Invalid API key, expired key, or missing Authorization header.

Resolution: Verify your API key in the OpenProspect dashboard. Ensure the header format is Authorization: Bearer lnc_live_....

Insufficient Permissions (403)

{
  "code": "AUTHORIZATION_ERROR",
  "message": "Insufficient permissions. Required scopes: orders:write",
  "required_scopes": ["orders:write"],
  "user_scopes": ["orders:read"]
}

Cause: Your API key is missing required scopes.

Resolution: Create a new API key with both orders:read and orders:write scopes in the dashboard.

Not Found (404)

{
  "code": "ORDER_NOT_FOUND",
  "message": "Order with identifier 00000000-0000-0000-0000-000000000000 not found",
  "resource_type": "Order",
  "identifier": "00000000-0000-0000-0000-000000000000"
}

Cause: The order ID does not exist or belongs to a different organization.

Resolution: Verify the order_id from the create order response.

Validation Error (422)

{
  "detail": [
    {
      "type": "too_short",
      "loc": ["body", "companies"],
      "msg": "List should have at least 1 item after validation, not 0",
      "input": [],
      "ctx": {"field_name": "List", "min_length": 1, "actual_length": 0}
    }
  ]
}

Cause: Request body fails validation.

Common validation errors:

Error Cause Fix
companies too short Empty companies list Provide at least 1 company
Invalid feature Unrecognized feature name Use one of the 8 valid feature names
Missing company_name Company without a name Every company must have company_name
Duplicate features Same feature listed twice Remove duplicates from the features array
Profile conflict Both profile_id and profile_name provided Use one or the other, not both

Limitations and FAQ

How long does enrichment take?

Enrichment time depends on the number of companies and features requested. Typical processing times:

Order Size Features Approximate Time
1-10 companies COMPANY_DATA, CONTACTS Minutes
50-100 companies COMPANY_DATA, CONTACTS, TECHNOLOGIES 1-2 hours
500+ companies Full feature set Several hours

Orders are processed by our admin team. You receive a webhook notification (or can poll) when processing completes.

Can I cancel an order?

Not directly via the API. Contact support if you need to cancel an order.

Can I resubmit a failed company?

Create a new order with the companies you want to retry. Each order is independent.

What happens if a company website is not found?

If you do not provide a website_url, we attempt to discover it via automated web search. If no website is found, the company is still imported but will have limited enrichment data (only the fields you provided in the order).

What is the maximum order size?

10,000 companies per order. For larger batches, create multiple orders.

Do I need profile_id or profile_name?

Use profile_name to auto-create a new enrichment profile for your order. Use profile_id if you want to reuse an existing profile. You can provide at most one of the two. If you omit both, a profile is auto-created from the order title.


API Reference Summary

Method Path Scope Description
POST /api/v1/orders/ orders:write Create enrichment order (202)
GET /api/v1/orders/ orders:read List your orders
GET /api/v1/orders/{order_id} orders:read Get order status
GET /api/v1/orders/{order_id}/results orders:read Get enriched results