New: API Reference docs are live — integrate Cleanlist enrichment into your apps. View API docs →
API Reference
Credits

TL;DR: Credits are deducted only when an enrichment succeeds. GET /public/credits/balance returns your organization's current balance. A 402 response on /public/enrich/bulk means you need to top up.

Credits

Cleanlist uses a credit-based pricing model. Credits live at the organization level — every user in your org draws from the same balance.

Endpoints

MethodPathPurpose
GET/api/v1/public/credits/balanceGet current credit balance
GET/api/v1/public/auth/validate-keyConfirm a key is active (no credit cost)

Get credit balance

GET /api/v1/public/credits/balance

curl https://api.cleanlist.ai/api/v1/public/credits/balance \
  -H "Authorization: Bearer clapi_your_api_key"

Response

{
  "organization_id": "org_clerk_id",
  "credits": 1234.5
}
FieldTypeDescription
organization_idstringYour Clerk organization id
creditsnumberCurrent credit balance (can be fractional — smart columns charge 0.1–3.0 credits)

The endpoint is rate-limited like the rest of the Public API (see Errors) but does not consume credits itself.

Validate an API key

GET /api/v1/public/auth/validate-key

A lightweight ping that confirms a key is valid without spending credits or hitting any other system. Use it from health checks, key-management scripts, or first-run setup wizards.

curl https://api.cleanlist.ai/api/v1/public/auth/validate-key \
  -H "Authorization: Bearer clapi_your_api_key"

Response

{
  "valid": true,
  "user_id": "user_clerk_id",
  "organization_id": "org_clerk_id"
}

A 401 means the key is missing, malformed, expired, or revoked.

Credit costs

Credits are deducted only when an enrichment succeeds. Failed lookups cost zero credits.

Enrichment

ActionCredits
Email found (partial)1
Phone found (phone_only)10
Email + phone found (full)11
Prospecting (find new contacts at a company)1 per discovered contact
Enrichment that returns no data0

Smart Columns (portal feature)

If you layer Smart Columns onto a list, each column type has its own cost:

Smart ColumnCredits / row
clean_first_name, format_phone0.1
email_validation0.2
enrich_company, linkedin_research, find_competitors, find_similar_companies, website_analysis, icp_fit_analysis, data_quality_*, contact_timezone0.5
custom_ai, custom_classification1.0
cold_intro_email3.0

Smart Columns are run from the portal but consume from the same organization credit pool.

Handling insufficient credits

When your organization runs out of credits, enrichment endpoints return 402 Payment Required:

{
  "detail": "Insufficient credits"
}

Recommended pattern

import requests
 
def enrich_with_topup_check(payload, api_key):
    r = requests.post(
        "https://api.cleanlist.ai/api/v1/public/enrich/bulk",
        headers={"Authorization": f"Bearer {api_key}"},
        json=payload,
    )
 
    if r.status_code == 402:
        # Notify your billing channel — out of credits
        notify_admin("Cleanlist credits exhausted; top up at portal.cleanlist.ai")
        raise RuntimeError("Out of credits")
 
    r.raise_for_status()
    return r.json()

Failed enrichments cost zero credits, so it is always safe to retry the same payload after a top-up.

Pre-flight check

For very large batches, check your balance first to fail fast:

balance = requests.get(
    "https://api.cleanlist.ai/api/v1/public/credits/balance",
    headers={"Authorization": f"Bearer {api_key}"},
).json()["credits"]
 
# Worst case: every contact yields a full enrichment (11 credits)
estimated_cost = len(contacts) * 11
if balance < estimated_cost:
    raise RuntimeError(
        f"Need ~{estimated_cost} credits, have {balance}. Top up first."
    )

This is a worst-case estimate — actual costs are usually lower because not every contact has both an email and a phone.

Topping up

Buy credits or change plans inside the portal (opens in a new tab) under Settings → Billing. New credits are available immediately after the Stripe payment completes.

Related