MENU navbar-image

Introduction

This documentation aims to provide all the information you need to work with our API.

Rate limit: all endpoints have a concurrent rate limit of 300 simultaneous requests, unless stated otherwise.

This documentation aims to provide all the information you need to work with our API.

Rate limit: all endpoints have a concurrent rate limit of 300 simultaneous requests, unless stated otherwise.

Authenticating requests

To authenticate requests, include an Authorization header with the value "Bearer {YOUR_AUTH_KEY}".

All authenticated endpoints are marked with a requires authentication badge in the documentation below.

You can retrieve your token by visiting API page.

Email Verifier

Verify an email

requires authentication

Uses one verifier credit on all attempted verification

Example request:
curl --request POST \
    "https://app.findymail.com/api/verify" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"email\": \"[email protected]\"
}"
const url = new URL(
    "https://app.findymail.com/api/verify"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "email": "[email protected]"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{ "email": "[email protected]", "verified" : true, "provider": 'Google'}
 

Example response (200):


{
    "error": "Not enough credits"
}
 

Example response (402, Error : Not enough credits):


{
    "error": "Not enough credits"
}
 

Example response (423, Error : Subscription is paused):


{
    "error": "Subscription is paused"
}
 

Request      

POST api/verify

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Body Parameters

email   string     

Email to verify Example: [email protected]

Contacts

Get the list of contact lists

requires authentication

Example request:
curl --request GET \
    --get "https://app.findymail.com/api/lists" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}"
const url = new URL(
    "https://app.findymail.com/api/lists"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "lists": [
        {
            "id": 1,
            "name": "my list",
            "created_at": "2022-08-23T16:46:43.000000Z",
            "updated_at": "2022-08-23T16:46:43.000000Z",
            "shared_with_team": false,
            "is_owner": true
        }
    ]
}
 

Request      

GET api/lists

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Create a new list

requires authentication

Example request:
curl --request POST \
    "https://app.findymail.com/api/lists" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"name\": \"dolores\"
}"
const url = new URL(
    "https://app.findymail.com/api/lists"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "dolores"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "list": {
        "id": 1,
        "name": "new list",
        "created_at": "2022-08-23T16:46:43.000000Z",
        "updated_at": "2022-08-23T16:46:43.000000Z",
        "shared_with_team": false,
        "is_owner": true
    }
}
 

Request      

POST api/lists

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Body Parameters

name   string     

Name of the list Example: dolores

Update a contact list

requires authentication

Example request:
curl --request PUT \
    "https://app.findymail.com/api/lists/17" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"name\": \"aut\",
    \"isShared\": false
}"
const url = new URL(
    "https://app.findymail.com/api/lists/17"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "aut",
    "isShared": false
};

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "id": 1,
    "name": "updated list name",
    "created_at": "2022-08-23T16:46:43.000000Z",
    "updated_at": "2022-08-23T16:46:43.000000Z",
    "shared_with_team": true,
    "is_owner": true
}
 

Request      

PUT api/lists/{id}

PATCH api/lists/{id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

URL Parameters

id   integer     

The ID of the list. Example: 17

Body Parameters

name   string     

New name of the list Example: aut

isShared   boolean     

Enable/disable list sharing with the team Example: false

Delete a given list

requires authentication

Example request:
curl --request DELETE \
    "https://app.findymail.com/api/lists/10" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}"
const url = new URL(
    "https://app.findymail.com/api/lists/10"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (200, Success):


{}
 

Request      

DELETE api/lists/{id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

URL Parameters

id   integer     

The ID of the list. Example: 10

Get contacts saved

requires authentication

Example request:
curl --request GET \
    --get "https://app.findymail.com/api/contacts/get/9" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}"
const url = new URL(
    "https://app.findymail.com/api/contacts/get/9"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
      "draw": 0,
      "recordsTotal": 1,
      "recordsFiltered": 1,
      "data": [
          {
              "id": 1,
              "name": "John Doe",
              "email": "[email protected]",
              "linkedin_url": "https://www.linkedin.com/in/linkedin",
              "company": "MyCompany",
              "job_title": "CEO"
          },
      ],
}
 

Request      

GET api/contacts/get/{id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

URL Parameters

id   integer  optional    

Get contacts from a specified list. If 0, no list used ("All contacts"). Example: 9

Email Finder

Find from name

requires authentication

Find someone's email from name and company (website or name). Uses one finder credit if a verified email is found.

Example request:
curl --request POST \
    "https://app.findymail.com/api/search/name" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"name\": \"John Doe\",
    \"domain\": \"website.com\"
}"
const url = new URL(
    "https://app.findymail.com/api/search/name"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "John Doe",
    "domain": "website.com"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200, Success):


{
    "contact": {
        "name": "John Doe",
        "domain": "website.com",
        "email": "[email protected]"
    }
}
 

Example response (200, Webhook URL provided process asynchronous):


{
    "payload": {
        "contact": {
            "name": "john doe",
            "email": "[email protected]",
            "domain": "website.com"
        }
    }
}
 

Example response (402, Error : Not enough credits):


{
    "error": "Not enough credits"
}
 

Example response (423, Error : Subscription is paused):


{
    "error": "Subscription is paused"
}
 

Request      

POST api/search/name

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Body Parameters

name   string     

Person's full name Example: John Doe

domain   string     

Company domain (best) or company name Example: website.com

webhook_url   string  optional    

Webhook URL that will receive the result as callback. If submitted, email search will happen in the background and notify this URL upon completion.

Response

Response Fields

payload        

(when using webhook_url) object POST method callback request triggered when webhook_url provided. See example response

Find from domain

requires authentication

Try finding a contact with a valid email at a given domain with a given role. A contact is only returned if we found a valid email.

Due to the heavy processing involved (real-time search), this endpoint is limited to 5 concurrent requests (when used synchronously) and async jobs can take up to 24 hours to be processed depending on our workload (usually sooner).

Example request:
curl --request POST \
    "https://app.findymail.com/api/search/domain" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"domain\": \"domain.com\",
    \"roles\": [
        \"CEO\",
        \"Founder\"
    ],
    \"webhook_url\": \"http:\\/\\/www.medhurst.com\\/tenetur-et-voluptatem-ut-et.html\"
}"
const url = new URL(
    "https://app.findymail.com/api/search/domain"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "domain": "domain.com",
    "roles": [
        "CEO",
        "Founder"
    ],
    "webhook_url": "http:\/\/www.medhurst.com\/tenetur-et-voluptatem-ut-et.html"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (0, Webhook URL provided process asynchronous):


{
    "payload": {
        "contacts": [
            {
                "name": "say my name",
                "email": "[email protected]",
                "domain": "domain.com"
            }
        ]
    }
}
 

Example response (200):


{
    "contacts": [
        {
            "domain": "website.com",
            "email": "[email protected]",
            "name": "john doe"
        }
    ]
}
 

Example response (402, Error : Not enough credits):


{
    "error": "Not enough credits"
}
 

Example response (423, Error : Subscription is paused):


{
    "error": "Subscription is paused"
}
 

Request      

POST api/search/domain

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Body Parameters

domain   string     

Email domain Example: domain.com

roles   string[]     

Target roles related to the given domain (max 3 roles)

webhook_url   string  optional    

Webhook URL that will receive the result as callback. If submitted, search will happen in the background and notify this URL upon completion. Example: http://www.medhurst.com/tenetur-et-voluptatem-ut-et.html

Response

Response Fields

payload        

(when using webhook_url) object POST method callback request triggered when webhook_url provided. See example response

Find from business profile

requires authentication

Find someone's email from a business profile URL. Uses one finder credit if a verified email is found.

This endpoint is limited to 30 concurrent requests (when used synchronously)

Example request:
curl --request POST \
    "https://app.findymail.com/api/search/business-profile" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"linkedin_url\": \"https:\\/\\/www.linkedin.com\\/in\\/johndoe\"
}"
const url = new URL(
    "https://app.findymail.com/api/search/business-profile"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "linkedin_url": "https:\/\/www.linkedin.com\/in\/johndoe"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (0, Webhook URL provided process asynchronous):


{
    "payload": {
        "contact": {
            "name": "john doe",
            "email": "[email protected]",
            "domain": "website.com"
        }
    }
}
 

Example response (200):


{
    "contact": {
        "name": "John Doe",
        "domain": "website.com",
        "email": "[email protected]"
    }
}
 

Example response (402, Error : Not enough credits):


{
    "error": "Not enough credits"
}
 

Example response (423, Error : Subscription is paused):


{
    "error": "Subscription is paused"
}
 

Request      

POST api/search/business-profile

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Body Parameters

linkedin_url   string     

Person's business profile URL. (can be full URL "https://www.linkedin.com/in/johndoe" or username only "johndoe") Example: https://www.linkedin.com/in/johndoe

webhook_url   string  optional    

Webhook URL that will receive the result as callback. If submitted, email search will happen in the background and notify this URL upon completion.

Response

Response Fields

payload        

(when using webhook_url) object POST method callback request triggered when webhook_url provided. See example response

Exclusion Lists

APIs for managing excluded websites from Intellimatch searches

Get all exclusion lists

requires authentication

Returns all exclusion lists the authenticated user has access to (owned lists and lists shared with their team)

Example request:
curl --request GET \
    --get "https://app.findymail.com/api/intellimatch/exclusion-lists" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}"
const url = new URL(
    "https://app.findymail.com/api/intellimatch/exclusion-lists"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Ok):


{
    "lists": [
        {
            "id": 1,
            "name": "Competitors",
            "is_shared": true,
            "is_owner": true,
            "user_id": 123,
            "owner_name": "John Doe"
        }
    ]
}
 

Example response (401, Unauthenticated):


{
    "message": "Unauthenticated."
}
 

Request      

GET api/intellimatch/exclusion-lists

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Create a new exclusion list

requires authentication

Creates a new exclusion list for the authenticated user.

Optionally share the list with the user's current team.

Example request:
curl --request POST \
    "https://app.findymail.com/api/intellimatch/exclusion-lists" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"name\": \"Competitors\",
    \"is_shared\": true
}"
const url = new URL(
    "https://app.findymail.com/api/intellimatch/exclusion-lists"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Competitors",
    "is_shared": true
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200, Ok):


{
    "id": 1,
    "name": "Competitors",
    "is_shared": true,
    "is_owner": true
}
 

Example response (401, Unauthenticated):


{
    "message": "Unauthenticated."
}
 

Example response (422, Validation failed):


{
    "message": "The given data was invalid.",
    "errors": {
        "name": [
            "The name has already been taken."
        ]
    }
}
 

Request      

POST api/intellimatch/exclusion-lists

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Body Parameters

name   string     

The name of the list (must be unique per user). Example: Competitors

is_shared   boolean  optional    

Whether to share the list with the current team. Example: true

Get exclusion list details

requires authentication

Returns the details of a specific exclusion list (without domains). To get domains, use the dedicated GET /api/intellimatch/domains?list_id={id} endpoint. Users can only access lists they own or lists shared with their team.

Example request:
curl --request GET \
    --get "https://app.findymail.com/api/intellimatch/exclusion-lists/15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}"
const url = new URL(
    "https://app.findymail.com/api/intellimatch/exclusion-lists/15"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Ok):


{
    "id": 1,
    "name": "Competitors",
    "is_shared": true,
    "is_owner": true,
    "user_id": 123,
    "owner_name": "John Doe"
}
 

Example response (401, Unauthenticated):


{
    "message": "Unauthenticated."
}
 

Example response (403, Forbidden):


{
    "message": "This action is unauthorized."
}
 

Example response (404, Not found):


{
    "message": "No query results for model [ExcludedDomainList]."
}
 

Request      

GET api/intellimatch/exclusion-lists/{excludedDomainList_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

URL Parameters

excludedDomainList_id   integer     

The ID of the excludedDomainList. Example: 15

Update an exclusion list

requires authentication

Updates an exclusion list's name and/or sharing status.

Only the list owner can update or change sharing settings.

Example request:
curl --request PUT \
    "https://app.findymail.com/api/intellimatch/exclusion-lists/6" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"name\": \"Updated List Name\",
    \"is_shared\": true
}"
const url = new URL(
    "https://app.findymail.com/api/intellimatch/exclusion-lists/6"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Updated List Name",
    "is_shared": true
};

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200, Ok):


{
    "success": true,
    "list": {
        "id": 1,
        "name": "Updated List Name",
        "is_shared": true,
        "is_owner": true
    }
}
 

Example response (400, No team):


{
    "error": "You must be part of a team to share lists."
}
 

Example response (401, Unauthenticated):


{
    "message": "Unauthenticated."
}
 

Example response (403, Forbidden):


{
    "message": "This action is unauthorized."
}
 

Example response (404, Not found):


{
    "message": "No query results for model [ExcludedDomainList]."
}
 

Example response (422, Validation failed):


{
    "message": "The given data was invalid.",
    "errors": {
        "name": [
            "The name has already been taken."
        ]
    }
}
 

Request      

PUT api/intellimatch/exclusion-lists/{excludedDomainList_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

URL Parameters

excludedDomainList_id   integer     

The ID of the excludedDomainList. Example: 6

Body Parameters

name   string     

The new name for the list (must be unique per user). Example: Updated List Name

is_shared   boolean  optional    

Optional. Set to true to share with team, false to make private. Example: true

Delete an exclusion list

requires authentication

Deletes an exclusion list and all its associated domains.

Only the list owner can delete the list.

Example request:
curl --request DELETE \
    "https://app.findymail.com/api/intellimatch/exclusion-lists/15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}"
const url = new URL(
    "https://app.findymail.com/api/intellimatch/exclusion-lists/15"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (200, Ok):


{
    "success": true
}
 

Example response (401, Unauthenticated):


{
    "message": "Unauthenticated."
}
 

Example response (403, Forbidden):


{
    "message": "This action is unauthorized."
}
 

Example response (404, Not found):


{
    "message": "No query results for model [ExcludedDomainList]."
}
 

Request      

DELETE api/intellimatch/exclusion-lists/{excludedDomainList_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

URL Parameters

excludedDomainList_id   integer     

The ID of the excludedDomainList. Example: 15

Get excluded domains

requires authentication

Returns a paginated list of excluded domains for the authenticated user.

Can be filtered by list_id to get domains from a specific list, otherwise returns the global exclusion list.

Example request:
curl --request GET \
    --get "https://app.findymail.com/api/intellimatch/domains?query=example.com&list_id=1&per_page=15&page=1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}"
const url = new URL(
    "https://app.findymail.com/api/intellimatch/domains"
);

const params = {
    "query": "example.com",
    "list_id": "1",
    "per_page": "15",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Ok):


{
    "data": [
        {
            "id": 1,
            "domain": "competitor.com",
            "excluded_domain_list_id": 1
        },
        {
            "id": 2,
            "domain": "blocked.io",
            "excluded_domain_list_id": null
        }
    ],
    "current_page": 1,
    "per_page": 15,
    "total": 150
}
 

Example response (401, Unauthenticated):


{
    "message": "Unauthenticated."
}
 

Request      

GET api/intellimatch/domains

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Query Parameters

query   string  optional    

Search query to filter domains. Example: example.com

list_id   integer  optional    

Filter domains by list ID. Example: 1

per_page   integer  optional    

Number of domains per page. Example: 15

page   integer  optional    

Page number. Example: 1

Add excluded domains

requires authentication

Adds one or more domains to the user's exclusion list. If list_id is provided, domains are added to that specific list. For large batches (>50 domains), the first 50 are processed immediately and the rest are queued for background processing.

Example request:
curl --request POST \
    "https://app.findymail.com/api/intellimatch/domains" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"domains\": [
        \"competitor.com\",
        \"blocked.io\"
    ],
    \"list_id\": 1
}"
const url = new URL(
    "https://app.findymail.com/api/intellimatch/domains"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "domains": [
        "competitor.com",
        "blocked.io"
    ],
    "list_id": 1
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200, Ok):


{
    "success": true,
    "total": 150,
    "processed_immediately": 50,
    "queued": 100,
    "list_id": 1
}
 

Example response (401, Unauthenticated):


{
    "message": "Unauthenticated."
}
 

Example response (403, Forbidden):


{
    "message": "This action is unauthorized."
}
 

Example response (422, Validation failed):


{
    "message": "The given data was invalid.",
    "errors": {
        "domains": [
            "The domains field is required."
        ]
    }
}
 

Request      

POST api/intellimatch/domains

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Body Parameters

domains   string[]     

Array of domain names to exclude (max 10000).

list_id   integer  optional    

Optional list ID to add domains to. If not provided, domains are added as global exclusions. Example: 1

Remove excluded domains

requires authentication

Removes one or more domains from the user's exclusion lists.

Only domains the user has permission to delete will be removed.

For domains in shared lists, the user must have removeDomains permission on the list.

For global domains (no list), the user must own the domain.

Example request:
curl --request DELETE \
    "https://app.findymail.com/api/intellimatch/domains" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"ids\": [
        1,
        2,
        3
    ]
}"
const url = new URL(
    "https://app.findymail.com/api/intellimatch/domains"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "ids": [
        1,
        2,
        3
    ]
};

fetch(url, {
    method: "DELETE",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200, Ok):


{
    "success": true,
    "deleted_count": 3
}
 

Example response (200, No permission):


{
    "success": false,
    "deleted_count": 0
}
 

Example response (401, Unauthenticated):


{
    "message": "Unauthenticated."
}
 

Example response (422, Validation failed):


{
    "message": "The given data was invalid.",
    "errors": {
        "ids": [
            "The ids field is required."
        ]
    }
}
 

Request      

DELETE api/intellimatch/domains

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Body Parameters

ids   integer[]     

Array of domain IDs to delete.

Intellimatch

requires authentication

Create an Intellimatch search task.

Intellimatch is Findymail’s intelligent company search tool that lets you build highly targeted lead lists using plain language queries.

Instead of manually applying filters or reviewing websites one by one, Intellimatch uses real-time semantic search to find the best-fit companies and contacts.

The API responds immediately with a hash identifying the task for polling completion status.

Please check https://help.findymail.com/en/article/what-is-supported-in-intellimatch-15s0u10/ for more information about what is supported or not.

Example request:
curl --request POST \
    "https://app.findymail.com/api/intellimatch/search" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"query\": \"SaaS companies in US with 50-200 employees\",
    \"limit\": 100,
    \"config\": {
        \"find_contact\": true,
        \"find_email\": true,
        \"target_job_titles\": [
            \"CEO\",
            \"CTO\"
        ],
        \"mode\": \"broad\",
        \"find_phone\": false,
        \"lead_list_id\": 123,
        \"require_email\": true,
        \"add_to_exclusion_list\": true,
        \"exclusion_list_id\": 456,
        \"exclusion_filter_list_ids\": [
            1,
            2,
            3
        ]
    }
}"
const url = new URL(
    "https://app.findymail.com/api/intellimatch/search"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "query": "SaaS companies in US with 50-200 employees",
    "limit": 100,
    "config": {
        "find_contact": true,
        "find_email": true,
        "target_job_titles": [
            "CEO",
            "CTO"
        ],
        "mode": "broad",
        "find_phone": false,
        "lead_list_id": 123,
        "require_email": true,
        "add_to_exclusion_list": true,
        "exclusion_list_id": 456,
        "exclusion_filter_list_ids": [
            1,
            2,
            3
        ]
    }
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200, Ok):


{
    "hash": "74ebbec924a9666053d234eecc685a1d73c699d1"
}
 

Example response (401, Unauthenticated):


{
    "message": "Unauthenticated."
}
 

Example response (422, Validation failed):


{
    "message": "The given data was invalid.",
    "errors": {
        "query": [
            "The search query is required."
        ],
        "limit": [
            "The limit cannot exceed 5000 companies."
        ]
    }
}
 

Example response (423, Subscription issue):


{
    "error": "Your subscription is currently paused."
}
 

Example response (429, Too Many Attempts):


{
    "message": "Too Many Attempts."
}
 

Response

Response Fields

hash   string     

Unique hash to track the export progress and retrieve results.

Get export status

requires authentication

Poll this endpoint to check if a given search is completed.

The response will contain a status field with one of the following values:

Example request:
curl --request GET \
    --get "https://app.findymail.com/api/intellimatch/status?hash=74ebbec924a9666053d234eecc685a1d73c699d1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}"
const url = new URL(
    "https://app.findymail.com/api/intellimatch/status"
);

const params = {
    "hash": "74ebbec924a9666053d234eecc685a1d73c699d1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Export processing):


{
    "status": "processing",
    "progress": 45,
    "total_jobs": 100,
    "processed_jobs": 45,
    "pending_jobs": 55,
    "failed_jobs": 0
}
 

Example response (401, Unauthenticated):


{
    "message": "Unauthenticated."
}
 

Example response (422, Validation failed):


{
    "message": "The given data was invalid.",
    "errors": {
        "hash": [
            "The hash parameter is required."
        ]
    }
}
 

Example response (423, Subscription issue):


{
    "error": "Your subscription is currently paused."
}
 

Example response (429, Too Many Attempts):


{
    "message": "Too Many Attempts."
}
 

Request      

GET api/intellimatch/status

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Query Parameters

hash   string     

The export hash returned by the search endpoint. Example: 74ebbec924a9666053d234eecc685a1d73c699d1

Response

Response Fields

status   string     

The current status of the export.

progress   integer     

The progress percentage (only when status is "processing").

total_jobs   integer     

Total number of jobs (only when status is "processing").

processed_jobs   integer     

Number of processed jobs (only when status is "processing").

pending_jobs   integer     

Number of pending jobs (only when status is "processing").

failed_jobs   integer     

Number of failed jobs (only when status is "processing").

Get results

requires authentication

Retrieve paginated company and contact results from a completed search task.

Example request:
curl --request GET \
    --get "https://app.findymail.com/api/intellimatch/data?hash=74ebbec924a9666053d234eecc685a1d73c699d1&page=1&per_page=100" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}"
const url = new URL(
    "https://app.findymail.com/api/intellimatch/data"
);

const params = {
    "hash": "74ebbec924a9666053d234eecc685a1d73c699d1",
    "page": "1",
    "per_page": "100",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Ok):


{
    "data": [
        {
            "id": 1,
            "name": "Acme Corp",
            "domain": "acme.com",
            "description": "Leading SaaS company",
            "employee_count_range": "51-200",
            "industries": [
                "Technology",
                "Software"
            ],
            "country": "FR",
            "match_score": 95,
            "contact_name": "John Doe",
            "contact_email": "[email protected]",
            "contact_job_title": "CEO",
            "contact_phone": "+33 6 12 34 56 78",
            "contact_linkedin_url": "https://www.linkedin.com/in/johndoe"
        }
    ],
    "meta": {
        "current_page": 1,
        "per_page": 100,
        "total": 250,
        "last_page": 3,
        "from": 1,
        "to": 100
    }
}
 

Example response (401, Unauthenticated):


{
    "message": "Unauthenticated."
}
 

Example response (404, Export not found):


{
    "status": "error",
    "message": "Export not found or not ready yet"
}
 

Example response (422, Validation failed):


{
    "message": "The given data was invalid.",
    "errors": {
        "hash": [
            "The hash parameter is required."
        ],
        "per_page": [
            "The per_page cannot exceed 500."
        ]
    }
}
 

Example response (423, Subscription issue):


{
    "error": "Your subscription is currently paused."
}
 

Example response (429, Too Many Attempts):


{
    "message": "Too Many Attempts."
}
 

Request      

GET api/intellimatch/data

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Query Parameters

hash   string     

The hash returned by the search endpoint. Example: 74ebbec924a9666053d234eecc685a1d73c699d1

page   integer  optional    

The page number (default: 1). Example: 1

per_page   integer  optional    

Results per page (max: 500, default: 100). Example: 100

requires authentication

Find companies similar to a given seed domain.

Optionally filter results by same country or same company size, and exclude companies from specific exclusion lists.

Credit cost: 1 Finder credit per 10 results returned (rounded up).

Example request:
curl --request POST \
    "https://app.findymail.com/api/lookalike/search" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"seed\": \"stripe.com\",
    \"same_country\": true,
    \"same_size\": false,
    \"limit\": 100,
    \"exclusion_list_ids\": [
        1,
        2
    ]
}"
const url = new URL(
    "https://app.findymail.com/api/lookalike/search"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "seed": "stripe.com",
    "same_country": true,
    "same_size": false,
    "limit": 100,
    "exclusion_list_ids": [
        1,
        2
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200, Ok):


{
    "companies": [
        {
            "domain": "notion.so",
            "name": "Notion",
            "linkedin_url": "https://www.linkedin.com/company/notionhq",
            "company_size": "501-1000",
            "country": "United States"
        },
        {
            "domain": "airtable.com",
            "name": "Airtable",
            "linkedin_url": "https://www.linkedin.com/company/airtable",
            "company_size": "501-1000",
            "country": "United States"
        }
    ],
    "total": 2,
    "credits_used": 1
}
 

Example response (200, No results with message):


{
    "companies": [],
    "total": 0,
    "credits_used": 0,
    "message": "We don't have country data for example.com yet. The same country filter is not available at the moment but will be soon."
}
 

Example response (402, Not enough credits):


{
    "error": "insufficient_credits",
    "message": "You don't have enough credits."
}
 

Example response (422, Seed not processable):


{
    "error": "seed_not_processable",
    "message": "We could not process this domain. Please try another one."
}
 

Example response (422, Validation failed):


{
    "message": "The given data was invalid.",
    "errors": {
        "seed": [
            "The seed must be a valid domain or URL. Given: not-a-domain"
        ]
    }
}
 

Example response (423, Subscription issue):


{
    "error": "Your subscription is currently paused."
}
 

Example response (429, Too Many Attempts):


{
    "message": "Too Many Attempts."
}
 

Example response (500, Internal error):


{
    "error": "internal_error",
    "message": "An unexpected error occurred. Please try again later."
}
 

Response

Response Fields

companies   object[]     

List of similar companies found.

domain   string     

The company domain.

name   string     

The company name.

linkedin_url   string     

The company LinkedIn URL (nullable).

company_size   string     

Employee count range (e.g. "51-200").

country   string     

Country display name (nullable).

total   integer     

Total number of companies returned.

credits_used   integer     

Number of Finder credits consumed.

message   string     

Informational message when filters cannot be applied (only present when relevant).

Misc

Reverse email lookup

requires authentication

Find a business profile from an email address (work email or personal email).

Credit usage:

Example request:
curl --request POST \
    "https://app.findymail.com/api/search/reverse-email" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"email\": \"[email protected]\",
    \"with_profile\": false
}"
const url = new URL(
    "https://app.findymail.com/api/search/reverse-email"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "email": "[email protected]",
    "with_profile": false
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200, Without profile enrichment):


{
    "linkedin_url": "https://www.linkedin.com/in/johndoe"
}
 

Example response (200, With profile enrichment):


{
    "fullName": "John Doe",
    "username": "johndoe",
    "headline": "CEO at Example",
    "jobTitle": "CEO",
    "summary": "Summary",
    "city": "City",
    "region": "Region",
    "country": "Country",
    "companyLinkedinUrl": "https://linkedin.com/company/example",
    "companyName": "Example",
    "companyWebsite": "example.com",
    "isPremium": true,
    "isOpenProfile": true,
    "skills": [],
    "jobs": [],
    "educations": [
        {
            "school": "Harvard University",
            "degree": "Bachelor of Science",
            "fieldOfStudy": "Computer Science",
            "startDate": "2010-09",
            "endDate": "2014-06"
        }
    ],
    "certificates": [
        {
            "name": "AWS Solutions Architect",
            "issuingOrganization": "Amazon Web Services",
            "issueDate": "2020-01",
            "expirationDate": "2023-01"
        }
    ]
}
 

Example response (200, No LinkedIn URL found):


{
    "linkedin_url": null
}
 

Example response (402, Error : Not enough credits):


{
    "error": "Not enough credits"
}
 

Example response (423, Error : Subscription is paused):


{
    "error": "Subscription is paused"
}
 

Request      

POST api/search/reverse-email

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Body Parameters

email   string     

Email address to lookup Example: [email protected]

with_profile   boolean  optional    

optional Whether to return profile metadata (default: false) Example: false

Get company information

requires authentication

Retrieve company data using a company profile URL, name, or website domain. At least one of these fields must be specified.

Consumes 1 Finder credit per successful response (only when company data is found).

Example request:
curl --request POST \
    "https://app.findymail.com/api/search/company" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"linkedin_url\": \"https:\\/\\/www.linkedin.com\\/company\\/findymail\\/\",
    \"domain\": \"stripe.com\",
    \"name\": \"Stripe\"
}"
const url = new URL(
    "https://app.findymail.com/api/search/company"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "linkedin_url": "https:\/\/www.linkedin.com\/company\/findymail\/",
    "domain": "stripe.com",
    "name": "Stripe"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "name": "Stripe",
    "domain": "stripe.com",
    "company_size": "1001-5000",
    "industry": "Financial Services",
    "linkedin_url": "https://www.linkedin.com/company/stripe/",
    "description": "Stripe is a technology company..."
}
 

Example response (404):


{
    "message": "Not Found"
}
 

Example response (422):


{
    "error": "One identifier is required: linkedin_url, domain, name"
}
 

Request      

POST api/search/company

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Body Parameters

linkedin_url   string  optional    

Company LinkedIn URL Example: https://www.linkedin.com/company/findymail/

domain   string  optional    

Company domain Example: stripe.com

name   string  optional    

Company name Example: Stripe

Find employees

requires authentication

Find one or more employees using the company website and job title.

This endpoint uses 1 credit per found contact.

This endpoint does NOT return an email.

Example request:
curl --request POST \
    "https://app.findymail.com/api/search/employees" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"website\": \"google.com\",
    \"job_titles\": [
        \"Software Engineer\",
        \"CEO\"
    ],
    \"count\": 2
}"
const url = new URL(
    "https://app.findymail.com/api/search/employees"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "website": "google.com",
    "job_titles": [
        "Software Engineer",
        "CEO"
    ],
    "count": 2
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


[
    {
        "name": "John Done",
        "linkedinUrl": "https://www.linkedin.com/in/john-doe/",
        "companyWebsite": "https://www.findymail.com",
        "companyName": "Findymail",
        "jobTitle": "Software Engineer"
    }
]
 

Example response (402, Error : Not enough credits):


{
    "error": "Not enough credits"
}
 

Example response (423, Error : Subscription is paused):


{
    "error": "Subscription is paused"
}
 

Request      

POST api/search/employees

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Body Parameters

website   string     

company website Example: google.com

job_titles   string[]     

target job titles (max 10)

count   integer  optional    

Number of contacts to return (max 5). Default 1. Example: 2

Phone Finder

Find phone

requires authentication

Find someone's phone number from a business profile URL. Uses 10 finder credits if a phone is found.

For legal reasons, requests for EU citizens will not return any result.

Example request:
curl --request POST \
    "https://app.findymail.com/api/search/phone" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"linkedin_url\": \"https:\\/\\/www.linkedin.com\\/in\\/johndoe\"
}"
const url = new URL(
    "https://app.findymail.com/api/search/phone"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "linkedin_url": "https:\/\/www.linkedin.com\/in\/johndoe"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "phone": "+1234567890",
    "line_type": "Mobile"
}
 

Example response (200, Phone not found):


{
    "phone": null,
    "line_type": null
}
 

Example response (402, Error : Not enough credits):


{
    "error": "Not enough credits"
}
 

Example response (423, Error : Subscription is paused):


{
    "error": "Subscription is paused"
}
 

Request      

POST api/search/phone

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Body Parameters

linkedin_url   string     

Person's business profile URL. (can be full URL "https://www.linkedin.com/in/johndoe" or username only "johndoe") Example: https://www.linkedin.com/in/johndoe

Response

Response Fields

phone   string     

The phone number in E.164 format (e.g. +1234567890), or null if not found. Only available for US numbers.

line_type   string     

The type of phone line (e.g. "Mobile", "Landline"), or null if not found.

Signals

List signals

requires authentication

Returns a paginated list of signals from monitors accessible by the authenticated user (owned and team-shared). Supports filtering by signal_type, monitor_id, and date range.

Example request:
curl --request GET \
    --get "https://app.findymail.com/api/signals?signal_type=keyword_mention&monitor_id=1&date_from=2026-01-01&date_to=2026-03-01&relevance_scores=3%2C4%2C5&page=1&per_page=50" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}"
const url = new URL(
    "https://app.findymail.com/api/signals"
);

const params = {
    "signal_type": "keyword_mention",
    "monitor_id": "1",
    "date_from": "2026-01-01",
    "date_to": "2026-03-01",
    "relevance_scores": "3,4,5",
    "page": "1",
    "per_page": "50",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Ok):


{
    "data": [
        {
            "id": 1,
            "type": "keyword_mention",
            "category": "contact",
            "payload": {
                "matched_keyword": "hiring",
                "snippet": "We are hiring a new VP of Sales..."
            },
            "detected_at": "2026-03-01T12:00:00+00:00",
            "expires_at": "2026-06-01T12:00:00+00:00",
            "contact": {
                "id": 1,
                "name": "John Doe",
                "job_title": "CEO",
                "linkedin_url": "https://www.linkedin.com/in/johndoe"
            },
            "company": {
                "id": 1,
                "name": "Acme Corp",
                "domain": "acme.com",
                "industry": "Technology, Information and Internet",
                "employee_count_range": "51-200",
                "country": "US"
            },
            "monitors": [
                {
                    "id": 1,
                    "name": "Hiring monitor",
                    "keywords": [
                        "hiring"
                    ],
                    "enrichment_level": "email",
                    "relevance_score": 4,
                    "relevance_reasoning": "Post discusses active hiring for sales roles"
                }
            ]
        }
    ],
    "meta": {
        "current_page": 1,
        "per_page": 50,
        "total": 1,
        "last_page": 1,
        "from": 1,
        "to": 1
    }
}
 

Example response (401, Unauthenticated):


{
    "message": "Unauthenticated."
}
 

Example response (404, Feature disabled):


{}
 

Example response (422, Validation failed):


{
    "message": "The given data was invalid."
}
 

Request      

GET api/signals

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Query Parameters

signal_type   string  optional    

Filter by signal type. Accepted values: keyword_mention, new_hire, job_change, post_engagement. Example: keyword_mention

monitor_id   integer  optional    

Filter by a specific monitor ID (must be accessible by the authenticated user). Example: 1

date_from   string  optional    

Filter signals detected on or after this date (format: YYYY-MM-DD). Example: 2026-01-01

date_to   string  optional    

Filter signals detected on or before this date (format: YYYY-MM-DD). Example: 2026-03-01

relevance_scores   string  optional    

Comma-separated AI relevance scores to include (0-5). Optionally combine with monitor_id to scope to a single monitor. Example: 3,4,5

page   integer  optional    

The page number (default: 1). Example: 1

per_page   integer  optional    

Results per page (max: 100, default: 50). Example: 50

List monitors

requires authentication

Returns all monitors accessible by the authenticated user (owned and team-shared), ordered by most recent first. Each monitor includes a match_count with the number of signals matched.

Example request:
curl --request GET \
    --get "https://app.findymail.com/api/signals/monitors?ownership=my" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}"
const url = new URL(
    "https://app.findymail.com/api/signals/monitors"
);

const params = {
    "ownership": "my",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Ok):


[
    {
        "id": 1,
        "name": "Hiring monitor",
        "signal_type": "keyword_mention",
        "signal_type_label": "Keyword Mention",
        "signal_level": "contact",
        "status": "active",
        "keywords": [
            "hiring",
            "fundraise"
        ],
        "icp_filters": {
            "industries": [
                "Biotechnology"
            ],
            "countries": [
                "US"
            ]
        },
        "webhook_url": "https://example.com/webhooks/signals",
        "webhook_paused_at": null,
        "post_url": null,
        "profile_url": null,
        "engagement_types": null,
        "enrichment_level": "email",
        "lead_list_id": null,
        "ai_relevance_prompt": null,
        "target_companies": null,
        "match_count": 42,
        "is_shared": true,
        "is_owner": true,
        "is_team_owner": false,
        "user_id": 42,
        "owner_name": "Jane Doe",
        "created_at": "2026-02-01T10:00:00.000000Z"
    }
]
 

Example response (401, Unauthenticated):


{
    "message": "Unauthenticated."
}
 

Example response (404, Feature disabled):


{}
 

Request      

GET api/signals/monitors

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Query Parameters

ownership   string  optional    

Filter by ownership scope. Accepted values: my, team, all. Example: my

Create a monitor

requires authentication

Creates a new signal monitor for the authenticated user.

Example request:
curl --request POST \
    "https://app.findymail.com/api/signals/monitors" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"name\": \"Hiring monitor\",
    \"signal_type\": \"keyword_mention\",
    \"keywords\": [
        \"hiring\",
        \"fundraise\"
    ],
    \"webhook_url\": \"https:\\/\\/example.com\\/webhooks\\/signals\",
    \"enrichment_level\": \"email\",
    \"lead_list_id\": 42,
    \"ai_relevance_prompt\": \"Focus on Series B+ SaaS companies hiring VP Sales.\",
    \"is_shared\": false,
    \"icp_filters\": {
        \"industries\": [
            \"Biotechnology\"
        ],
        \"employee_count_ranges\": [
            \"51-200\"
        ],
        \"countries\": [
            \"US\",
            \"FR\"
        ],
        \"job_title_keywords\": [
            \"VP Sales\",
            \"CTO\"
        ],
        \"seniority_levels\": [
            11,
            13
        ]
    }
}"
const url = new URL(
    "https://app.findymail.com/api/signals/monitors"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Hiring monitor",
    "signal_type": "keyword_mention",
    "keywords": [
        "hiring",
        "fundraise"
    ],
    "webhook_url": "https:\/\/example.com\/webhooks\/signals",
    "enrichment_level": "email",
    "lead_list_id": 42,
    "ai_relevance_prompt": "Focus on Series B+ SaaS companies hiring VP Sales.",
    "is_shared": false,
    "icp_filters": {
        "industries": [
            "Biotechnology"
        ],
        "employee_count_ranges": [
            "51-200"
        ],
        "countries": [
            "US",
            "FR"
        ],
        "job_title_keywords": [
            "VP Sales",
            "CTO"
        ],
        "seniority_levels": [
            11,
            13
        ]
    }
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (201, Created):


{
    "id": 1,
    "name": "Hiring monitor",
    "signal_type": "keyword_mention",
    "signal_type_label": "Keyword Mention",
    "signal_level": "contact",
    "status": "active",
    "keywords": [
        "hiring",
        "fundraise"
    ],
    "icp_filters": null,
    "webhook_url": null,
    "webhook_paused_at": null,
    "post_url": null,
    "profile_url": null,
    "engagement_types": null,
    "enrichment_level": null,
    "lead_list_id": null,
    "ai_relevance_prompt": null,
    "target_companies": null,
    "match_count": 0,
    "is_shared": false,
    "is_owner": true,
    "is_team_owner": false,
    "user_id": 42,
    "owner_name": "Jane Doe",
    "created_at": "2026-02-01T10:00:00.000000Z"
}
 

Example response (401, Unauthenticated):


{
    "message": "Unauthenticated."
}
 

Example response (404, Feature disabled):


{}
 

Example response (422, Validation failed):


{
    "message": "The given data was invalid."
}
 

Request      

POST api/signals/monitors

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Body Parameters

name   string     

The monitor name. Example: Hiring monitor

signal_type   string     

The signal type. Accepted values: keyword_mention, new_hire, job_change, post_engagement, company_hiring. Example: keyword_mention

keywords   string[]  optional    

Keywords to track (required for keyword_mention and post_engagement without post_url, max 5).

webhook_url   string  optional    

Optional HTTPS URL to receive webhook notifications when new signals match. Example: https://example.com/webhooks/signals

post_url   string  optional    

LinkedIn post URL to monitor engagement on (post_engagement only).

profile_url   string  optional    

LinkedIn profile URL to monitor (alternative to post_url, post_engagement only).

engagement_types   string[]  optional    

Engagement types to track (required for post_engagement). Accepted values: like, comment.

enrichment_level   string  optional    

Contact enrichment level. Accepted values: email, email_phone. Example: email

lead_list_id   integer  optional    

ID of a lead list to automatically add matched contacts to. Example: 42

ai_relevance_prompt   string  optional    

Optional custom prompt used to score AI relevance of matched signals (max 500 chars). Example: Focus on Series B+ SaaS companies hiring VP Sales.

target_companies   string[]  optional    

Target companies (names or domains) to filter signals (max 100). Only accepted for new_hire and job_change — returns 422 for any other signal type.

is_shared   boolean  optional    

Opt-in flag to share the monitor with the user's current team (defaults to false). Example: false

icp_filters   object  optional    

Optional ICP filter criteria to narrow signal matching.

industries   string[]  optional    

Industries to match (LinkedIn Industry Codes V2).

employee_count_ranges   string[]  optional    

Employee count ranges. Accepted values: 1-10, 11-50, 51-200, 201-500, 501-1000, 1001-5000, 5001-10000, 10001+.

countries   string[]  optional    

2-letter ISO 3166-1 alpha-2 country codes.

job_title_keywords   string[]  optional    

Contact job title keywords (max 10, rejected for company_hiring — no contact).

seniority_levels   integer[]  optional    

Seniority levels (rejected for company_hiring — no contact). (1=Entry, 4=IC, 6=Senior IC, 8=Management, 9=Director, 11=VP, 13=Executive, 14=C-Suite, 15=Founder).

job_offer_title_keywords   string[]  optional    

Job offer title keywords to watch for (required for company_hiring, rejected for other types, max 10). Substring match, OR logic, case-insensitive.

Update a monitor

requires authentication

Updates an existing monitor. The signal_type cannot be changed after creation.

Example request:
curl --request PATCH \
    "https://app.findymail.com/api/signals/monitors/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"name\": \"Updated monitor name\",
    \"keywords\": [
        \"hiring\",
        \"fundraise\"
    ],
    \"webhook_url\": \"https:\\/\\/example.com\\/webhooks\\/signals\",
    \"enrichment_level\": \"email\",
    \"lead_list_id\": 42,
    \"ai_relevance_prompt\": \"Focus on Series B+ SaaS companies hiring VP Sales.\",
    \"is_shared\": true,
    \"icp_filters\": {
        \"industries\": [
            \"Biotechnology\"
        ],
        \"employee_count_ranges\": [
            \"51-200\"
        ],
        \"countries\": [
            \"US\",
            \"FR\"
        ],
        \"job_title_keywords\": [
            \"VP Sales\"
        ],
        \"seniority_levels\": [
            11,
            13
        ]
    }
}"
const url = new URL(
    "https://app.findymail.com/api/signals/monitors/1"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Updated monitor name",
    "keywords": [
        "hiring",
        "fundraise"
    ],
    "webhook_url": "https:\/\/example.com\/webhooks\/signals",
    "enrichment_level": "email",
    "lead_list_id": 42,
    "ai_relevance_prompt": "Focus on Series B+ SaaS companies hiring VP Sales.",
    "is_shared": true,
    "icp_filters": {
        "industries": [
            "Biotechnology"
        ],
        "employee_count_ranges": [
            "51-200"
        ],
        "countries": [
            "US",
            "FR"
        ],
        "job_title_keywords": [
            "VP Sales"
        ],
        "seniority_levels": [
            11,
            13
        ]
    }
};

fetch(url, {
    method: "PATCH",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200, Ok):


{
    "id": 1,
    "name": "Updated monitor name",
    "signal_type": "keyword_mention",
    "signal_type_label": "Keyword Mention",
    "signal_level": "contact",
    "status": "active",
    "keywords": [
        "hiring",
        "fundraise"
    ],
    "icp_filters": null,
    "webhook_url": null,
    "webhook_paused_at": null,
    "post_url": null,
    "profile_url": null,
    "engagement_types": null,
    "enrichment_level": null,
    "lead_list_id": null,
    "ai_relevance_prompt": null,
    "target_companies": null,
    "match_count": 42,
    "is_shared": true,
    "is_owner": true,
    "is_team_owner": false,
    "user_id": 42,
    "owner_name": "Jane Doe",
    "created_at": "2026-02-01T10:00:00.000000Z"
}
 

Example response (401, Unauthenticated):


{
    "message": "Unauthenticated."
}
 

Example response (403, Forbidden):


{
    "message": "This action is unauthorized."
}
 

Example response (404, Feature disabled):


{}
 

Example response (422, Validation failed):


{
    "message": "The given data was invalid."
}
 

Request      

PATCH api/signals/monitors/{id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

URL Parameters

id   integer     

The ID of the monitor. Example: 1

Body Parameters

name   string     

The monitor name. Example: Updated monitor name

keywords   string[]  optional    

Keywords to track (required for keyword_mention, nullable otherwise, max 5).

webhook_url   string  optional    

Optional HTTPS URL to receive webhook notifications. Example: https://example.com/webhooks/signals

engagement_types   string[]  optional    

Engagement types to track (required for post_engagement). Accepted values: like, comment.

enrichment_level   string  optional    

Contact enrichment level. Accepted values: email, email_phone. Example: email

lead_list_id   integer  optional    

ID of a lead list to automatically add matched contacts to. Example: 42

ai_relevance_prompt   string  optional    

Optional custom prompt used to score AI relevance of matched signals (max 500 chars). Example: Focus on Series B+ SaaS companies hiring VP Sales.

target_companies   string[]  optional    

Target companies (names or domains) to filter signals (max 100). Only accepted for new_hire and job_change — returns 422 for any other signal type.

is_shared   boolean  optional    

Optional opt-in flag to share/unshare the monitor with the user's current team. Only owner or team admin can change sharing. Example: true

icp_filters   object  optional    

Optional ICP filter criteria.

industries   string[]  optional    

Industries to match (LinkedIn Industry Codes V2).

employee_count_ranges   string[]  optional    

Accepted values: 1-10, 11-50, 51-200, 201-500, 501-1000, 1001-5000, 5001-10000, 10001+.

countries   string[]  optional    

2-letter ISO 3166-1 alpha-2 country codes.

job_title_keywords   string[]  optional    

Contact job title keywords (max 10, rejected for company_hiring — no contact).

seniority_levels   integer[]  optional    

Seniority levels (rejected for company_hiring — no contact). (1=Entry, 4=IC, 6=Senior IC, 8=Management, 9=Director, 11=VP, 13=Executive, 14=C-Suite, 15=Founder).

job_offer_title_keywords   string[]  optional    

Job offer title keywords (company_hiring only, max 10).

Delete a monitor

requires authentication

Soft-deletes the specified monitor.

Example request:
curl --request DELETE \
    "https://app.findymail.com/api/signals/monitors/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}"
const url = new URL(
    "https://app.findymail.com/api/signals/monitors/1"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (204, Deleted):

Empty response
 

Example response (401, Unauthenticated):


{
    "message": "Unauthenticated."
}
 

Example response (403, Forbidden):


{
    "message": "This action is unauthorized."
}
 

Example response (404, Feature disabled):


{}
 

Request      

DELETE api/signals/monitors/{id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

URL Parameters

id   integer     

The ID of the monitor. Example: 1

Get a signal

requires authentication

Returns a single signal with its associated contact, company, and the authenticated user's monitors.

Example request:
curl --request GET \
    --get "https://app.findymail.com/api/signals/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}"
const url = new URL(
    "https://app.findymail.com/api/signals/1"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Ok):


{
    "id": 1,
    "type": "keyword_mention",
    "category": "contact",
    "payload": {
        "matched_keyword": "hiring",
        "snippet": "We are hiring a new VP of Sales..."
    },
    "detected_at": "2026-03-01T12:00:00+00:00",
    "expires_at": "2026-06-01T12:00:00+00:00",
    "contact": {
        "id": 1,
        "name": "John Doe",
        "job_title": "CEO",
        "linkedin_url": "https://www.linkedin.com/in/johndoe"
    },
    "company": {
        "id": 1,
        "name": "Acme Corp",
        "domain": "acme.com",
        "industry": "Technology, Information and Internet",
        "employee_count_range": "51-200",
        "country": "US"
    },
    "monitors": [
        {
            "id": 1,
            "name": "Hiring monitor",
            "keywords": [
                "hiring"
            ],
            "enrichment_level": "email"
        }
    ]
}
 

Example response (401, Unauthenticated):


{
    "message": "Unauthenticated."
}
 

Example response (403, Forbidden):


{
    "message": "This action is unauthorized."
}
 

Example response (404, Feature disabled):


{}
 

Request      

GET api/signals/{id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

URL Parameters

id   integer     

The ID of the signal. Example: 1

Technologies

requires authentication

Search the technology catalog by name. Returns up to 25 technologies.

Free endpoint — no credits consumed. Rate-limited to 10 requests per minute.

Example request:
curl --request GET \
    --get "https://app.findymail.com/api/technologies/search?q=React" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}"
const url = new URL(
    "https://app.findymail.com/api/technologies/search"
);

const params = {
    "q": "React",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Ok):


{
    "data": [
        {
            "name": "React",
            "category": "Programming Languages And Frameworks",
            "subcategory": "Frameworks"
        }
    ]
}
 

Example response (422, Validation failed):


{
    "message": "The given data was invalid.",
    "errors": {
        "q": [
            "The q field is required."
        ]
    }
}
 

Example response (429, Too Many Attempts):


{
    "message": "Too Many Attempts."
}
 

Response

Response Fields

data   object[]     

List of matching technologies.

name   string     

Technology name.

category   string     

Technology category (nullable).

subcategory   string     

Technology subcategory (nullable).

Lookup technologies by domain

requires authentication

Get the technology stack for a company by its domain.

Optionally filter by technology name (case-insensitive).

Credit cost: 1 Finder credit when technologies are found. Free when no results.

Example request:
curl --request POST \
    "https://app.findymail.com/api/technologies" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --data "{
    \"domain\": \"stripe.com\",
    \"technologies\": [
        \"React\",
        \"typescript\"
    ]
}"
const url = new URL(
    "https://app.findymail.com/api/technologies"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "domain": "stripe.com",
    "technologies": [
        "React",
        "typescript"
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200, Technologies found):


{
    "domain": "stripe.com",
    "technologies": [
        {
            "name": "React",
            "category": "Programming Languages And Frameworks",
            "subcategory": "Frameworks",
            "last_detected_at": "2026-03-15T10:00:00.000000Z"
        }
    ]
}
 

Example response (200, No results (no credit charged)):


{
    "domain": "unknown-domain.com",
    "technologies": []
}
 

Example response (402, Not enough credits):


{
    "error": "insufficient_credits",
    "message": "You don't have enough credits."
}
 

Example response (422, Validation failed):


{
    "message": "The given data was invalid.",
    "errors": {
        "domain": [
            "The domain field is required."
        ]
    }
}
 

Example response (423, Subscription issue):


{
    "error": "Your subscription is currently paused."
}
 

Request      

POST api/technologies

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Body Parameters

domain   string     

The company domain to look up. Example: stripe.com

technologies   string[]  optional    

Filter by technology names (case-insensitive).

Response

Response Fields

domain   string     

The resolved company domain.

technologies   object[]     

List of technologies detected for this company.

name   string     

Technology name.

category   string     

Technology category (nullable).

subcategory   string     

Technology subcategory (nullable).

last_detected_at   string     

ISO 8601 timestamp of the most recent detection (nullable).

Usage

Get remaining credits

requires authentication

Example request:
curl --request GET \
    --get "https://app.findymail.com/api/credits" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}"
const url = new URL(
    "https://app.findymail.com/api/credits"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "credits": 150,
    "verifier_credits": 100
}
 

Request      

GET api/credits

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Get usage

requires authentication

Returns the daily or monthly credit usage of the authenticated user.

Groups by day for periods shorter than 2 months, otherwise groups by month.

Example request:
curl --request GET \
    --get "https://app.findymail.com/api/credits/report/summary?from=2025-01-01&to=2025-01-31" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}"
const url = new URL(
    "https://app.findymail.com/api/credits/report/summary"
);

const params = {
    "from": "2025-01-01",
    "to": "2025-01-31",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "from": "2025-01-01",
    "to": "2025-01-31",
    "total": {
        "finder": 250,
        "verifier": 180
    },
    "items": [
        {
            "date": "2025-01-01",
            "finder": 10,
            "verifier": 5
        },
        {
            "date": "2025-01-02",
            "finder": 15,
            "verifier": 8
        },
        {
            "date": "2025-01-03",
            "finder": 0,
            "verifier": 0
        }
    ]
}
 

Example response (422):


{
    "message": "The from field must be a valid date.",
    "errors": {
        "from": [
            "The from field must be a valid date."
        ]
    }
}
 

Request      

GET api/credits/report/summary

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Query Parameters

from   string  optional    

optional The start date (incl.) for the timeline (YYYY-MM-DD format). Defaults to 30 days ago. Example: 2025-01-01

to   string  optional    

optional The end date (incl.) for the timeline (YYYY-MM-DD format). Defaults to today. Example: 2025-01-31

Get team usage

requires authentication

Returns a summary of credit usage of all team members within a specific date range.

Only team owners can access this endpoint.

Example request:
curl --request GET \
    --get "https://app.findymail.com/api/credits/report/team-summary?from=2025-01-01&to=2025-01-31" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}"
const url = new URL(
    "https://app.findymail.com/api/credits/report/team-summary"
);

const params = {
    "from": "2025-01-01",
    "to": "2025-01-31",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "from": "2025-01-01",
    "to": "2025-01-31",
    "total": {
        "finder": 150,
        "verifier": 75
    },
    "members": [
        {
            "name": "John Doe",
            "finder": 100,
            "verifier": 50
        },
        {
            "name": "Jane Smith",
            "finder": 50,
            "verifier": 25
        }
    ]
}
 

Example response (403):


{
    "error": "You must be the team owner to access this endpoint"
}
 

Example response (422):


{
    "message": "The from field must be a valid date.",
    "errors": {
        "from": [
            "The from field must be a valid date."
        ]
    }
}
 

Request      

GET api/credits/report/team-summary

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Query Parameters

from   string  optional    

optional The start date (incl.) for the report (YYYY-MM-DD format). Defaults to 30 days ago. Example: 2025-01-01

to   string  optional    

optional The end date (incl.) for the report (YYYY-MM-DD format). Defaults to today. Example: 2025-01-31