Updated
Before you start
- An API key: in Coolie, open Settings → API keys, name the key and click Create key. It is shown once, so keep it in an environment variable (
COOLIE_API_KEYin these examples). It acts as you, with your plan, your credits and your agents. - Credits on the account:
GET /api/v1/accountgives the balance, inaccount.credits. - The lead's
agentId,runIdandprospectId, fromGET /api/v1/leads.
Find one email with curl
curl https://trycoolie.ai/api/v1/agents/agent-3f2a91c0/leads/contact \
-H "Authorization: Bearer $COOLIE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "runId": "ui-7c03aa19", "prospectId": "p-9e21f4b6c8d0", "field": "email" }'The request waits for the lookup, up to a minute. An email found is saved on the lead, and webhooks subscribed to lead.enriched receive the lead with it.
Fill in every missing email in Python
The loop reads one agent's newest leads, skips those with no contact or with an email already, and asks for the others one by one. It stops when the credits run out.
import os
import time
import requests
API = "https://trycoolie.ai/api/v1"
SESSION = requests.Session()
SESSION.headers["Authorization"] = f"Bearer {os.environ['COOLIE_API_KEY']}"
AGENT_ID = os.environ["COOLIE_AGENT_ID"]
def call(method, path, **kwargs):
"""One call. Waits and tries again when the minute's 60 requests are used up."""
while True:
response = SESSION.request(method, f"{API}{path}", timeout=120, **kwargs)
if response.status_code == 429 and response.json().get("error") == "rate_limited":
time.sleep(int(response.headers.get("Retry-After", "1")))
continue
return response
page = call("GET", f"/agents/{AGENT_ID}/leads", params={"limit": 100}).json()
for lead in page["leads"]:
if lead["contact"] is None or lead["contact"]["email"]:
continue # nobody to look up, or an email already
answer = call("POST", f"/agents/{AGENT_ID}/leads/contact", json={
"runId": lead["runId"],
"prospectId": lead["prospectId"],
"field": "email",
})
result = answer.json()
if answer.status_code == 402:
print("Out of credits:", result["message"])
break
if answer.ok:
print(lead["contact"]["name"], result["value"] if result["found"] else "not found")
else:
print(lead["contact"]["name"], result["error"])For more than 100 leads, follow nextCursor as in the new leads guide.
The same in JavaScript
const response = await fetch("https://trycoolie.ai/api/v1/agents/agent-3f2a91c0/leads/contact", {
method: "POST",
headers: {
Authorization: "Bearer " + process.env.COOLIE_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ runId: "ui-7c03aa19", prospectId: "p-9e21f4b6c8d0", field: "email" }),
});
const result = await response.json();
if (!response.ok) throw new Error(response.status + " " + result.error + ": " + result.message);
console.log(result.found ? result.value : "No email found", "(" + result.charged + " credit)");What it costs
- An email found: 0.1 credit. A phone found: 1 credit.
- Nothing found: nothing charged, and
foundis false. - Already on the lead: nothing charged; the value comes back with
charged0. - The balance must cover the price before the lookup starts (402 no_credits otherwise).
- To have the agent look emails up as it finds leads, create it with
findEmailtrue.
What the lookup answers
found says whether an address was found, value is the address (null when none was found), charged what it cost in credits. The values are examples.
{
"found": true,
"value": "jonas.weber@halden.example",
"charged": 0.1
}Errors
An error answers with its HTTP status and a body { "error": code, "message": sentence }: branch on the code, show or log the message.
| Status | Code | What to do |
|---|---|---|
| 400 | invalid_body | runId, prospectId or field is missing, or field is not email or phone. |
| 400 | no_contact | Nobody at this company matches the agent's ICP, so there is no one to look up. |
| 402 | no_credits | Not enough credits for this lookup; the answer's price says how many it needs. |
| 404 | agent_not_found | No agent with this id in your account. |
| 404 | lead_not_found | No lead with this runId and prospectId in this agent. |
| 503 | sources_unavailable | No source could answer right now. Nothing was charged: try again later. |
| 401 | missing_api_key | No key in the request: send Authorization: Bearer coolie_sk_… or an x-api-key header. |
| 401 | invalid_api_key | Not a Coolie key, or a key that is unknown or revoked: copy it again from Settings → API keys. |
| 429 | rate_limited | More than 60 requests in the minute for your account: wait the seconds Retry-After gives, then try again. |
Frequently asked questions
How much does finding an email cost?
0.1 credit when an email is found, 1 credit for a phone, and nothing when none is found or when the lead already has one.
Why does the API answer no_contact?
Nobody at the company matches the agent's job titles, so there is no one to look up: the lead's contact is null.
What is emailConfidence?
How sure the lookup is of the address, from 0 to 1, on the lead's contact in GET /api/v1/leads.
Can I find phone numbers too?
Yes: send field phone. A phone found costs 1 credit, and nothing when none is found.
Can I look up many leads at once?
One lead per call: loop over the leads within your account's 60 requests a minute, as in the Python example.
Every endpoint, field and error is in the API reference, and more guides are in the developer hub.
