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, the same per-row work is done with Skills in the Actions drawer; smart agents are not 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: from an estimate of the work your prompt asks for, so a short classification prompt costs less than a research prompt. The run total is rounded up once to a whole credit.
  • 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.

# 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.

🧑‍💻

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.

{
  "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 }
  ]
}

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.cleanlist.ai/plans)
feature_not_available501The agent_type isn't enabled
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.

Related