TL;DR: Check the API key, check the credit balance, check the request shape, then check GET /public/webhooks/deliveries if you're using webhooks. Most issues fall into one of those four buckets.
Troubleshooting
If something isn't working, run through this list before opening a support ticket. Most issues are one of these.
"I'm getting a 401 Unauthorized"
What it means: Cleanlist couldn't authenticate the request.
Checklist:
- Confirm the header is exactly
Authorization: Bearer clapi_...- Not
X-API-Key - Not basic auth
- The word
Beareris required, with a space before the key
- Not
- Confirm the key starts with
clapi_ - Run a sanity check:
curl https://api.cleanlist.ai/api/v1/public/auth/validate-key \ -H "Authorization: Bearer $CLEANLIST_API_KEY" - If
valid: falseor 401: open the portal → Settings → API Keys and confirm the key is still active - If the key was rotated, generate a fresh one
"I'm getting a 402 Payment Required"
What it means: Your organization is out of credits.
Fix: Top up in the portal (opens in a new tab) under Settings → Billing. New credits land within seconds of the Stripe payment.
curl https://api.cleanlist.ai/api/v1/public/credits/balance \
-H "Authorization: Bearer $CLEANLIST_API_KEY"Failed enrichments cost 0 credits, so retrying after a top-up is safe — you won't be double-charged for the rows that already succeeded.
"I'm getting a 422 Validation Error"
What it means: One or more contacts didn't pass Pydantic validation. Usually a missing field combo.
Fix: Each contact must include either:
linkedin_url, orfirst_name+last_name+ (company_domainorcompany_name)
The detail array tells you which contact index is bad:
{
"detail": [
{
"loc": ["body", "contacts", 7],
"msg": "Each contact must include linkedin_url OR ..."
}
]
}In this example, fix contacts[7].
"My bulk request is failing with 'Bulk enrichment supports up to 250 contacts per request'"
What it means: You sent more than 250 contacts.
Fix: Split the input client-side:
def chunked(iterable, size):
for i in range(0, len(iterable), size):
yield iterable[i:i + size]
for batch in chunked(all_contacts, 250):
submit_batch(batch)You can submit batches in parallel, but watch the rate limit.
"I submitted a workflow but never got the webhook"
What it means: Webhook delivery may have failed.
Checklist:
- Confirm your
webhook_urlis HTTPS, publicly reachable, and ACKs with 2xx within 10 seconds - Query the delivery log:
curl "https://api.cleanlist.ai/api/v1/public/webhooks/deliveries?workflow_id=$WORKFLOW_ID" \ -H "Authorization: Bearer $CLEANLIST_API_KEY" - Look at the
attempt_number,status,response_status_code, anderror_messagefields - Common reasons for failure:
- Endpoint returned 5xx (your server bug)
- Endpoint returned 4xx (your auth or routing rule rejected the payload)
- Connection timed out (your endpoint took longer than 10s)
- DNS / TLS error (URL or cert issue)
- Fix the endpoint and re-submit the workflow
If all 5 attempts failed, the result is still available via GET /api/v1/public/enrich/status?workflow_id=....
"My enrichment came back empty"
What it means: The waterfall ran but no provider found verified data.
Why it happens:
- The contact is at a stealth-mode company
- The contact is too new (LinkedIn / databases haven't indexed them yet)
- The company domain doesn't match the contact's actual employer
- The
linkedin_urlis malformed or points to a deactivated profile
Fix:
- Try sending with a different identifier (name + company instead of LinkedIn URL, or vice versa)
- If you're using
partial, tryfullto engage phone providers as a backup signal - Check
email_status—riskyresults often have a working email even if it's not markedreliable
You're not charged for empty results, so retrying is free.
"I'm getting 429 Too Many Requests"
What it means: You hit a per-organization, per-endpoint rate limit.
Fix: Back off with exponential backoff + jitter:
import time, random, requests
def call_with_backoff(method, url, **kwargs):
for attempt in range(6):
r = requests.request(method, url, **kwargs)
if r.status_code != 429:
return r
time.sleep(2 ** attempt + random.random())
r.raise_for_status()If you're hitting 429s during normal use, contact us — your plan may need a higher rate limit.
"I created an API key but I lost the secret"
What it means: Cleanlist only shows the secret once at creation, by design.
Fix: Revoke the key and generate a new one. Use a secret manager next time so you don't lose it.
# Revoke
curl -X POST "https://api.cleanlist.ai/api/v1/api-keys/$KEY_ID/revoke" \
-H "Authorization: Bearer $CLERK_SESSION_JWT"Or use the portal: Settings → API Keys → Revoke.
"I hit the 'maximum API keys' limit"
What it means: You already have 10 active keys and tried to create an 11th.
Fix: Revoke an unused key first (POST /api/v1/api-keys/{key_id}/revoke) or use revoke-all if you want to start fresh.
"Smart Columns are stuck on 'pending'"
What it means: The smart-columns Temporal queue is processing your job but hasn't reached your row yet.
Checklist:
- Open the column header menu — does it show progress (e.g., "120 / 500 done")?
- If progress is moving, just wait
- If progress is 0 and it's been more than a few minutes, refresh the page (the live update may be stuck)
- If still stuck after a refresh, contact support with the column id
"My Public API enrichments don't show up in any lead list"
What it means: They are in your DEFAULT lead list — you may not have noticed it.
Fix: Open the portal → Lead Lists → look for a list named DEFAULT. Every Public API enrichment lands there. See Lead Lists for the full explanation.
"My CRM push isn't working"
Checklist:
- Open Settings → Integrations and confirm the connection is healthy
- Check the field mapping for the destination object
- Look at the Action Column's per-row error messages — they include the destination's response
- Most CRM failures are auth-token expiration or required-field validation; both are visible in the error message
When to reach out to support
If you've worked through this list and you're still stuck, email support with:
- The endpoint or feature you're using
- The exact error message and status code
- The
workflow_id(orkey_id, orcolumn_id) involved - A sample request body (with secrets redacted)
We respond within one business day.