All resources
Guide

Send leads in from Airscale, Clay, or anything else

Most list-building tools can post rows to a URL. Give them this one and every row comes back with an address that was checked against the mail server.

There are two ways to feed us rows, and picking the right one takes ten seconds: does your tool let you set a request header?

  1. Yes — use a normal API key against /api/v1/email/find. That is the path Clay’s HTTP API column and Airscale’s HTTP API action both take. See the Clay guide for that setup.
  2. No — use an inbound webhook. A tool’s “export to webhook” usually sends a URL and nothing else: no headers, no way to rename columns. That is what this guide is for.

Create the URL

  1. Open Developers and, under Inbound webhooks, click New webhook.
  2. Copy the URL straight away — it is shown once and cannot be retrieved later.
  3. Paste it into your tool as the webhook or POST destination.
https://www.findleademails.com/api/webhooks/ingest/whk_live_…

Anyone holding that URL can submit rows and spend your credits, which is why it is not your API key: it cannot read results, list your batches, or change anything in the workspace. If it leaks, revoke it on the same screen — revocation is immediate.

You do not have to rename your columns

This is the part that usually blocks a webhook integration, so it is handled at our end. We need a first name, a last name and a company domain, and we accept the spellings tools actually use:

What we needWhat we also accept
first_namefirstname, firstName, first, given_name
last_namelastname, lastName, last, surname
company_domaindomain, website, company_website
company_namecompany, companyName, organization

Everything else in the payload is ignored rather than rejected, so a tool that sends forty columns per row is fine. One flat object per request, a bare array, or a list under records, rows or leads all work — up to 50 rows per request.

Body or query params — either works

Clay and Airscale both give you a body editor and a “Query params” section, and either can hold column references. Use whichever suits the tool in front of you:

…/api/webhooks/ingest/whk_live_…?first_name=Ada&last_name=Lovelace&domain=example.com

The body is optional if the query carries everything, so a tool with no usable body editor can still drive the whole call. If both supply the same field the body wins — query params apply to the entire request, so treating them as defaults means adding one can never quietly override the per-row values you are already sending. With several rows in the body, query fields apply to all of them, which is handy for something genuinely shared like one domain.

Airscale

Airscale posts one row per request as a flat JSON object with all of its columns, and attaches no auth header — so the inbound webhook is the right fit for its webhook export.

  1. In Airscale, add a webhook export on your table and paste the URL as the destination.
  2. Leave its columns alone. Airscale sends domain rather than company_domain, which we map for you, along with first_name, last_name and company_name, which already match.
  3. Run it on a handful of rows first and check the result before sending a whole list.

One Airscale-specific thing worth knowing: when it has no address for a row it does not send an empty field — it sends the literal text not found in the email column. We treat that as “no email” and look one up. If you build your own integration against Airscale, handle that case explicitly, or you will end up trying to mail an address called “not found”.

If you use Airscale’s HTTP API action instead of its webhook export, that one can set headers — so you can use an API key and /api/v1/email/find directly. Either works; the inbound webhook just needs no header configuration at all.

Clay

Clay’s HTTP API column can set headers, so the API-key route is usually the better fit there. Use an inbound webhook when you are pushing rows out of Clay with a webhook action rather than enriching them in place — point the action at the URL and map your columns into the body, or send the whole row and let us pick out what we need.

Keeping guesses out of your sending column

By default we return our best result whatever its status, including a catch-all or a pattern prediction, both clearly labelled. That is right for research and wrong for a column you are about to mail-merge. Add a query parameter to the URL:

https://www.findleademails.com/api/webhooks/ingest/whk_live_…?verified_only=true

Now anything we could not confirm against the mail server comes back empty, with a reason. That includes an address you sent us — we never checked it, so we will not vouch for it. The column then contains confirmed addresses and blanks, and nothing in between.

What you get back

{
  "email":  "sarah.jones@acme.com",
  "status": "verified",
  "received": 1,
  "found": 1,
  "already_had_email": 0,
  "credits_used": 1
}

When you post a single row — which is how most tools do it — email and status sit at the top level, so a tool that writes one field into one column has something simple to point at.

Just the address, nothing else

If your tool writes the whole response body into a cell rather than letting you pick a field out of it, add format=text and the reply is the bare address:

…?first_name=Ada&last_name=Lovelace&domain=example.com&format=text

ada.lovelace@example.com

When there is no address, you get the row’s status instead — not_found, catch_all, predicted — rather than a phrase like “not found”. That is on purpose: the value is going into a column something downstream will treat as an address, and a status cannot be mistaken for one. It is the same trap Airscale sets by writing the literal text “not found” into its own email field, and it would be a poor joke to hand it straight back to you. It tells you more, too — a row withheld by verified_only says catch_all, so you can tell “we could not confirm this” from “there is nothing here”. Several rows give one line each, in order.

What it costs

The same as everywhere else: one credit for a confirmed mailbox, nothing for a catch-all, nothing for a miss, nothing for looking up someone you have already found. And nothing at all for a row that arrives with a usable address already on it — that one is handed straight back rather than looked up again, so pushing a mixed list through costs you only the rows that actually needed work.

Throughput — you should not have to tune anything

Tools like Airscale fire a burst by default: ten rows at once, whatever your plan allows. Rather than rejecting the overflow, an inbound webhook holds each request until a slot is free and then runs it. You get all ten answers, in the same response you were already reading — no retry settings to configure, no rows quietly missing.

The work is still paced to your rate, so the trade is time rather than failure: a launch of ten on the entry rate of 3 a second takes around fifteen seconds for the last row to come back. If that is too slow, raising your rate is what shortens it — the tier follows your plan and your credit balance, so topping up moves it as much as subscribing does.

Two things are still refused straight away rather than waited on, because waiting cannot help: running out of your daily allowance, and a queue so long the wait would outlast the request. Nothing is charged in either case. And for several thousand rows sitting in a file, uploading to Bulk is still faster and cheaper than streaming them through a webhook one at a time.

Ready to try it on a real list?

A few free lookups a day, no card. If it comes back verified, it’s genuinely verified.

Get started