The LinkedIn e-mail check answers whether an e-mail address is associated with a LinkedIn account. It runs in bulk jobs and returns registered: true, false or null (unknown) for each address, with the time we checked. It is built for qualifying B2B leads. Nothing is sent to the address, and no name, employer, job title or profile is returned.
What does the LinkedIn e-mail check tell you?
It tells you whether LinkedIn has an account that uses the address, as the sign-in or as one of the addresses on the account. LinkedIn, owned by Microsoft since 2016, is the main professional network. Its accounts can carry more than one e-mail address, typically a personal one and sometimes a work one.
That last point is the key to reading the result:
registered: true: an account is associated with the address. For a work address, that is a useful sign the address belongs to a real professional who uses it.registered: false: a conclusive "no account for this address". For work addresses this is common and neutral, because many people keep LinkedIn on a personal address.registered: null: no conclusive answer (statusandreasonsay why). Not charged.
Who uses it, and why?
The LinkedIn check is a B2B tool. It helps sales and marketing teams qualify people who have already come to them.
- Inbound lead qualification. Demo requests, trial sign-ups and gated-content forms fill up with fake and throwaway entries. A lead whose address has a mailbox and a LinkedIn account is more likely to be a real professional. See lead verification.
- CRM hygiene. A batch run over older B2B contacts, together with the mailbox check or Outlook check, shows which addresses are still in use.
- Trial abuse in B2B software. Repeated free trials from invented addresses rarely come with a LinkedIn account.
Since "no" is normal for many work addresses, use the result to prioritise leads, not to reject them. For phone numbers, the LinkedIn number check covers US and Indian numbers.
What do you get back?
Each address becomes a row with kind: "email" and one entry per check in checks.
| Field | Type | Meaning |
|---|---|---|
email | string or null | Normalized address (trimmed, lowercased); null when invalid |
email_status | enum | valid, invalid_email, duplicate or suppressed |
checks["linkedin.email"].registered | boolean or null | true account exists, false none, null unknown |
…status | enum | completed, pending, unknown, unsupported_country or failed |
…reason | string or null | e.g. UPSTREAM_TIMEOUT |
…confidence, …checked_at | enum, timestamp | How sure the answer is, and when it was obtained |
…cached, …billed | boolean | Cache hit, and whether it was charged |
Downloads add linkedin.email.status, linkedin.email.registered and linkedin.email.billed columns in your original row order.
How is it billed?
You pay the bulk price per address with a conclusive answer. You're not charged for inconclusive results (unknown, unsupported country, timeout, invalid, duplicate). The free POST /v1/jobs/estimate call shows the maximum cost before you start. See pricing.
Repeat checks of the same address inside the freshness window can come from your account's cache. Cache hits are free.
What are the limits?
The LinkedIn e-mail check is bulk only. POST /v1/lookup refuses it with 403 service_disabled ("The check 'linkedin.email' is available in bulk jobs only (POST /v1/jobs)."). Use the code linkedin.email. The alias linkedin means the phone-number check. A job takes up to 50,000 numbers and e-mails, as JSON or as a CSV upload with an email column.
- Up to 20 checks per request. Identifiers × applicable checks are capped at 100,000 per job.
- Requests that look like sequential number ranges or generated e-mail lists are rejected. Twenty or more addresses in one request on one domain whose local parts differ only by digits or separators are refused with
suspected_enumeration. Live keys are also limited to 50 addresses of one such pattern per account per UTC day. - The daily cap counts e-mail addresses like numbers (see
GET /v1/limits).
How do I use it responsibly?
Check the addresses of leads and customers who contacted you or signed up. Never use the check to guess work addresses (firstname.lastname@company) or to find people for cold outreach. That is list building, and the acceptable use policy forbids it. We never read mailboxes or send e-mail to the address, and the answer is only yes, no or unknown, never a profile. Anyone can object through the opt-out form.
Example request
Test keys return fixed answers for test.mobilevalidate.com addresses (see test mode).
curl https://api.mobilevalidate.com/v1/jobs \
-H "Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym" \
-H "Content-Type: application/json" \
-d '{"emails":["[email protected]","[email protected]","[email protected]"],"checks":["linkedin.email"]}'// npm install mobilevalidate · Node.js 20+ · save as check.mjs and run: node check.mjs
import { MobileValidate } from "mobilevalidate";
// Omit apiKey to read MOBILEVALIDATE_API_KEY from the environment.
const mv = new MobileValidate({ apiKey: "mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym" });
const { data, error } = await mv.jobs.create({
emails: [
"[email protected]",
"[email protected]",
"[email protected]",
],
checks: ["linkedin.email"],
});
if (error) console.error(error.code, error.message);
else console.dir(data, { depth: null });// Node.js 18+, Deno, Bun or the browser console (ES module: save as .mjs or use "type": "module").
const res = await fetch("https://api.mobilevalidate.com/v1/jobs", {
method: "POST",
headers: {
Authorization: "Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym",
"Content-Type": "application/json",
},
body: JSON.stringify({
emails: [
"[email protected]",
"[email protected]",
"[email protected]",
],
checks: ["linkedin.email"],
}),
});
console.log(res.status, res.headers.get("x-request-id"));
console.dir(await res.json(), { depth: null });# pip install mobilevalidate-sdk
from mobilevalidate import MobileValidate
# Omit api_key to read MOBILEVALIDATE_API_KEY from the environment.
mv = MobileValidate(api_key="mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym")
result = mv.jobs.create(
emails=[
"[email protected]",
"[email protected]",
"[email protected]",
],
checks=["linkedin.email"],
)
print(result)<?php
$ch = curl_init('https://api.mobilevalidate.com/v1/jobs');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'emails' => [
'[email protected]',
'[email protected]',
'[email protected]',
],
'checks' => ['linkedin.email'],
]),
]);
$response = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL, $response, PHP_EOL;package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"emails":["[email protected]","[email protected]","[email protected]"],"checks":["linkedin.email"]}`)
req, err := http.NewRequest("POST", "https://api.mobilevalidate.com/v1/jobs", body)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.Status, string(out))
}require "net/http"
require "json"
uri = URI("https://api.mobilevalidate.com/v1/jobs")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym"
req["Content-Type"] = "application/json"
req.body = JSON.generate({
"emails" => [
"[email protected]",
"[email protected]",
"[email protected]"
],
"checks" => ["linkedin.email"]
})
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.code, res.bodyRuns as pasted with the public sandbox key, which answers the test values only. In the SDKs, omit the key to use MOBILEVALIDATE_API_KEY.
Response of GET /v1/jobs/{id}/results (excerpt, test mode: the first item of data):
{
"kind": "email",
"input": "re•••@test.mobilevalidate.com",
"email": "[email protected]",
"email_status": "valid",
"e164": null,
"country": null,
"checks": {
"linkedin.email": {
"service": "linkedin.email",
"status": "completed",
"registered": true,
"attributes": null,
"confidence": "high",
"confidence_score": 0.99,
"checked_at": "2026-09-25T14:25:47.920Z",
"cached": false,
"age_seconds": 0,
"billed": false,
"reason": null,
"poll_after_ms": null
}
},
"test": true
}Try it now
Bulk-only service: create a job via POST /v1/jobs, then read GET /v1/jobs/{id}/results. Every example runs as pasted: it uses the public sandbox key, which answers the test values for free. In the SDKs, omit the key to use MOBILEVALIDATE_API_KEY.
curl https://api.mobilevalidate.com/v1/jobs \
-H "Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym" \
-H "Content-Type: application/json" \
-d '{"emails":["[email protected]"],"checks":["linkedin.email"]}'// npm install mobilevalidate · Node.js 20+ · save as check.mjs and run: node check.mjs
import { MobileValidate } from "mobilevalidate";
// Omit apiKey to read MOBILEVALIDATE_API_KEY from the environment.
const mv = new MobileValidate({ apiKey: "mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym" });
const { data, error } = await mv.jobs.create({
emails: ["[email protected]"],
checks: ["linkedin.email"],
});
if (error) console.error(error.code, error.message);
else console.dir(data, { depth: null });// Node.js 18+, Deno, Bun or the browser console (ES module: save as .mjs or use "type": "module").
const res = await fetch("https://api.mobilevalidate.com/v1/jobs", {
method: "POST",
headers: {
Authorization: "Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym",
"Content-Type": "application/json",
},
body: JSON.stringify({
emails: ["[email protected]"],
checks: ["linkedin.email"],
}),
});
console.log(res.status, res.headers.get("x-request-id"));
console.dir(await res.json(), { depth: null });# pip install mobilevalidate-sdk
from mobilevalidate import MobileValidate
# Omit api_key to read MOBILEVALIDATE_API_KEY from the environment.
mv = MobileValidate(api_key="mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym")
result = mv.jobs.create(
emails=["[email protected]"],
checks=["linkedin.email"],
)
print(result)<?php
$ch = curl_init('https://api.mobilevalidate.com/v1/jobs');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'emails' => ['[email protected]'],
'checks' => ['linkedin.email'],
]),
]);
$response = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL, $response, PHP_EOL;package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"emails":["[email protected]"],"checks":["linkedin.email"]}`)
req, err := http.NewRequest("POST", "https://api.mobilevalidate.com/v1/jobs", body)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.Status, string(out))
}require "net/http"
require "json"
uri = URI("https://api.mobilevalidate.com/v1/jobs")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym"
req["Content-Type"] = "application/json"
req.body = JSON.generate({
"emails" => ["[email protected]"],
"checks" => ["linkedin.email"]
})
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.code, res.body// .mcp.json (Claude Code), ~/.cursor/mcp.json (Cursor) or .vscode/mcp.json ("servers" instead of "mcpServers")
{
"mcpServers": {
"mobilevalidate": {
"type": "http",
"url": "https://mcp.mobilevalidate.com/mcp",
"headers": { "Authorization": "Bearer ${MOBILEVALIDATE_API_KEY}" }
}
}
}
// Then ask your agent, e.g.:
// "Check [email protected] with linkedin.email" → tool: create_lookup_jobThe hosted MCP server is live for customers with an agent key (mv_agent_…) or a test key. Or run it locally with npx -y @mobilevalidate/mcp.
Real test-mode result for this check
{
"service": "linkedin.email",
"status": "completed",
"registered": true,
"attributes": null,
"confidence": "high",
"confidence_score": 0.99,
"checked_at": "2026-09-25T14:25:29.021Z",
"cached": false,
"age_seconds": 0,
"billed": false,
"reason": null,
"poll_after_ms": null
}What you get
Fields of checks["linkedin.email"], generated from the public service catalog.
| Field | Type | Meaning |
|---|---|---|
| registered | boolean | null | true = found, false = not found, null = unknown (not charged). |
| status | enum | completed, pending, unknown, unsupported_country or failed. |
| checked_at | timestamp | When the answer was obtained. |
Frequently asked questions
Does the check return the LinkedIn profile, name or job title?
No. It only answers whether a LinkedIn account is associated with the address: yes, no or unknown. No profile, name, employer or job title is ever returned.
A real business contact came back as no. Is the lead fake?
Not necessarily. Many people register LinkedIn with a personal address rather than their work address, so a work address often has no account even for a genuine professional. Treat no as neutral for work addresses.
Why is the LinkedIn e-mail check only in bulk jobs?
It is offered in bulk jobs only for now. POST /v1/lookup refuses it with service_disabled; use POST /v1/jobs. GET /v1/services always shows the current modes.
Can I check phone numbers for LinkedIn?
Yes, with the LinkedIn number check, which covers numbers from the US and India only.
Can I use it to find people for outreach?
No. The check qualifies leads who already came to you. Using it to discover people or build outreach lists breaks the acceptable use policy.

