Developer guide

How to find a lead's email with the Coolie API

Send POST /api/v1/agents/{agentId}/leads/contact with the lead's runId and prospectId and field set to email (or phone). Coolie looks the address up and answers { found, value, charged }: 0.1 credit when an email is found, 1 credit for a phone, nothing when none is found, and nothing when the lead already has one, which comes back as it is.

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_KEY in these examples). It acts as you, with your plan, your credits and your agents.
  • Credits on the account: GET /api/v1/account gives the balance, in account.credits.
  • The lead's agentId, runId and prospectId, from GET /api/v1/leads.

Find one email with curl

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.

Python
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

JavaScript (Node.js 18+)
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 found is false.
  • Already on the lead: nothing charged; the value comes back with charged 0.
  • 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 findEmail true.

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.

JSON
{
  "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.

StatusCodeWhat to do
400invalid_bodyrunId, prospectId or field is missing, or field is not email or phone.
400no_contactNobody at this company matches the agent's ICP, so there is no one to look up.
402no_creditsNot enough credits for this lookup; the answer's price says how many it needs.
404agent_not_foundNo agent with this id in your account.
404lead_not_foundNo lead with this runId and prospectId in this agent.
503sources_unavailableNo source could answer right now. Nothing was charged: try again later.
401missing_api_keyNo key in the request: send Authorization: Bearer coolie_sk_… or an x-api-key header.
401invalid_api_keyNot a Coolie key, or a key that is unknown or revoked: copy it again from Settings → API keys.
429rate_limitedMore 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.

Your next conversation is already happening somewhere.

Set up an agent in five minutes. The first leads arrive with their reason to write.