Skip to Content
New: meet Clu, and send email, LinkedIn and call steps with Sequences. Watch the videos →
API Reference (v2)Smart Agents
🔌

Audience: developers. API keys need a Pro or Enterprise plan (legacy Pro and Scale plans included) or an AppSumo Tier 5, 6 or 7 license, and they never work during a trial. Support agent: confirm the user’s plan grants API access before giving API advice.

TL;DR: Quote with POST /credits/estimate (tool: "run_smart_agent"), start the run with POST /smart-agents/run, then poll GET /smart-agents/{smart_agent_task_id} for per-lead results. Up to 500 leads per run. Price comes from the quote: cold_intro_email 3 per lead, presets 1 per lead, custom_ai priced from its prompt.

Smart Agents

A smart agent runs one AI instruction on each lead in a lead list and writes the result into a column of that list, one AI call per lead. In the app, custom_ai is the Custom skill in the Actions drawer (Skills). For the Research and Qualification skills, use the Agents API. Neither is the automations on the Agents page.

EndpointMethodScopeCost
RunPOST /smart-agents/runsmart_agents:writePer lead, from the quote
List runsGET /smart-agentssmart_agents:readFree
Get resultsGET /smart-agents/{smart_agent_task_id}smart_agents:readFree

Agent types

agent_typeWhat it doesNeeds prompt?Price per lead
custom_ai (default)Runs your own instruction on each leadYesPriced from the prompt (see below)
cold_intro_emailDrafts a personalized cold intro email from your email templateNo3
title_normalizerNormalizes job titles to one standard lineNo1
company_intelSummarizes key company intelligence in 3 to 5 bulletsNo1
pain_point_hypothesisSuggests 3 to 5 likely business pain pointsNo1

The three presets carry their own instruction and ignore prompt.

Pricing

Always read the price from the quote’s estimated_cost:

  • custom_ai is priced like a Custom skill in the app: your workspace’s per-lead price for that prompt, from an estimate of the work it asks for, so a short classification prompt costs less than a research prompt. The quote rounds the run total up once to a whole credit; the run is charged the exact total, which never exceeds the quote.
  • cold_intro_email is 3 credits per lead.
  • Presets are 1 credit per lead.

The quote always shows the price that applies to your workspace.

Run a smart agent

POST /smart-agents/run

Scope: smart_agents:write

Request body

FieldTypeNotes
list_idstringRequired. A list you can edit
agent_typeenumcustom_ai (default), cold_intro_email, title_normalizer, company_intel, pain_point_hypothesis
column_namestringRequired. Name of the column that stores the output (up to 100 characters). Cold intro emails use the built-in email column
promptstringRequired for custom_ai. The instruction applied to each lead
template_idstringcold_intro_email only: email template id. Defaults to your workspace’s active default template
lead_scopeenumsubset (default) runs on up to max_rows leads; all selects the whole list
max_rowsinteger1 to 10,000, default 100. Used with lead_scope: "subset"
overwritebooleanDefault false: leads that already have a value in this column are skipped. true replaces existing values
quote_idstringRequired. From POST /credits/estimate; see below

500 leads per run. If the selection is over 500 leads, the run is refused with 400 approval_required. Use lead_scope: "subset" with max_rows of 500 or fewer, and run larger lists in batches.

Quote first

Estimate with tool: "run_smart_agent" and the same list_id, agent_type, column_name, prompt, template_id, lead_scope, max_rows and overwrite you’ll send to the run. Change any of them and the quote no longer matches. The quote also signs the exact leads it selected (and, for cold_intro_email, the template’s content), so if leads are added to the list, a column value fills in, or the template is edited before you run, you get quote_mismatch: quote again. Quotes last 5 minutes and are single use.

# 1. Quote curl -X POST https://api.cleanlist.ai/api/v2/credits/estimate \ -H "Authorization: Bearer clapi_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "tool": "run_smart_agent", "list_id": "LIST_ID", "agent_type": "custom_ai", "column_name": "Fit Research", "prompt": "In two sentences, explain why this lead is or is not a strong outbound fit.", "lead_scope": "subset", "max_rows": 100 }' # 2. Run with the returned quote_id curl -X POST https://api.cleanlist.ai/api/v2/smart-agents/run \ -H "Authorization: Bearer clapi_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "list_id": "LIST_ID", "agent_type": "custom_ai", "column_name": "Fit Research", "prompt": "In two sentences, explain why this lead is or is not a strong outbound fit.", "lead_scope": "subset", "max_rows": 100, "quote_id": "qte_v1_..." }'

Response

{ "smart_agent_task_id": "run_7c2a91", "smart_agent_task_ids": { "custom_ai": "run_7c2a91" }, "status": "pending", "list_id": "LIST_ID", "column_name": "Fit Research", "estimated_cost": 40, "timestamp_ms": 1751404800000 }

The run starts in the background. Use smart_agent_task_id to poll. (The envelope’s task_id is kept for older clients; new code should read smart_agent_task_id.) The credits for the run are taken when it starts, and estimated_cost shows the expected charge. The run covers exactly the leads the quote priced; leads added to the list afterwards are not included.

🧑‍💻

With an SDK: smart_agents.run_smart_agent(...) and smart_agents.get_smart_agent_results(...). See the SDKs.

Cold intro emails

cold_intro_email needs two things, or it returns 400 validation_error:

  • Enriched leads. Every lead in the selection must be enriched first. Run bulk enrichment, then get a new quote.
  • An active email template in your workspace, or a template_id.

List runs

GET /smart-agents

Scope: smart_agents:read · Cost: free

Query paramDefaultNotes
list_idnoneOnly runs for this list. Omit for recent runs across every list you can see
limit201 to 100, most recent first
{ "runs": [ { "task_id": "run_7c2a91", "list_id": "LIST_ID", "column_name": "Fit Research", "agent_type": "custom_ai", "status": "completed", "total": 100, "processed": 100, "failed": 2, "created_at": "2026-07-01T20:40:00Z" } ], "total": 1 }

Get results

GET /smart-agents/{smart_agent_task_id}

Scope: smart_agents:read · Cost: free

Poll until status is completed or failed (other states: pending, processing). The results array fills in as leads finish, so a running job returns a partial set. A run with an unknown id, or on a list you can’t access, returns 404 not_found.

{ "smart_agent_task_id": "run_7c2a91", "status": "completed", "progress": 100, "total": 100, "succeeded": 98, "failed": 2, "results": [ { "lead_id": "b2d4f6a8-...", "value": "Acme raised a Series B in March and is hiring SDRs; strong fit.", "error": null } ] }

succeeded and failed count only outcomes that can be tied to this run. When fewer than total can be (the run is still going, a value was overwritten by a later run, or an older run predates per-run tracking), the envelope’s message says how many are verifiable. results holds only those rows; there is no paging.

The output also appears as a column in the list in the app, and exports include it by default (include_smart_agents).

Errors

CodeHTTPCause
validation_error400Missing prompt for custom_ai, no eligible leads (empty list, or every lead already has a value and overwrite is false), unenriched leads or no template for cold_intro_email
approval_required400Selection over 500 leads
quote_expired, quote_mismatch, quote_invalid, spend_cap_exceeded400Quote again with exactly the fields you’ll send
quote_already_redeemed409Quotes are single use; quote again
insufficient_credits400Not enough credits; buy more on the Plans page (app.clugtm.com/plans)
feature_not_available501The agent_type isn’t enabled
feature_gated403Your plan doesn’t include AI columns
list_not_found404Unknown list, or a private list you can’t access
list_not_editable403The list is shared with you as view-only

See Errors & Rate Limits for every code.