getLeads

getLeads API and MCP server

Search for B2B leads, check prices and unlock leads from your own code, or let an AI assistant do it through MCP. The API uses your account: the same wallet, free unlocks, prices and daily limits as the website.

Authentication

Create a key in the app under Profile Settings, Password & Security, API keys. You see the key once, so store it in a secret manager or an environment variable. Up to 5 keys per account; revoke one at any time and it stops working at once. Live keys start with gl_live_; test keys (gl_test_) only work on test deployments.

Authorization: Bearer gl_live_your_key_here

Send JSON with Content-Type: application/json. Never put a key in a browser, a mobile app or a public repository: anyone with it can spend your credit. You can set a daily spend cap per key.

Endpoints

Base URL: https://getleads.site/api/v1

API endpoints
MethodPathWhat it does
GET/api/v1/meYour account, wallet balance (USD cents) and free unlocks left.
GET/api/v1/pricing?country=KEPrice tiers, wallet packs and the exact per-lead price for a country.
POST/api/v1/leads/searchStart a lead search (free; uses one daily search). Answers 202 with a job.
GET/api/v1/jobs/{id}Poll a search or scan job: running, succeeded (with results) or failed.
GET/api/v1/leads?limit=25&cursor=Your unlocked leads, newest first. Follow nextCursor for more.
GET/api/v1/leads/{id}One lead: full if you own it, otherwise the locked preview (with its price when unlocking it costs money).
POST/api/v1/leads/{id}/unlockUnlock a lead. Charges your wallet or uses a free unlock. Needs an Idempotency-Key header.
POST/api/v1/domain/scanScan a company website for target niches and buyer roles. Answers 202 with a job.
GET/api/v1/domain/scan/{id}Status of a domain scan (same as /api/v1/jobs/{id}).
GET/api/v1/openapi.jsonThe OpenAPI 3.1 description of all of the above. No key needed.

Searches return locked previews: niche, country, fit score and, when unlocking costs money, the price; no company name or links. Unlocking a lead returns the company, its checked website and LinkedIn page, the suggested decision-maker role and an opening line. Leads you have unlocked stay yours; unlocking one again never charges twice. There are no payment or admin endpoints: top up on the website. Full schema: openapi.json.

Examples

curl

export GETLEADS_API_KEY=gl_live_...

# Balance
curl -s https://getleads.site/api/v1/me -H "Authorization: Bearer $GETLEADS_API_KEY"

# Start a search, then poll the job it returns
curl -s -X POST https://getleads.site/api/v1/leads/search \
  -H "Authorization: Bearer $GETLEADS_API_KEY" -H "Content-Type: application/json" \
  -d '{"niche":"Logistics","location":"Kenya","count":10}'
curl -s https://getleads.site/api/v1/jobs/job_... -H "Authorization: Bearer $GETLEADS_API_KEY"

# Unlock one lead (safe to retry with the same Idempotency-Key)
curl -s -X POST https://getleads.site/api/v1/leads/LEAD_ID/unlock \
  -H "Authorization: Bearer $GETLEADS_API_KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" -d '{"payWith":"credit"}'

JavaScript (Node 18+)

const base = 'https://getleads.site/api/v1';
const headers = {Authorization: `Bearer ${process.env.GETLEADS_API_KEY}`, 'Content-Type': 'application/json'};

const start = await fetch(`${base}/leads/search`, {method: 'POST', headers, body: JSON.stringify({niche: 'Logistics', location: 'KE'})});
let {job} = await start.json();
while (job.status === 'running' || job.status === 'queued') {
  await new Promise((r) => setTimeout(r, 5000));
  ({job} = await (await fetch(`${base}/jobs/${job.id}`, {headers})).json());
}
const lead = job.result.leads.find((l) => l.unlockable);
const res = await fetch(`${base}/leads/${lead.id}/unlock`, {
  method: 'POST',
  headers: {...headers, 'Idempotency-Key': crypto.randomUUID()},
  body: JSON.stringify({payWith: 'credit'}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.lead.company, body.lead.website, body.chargedCents);

Python (requests)

import os, time, uuid, requests

BASE = "https://getleads.site/api/v1"
s = requests.Session()
s.headers["Authorization"] = f"Bearer {os.environ['GETLEADS_API_KEY']}"

job = s.post(f"{BASE}/leads/search", json={"niche": "Logistics", "location": "Kenya"}).json()["job"]
while job["status"] in ("queued", "running"):
    time.sleep(5)
    job = s.get(f"{BASE}/jobs/{job['id']}").json()["job"]

lead = next(l for l in job["result"]["leads"] if l["unlockable"])
r = s.post(f"{BASE}/leads/{lead['id']}/unlock", json={"payWith": "credit"},
           headers={"Idempotency-Key": str(uuid.uuid4())})
if r.status_code == 429:
    time.sleep(int(r.headers.get("Retry-After", "5")))
r.raise_for_status()
print(r.json()["lead"]["company"])

Errors

Every error has the same shape. Branch on code; the message is for people.

{
  "error": {
    "code": "insufficient_credit",
    "message": "Not enough credit to unlock this lead. Top up on the website. Nothing was charged."
  }
}
Error status codes
StatusCodesMeaning
400invalid_request, idempotency_key_required, unknown_countryThe request is missing something or has a wrong value. Fix it before retrying.
401missing_api_key, invalid_api_key, revoked_api_key, wrong_environmentNo key, an unknown or revoked key, or a test key on the live site.
402insufficient_credit, no_free_unlocksNot enough credit. Top up on the website; nothing was charged.
403account_suspended, daily_spend_cap_reached, email_not_verifiedThe account or key may not do this right now.
404not_found, lead_not_found, job_not_foundNo such endpoint, lead or job on your account.
409already_unlocked, not_unlockable, idempotency_in_progressAlready yours, cannot be sold (no checked website), or the same request is still running.
422idempotency_key_reusedThat Idempotency-Key was used for a different request.
429rate_limitedToo many requests. Wait for the number of seconds in the Retry-After header.
503kill_switch, unavailableSearches and free unlocks are paused, or the daily capacity is used up. Nothing was charged.

Limits and retries

  • 60 requests per minute per key; lead searches and domain scans 6 per minute per key.
  • Your account's daily limits apply too (the same as the website: searches and domain scans per day, reset at 00:00 UTC).
  • A 429 answer carries Retry-After in seconds. Wait that long; do not retry in a tight loop.
  • POST /leads/{id}/unlock needs an Idempotency-Key header (for example a UUID). A retry with the same key returns the first answer and never charges twice. Errors are not stored, so after a top-up you can retry with the same key.
  • Searches take 20 to 60 seconds. Poll the job every 5 seconds; a job that has not finished after 3 minutes is reported as failed and you are not charged.
  • Optional per-key daily spend cap (set it when you create the key). Unlocks over the cap answer 403 daily_spend_cap_reached.

Pricing

The API costs nothing extra. Searching is free within your daily limits; you pay only for leads you unlock, at the same per-country price as on the pricing page, from the same prepaid credit. Free unlocks from a verified account can be used through the API too (send payWith: "credit" to keep them). A free unlock costs nothing, so no price is shown for it: priceUsd is left out of a lead you unlocked for free and of locked leads your free unlocks will pay for, and a free unlock's response has no chargedCents. Paid unlocks always show the price. If a lead you unlocked fails its checks, its price goes back to your balance, as on the website. Use of the API is covered by the Terms of Service and the email compliance rules.

MCP server for AI assistants

getLeads runs a remote MCP server (streamable HTTP) at https://getleads.site/api/mcp, using the same API key. Tools: get_balance, get_pricing, search_leads, get_job, list_leads, unlock_lead and scan_domain. unlock_lead spends money, so it only runs with confirm: true; the assistant is told to show you the price (or tell you it uses one of your free unlocks) and ask first. A search can take up to a minute; if it is still running the tool returns a job id and the assistant checks it with get_job.

Cursor

Add to ~/.cursor/mcp.json (or .cursor/mcp.json in a project you do not commit secrets from):

{
  "mcpServers": {
    "getleads": {
      "url": "https://getleads.site/api/mcp",
      "headers": {
        "Authorization": "Bearer gl_live_your_key_here"
      }
    }
  }
}

Claude Desktop

Claude Desktop's custom connectors expect OAuth, so connect through the mcp-remote bridge (needs Node.js). In Settings, Developer, Edit Config (claude_desktop_config.json):

{
  "mcpServers": {
    "getleads": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://getleads.site/api/mcp",
        "--header",
        "Authorization:${GETLEADS_AUTH}"
      ],
      "env": {
        "GETLEADS_AUTH": "Bearer gl_live_your_key_here"
      }
    }
  }
}

Hermes Agent (Nous Research)

Put the key in ~/.hermes/.env as GETLEADS_API_KEY=gl_live_..., then add to ~/.hermes/config.yaml:

mcp_servers:
  getleads:
    url: "https://getleads.site/api/mcp"
    headers:
      Authorization: "Bearer ${GETLEADS_API_KEY}"
    timeout: 120

Any other MCP client: point it at the URL above with the header Authorization: Bearer gl_live_.... The server is stateless (no session id, no server-sent events); a GET answers 405 as the protocol allows.

Get your API key

Sign in, open Profile Settings, Password & Security, and create a key. Searching is free; you pay only for leads you unlock.