Back to the leads

Free100Leads

API

Last updated 19 August 2026

Getting a key

Keys are created in your account and shown once. We store a hash, so nobody can look one up later, including us. Lose it and you create another. Revoking is immediate.

A key looks like f100_live_…. That prefix is fixed so secret scanners can recognise it if it ever reaches a public repository. Treat it as a password: server side only, never in a browser, never in a mobile app.

Making a request

Everything lives under https://api.free100leads.com/v1. Send the key as a bearer token.

curl "https://api.free100leads.com/v1/search?country=DE&industry_id=4&limit=100" \
  -H "Authorization: Bearer f100_live_..."

Searching

GET /v1/search needs at least one of country, industry_id or size_bucket. That is the same floor the website has: there is no way to ask for everything.

ParameterMeaning
countryISO-3166 alpha-2, e.g. DE
regionUS state name, lowercase. Only meaningful with country=US
industry_idFrom /v1/facets
size_bucket1 (1-10) through 8 (10001+)
contactemail or phone, to require that channel
titleJob title contains this text
limitUp to 500 a page
cursorFrom the previous response
{
  "data": [
    {
      "name": "…",
      "job_title": "…",
      "company": "…",
      "email": "…",
      "phone": "…",
      "city": "…",
      "region": null,
      "country": "DE",
      "industry": "computer software",
      "company_size": "51-200"
    }
  ],
  "next_cursor": "c_…",
  "exhausted": false,
  "usage": { "records_used": 4210, "records_included": 100000, "period_end": "…" }
}

Paging, and why there is no page number

Keep the next_cursor and pass it back to continue. You are never handed the same record twice within a search, until exhausted comes back true.

The cursor is signed and bound to your account and to the exact filters you used. One issued for a German search will be refused for a French one, and one issued to another account will be refused for yours. Start a new search by leaving it out.

There is deliberately no way to fetch a record by id, and no offset parameter. Both would let somebody walk the whole database in parallel, which is what this design exists to prevent.

The other endpoints

EndpointWhat it gives you
GET /v1/facetsEvery country, industry and size you can filter on, with counts
GET /v1/usageRecords used and left this period, and today
GET /v1/meWhich key this is, which plan, and its limits

Not being sold the same contact twice

Two different things stop a record reaching you twice.

Inside one search, the cursor is the guarantee. The walk only ever moves forward, so paging through a search cannot hand back a record it has already handed you, however many pages you take. It needs nothing from you beyond passing next_cursor back.

Across exports, a ledger is the guarantee. Every row that leaves as a CSV row is recorded against your account. Later exports skip it, and /v1/search stops returning it, so a contact you have already taken away does not reappear in a search two months later, and does not land in your CRM a second time.

Records count against your plan when they are delivered: on screen, in an API response, or in a bulk file. The suppression ledger is filled by exports, not searches. The bulk endpoint always skips records already in the ledger.

A record is written to the ledger when it leaves as a file, not when it appears in a search response. Within one search the cursor guarantees no repeats. Across two searches with overlapping filters, a record you saw but never exported can come round again. exhausted marks the end of a search.

The ledger belongs to the account rather than to a key, so every key and the web app read and write the same one, and it does not expire: a record exported in March is still suppressed in December. If you need a list back after losing it, the CSV download on your dashboard takes include_exported=true, and that does not charge you again. Those records were counted the first time they were delivered.

Limits

These numbers are published here so you never discover them in production.

LimitGrowthScale
Records a month100,0001,500,000
Records a day10,00050,000
Records an hour5,00025,000
Requests a minute2560
Requests in flight24
Keys310

Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset. A 429 also carries Retry-After in seconds. Usage counts the records you actually received, never the ones you asked for.

Daily limits ramp up to the plan's full rate over your first week. Monthly totals are never reduced.

Errors

{
  "error": {
    "type": "rate_limited",
    "message": "60 requests a minute is the limit on this plan.",
    "retry_after": 12,
    "docs": "https://free100leads.com/docs/api#rate_limited"
  }
}
TypeStatusWhat to do
invalid_request400Fix the parameters. Retrying unchanged will not help
unauthorized401The key is wrong, revoked or missing
quota_exhausted402Out of records. Deliberately not a 429, because backing off will not fix a billing state. Wait for the reset or upgrade
forbidden403The plan or the key does not carry this
not_found404No such endpoint or resource. Check the path
rate_limited429Slow down. Honour Retry-After
server_error500Ours. Retry with backoff, and tell us if it persists

What you may do with the data

Records are licensed for your own outreach. Do not resell them, republish them, or fold them into a product you sell. Delivered records carry traceable markers tied to the key that fetched them, so a list that turns up somewhere else can be traced back to the account it came from. The terms state this in full.

MCP

Point Claude, Codex or any other MCP-aware agent at https://api.free100leads.com/v1/mcp with the same key. It speaks JSON-RPC over HTTP and offers three tools: search_leads, get_facets and get_usage. They run the same code the endpoints above run, so an agent gets the same allowance, the same rate limits and the same cursor rules. There is no separate quota to keep track of.

Most MCP clients take a config block like this one, with your own key in place of the placeholder:

{
  "mcpServers": {
    "free100leads": {
      "url": "https://api.free100leads.com/v1/mcp",
      "headers": { "Authorization": "Bearer f100_live_..." }
    }
  }
}

Webhooks

Save a search, attach an endpoint, and new matches are posted to it as they land. Every delivery carries x-f100-timestamp and x-f100-signature. Check the signature against the secret shown when you created the endpoint, and reject anything with a timestamp more than five minutes old. A receiver that cannot tell our POST from anybody else's has an open endpoint.

Failures back off and retry. Ten consecutive failures switch the endpoint off and the error appears on your account page, so a dead URL stops being retried forever.

What is deliberately missing

Enrichment, meaning looking a person up by email, is not offered. Direct lookup of a specific individual would undo the anti-abuse design of the whole API.

Missing something you need? The contact form reaches a person.