Python SDK Enrichment: Developer Quickstart Guide

Python SDK quickstart for Databar enrichment. Install, authenticate, run single lookups, batch enrichment, and waterfall

Jan Berning

Head of Growth at Databar

Blog

— min read

Python SDK Enrichment: Developer Quickstart Guide

Python SDK quickstart for Databar enrichment. Install, authenticate, run single lookups, batch enrichment, and waterfall

Jan Berning

Head of Growth at Databar

Blog

— min read

Unlock the full potential of your data with the world’s most comprehensive no-code API tool.

You want to run enrichment from Python. Maybe you are building it into a data pipeline, a CRM integration, or a lead qualification workflow. The Databar Python SDK gives you programmatic access to 100+ data providers through a single interface. This enrichment quickstart gets you from install to first result in under 10 minutes.

This guide covers installation, authentication, single lookups, batch enrichment, waterfall cascades, response parsing, and error handling. Every code example is production-ready.

Installation

Install the SDK via pip:

pip install databar
pip install databar
pip install databar
pip install databar

Requirements: Python 3.8+. No additional dependencies beyond what pip installs automatically.

Verify the installation:

pip show databar
pip show databar
pip show databar
pip show databar

Authentication

Every API call requires an API key. Get yours from the Databar dashboard under Settings → API Keys.

from databar import Databar

client = Databar(api_key="your_api_key_here")
from databar import Databar

client = Databar(api_key="your_api_key_here")
from databar import Databar

client = Databar(api_key="your_api_key_here")
from databar import Databar

client = Databar(api_key="your_api_key_here")

For production, store your API key in an environment variable:

import os
from databar import Databar

client = Databar(api_key=os.environ["DATABAR_API_KEY"])
import os
from databar import Databar

client = Databar(api_key=os.environ["DATABAR_API_KEY"])
import os
from databar import Databar

client = Databar(api_key=os.environ["DATABAR_API_KEY"])
import os
from databar import Databar

client = Databar(api_key=os.environ["DATABAR_API_KEY"])

The client handles authentication headers, base URL configuration, and session management. You create it once and reuse it across your application.

Single Contact Enrichment

The simplest use case: enrich one contact by email.

result = client.enrich(
    email="jane@acme.com",
    providers=["clearbit", "apollo"],
    fields=["name", "title", "company", "phone", "linkedin"]
)

print(result.name)        # "Jane Smith"
print(result.title)       # "VP of Revenue Operations"
print(result.company)     # "Acme Corp"
print(result.phone)       # "+1-555-0123"
print(result.linkedin)    # "linkedin.com/in/janesmith"
print(result.provider)    # "clearbit" (which provider returned the data)
print(result.confidence)  # 0.92
result = client.enrich(
    email="jane@acme.com",
    providers=["clearbit", "apollo"],
    fields=["name", "title", "company", "phone", "linkedin"]
)

print(result.name)        # "Jane Smith"
print(result.title)       # "VP of Revenue Operations"
print(result.company)     # "Acme Corp"
print(result.phone)       # "+1-555-0123"
print(result.linkedin)    # "linkedin.com/in/janesmith"
print(result.provider)    # "clearbit" (which provider returned the data)
print(result.confidence)  # 0.92
result = client.enrich(
    email="jane@acme.com",
    providers=["clearbit", "apollo"],
    fields=["name", "title", "company", "phone", "linkedin"]
)

print(result.name)        # "Jane Smith"
print(result.title)       # "VP of Revenue Operations"
print(result.company)     # "Acme Corp"
print(result.phone)       # "+1-555-0123"
print(result.linkedin)    # "linkedin.com/in/janesmith"
print(result.provider)    # "clearbit" (which provider returned the data)
print(result.confidence)  # 0.92
result = client.enrich(
    email="jane@acme.com",
    providers=["clearbit", "apollo"],
    fields=["name", "title", "company", "phone", "linkedin"]
)

print(result.name)        # "Jane Smith"
print(result.title)       # "VP of Revenue Operations"
print(result.company)     # "Acme Corp"
print(result.phone)       # "+1-555-0123"
print(result.linkedin)    # "linkedin.com/in/janesmith"
print(result.provider)    # "clearbit" (which provider returned the data)
print(result.confidence)  # 0.92

The providers parameter specifies which data providers to query. The fields parameter limits the response to only the data you need. Both are optional. If omitted, Databar uses defaults based on the enrichment type.

Company Enrichment

Enrich a company by domain:

company = client.enrich_company(
    domain="acme.com",
    fields=["name", "industry", "employee_count", "funding_total",
            "tech_stack", "revenue_estimate"]
)

print(company.name)              # "Acme Corp"
print(company.industry)          # "SaaS"
print(company.employee_count)    # 340
print(company.funding_total)     # 45000000
print(company.tech_stack)        # ["Salesforce", "HubSpot", "Snowflake"]
print(company.revenue_estimate)  # "10M-50M"
company = client.enrich_company(
    domain="acme.com",
    fields=["name", "industry", "employee_count", "funding_total",
            "tech_stack", "revenue_estimate"]
)

print(company.name)              # "Acme Corp"
print(company.industry)          # "SaaS"
print(company.employee_count)    # 340
print(company.funding_total)     # 45000000
print(company.tech_stack)        # ["Salesforce", "HubSpot", "Snowflake"]
print(company.revenue_estimate)  # "10M-50M"
company = client.enrich_company(
    domain="acme.com",
    fields=["name", "industry", "employee_count", "funding_total",
            "tech_stack", "revenue_estimate"]
)

print(company.name)              # "Acme Corp"
print(company.industry)          # "SaaS"
print(company.employee_count)    # 340
print(company.funding_total)     # 45000000
print(company.tech_stack)        # ["Salesforce", "HubSpot", "Snowflake"]
print(company.revenue_estimate)  # "10M-50M"
company = client.enrich_company(
    domain="acme.com",
    fields=["name", "industry", "employee_count", "funding_total",
            "tech_stack", "revenue_estimate"]
)

print(company.name)              # "Acme Corp"
print(company.industry)          # "SaaS"
print(company.employee_count)    # 340
print(company.funding_total)     # 45000000
print(company.tech_stack)        # ["Salesforce", "HubSpot", "Snowflake"]
print(company.revenue_estimate)  # "10M-50M"

Company enrichment pulls from firmographic, technographic, and funding providers in a single call. See our guide on multi-source enrichment for details on how providers combine.

Waterfall Enrichment

A waterfall cascades through multiple providers in sequence until one returns a result. This is the core pattern for maximizing match rates while minimizing cost.

email_result = client.waterfall(
    enrichment_type="email_finder",
    inputs={
        "first_name": "Jane",
        "last_name": "Smith",
        "domain": "acme.com"
    },
    providers=["hunter", "findymail", "prospeo", "snov",
               "apollo", "contactout", "rocketreach", "icypeas", "datagma"]
)

print(email_result.email)       # "jane.smith@acme.com"
print(email_result.verified)    # True
print(email_result.provider)    # "hunter" (first provider that matched)
print(email_result.confidence)  # 0.95
email_result = client.waterfall(
    enrichment_type="email_finder",
    inputs={
        "first_name": "Jane",
        "last_name": "Smith",
        "domain": "acme.com"
    },
    providers=["hunter", "findymail", "prospeo", "snov",
               "apollo", "contactout", "rocketreach", "icypeas", "datagma"]
)

print(email_result.email)       # "jane.smith@acme.com"
print(email_result.verified)    # True
print(email_result.provider)    # "hunter" (first provider that matched)
print(email_result.confidence)  # 0.95
email_result = client.waterfall(
    enrichment_type="email_finder",
    inputs={
        "first_name": "Jane",
        "last_name": "Smith",
        "domain": "acme.com"
    },
    providers=["hunter", "findymail", "prospeo", "snov",
               "apollo", "contactout", "rocketreach", "icypeas", "datagma"]
)

print(email_result.email)       # "jane.smith@acme.com"
print(email_result.verified)    # True
print(email_result.provider)    # "hunter" (first provider that matched)
print(email_result.confidence)  # 0.95
email_result = client.waterfall(
    enrichment_type="email_finder",
    inputs={
        "first_name": "Jane",
        "last_name": "Smith",
        "domain": "acme.com"
    },
    providers=["hunter", "findymail", "prospeo", "snov",
               "apollo", "contactout", "rocketreach", "icypeas", "datagma"]
)

print(email_result.email)       # "jane.smith@acme.com"
print(email_result.verified)    # True
print(email_result.provider)    # "hunter" (first provider that matched)
print(email_result.confidence)  # 0.95

The waterfall processes providers in the order you specify. It stops at the first successful match. You only pay for the provider that returns the result. Read more about waterfall enrichment and provider ordering strategy.

Batch Enrichment

For lists of contacts, use batch enrichment. It processes multiple contacts in parallel with automatic rate limit management.

contacts = [
    {"email": "jane@acme.com"},
    {"email": "bob@widgets.io"},
    {"email": "sarah@startup.co"},
    # ... up to thousands of contacts
]

batch = client.enrich_batch(
    contacts=contacts,
    providers=["clearbit", "apollo", "pdl"],
    fields=["name", "title", "company", "phone"]
)

# Poll for completion
batch.wait()  # Blocks until batch completes

# Access results
for result in batch.results:
    print(f"{result.email}: {result.name}, {result.title} at {result.company}")
contacts = [
    {"email": "jane@acme.com"},
    {"email": "bob@widgets.io"},
    {"email": "sarah@startup.co"},
    # ... up to thousands of contacts
]

batch = client.enrich_batch(
    contacts=contacts,
    providers=["clearbit", "apollo", "pdl"],
    fields=["name", "title", "company", "phone"]
)

# Poll for completion
batch.wait()  # Blocks until batch completes

# Access results
for result in batch.results:
    print(f"{result.email}: {result.name}, {result.title} at {result.company}")
contacts = [
    {"email": "jane@acme.com"},
    {"email": "bob@widgets.io"},
    {"email": "sarah@startup.co"},
    # ... up to thousands of contacts
]

batch = client.enrich_batch(
    contacts=contacts,
    providers=["clearbit", "apollo", "pdl"],
    fields=["name", "title", "company", "phone"]
)

# Poll for completion
batch.wait()  # Blocks until batch completes

# Access results
for result in batch.results:
    print(f"{result.email}: {result.name}, {result.title} at {result.company}")
contacts = [
    {"email": "jane@acme.com"},
    {"email": "bob@widgets.io"},
    {"email": "sarah@startup.co"},
    # ... up to thousands of contacts
]

batch = client.enrich_batch(
    contacts=contacts,
    providers=["clearbit", "apollo", "pdl"],
    fields=["name", "title", "company", "phone"]
)

# Poll for completion
batch.wait()  # Blocks until batch completes

# Access results
for result in batch.results:
    print(f"{result.email}: {result.name}, {result.title} at {result.company}")

For large batches, use the async pattern instead of blocking:

# Start the batch
batch = client.enrich_batch(
    contacts=contacts,
    providers=["clearbit", "apollo"],
    fields=["name", "title", "company"]
)

# Check status without blocking
print(batch.status)       # "processing"
print(batch.progress)     # 0.45 (45% complete)
print(batch.estimated_time)  # 120 (seconds remaining)

# Or use a callback
batch.on_complete(lambda results: process_results(results))
# Start the batch
batch = client.enrich_batch(
    contacts=contacts,
    providers=["clearbit", "apollo"],
    fields=["name", "title", "company"]
)

# Check status without blocking
print(batch.status)       # "processing"
print(batch.progress)     # 0.45 (45% complete)
print(batch.estimated_time)  # 120 (seconds remaining)

# Or use a callback
batch.on_complete(lambda results: process_results(results))
# Start the batch
batch = client.enrich_batch(
    contacts=contacts,
    providers=["clearbit", "apollo"],
    fields=["name", "title", "company"]
)

# Check status without blocking
print(batch.status)       # "processing"
print(batch.progress)     # 0.45 (45% complete)
print(batch.estimated_time)  # 120 (seconds remaining)

# Or use a callback
batch.on_complete(lambda results: process_results(results))
# Start the batch
batch = client.enrich_batch(
    contacts=contacts,
    providers=["clearbit", "apollo"],
    fields=["name", "title", "company"]
)

# Check status without blocking
print(batch.status)       # "processing"
print(batch.progress)     # 0.45 (45% complete)
print(batch.estimated_time)  # 120 (seconds remaining)

# Or use a callback
batch.on_complete(lambda results: process_results(results))

Batch enrichment is the right choice for lists of 100+ contacts. It is significantly faster than looping single lookups because Databar parallelizes across providers and manages rate limits server-side. See batch vs real-time enrichment for when to use each.

Batch Waterfall Enrichment

Combine batch and waterfall for the highest coverage on large lists:

contacts = [
    {"first_name": "Jane", "last_name": "Smith", "domain": "acme.com"},
    {"first_name": "Bob", "last_name": "Johnson", "domain": "widgets.io"},
    # ...
]

batch = client.waterfall_batch(
    enrichment_type="email_finder",
    contacts=contacts,
    providers=["hunter", "findymail", "prospeo", "snov",
               "apollo", "contactout", "rocketreach"]
)

batch.wait()

for result in batch.results:
    if result.found:
        print(f"{result.first_name} {result.last_name}: {result.email} "
              f"(via {result.provider}, verified: {result.verified})")
    else:
        print(f"{result.first_name} {result.last_name}: not found")
contacts = [
    {"first_name": "Jane", "last_name": "Smith", "domain": "acme.com"},
    {"first_name": "Bob", "last_name": "Johnson", "domain": "widgets.io"},
    # ...
]

batch = client.waterfall_batch(
    enrichment_type="email_finder",
    contacts=contacts,
    providers=["hunter", "findymail", "prospeo", "snov",
               "apollo", "contactout", "rocketreach"]
)

batch.wait()

for result in batch.results:
    if result.found:
        print(f"{result.first_name} {result.last_name}: {result.email} "
              f"(via {result.provider}, verified: {result.verified})")
    else:
        print(f"{result.first_name} {result.last_name}: not found")
contacts = [
    {"first_name": "Jane", "last_name": "Smith", "domain": "acme.com"},
    {"first_name": "Bob", "last_name": "Johnson", "domain": "widgets.io"},
    # ...
]

batch = client.waterfall_batch(
    enrichment_type="email_finder",
    contacts=contacts,
    providers=["hunter", "findymail", "prospeo", "snov",
               "apollo", "contactout", "rocketreach"]
)

batch.wait()

for result in batch.results:
    if result.found:
        print(f"{result.first_name} {result.last_name}: {result.email} "
              f"(via {result.provider}, verified: {result.verified})")
    else:
        print(f"{result.first_name} {result.last_name}: not found")
contacts = [
    {"first_name": "Jane", "last_name": "Smith", "domain": "acme.com"},
    {"first_name": "Bob", "last_name": "Johnson", "domain": "widgets.io"},
    # ...
]

batch = client.waterfall_batch(
    enrichment_type="email_finder",
    contacts=contacts,
    providers=["hunter", "findymail", "prospeo", "snov",
               "apollo", "contactout", "rocketreach"]
)

batch.wait()

for result in batch.results:
    if result.found:
        print(f"{result.first_name} {result.last_name}: {result.email} "
              f"(via {result.provider}, verified: {result.verified})")
    else:
        print(f"{result.first_name} {result.last_name}: not found")

Each contact runs through the full waterfall independently. Databar handles the parallel execution and rate limiting across all providers.

Response Parsing

Enrichment responses come back as typed objects with consistent field names regardless of which provider returned the data. Databar normalizes provider-specific field names into a standard schema.

result = client.enrich(email="jane@acme.com")

# Access as attributes
name = result.name
title = result.title

# Access as dictionary
data = result.to_dict()
print(data["name"])

# Check which fields were populated
print(result.populated_fields)  # ["name", "title", "company", "phone"]
print(result.missing_fields)    # ["linkedin", "twitter"]

# Get raw provider response (useful for debugging)
raw = result.raw_response
result = client.enrich(email="jane@acme.com")

# Access as attributes
name = result.name
title = result.title

# Access as dictionary
data = result.to_dict()
print(data["name"])

# Check which fields were populated
print(result.populated_fields)  # ["name", "title", "company", "phone"]
print(result.missing_fields)    # ["linkedin", "twitter"]

# Get raw provider response (useful for debugging)
raw = result.raw_response
result = client.enrich(email="jane@acme.com")

# Access as attributes
name = result.name
title = result.title

# Access as dictionary
data = result.to_dict()
print(data["name"])

# Check which fields were populated
print(result.populated_fields)  # ["name", "title", "company", "phone"]
print(result.missing_fields)    # ["linkedin", "twitter"]

# Get raw provider response (useful for debugging)
raw = result.raw_response
result = client.enrich(email="jane@acme.com")

# Access as attributes
name = result.name
title = result.title

# Access as dictionary
data = result.to_dict()
print(data["name"])

# Check which fields were populated
print(result.populated_fields)  # ["name", "title", "company", "phone"]
print(result.missing_fields)    # ["linkedin", "twitter"]

# Get raw provider response (useful for debugging)
raw = result.raw_response

Normalized fields mean you do not have to write provider-specific parsing logic. Whether the data came from Clearbit, Apollo, or PDL, the field names and types are identical.

Error Handling

Production code needs to handle failures gracefully. The SDK raises typed exceptions for different error conditions:

from databar import (
    Databar,
    AuthenticationError,
    RateLimitError,
    ProviderError,
    NotFoundError,
    ValidationError
)

client = Databar(api_key=os.environ["DATABAR_API_KEY"])

try:
    result = client.enrich(email="jane@acme.com")
except AuthenticationError:
    # Invalid or expired API key
    print("Check your DATABAR_API_KEY")
except RateLimitError as e:
    # You hit the platform rate limit (not provider rate limit)
    print(f"Rate limited. Retry after {e.retry_after} seconds")
except ProviderError as e:
    # A specific provider failed
    print(f"Provider {e.provider} returned error: {e.message}")
except NotFoundError:
    # No provider returned data for this input
    print("Contact not found across all providers")
except ValidationError as e:
    # Invalid input (bad email format, missing required fields)
    print(f"Invalid input: {e.message}")
from databar import (
    Databar,
    AuthenticationError,
    RateLimitError,
    ProviderError,
    NotFoundError,
    ValidationError
)

client = Databar(api_key=os.environ["DATABAR_API_KEY"])

try:
    result = client.enrich(email="jane@acme.com")
except AuthenticationError:
    # Invalid or expired API key
    print("Check your DATABAR_API_KEY")
except RateLimitError as e:
    # You hit the platform rate limit (not provider rate limit)
    print(f"Rate limited. Retry after {e.retry_after} seconds")
except ProviderError as e:
    # A specific provider failed
    print(f"Provider {e.provider} returned error: {e.message}")
except NotFoundError:
    # No provider returned data for this input
    print("Contact not found across all providers")
except ValidationError as e:
    # Invalid input (bad email format, missing required fields)
    print(f"Invalid input: {e.message}")
from databar import (
    Databar,
    AuthenticationError,
    RateLimitError,
    ProviderError,
    NotFoundError,
    ValidationError
)

client = Databar(api_key=os.environ["DATABAR_API_KEY"])

try:
    result = client.enrich(email="jane@acme.com")
except AuthenticationError:
    # Invalid or expired API key
    print("Check your DATABAR_API_KEY")
except RateLimitError as e:
    # You hit the platform rate limit (not provider rate limit)
    print(f"Rate limited. Retry after {e.retry_after} seconds")
except ProviderError as e:
    # A specific provider failed
    print(f"Provider {e.provider} returned error: {e.message}")
except NotFoundError:
    # No provider returned data for this input
    print("Contact not found across all providers")
except ValidationError as e:
    # Invalid input (bad email format, missing required fields)
    print(f"Invalid input: {e.message}")
from databar import (
    Databar,
    AuthenticationError,
    RateLimitError,
    ProviderError,
    NotFoundError,
    ValidationError
)

client = Databar(api_key=os.environ["DATABAR_API_KEY"])

try:
    result = client.enrich(email="jane@acme.com")
except AuthenticationError:
    # Invalid or expired API key
    print("Check your DATABAR_API_KEY")
except RateLimitError as e:
    # You hit the platform rate limit (not provider rate limit)
    print(f"Rate limited. Retry after {e.retry_after} seconds")
except ProviderError as e:
    # A specific provider failed
    print(f"Provider {e.provider} returned error: {e.message}")
except NotFoundError:
    # No provider returned data for this input
    print("Contact not found across all providers")
except ValidationError as e:
    # Invalid input (bad email format, missing required fields)
    print(f"Invalid input: {e.message}")

For batch enrichment, errors are per-contact, not per-batch:

batch.wait()

for result in batch.results:
    if result.error:
        print(f"Error for {result.email}: {result.error.message}")
    else:
        print(f"Found: {result.name} at {result.company}")
batch.wait()

for result in batch.results:
    if result.error:
        print(f"Error for {result.email}: {result.error.message}")
    else:
        print(f"Found: {result.name} at {result.company}")
batch.wait()

for result in batch.results:
    if result.error:
        print(f"Error for {result.email}: {result.error.message}")
    else:
        print(f"Found: {result.name} at {result.company}")
batch.wait()

for result in batch.results:
    if result.error:
        print(f"Error for {result.email}: {result.error.message}")
    else:
        print(f"Found: {result.name} at {result.company}")

Common Patterns

CRM Enrichment Pipeline

import csv

# Read contacts from CSV
with open("leads.csv") as f:
    contacts = list(csv.DictReader(f))

# Enrich in batch
batch = client.enrich_batch(
    contacts=[{"email": c["email"]} for c in contacts],
    fields=["name", "title", "company", "phone", "employee_count"]
)
batch.wait()

# Write enriched data back
with open("leads_enriched.csv", "w", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=[
        "email", "name", "title", "company", "phone", "employee_count"
    ])
    writer.writeheader()
    for result in batch.results:
        writer.writerow(result.to_dict())
import csv

# Read contacts from CSV
with open("leads.csv") as f:
    contacts = list(csv.DictReader(f))

# Enrich in batch
batch = client.enrich_batch(
    contacts=[{"email": c["email"]} for c in contacts],
    fields=["name", "title", "company", "phone", "employee_count"]
)
batch.wait()

# Write enriched data back
with open("leads_enriched.csv", "w", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=[
        "email", "name", "title", "company", "phone", "employee_count"
    ])
    writer.writeheader()
    for result in batch.results:
        writer.writerow(result.to_dict())
import csv

# Read contacts from CSV
with open("leads.csv") as f:
    contacts = list(csv.DictReader(f))

# Enrich in batch
batch = client.enrich_batch(
    contacts=[{"email": c["email"]} for c in contacts],
    fields=["name", "title", "company", "phone", "employee_count"]
)
batch.wait()

# Write enriched data back
with open("leads_enriched.csv", "w", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=[
        "email", "name", "title", "company", "phone", "employee_count"
    ])
    writer.writeheader()
    for result in batch.results:
        writer.writerow(result.to_dict())
import csv

# Read contacts from CSV
with open("leads.csv") as f:
    contacts = list(csv.DictReader(f))

# Enrich in batch
batch = client.enrich_batch(
    contacts=[{"email": c["email"]} for c in contacts],
    fields=["name", "title", "company", "phone", "employee_count"]
)
batch.wait()

# Write enriched data back
with open("leads_enriched.csv", "w", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=[
        "email", "name", "title", "company", "phone", "employee_count"
    ])
    writer.writeheader()
    for result in batch.results:
        writer.writerow(result.to_dict())

Real-Time Form Enrichment

from flask import Flask, request, jsonify

app = Flask(__name__)
client = Databar(api_key=os.environ["DATABAR_API_KEY"])

@app.route("/api/enrich-lead", methods=["POST"])
def enrich_lead():
    email = request.json["email"]

    try:
        result = client.enrich(
            email=email,
            fields=["name", "title", "company", "employee_count"],
            timeout=3000  # 3 second timeout
        )
        return jsonify(result.to_dict())
    except Exception:
        # Return partial data on failure
        return jsonify({"email": email, "enriched": False})
from flask import Flask, request, jsonify

app = Flask(__name__)
client = Databar(api_key=os.environ["DATABAR_API_KEY"])

@app.route("/api/enrich-lead", methods=["POST"])
def enrich_lead():
    email = request.json["email"]

    try:
        result = client.enrich(
            email=email,
            fields=["name", "title", "company", "employee_count"],
            timeout=3000  # 3 second timeout
        )
        return jsonify(result.to_dict())
    except Exception:
        # Return partial data on failure
        return jsonify({"email": email, "enriched": False})
from flask import Flask, request, jsonify

app = Flask(__name__)
client = Databar(api_key=os.environ["DATABAR_API_KEY"])

@app.route("/api/enrich-lead", methods=["POST"])
def enrich_lead():
    email = request.json["email"]

    try:
        result = client.enrich(
            email=email,
            fields=["name", "title", "company", "employee_count"],
            timeout=3000  # 3 second timeout
        )
        return jsonify(result.to_dict())
    except Exception:
        # Return partial data on failure
        return jsonify({"email": email, "enriched": False})
from flask import Flask, request, jsonify

app = Flask(__name__)
client = Databar(api_key=os.environ["DATABAR_API_KEY"])

@app.route("/api/enrich-lead", methods=["POST"])
def enrich_lead():
    email = request.json["email"]

    try:
        result = client.enrich(
            email=email,
            fields=["name", "title", "company", "employee_count"],
            timeout=3000  # 3 second timeout
        )
        return jsonify(result.to_dict())
    except Exception:
        # Return partial data on failure
        return jsonify({"email": email, "enriched": False})

Waterfall With Verification

Configuration Options

client = Databar(
    api_key=os.environ["DATABAR_API_KEY"],
    timeout=5000,       # Default timeout in ms for all requests
    max_retries=3,      # Retry failed requests up to 3 times
    retry_delay=1000,   # Wait 1 second between retries
    cache=True          # Use platform-level caching (default: True)
)
client = Databar(
    api_key=os.environ["DATABAR_API_KEY"],
    timeout=5000,       # Default timeout in ms for all requests
    max_retries=3,      # Retry failed requests up to 3 times
    retry_delay=1000,   # Wait 1 second between retries
    cache=True          # Use platform-level caching (default: True)
)
client = Databar(
    api_key=os.environ["DATABAR_API_KEY"],
    timeout=5000,       # Default timeout in ms for all requests
    max_retries=3,      # Retry failed requests up to 3 times
    retry_delay=1000,   # Wait 1 second between retries
    cache=True          # Use platform-level caching (default: True)
)
client = Databar(
    api_key=os.environ["DATABAR_API_KEY"],
    timeout=5000,       # Default timeout in ms for all requests
    max_retries=3,      # Retry failed requests up to 3 times
    retry_delay=1000,   # Wait 1 second between retries
    cache=True          # Use platform-level caching (default: True)
)

These defaults work for most use cases. Lower the timeout for real-time use cases. Increase max_retries for batch jobs where reliability matters more than speed.

Company Enrichment

Enrich companies alongside contacts to get firmographic data:

# Enrich a batch of companies
domains = ["acme.com", "widgets.io", "startup.co"]

company_batch = client.enrich_batch(
    contacts=[{"domain": d} for d in domains],
    enrichment_type="company",
    fields=["name", "industry", "employee_count", "funding_total",
            "tech_stack", "revenue_estimate", "founded_year"]
)
company_batch.wait()

for company in company_batch.results:
    print(f"{company.name}: {company.employee_count} employees, "
          f"{company.industry}, raised ${company.funding_total:,}")
# Enrich a batch of companies
domains = ["acme.com", "widgets.io", "startup.co"]

company_batch = client.enrich_batch(
    contacts=[{"domain": d} for d in domains],
    enrichment_type="company",
    fields=["name", "industry", "employee_count", "funding_total",
            "tech_stack", "revenue_estimate", "founded_year"]
)
company_batch.wait()

for company in company_batch.results:
    print(f"{company.name}: {company.employee_count} employees, "
          f"{company.industry}, raised ${company.funding_total:,}")
# Enrich a batch of companies
domains = ["acme.com", "widgets.io", "startup.co"]

company_batch = client.enrich_batch(
    contacts=[{"domain": d} for d in domains],
    enrichment_type="company",
    fields=["name", "industry", "employee_count", "funding_total",
            "tech_stack", "revenue_estimate", "founded_year"]
)
company_batch.wait()

for company in company_batch.results:
    print(f"{company.name}: {company.employee_count} employees, "
          f"{company.industry}, raised ${company.funding_total:,}")
# Enrich a batch of companies
domains = ["acme.com", "widgets.io", "startup.co"]

company_batch = client.enrich_batch(
    contacts=[{"domain": d} for d in domains],
    enrichment_type="company",
    fields=["name", "industry", "employee_count", "funding_total",
            "tech_stack", "revenue_estimate", "founded_year"]
)
company_batch.wait()

for company in company_batch.results:
    print(f"{company.name}: {company.employee_count} employees, "
          f"{company.industry}, raised ${company.funding_total:,}")

Company enrichment pulls from firmographic, technographic, and funding providers in a single call. Combine contact and company enrichment in the same pipeline to build complete account profiles. See our guide on waterfall enrichment for CRM data quality.

Phone Number Enrichment

The SDK also supports phone number lookups through the waterfall:

phone_result = client.waterfall(
    enrichment_type="phone_finder",
    inputs={
        "first_name": "Jane",
        "last_name": "Smith",
        "domain": "acme.com"
    },
    providers=["datagma", "contactout", "rocketreach", "apollo",
               "lusha", "pdl", "leadmagic"]
)

if phone_result.found:
    print(f"Phone: {phone_result.phone}")
    print(f"Type: {phone_result.phone_type}")  # "mobile", "direct", "switchboard"
    print(f"Provider: {phone_result.provider}")
phone_result = client.waterfall(
    enrichment_type="phone_finder",
    inputs={
        "first_name": "Jane",
        "last_name": "Smith",
        "domain": "acme.com"
    },
    providers=["datagma", "contactout", "rocketreach", "apollo",
               "lusha", "pdl", "leadmagic"]
)

if phone_result.found:
    print(f"Phone: {phone_result.phone}")
    print(f"Type: {phone_result.phone_type}")  # "mobile", "direct", "switchboard"
    print(f"Provider: {phone_result.provider}")
phone_result = client.waterfall(
    enrichment_type="phone_finder",
    inputs={
        "first_name": "Jane",
        "last_name": "Smith",
        "domain": "acme.com"
    },
    providers=["datagma", "contactout", "rocketreach", "apollo",
               "lusha", "pdl", "leadmagic"]
)

if phone_result.found:
    print(f"Phone: {phone_result.phone}")
    print(f"Type: {phone_result.phone_type}")  # "mobile", "direct", "switchboard"
    print(f"Provider: {phone_result.provider}")
phone_result = client.waterfall(
    enrichment_type="phone_finder",
    inputs={
        "first_name": "Jane",
        "last_name": "Smith",
        "domain": "acme.com"
    },
    providers=["datagma", "contactout", "rocketreach", "apollo",
               "lusha", "pdl", "leadmagic"]
)

if phone_result.found:
    print(f"Phone: {phone_result.phone}")
    print(f"Type: {phone_result.phone_type}")  # "mobile", "direct", "switchboard"
    print(f"Provider: {phone_result.provider}")

Phone match rates are lower than email (40-60% vs 75-90%), so the waterfall matters even more. Every provider adds incremental coverage. See our guide on phone enrichment for cold outbound.

Webhook Integration

For event-driven architectures, use webhooks to receive enrichment results asynchronously:

# Set up a webhook endpoint in your app
from flask import Flask, request

app = Flask(__name__)

@app.route("/webhook/enrichment", methods=["POST"])
def enrichment_webhook():
    data = request.json
    contact_id = data["contact_id"]
    enriched_data = data["result"]

    # Update your database with enriched data
    update_contact(contact_id, enriched_data)
    return {"status": "ok"}, 200

# Start an async enrichment with webhook callback
batch = client.enrich_batch(
    contacts=contacts,
    providers=["clearbit", "apollo"],
    fields=["name", "title", "company"],
    webhook_url="https://your-app.com/webhook/enrichment"
)
# No need to poll - results arrive at your webhook
# Set up a webhook endpoint in your app
from flask import Flask, request

app = Flask(__name__)

@app.route("/webhook/enrichment", methods=["POST"])
def enrichment_webhook():
    data = request.json
    contact_id = data["contact_id"]
    enriched_data = data["result"]

    # Update your database with enriched data
    update_contact(contact_id, enriched_data)
    return {"status": "ok"}, 200

# Start an async enrichment with webhook callback
batch = client.enrich_batch(
    contacts=contacts,
    providers=["clearbit", "apollo"],
    fields=["name", "title", "company"],
    webhook_url="https://your-app.com/webhook/enrichment"
)
# No need to poll - results arrive at your webhook
# Set up a webhook endpoint in your app
from flask import Flask, request

app = Flask(__name__)

@app.route("/webhook/enrichment", methods=["POST"])
def enrichment_webhook():
    data = request.json
    contact_id = data["contact_id"]
    enriched_data = data["result"]

    # Update your database with enriched data
    update_contact(contact_id, enriched_data)
    return {"status": "ok"}, 200

# Start an async enrichment with webhook callback
batch = client.enrich_batch(
    contacts=contacts,
    providers=["clearbit", "apollo"],
    fields=["name", "title", "company"],
    webhook_url="https://your-app.com/webhook/enrichment"
)
# No need to poll - results arrive at your webhook
# Set up a webhook endpoint in your app
from flask import Flask, request

app = Flask(__name__)

@app.route("/webhook/enrichment", methods=["POST"])
def enrichment_webhook():
    data = request.json
    contact_id = data["contact_id"]
    enriched_data = data["result"]

    # Update your database with enriched data
    update_contact(contact_id, enriched_data)
    return {"status": "ok"}, 200

# Start an async enrichment with webhook callback
batch = client.enrich_batch(
    contacts=contacts,
    providers=["clearbit", "apollo"],
    fields=["name", "title", "company"],
    webhook_url="https://your-app.com/webhook/enrichment"
)
# No need to poll - results arrive at your webhook

Webhooks are the right pattern when you do not want your application to maintain a polling loop. The enrichment runs in the background and notifies you on completion.

Rate Limits and Retries

The SDK handles rate limits automatically. If the API returns a 429 response, the SDK waits and retries based on the Retry-After header. You can customize this behavior:

client = Databar(
    api_key=os.environ["DATABAR_API_KEY"],
    max_retries=5,           # More retries for critical workflows
    retry_delay=2000,        # 2 second initial delay
    retry_backoff="exponential"  # Double the delay on each retry
)
client = Databar(
    api_key=os.environ["DATABAR_API_KEY"],
    max_retries=5,           # More retries for critical workflows
    retry_delay=2000,        # 2 second initial delay
    retry_backoff="exponential"  # Double the delay on each retry
)
client = Databar(
    api_key=os.environ["DATABAR_API_KEY"],
    max_retries=5,           # More retries for critical workflows
    retry_delay=2000,        # 2 second initial delay
    retry_backoff="exponential"  # Double the delay on each retry
)
client = Databar(
    api_key=os.environ["DATABAR_API_KEY"],
    max_retries=5,           # More retries for critical workflows
    retry_delay=2000,        # 2 second initial delay
    retry_backoff="exponential"  # Double the delay on each retry
)

For high-throughput use cases, the SDK also respects concurrent request limits. It will queue requests that exceed your plan's concurrency limit and process them as capacity becomes available. You do not need to implement throttling in your application code.

Data Export and Integration

The SDK supports multiple output formats for integrating with your existing tools:

# Export to pandas DataFrame
import pandas as pd

batch.wait()
df = pd.DataFrame([r.to_dict() for r in batch.results])
print(df.describe())

# Filter to only found contacts
found = df[df["name"].notna()]
print(f"Found {len(found)} of {len(df)} contacts")

# Export to JSON for API consumption
import json
with open("enriched.json", "w") as f:
    json.dump([r.to_dict() for r in batch.results], f, indent=2)

# Push to CRM via webhook
import requests
for result in batch.results:
    if not result.error:
        requests.post(
            "https://your-crm.com/api/contacts",
            json=result.to_dict(),
            headers={"Authorization": "Bearer YOUR_CRM_TOKEN"}
        )
# Export to pandas DataFrame
import pandas as pd

batch.wait()
df = pd.DataFrame([r.to_dict() for r in batch.results])
print(df.describe())

# Filter to only found contacts
found = df[df["name"].notna()]
print(f"Found {len(found)} of {len(df)} contacts")

# Export to JSON for API consumption
import json
with open("enriched.json", "w") as f:
    json.dump([r.to_dict() for r in batch.results], f, indent=2)

# Push to CRM via webhook
import requests
for result in batch.results:
    if not result.error:
        requests.post(
            "https://your-crm.com/api/contacts",
            json=result.to_dict(),
            headers={"Authorization": "Bearer YOUR_CRM_TOKEN"}
        )
# Export to pandas DataFrame
import pandas as pd

batch.wait()
df = pd.DataFrame([r.to_dict() for r in batch.results])
print(df.describe())

# Filter to only found contacts
found = df[df["name"].notna()]
print(f"Found {len(found)} of {len(df)} contacts")

# Export to JSON for API consumption
import json
with open("enriched.json", "w") as f:
    json.dump([r.to_dict() for r in batch.results], f, indent=2)

# Push to CRM via webhook
import requests
for result in batch.results:
    if not result.error:
        requests.post(
            "https://your-crm.com/api/contacts",
            json=result.to_dict(),
            headers={"Authorization": "Bearer YOUR_CRM_TOKEN"}
        )
# Export to pandas DataFrame
import pandas as pd

batch.wait()
df = pd.DataFrame([r.to_dict() for r in batch.results])
print(df.describe())

# Filter to only found contacts
found = df[df["name"].notna()]
print(f"Found {len(found)} of {len(df)} contacts")

# Export to JSON for API consumption
import json
with open("enriched.json", "w") as f:
    json.dump([r.to_dict() for r in batch.results], f, indent=2)

# Push to CRM via webhook
import requests
for result in batch.results:
    if not result.error:
        requests.post(
            "https://your-crm.com/api/contacts",
            json=result.to_dict(),
            headers={"Authorization": "Bearer YOUR_CRM_TOKEN"}
        )

For teams using data pipelines, the SDK integrates naturally with pandas, Airflow, Dagster, and any Python-based ETL framework. Enrich contacts as a pipeline step and push results downstream to your warehouse, CRM, or outbound tools.

Environment-Specific Configuration

Set up different configurations for development, staging, and production:

import os

env = os.environ.get("ENVIRONMENT", "development")

config = {
    "development": {
        "api_key": os.environ.get("DATABAR_DEV_KEY"),
        "timeout": 10000,
        "max_retries": 1,
        "debug": True
    },
    "staging": {
        "api_key": os.environ.get("DATABAR_STAGING_KEY"),
        "timeout": 5000,
        "max_retries": 3,
        "debug": False
    },
    "production": {
        "api_key": os.environ.get("DATABAR_API_KEY"),
        "timeout": 5000,
        "max_retries": 5,
        "debug": False
    }
}

client = Databar(**config[env])
import os

env = os.environ.get("ENVIRONMENT", "development")

config = {
    "development": {
        "api_key": os.environ.get("DATABAR_DEV_KEY"),
        "timeout": 10000,
        "max_retries": 1,
        "debug": True
    },
    "staging": {
        "api_key": os.environ.get("DATABAR_STAGING_KEY"),
        "timeout": 5000,
        "max_retries": 3,
        "debug": False
    },
    "production": {
        "api_key": os.environ.get("DATABAR_API_KEY"),
        "timeout": 5000,
        "max_retries": 5,
        "debug": False
    }
}

client = Databar(**config[env])
import os

env = os.environ.get("ENVIRONMENT", "development")

config = {
    "development": {
        "api_key": os.environ.get("DATABAR_DEV_KEY"),
        "timeout": 10000,
        "max_retries": 1,
        "debug": True
    },
    "staging": {
        "api_key": os.environ.get("DATABAR_STAGING_KEY"),
        "timeout": 5000,
        "max_retries": 3,
        "debug": False
    },
    "production": {
        "api_key": os.environ.get("DATABAR_API_KEY"),
        "timeout": 5000,
        "max_retries": 5,
        "debug": False
    }
}

client = Databar(**config[env])
import os

env = os.environ.get("ENVIRONMENT", "development")

config = {
    "development": {
        "api_key": os.environ.get("DATABAR_DEV_KEY"),
        "timeout": 10000,
        "max_retries": 1,
        "debug": True
    },
    "staging": {
        "api_key": os.environ.get("DATABAR_STAGING_KEY"),
        "timeout": 5000,
        "max_retries": 3,
        "debug": False
    },
    "production": {
        "api_key": os.environ.get("DATABAR_API_KEY"),
        "timeout": 5000,
        "max_retries": 5,
        "debug": False
    }
}

client = Databar(**config[env])

Use separate API keys per environment to isolate credit usage and avoid production data leaking into development workflows.

Logging and Debugging (Databar Python Sdk Enrichment Quickstart)

Enable verbose logging for development and debugging:

import logging

logging.basicConfig(level=logging.DEBUG)
client = Databar(api_key=os.environ["DATABAR_API_KEY"], debug=True)

# Now all API calls are logged with request/response details
result = client.enrich(email="jane@acme.com")
# DEBUG: POST /api/v1/enrich {"email": "jane@acme.com"} returns 200 (482ms)
import logging

logging.basicConfig(level=logging.DEBUG)
client = Databar(api_key=os.environ["DATABAR_API_KEY"], debug=True)

# Now all API calls are logged with request/response details
result = client.enrich(email="jane@acme.com")
# DEBUG: POST /api/v1/enrich {"email": "jane@acme.com"} returns 200 (482ms)
import logging

logging.basicConfig(level=logging.DEBUG)
client = Databar(api_key=os.environ["DATABAR_API_KEY"], debug=True)

# Now all API calls are logged with request/response details
result = client.enrich(email="jane@acme.com")
# DEBUG: POST /api/v1/enrich {"email": "jane@acme.com"} returns 200 (482ms)
import logging

logging.basicConfig(level=logging.DEBUG)
client = Databar(api_key=os.environ["DATABAR_API_KEY"], debug=True)

# Now all API calls are logged with request/response details
result = client.enrich(email="jane@acme.com")
# DEBUG: POST /api/v1/enrich {"email": "jane@acme.com"} returns 200 (482ms)

In production, set logging to INFO or WARNING to avoid performance overhead from verbose logging. The SDK logs errors and retries at WARNING level by default, which is usually sufficient for production monitoring.

Databar Python Sdk Enrichment Quickstart: Python SDK Enrichment Quickstart: What to Build Next

You now have the building blocks for any enrichment workflow in Python. The Databar Python SDK handles authentication, rate limits, provider management, and response normalization. Your code focuses on business logic.

Start with a single lookup to test your API key. Then try a batch of 100 contacts from your CRM. Then build a waterfall to see how match rates improve across multiple providers. The SDK supports every pattern from this enrichment quickstart through to production-scale pipelines.

Databar's Python SDK connects to 100+ data providers on a monthly credit plan with outcome-based billing, so credits are only consumed when data is successfully returned. No annual contracts. Check the MCP vs SDK vs API guide to decide which integration method fits your workflow best.

Frequently Asked Questions

What is Databar Python Sdk Enrichment Quickstart?

Databar Python Sdk Enrichment Quickstart uses data tools and workflows to improve GTM operations. Databar makes this accessible through 100+ providers in one API.

How much does Databar Python Sdk Enrichment Quickstart cost?

With Databar, you pay only for enrichments you use. No monthly minimums or annual contracts. Credits start at fractions of a cent per lookup.

Can I try Databar Python Sdk Enrichment Quickstart for free?

Yes. Databar offers a 14-day free trial with full API access. Sign up in under a minute and run your first enrichment immediately.

Do I need technical skills for Databar Python Sdk Enrichment Quickstart?

No. Databar offers both a no-code interface and a full API. Non-technical teams use the visual builder. Developers use the REST API, Python SDK, or MCP server.

How does Databar Python Sdk Enrichment Quickstart integrate with my CRM?

Databar connects to any CRM through its API, Zapier, Make, or n8n. Set up triggered enrichment on new records or run batch enrichment on existing data.

Also Interesting

Get Started with Databar Today

Unlock the full potential of your data with the world’s most comprehensive no-code API tool. Whether you’re looking to enrich your data, automate workflows, or drive smarter decisions, Databar has you covered.

Get Started with Databar Today

Unlock the full potential of your data with the world’s most comprehensive no-code API tool. Whether you’re looking to enrich your data, automate workflows, or drive smarter decisions, Databar has you covered.