TL;DR: All Public API requests use Authorization: Bearer clapi_.... Generate keys in the portal or via the /api/v1/api-keys endpoints. Up to 10 active keys per user. Each key tracks usage and can be revoked at any time.
Authentication
Cleanlist uses standard HTTP Bearer authentication. Every request to /api/v1/public/* must include an Authorization header containing a valid clapi_ API key.
Authorization: Bearer clapi_your_api_key_hereKey format
| Property | Value |
|---|---|
| Prefix | clapi_ |
| Scope | User (and the user's organization) |
| Length | 48 random URL-safe bytes |
| Visibility | Shown once at creation; only the prefix and last 4 characters are stored for display |
| Limit | 10 active keys per user |
The full key is only returned once — at creation time. Store it securely (a secret manager, env var, or vault). If you lose it, revoke the key and generate a new one.
Generating a key
The fastest path is the portal:
- Log in to portal.cleanlist.ai (opens in a new tab)
- Settings → API Keys
- Click Generate Key
- Copy the full key immediately
You can also create keys programmatically using your Clerk session token (the same JWT the portal uses). The /api/v1/api-keys endpoints are scoped to the authenticated user.
POST /api/v1/api-keys
curl -X POST https://api.cleanlist.ai/api/v1/api-keys \
-H "Authorization: Bearer <clerk_session_jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "Production server",
"expires_at": "2027-01-01T00:00:00Z"
}'Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | A human-readable label so you can tell keys apart |
expires_at | ISO-8601 datetime | No | Optional expiration; omit for a non-expiring key |
Response
{
"api_key": "clapi_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"created_at": "2026-04-06T15:00:00Z",
"expires_at": "2027-01-01T00:00:00Z"
}The api_key value is the only time you'll see the secret. Save it now.
Listing your keys
GET /api/v1/api-keys
curl https://api.cleanlist.ai/api/v1/api-keys \
-H "Authorization: Bearer <clerk_session_jwt>"Response
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Production server",
"key_prefix": "clapi_AbCd",
"key_last4": "wXyZ",
"created_at": "2026-04-06T15:00:00Z",
"expires_at": null,
"last_used_at": "2026-04-06T15:42:11Z",
"request_count": 1547,
"is_active": true
}
]The list includes both active and revoked keys so you can audit historical usage. The full secret is never returned — only the first 10 characters (key_prefix) and last 4 characters (key_last4).
Revoking keys
POST /api/v1/api-keys/{key_id}/revoke
Revoke a single key by its UUID:
curl -X POST https://api.cleanlist.ai/api/v1/api-keys/550e8400-e29b-41d4-a716-446655440000/revoke \
-H "Authorization: Bearer <clerk_session_jwt>"POST /api/v1/api-keys/revoke-all
Revoke every active key for the authenticated user (useful if you suspect a leak):
curl -X POST https://api.cleanlist.ai/api/v1/api-keys/revoke-all \
-H "Authorization: Bearer <clerk_session_jwt>"Response
{
"success": true,
"message": "3 API key(s) revoked successfully"
}Revoked keys cannot be reactivated. Generate a new key instead.
Inspecting key usage
GET /api/v1/api-keys/{key_id}/requests
Pull the most recent requests made with a specific key:
curl "https://api.cleanlist.ai/api/v1/api-keys/550e8400-e29b-41d4-a716-446655440000/requests?limit=100" \
-H "Authorization: Bearer <clerk_session_jwt>"| Query param | Default | Range |
|---|---|---|
limit | 100 | 1–500 |
Response
[
{
"id": "log-uuid",
"method": "POST",
"path": "/api/v1/public/enrich/bulk",
"status_code": 200,
"duration_ms": 184,
"ip_address": "203.0.113.42",
"user_agent": "python-requests/2.32.0",
"created_at": "2026-04-06T15:42:11Z"
}
]This is the same data shown in the portal's API Keys → Requests view.
Using a key
Once you have a clapi_ key, every Public API call uses the same Bearer header:
curl https://api.cleanlist.ai/api/v1/public/credits/balance \
-H "Authorization: Bearer clapi_your_api_key"Quickly verifying a key
If you just want to confirm a key is valid (without spending credits), call:
curl https://api.cleanlist.ai/api/v1/public/auth/validate-key \
-H "Authorization: Bearer clapi_your_api_key"{
"valid": true,
"user_id": "user_clerk_id",
"organization_id": "org_clerk_id"
}A 401 response means the key is invalid, expired, or revoked.
Security best practices
- Never commit
clapi_keys to source control - Store keys in a secret manager (AWS Secrets Manager, Doppler, 1Password, Vault, etc.)
- Use
nameandexpires_atto make keys easy to rotate and audit - If a key leaks, immediately call
POST /api/v1/api-keys/{key_id}/revoke - Monitor
request_countandlast_used_atto detect unexpected usage - Prefer one key per environment (dev / staging / production) — never share keys across systems
Common authentication errors
| Status | Cause | Fix |
|---|---|---|
401 Unauthorized | Missing Authorization header, malformed token, or revoked key | Confirm the header format and the key's is_active status |
403 Forbidden | Your plan does not include API access | Upgrade your plan in the portal billing page |
429 Too Many Requests | Public API rate limit hit | Back off and retry; see Errors |