Free cold email tools API
The checks behind Ken's free tools, as JSON. Clean company names and job titles, grade a cold email, check a domain's SPF, DKIM and DMARC, or run the outbound calculators from your own code, a Clay column or an AI agent. Most calls need no key. A free Ken API key raises the limits and unlocks bulk calls and the model steps.
Try it now
No signup. Paste this into a terminal.curl https://ken.so/api/free/v1/clean/company-name \
-H "Content-Type: application/json" \
-d '{
"names": [
"ACME LOGISTICS LLC",
"The Home Depot, Inc.",
"Northwind Technologies GmbH & Co. KG"
]
}'{
"results": [
{
"input": "ACME LOGISTICS LLC",
"name": "Acme Logistics",
"needsModel": true,
"review": false,
"placeholder": false,
"changed": true,
"source": "rules"
},
{
"input": "The Home Depot, Inc.",
"name": "Home Depot",
"needsModel": false,
"review": false,
"placeholder": false,
"changed": true,
"source": "rules"
},
{
"input": "Northwind Technologies GmbH & Co. KG",
"name": "Northwind Technologies",
"needsModel": false,
"review": true,
"placeholder": false,
"changed": true,
"source": "rules"
}
],
"source_url": "https://ken.so/tools/company-name-cleaner"
}With a free key, add one header. The limits go up and are counted per Ken account.
curl https://ken.so/api/free/v1/clean/company-name \
-H "Authorization: Bearer $KEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"names": [
"ACME LOGISTICS LLC",
"The Home Depot, Inc.",
"Northwind Technologies GmbH & Co. KG"
]
}'Keys and limits
Anonymous calls are counted per IP. A free key is counted per Ken account.Call without a key and the limits are counted per IP address (per /64 on IPv6). Lookups and probes share that allowance with their tool pages: one IP gets one allowance across the page and the API.
To raise them, sign up for Ken free, then create an API key in Ken under Settings, Integrations. Send it as Authorization: Bearer <key> (or X-Api-Key: <key>). Keys expire within 90 days; make a new one when yours does.
Limits are counted per Ken account, not per key: a second key or workspace doesn't add quota. Every response carries X-RateLimit-* headers, and a refused call says when to retry.
Already on Ken? Create a key in Settings, Integrations.
ai: true on the cleaners: a model fixes only what the rules leave unsure.Endpoints
Every endpoint runs the same engine as its tool page. Results carrysource_url: link it when you publish a result./api/free/v1/openapi.jsonClean
POST/clean/company-nameClean company names
Turns "ACME LOGISTICS LLC" into "Acme Logistics" for a {{company}} merge field: legal forms out, casing fixed, acronyms kept, placeholders such as "N/A" cleaned to "". Ken's own rules, then the web cleaner's fixes.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account. ai: true (key only): 100 model items a day per account, 5,000 across the API, shared by every model step.
Same engine as Company name cleaner.
curl https://ken.so/api/free/v1/clean/company-name \
-H "Content-Type: application/json" \
-d '{
"names": [
"ACME LOGISTICS LLC",
"The Home Depot, Inc.",
"Northwind Technologies GmbH & Co. KG"
]
}'{
"results": [
{
"input": "ACME LOGISTICS LLC",
"name": "Acme Logistics",
"needsModel": true,
"review": false,
"placeholder": false,
"changed": true,
"source": "rules"
},
{
"input": "The Home Depot, Inc.",
"name": "Home Depot",
"needsModel": false,
"review": false,
"placeholder": false,
"changed": true,
"source": "rules"
},
{
"input": "Northwind Technologies GmbH & Co. KG",
"name": "Northwind Technologies",
"needsModel": false,
"review": true,
"placeholder": false,
"changed": true,
"source": "rules"
}
],
"source_url": "https://ken.so/tools/company-name-cleaner"
}POST/clean/person-nameClean person names
Splits a full name into first, middle and last; removes honorifics, credentials, pronouns, nicknames and emoji; fixes casing (O'Neil, McDonald, van Beethoven). Non-names such as "Info Team" come back with isPerson false and a reason. Rules only.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Name cleaner.
curl https://ken.so/api/free/v1/clean/person-name \
-H "Content-Type: application/json" \
-d '{"names":["DR. JANE O'\''NEIL, PHD (she/her)","mcdonald, ronald","Info Team"]}'{
"results": [
{
"input": "DR. JANE O'NEIL, PHD (she/her)",
"first": "Jane",
"middle": "",
"last": "O'Neil",
"full": "Jane O'Neil",
"isPerson": true,
"removed": [
"pronouns",
"credential",
"honorific"
],
"changed": true
},
{
"input": "mcdonald, ronald",
"first": "Ronald",
"middle": "",
"last": "McDonald",
"full": "Ronald McDonald",
"isPerson": true,
"removed": [],
"changed": true
},
{
"input": "Info Team",
"first": "",
"middle": "",
"last": "",
"full": "Info Team",
…POST/clean/job-titleNormalize job titles
Returns the clean title, a short one that fits "as {{title}} at {{company}}", and the seniority and department Ken Search indexes. needsModel marks titles no rule matched; send ai: true with a key to settle those.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account. ai: true (key only): 100 model items a day per account, 5,000 across the API, shared by every model step.
Same engine as Job title normalizer.
curl https://ken.so/api/free/v1/clean/job-title \
-H "Content-Type: application/json" \
-d '{
"titles": [
"Sr. VP, Global Sales & BD (EMEA)",
"Head of Growth @ Acme | Ex-Stripe",
"Chief Revenue Officer"
]
}'{
"results": [
{
"input": "Sr. VP, Global Sales & BD (EMEA)",
"clean": "SVP, Global Sales & Business Development",
"short": "SVP Sales",
"seniority": "VP",
"seniorityLabel": "VP",
"seniorityGroup": "vp",
"department": "Sales",
"matchedOn": "typed",
"placeholder": false,
"needsModel": false,
"changed": true,
"source": "rules"
},
{
"input": "Head of Growth @ Acme | Ex-Stripe",
"clean": "Head of Growth @ Acme | Ex-Stripe",
"short": "Head of Growth @ Acme",
"seniority": "Director",
"seniorityLabel": "Director",
"seniorityGroup": "director",
"department": "Marketing",
"matchedOn": "typed",
"placeholder": false,
"needsModel": false,
"changed": false,
"source": "rules"
},
{
"input": "Chief Revenue Officer",
…POST/clean/domainNormalize websites and domains
Turns a URL, email or bare domain into its registrable domain through the Public Suffix List (acme.co.uk, acme.com.au), flags freemail, and gives LinkedIn URLs a canonical key for dedupe.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Domain normalizer.
curl https://ken.so/api/free/v1/clean/domain \
-H "Content-Type: application/json" \
-d '{
"values": [
"https://www.Acme.co.uk/about?utm_source=x",
"[email protected]",
"linkedin.com/company/acme-inc/about"
]
}'{
"results": [
{
"input": "https://www.Acme.co.uk/about?utm_source=x",
"kind": "url",
"host": "acme.co.uk",
"domain": "acme.co.uk",
"freemail": false,
"linkedin": null,
"dedupeKey": "acme.co.uk"
},
{
"input": "[email protected]",
"kind": "email",
"host": "mail.acme.com.au",
"domain": "acme.com.au",
"freemail": false,
"linkedin": null,
"dedupeKey": "acme.com.au"
},
{
"input": "linkedin.com/company/acme-inc/about",
"kind": "linkedin",
"host": "linkedin.com",
"domain": "linkedin.com",
"freemail": false,
"linkedin": {
"url": "https://linkedin.com/company/acme-inc",
"kind": "company",
"handle": "acme-inc",
"key": "company/acme-inc"
},
…POST/clean/phoneFormat phone numbers
E.164 (or another format) for each number with libphonenumber's full metadata, plus whether it is valid, its country and its line type.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Phone number formatter.
curl https://ken.so/api/free/v1/clean/phone \
-H "Content-Type: application/json" \
-d '{"numbers":["(415) 555-0132","+44 20 7946 0958","020 7946 0018"],"defaultCountry":"US"}'{
"results": [
{
"input": "(415) 555-0132",
"formatted": "+14155550132",
"e164": "+14155550132",
"valid": true,
"possible": true,
"country": "US",
"type": "FIXED_LINE_OR_MOBILE",
"extension": null
},
{
"input": "+44 20 7946 0958",
"formatted": "+442079460958",
"e164": "+442079460958",
"valid": true,
"possible": true,
"country": "GB",
"type": "FIXED_LINE",
"extension": null
},
{
"input": "020 7946 0018",
"formatted": "+102079460018",
"e164": "+102079460018",
"valid": false,
"possible": false,
"country": "US",
"type": null,
"extension": null
}
…POST/clean/rowsClean lead rows
The list cleaner on up to 100 rows: every cleaner in one pass over the mapped columns, dedupe within the call, and the freemail, role, disposable and missing-field flags. Each row counts as one item. A 10,000-row CSV stays a browser job on the page.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account. ai: true (key only): 100 model items a day per account, 5,000 across the API, shared by every model step.
Same engine as CSV list cleaner.
curl https://ken.so/api/free/v1/clean/rows \
-H "Content-Type: application/json" \
-d '{
"rows": [
{
"Email": " [email protected]",
"First Name": "jane",
"Last Name": "DOE",
"Company": "ACME LOGISTICS LLC",
"Title": "Sr. VP, Global Sales & BD (EMEA)",
"Website": "https://www.acme.com/about"
},
{
"Email": "[email protected]",
"First Name": "",
"Last Name": "",
"Company": "Northwind Technologies, Inc.",
"Title": "",
"Website": "northwind.io"
},
{
"Email": "[email protected]",
"First Name": "Jane",
"Last Name": "Doe",
"Company": "Acme Logistics",
"Title": "SVP Sales",
"Website": "acme.com"
}
]
}'{
"columns": {
"email": "Email",
"first_name": "First Name",
"last_name": "Last Name",
"company_name": "Company",
"title": "Title",
"company_domain": "Website"
},
"rows": [
{
"index": 0,
"removed": false,
"flags": [],
"values": {
"Email": "[email protected]",
"First Name": "Jane",
"Last Name": "Doe",
"Company": "Acme Logistics",
"Title": "SVP, Global Sales & Business Development",
"Website": "acme.com"
}
},
{
"index": 1,
"removed": false,
"flags": [
"role",
"missing-name",
"review-company",
"missing-title"
],
…Copy
POST/grade/emailGrade a cold email
The grader's rule checks: spam words, formatting, links, fake Re: or Fwd:, unfilled variables, length, reading level, AI tells and the subject. rulesScore is 100 minus every point the checks took; each check and inline mark carries its reason and a fix.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Cold email grader.
curl https://ken.so/api/free/v1/grade/email \
-H "Content-Type: application/json" \
-d '{
"subject": "quick question about Northwind'\''s outbound",
"body": "Hi {{first_name}},\n\nSaw Northwind opened a second warehouse in Leeds. Teams that grow that fast usually hit a wall booking carrier meetings.\n\nWe help logistics teams book 7 meetings per 10,000 contacts with cold email and LinkedIn, without hiring SDRs.\n\nWorth a look next week?\n\nJane"
}'{
"rulesScore": 93,
"checks": [
{
"id": "spam_words",
"label": "Spam words",
"status": "pass",
"pointsLost": 0,
"reason": "No spam words. The budget is untouched.",
"marks": []
},
{
"id": "formatting",
"label": "Formatting",
"status": "pass",
"pointsLost": 0,
"reason": "No ALL CAPS, stacked punctuation or money promises.",
"marks": []
},
{
"id": "links",
"label": "Links",
"status": "pass",
"pointsLost": 0,
"reason": "No links. Best for a first email.",
"marks": []
},
{
"id": "fake_reply",
"label": "Fake Re: or Fwd:",
"status": "pass",
"pointsLost": 0,
…POST/ai-tellsFind AI tells
Scores how human a text reads (0 to 100) and lists every phrase and structure that reads as AI, with a plainer alternative. It says a text "reads as AI", never who wrote it.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as AI content detector.
curl https://ken.so/api/free/v1/ai-tells \
-H "Content-Type: application/json" \
-d '{
"text": "I hope this email finds you well. In today'\''s fast-paced landscape, leveraging cutting-edge solutions isn'\''t just a nice-to-have, it'\''s a game-changer. Let'\''s dive in.",
"contentType": "cold-email"
}'{
"contentType": "cold-email",
"score": 50,
"verdict": {
"id": "mixed",
"label": "Some AI tells"
},
"tells": [
{
"id": "hope-finds-you-well",
"kind": "phrase",
"category": "dead-phrase",
"label": "Dead phrase",
"start": 0,
"end": 32,
"text": "I hope this email finds you well",
"reason": "A stock line from thousands of templates. Readers skip it on sight.",
"alternative": "Delete it and open with the reason you're writing.",
"weight": 10
},
{
"id": "fast-paced-world",
"kind": "phrase",
"category": "dead-phrase",
"label": "Dead phrase",
"start": 34,
"end": 55,
"text": "In today's fast-paced",
"reason": "A stock line from thousands of templates. Readers skip it on sight.",
"alternative": "Start with a specific fact about the reader.",
"weight": 10
},
…POST/spam-checkCheck spam words
The rules Ken checks every email against: each spam word with its tier (never, high, medium), position and a safer alternative, the spam budget, formatting flags and the structure rows. Not a prediction of any inbox provider's filter.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Spam word checker.
curl https://ken.so/api/free/v1/spam-check \
-H "Content-Type: application/json" \
-d '{
"subject": "50% OFF, act now!!!",
"body": "Guaranteed results or your money back. Click here to claim your free gift today."
}'{
"subject": "50% OFF, act now!!!",
"bodyText": "Guaranteed results or your money back. Click here to claim your free gift today.",
"flags": [
{
"id": "discount",
"tier": "high",
"cluster": "money",
"clusterLabel": "Money and pricing",
"field": "subject",
"start": 0,
"end": 7,
"text": "50% OFF",
"alternative": "Make it concrete: \"teams that start this quarter get onboarding included\"",
"reason": "Aim for zero. One HIGH word spends the email's whole spam budget.",
"alsoMatched": [],
"exempt": false
},
{
"id": "act-now",
"tier": "high",
"cluster": "urgency",
"clusterLabel": "Urgency and pressure",
"field": "subject",
"start": 9,
"end": 16,
"text": "act now",
"alternative": "\"Want to try it?\" or \"Want me to send details?\"",
"reason": "Aim for zero. One HIGH word spends the email's whole spam budget.",
"alsoMatched": [],
"exempt": false
},
…POST/subject-lineScore a subject line
Scores a cold email subject 0 to 100 on Ken's rules (short, plain, no punctuation tricks, tied to the first line), with each deduction, and shows how Gmail, Outlook and Apple Mail cut it off on desktop and phone.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Subject line tester.
curl https://ken.so/api/free/v1/subject-line \
-H "Content-Type: application/json" \
-d '{
"subject": "Northwind'\''s Leeds warehouse",
"firstLine": "Saw Northwind opened a second warehouse in Leeds."
}'{
"subject": "Northwind's Leeds warehouse",
"score": 100,
"verdict": {
"id": "strong",
"label": "Ready to send"
},
"deductions": [],
"spamFlags": [],
"stats": {
"words": 3,
"characters": 27,
"mobileCutoff": 35,
"cutOnMobile": false,
"isQuestion": false
},
"previews": [
{
"client": "gmail-desktop",
"label": "Gmail, desktop",
"limit": 70,
"shown": "Northwind's Leeds warehouse",
"truncated": false,
"snippet": "Saw Northwind opened a second warehouse in Leeds."
},
{
"client": "gmail-mobile",
"label": "Gmail, phone",
"limit": 35,
"shown": "Northwind's Leeds warehouse",
"truncated": false,
"snippet": "Saw Northwind opened a second warehouse in Leeds."
…POST/compliance-checkCheck a cold email against the law
CAN-SPAM, CASL, PECR and UK GDPR, or GDPR and ePrivacy for the EU, depending on the recipient country: each check with its citation and the official source. Checks that text alone can't prove come back as manual. This is not legal advice. It checks the email against the rules as written. It can't see your consent records, your list source or your headers, so ask a lawyer about your own case.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Cold email compliance checker.
curl https://ken.so/api/free/v1/compliance-check \
-H "Content-Type: application/json" \
-d '{
"subject": "quick question about Northwind'\''s outbound",
"body": "Hi {{first_name}},\n\nSaw Northwind opened a second warehouse in Leeds. Teams that grow that fast usually hit a wall booking carrier meetings.\n\nWe help logistics teams book 7 meetings per 10,000 contacts with cold email and LinkedIn, without hiring SDRs.\n\nWorth a look next week?\n\nJane\n\nReply \"no thanks\" and I won'\''t follow up.",
"country": "US"
}'{
"country": {
"code": "US",
"name": "United States",
"supported": true
},
"region": "us",
"laws": [
{
"id": "can-spam",
"name": "CAN-SPAM Act",
"full": "Controlling the Assault of Non-Solicited Pornography And Marketing Act of 2003, 15 U.S.C. 7701-7713, and the FTC rule at 16 CFR Part 316",
"url": "https://www.ftc.gov/business-guidance/resources/can-spam-act-compliance-guide-business"
},
{
"id": "ftc-act",
"name": "FTC Act",
"full": "Federal Trade Commission Act, section 5, 15 U.S.C. 45",
"url": "https://www.law.cornell.edu/uscode/text/15/45"
}
],
"checks": [
{
"id": "sender_identity",
"title": "Says who is sending",
"status": "warn",
"rule": "Header and sender information must not be false or misleading.",
"citation": "CAN-SPAM Act, 15 U.S.C. 7704(a)(1)",
"law": {
"id": "can-spam",
"name": "CAN-SPAM Act",
"url": "https://www.ftc.gov/business-guidance/resources/can-spam-act-compliance-guide-business"
…POST/spintax/validateValidate spintax
Errors (unclosed spins, empty options, broken variables) and warnings for the chosen tool's syntax, each with line and column.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Spintax generator.
curl https://ken.so/api/free/v1/spintax/validate \
-H "Content-Type: application/json" \
-d '{"template":"{Hi|Hey {{first_name}}, {saw|noticed} your post","syntax":"plain"}'{
"valid": false,
"issues": [
{
"code": "unclosed_spin",
"severity": "error",
"message": "This spin is never closed.",
"offset": 0,
"length": 1,
"line": 1,
"column": 1
}
],
"source_url": "https://ken.so/tools/spintax-generator"
}POST/spintax/countCount spintax combinations
The exact number of versions a template makes (a decimal string, since it passes 2^53 easily), an approximate number and the spin count.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Spintax generator.
curl https://ken.so/api/free/v1/spintax/count \
-H "Content-Type: application/json" \
-d '{
"template": "{Hi|Hey|Hello} {{first_name}}, {saw|noticed} {{company}} is {hiring|growing} {fast|quickly}."
}'{
"exact": "24",
"approx": 24,
"spins": 4,
"source_url": "https://ken.so/tools/spintax-generator"
}POST/spintax/expandExpand spintax
Random versions of a template, at most 100 a call. The same seed gives the same versions. A template with fewer combinations than count returns all of them.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Spintax generator.
curl https://ken.so/api/free/v1/spintax/expand \
-H "Content-Type: application/json" \
-d '{
"template": "{Hi|Hey|Hello} {{first_name}}, {saw|noticed} {{company}} is {hiring|growing} {fast|quickly}.",
"count": 5,
"seed": 7
}'{
"expansions": [
"Hi {{first_name}}, saw {{company}} is growing quickly.",
"Hey {{first_name}}, saw {{company}} is hiring fast.",
"Hey {{first_name}}, noticed {{company}} is hiring fast.",
"Hello {{first_name}}, noticed {{company}} is hiring fast.",
"Hi {{first_name}}, noticed {{company}} is hiring quickly."
],
"total": {
"exact": "24",
"approx": 24,
"spins": 4
},
"valid": true,
"source_url": "https://ken.so/tools/spintax-generator"
}POST/spintax/convertConvert spintax between tools
Rewrites a template from one tool's syntax to another's. Nested spins are flattened for tools without nesting; merge fields are kept exactly as written, with a warning to check them.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Spintax generator.
curl https://ken.so/api/free/v1/spintax/convert \
-H "Content-Type: application/json" \
-d '{
"template": "{Hi|Hey|Hello} {{first_name}}, {saw|noticed} {{company}} is {hiring|growing} {fast|quickly}.",
"from": "plain",
"to": "lemlist"
}'{
"output": "{% spin %} {% variation %} Hi {% variation %} Hey {% variation %} Hello {% endspin %} {{first_name}}, {% spin %} {% variation %} saw {% variation %} noticed {% endspin %} {{company}} is {% spin %} {% variation %} hiring {% variation %} growing {% endspin %} {% spin %} {% variation %} fast {% variation %} quickly {% endspin %}.",
"from": "plain",
"to": "lemlist",
"issues": [],
"warnings": [
{
"code": "check_merge_fields",
"message": "Merge fields were kept as written. lemlist may name them differently (first_name, firstName, First Name)."
}
],
"source_url": "https://ken.so/tools/spintax-generator"
}POST/spintax/suggestSuggest spins
Spins for plain copy from Ken's phrase bank and synonym list, no AI. Returns each suggestion with its options (the original first) and the template with all of them applied.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Spintax generator.
curl https://ken.so/api/free/v1/spintax/suggest \
-H "Content-Type: application/json" \
-d '{
"text": "Hi {{first_name}}, I noticed your team is hiring. Would you be open to a quick call next week?"
}'{
"suggestions": [
{
"id": "greeting",
"category": "greeting",
"start": 0,
"end": 2,
"original": "Hi",
"options": [
"Hi",
"Hey",
"Hello"
]
},
{
"id": "word:noticed",
"category": "word",
"start": 21,
"end": 28,
"original": "noticed",
"options": [
"noticed",
"saw"
]
}
],
"template": "{Hi|Hey|Hello} {{first_name}}, I {noticed|saw} your team is hiring. Would you be open to a quick call next week?",
"source_url": "https://ken.so/tools/spintax-generator"
}Calculate
POST/calculate/funnelForecast a funnel
Nodes, edges and conversion rates in, up to 50 nodes; the monthly forecast out: meetings, pipeline, revenue, cost, CAC and ROI, plus a month-by-month timeline. The canvas stays on the page.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as B2B funnel builder.
curl https://ken.so/api/free/v1/calculate/funnel \
-H "Content-Type: application/json" \
-d '{
"nodes": [
{
"id": "list",
"label": "Contacts",
"kind": "source",
"volume": 10000,
"costPerUnit": 0.05
},
{
"id": "reply",
"label": "Replies",
"kind": "outcome",
"role": "reply"
},
{
"id": "positive",
"label": "Positive replies",
"kind": "outcome",
"role": "positive_reply"
},
{
"id": "meeting",
"label": "Meetings booked",
"kind": "outcome",
"role": "meeting_booked"
}
],
"edges": [
{
"from": "list",
"to": "reply",
"rate": 0.03
},
{
"from": "reply",
"to": "positive",
"rate": 0.3
},
{
"from": "positive",
"to": "meeting",
"rate": 0.7778
}
],
"dealSize": 12000,
"salesCycleMonths": 2
}'{
"ok": true,
"nodes": [
{
"id": "list",
"label": "Contacts",
"volume": 10000,
"cost": 500
},
{
"id": "reply",
"label": "Replies",
"volume": 300,
"cost": 0
},
{
"id": "positive",
"label": "Positive replies",
"volume": 90,
"cost": 0
},
{
"id": "meeting",
"label": "Meetings booked",
"volume": 70.00200000000001,
"cost": 0
}
],
"totals": {
"reply": 300,
"positive_reply": 90,
"meeting_booked": 70.00200000000001,
…POST/calculate/outbound-costCompare outbound costs
DIY stack vs in-house SDR vs agency vs Ken: monthly cost, meetings and cost per meeting for each, with every competitor price's verifiedAt date.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Outbound cost calculator.
curl https://ken.so/api/free/v1/calculate/outbound-cost \
-H "Content-Type: application/json" \
-d '{"leadsPerMonth":5000,"channels":{"email":true,"linkedin":true},"teamSize":1}'{
"options": [
{
"id": "diy",
"label": "DIY stack (Instantly)",
"monthlyCost": 569,
"meetingsPerMonth": 0.5,
"costPerMeeting": 1138,
"meetingsSource": {
"kind": "ken-published",
"source": "The industry norm published on /why-ken."
},
"verifiedAt": "2026-10-12",
"verifiedLabel": "Pricing verified",
"notes": [
"Your own time to build and run it is not priced."
]
},
{
"id": "in-house",
"label": "In-house SDR",
"monthlyCost": 8983.33,
"meetingsPerMonth": 12,
"costPerMeeting": 748.61,
"meetingsSource": {
"kind": "assumption",
"source": "Planning default of 12 meetings per ramped SDR a month. Capacity, not a function of your lead count."
},
"notes": [
"A ramped SDR on the US salary preset (a planning default, not sourced). Ramp months and turnover add to the real cost: see the SDR cost calculator."
]
},
…POST/calculate/pipeline-roiPipeline and ROI
Leads to replies, positive replies, meetings, deals, pipeline, revenue, ROI and payback months.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Outbound ROI calculator.
curl https://ken.so/api/free/v1/calculate/pipeline-roi \
-H "Content-Type: application/json" \
-d '{
"leadsPerMonth": 5000,
"replyRate": 0.03,
"positiveRate": 0.3,
"meetingRate": 0.7778,
"showRate": 0.8,
"closeRate": 0.2,
"dealSize": 12000,
"monthlyCost": 1500,
"salesCycleMonths": 2
}'{
"replies": 150,
"positiveReplies": 45,
"meetingsBooked": 35,
"meetingsHeld": 28,
"deals": 5.6,
"pipeline": 336009.6,
"revenue": 67201.92,
"monthlyCost": 1500,
"roi": 43.8013,
"costPerMeeting": 53.57,
"costPerDeal": 267.85,
"paybackMonths": 2.02,
"source_url": "https://ken.so/tools/roi-calculator"
}POST/calculate/sdr-costTrue cost of an SDR
Loaded cost, productive months after ramp, total cost over tenure and cost per meeting, against Ken's cost for the same meetings. Tenure and ramp default to MAR-48's medians, with the citation in the result.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as SDR cost calculator.
curl https://ken.so/api/free/v1/calculate/sdr-cost \
-H "Content-Type: application/json" \
-d '{"country":"US","stage":"startup"}'{
"monthlyRunCost": 8191.67,
"loadedAnnualCost": 98300,
"rampMonths": 3,
"tenureMonths": 12,
"productiveMonths": 9,
"totalCostOverTenure": 104300,
"costPerProductiveMonth": 11588.89,
"meetingsPerProductiveMonth": 12,
"costPerMeeting": 965.74,
"ken": {
"costPerMeeting": 96.67,
"monthlyCost": 1160,
"savingsPerMeeting": 869.07
},
"tenureSource": {
"kind": "study",
"source": "MAR-48: median 12 months at 11-50 employees companies."
},
"rampSource": {
"months": 3,
"kind": "external-guideline",
"source": "The Bridge Group, SDR Models, Motions and Metrics 2025: average SDR ramp time 3.0 months."
},
"citation": "Ken research, MAR-48: Kaplan-Meier time in an SDR or BDR seat, 363,028 people who started 2012-2025 across six countries, Ken work data snapshot 2026-06.",
"source_url": "https://ken.so/tools/sdr-cost-calculator"
}POST/calculate/quotaSales quota
Top-down (target split across ramping reps) or bottom-up (what a rep's open opportunities can close), plus the outbound activity per rep per month behind it.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Sales quota calculator.
curl https://ken.so/api/free/v1/calculate/quota \
-H "Content-Type: application/json" \
-d '{"mode":"top-down","revenueTarget":2400000,"reps":4,"newHires":2,"dealSize":24000}'{
"mode": "top-down",
"effectiveReps": 3.5,
"quotaPerRep": 685714.29,
"quotaPerNewHire": 514285.71,
"monthlyQuotaPerRep": 57142.86,
"activity": {
"required": {
"contacts": 42517.01,
"replies": 1275.51,
"positiveReplies": 382.65,
"meetingsBooked": 29.76,
"meetingsHeld": 23.81,
"opportunities": 11.9,
"deals": 2.38
},
"emailsPerMonth": 170069,
"linkedinTouchesPerMonth": 85035,
"rates": {
"replyRate": 0.03,
"positiveRate": 0.3,
"meetingRate": 0.07777777777777778,
"showRate": 0.8,
"meetingToOpportunityRate": 0.5,
"winRate": 0.2,
"emailsPerContact": 4
},
"ratesSource": "Ken's published numbers for reply, positive reply and meeting rates; planning defaults for the stages after the meeting."
},
"source_url": "https://ken.so/tools/quota-calculator"
}POST/calculate/forecastSales forecast
Pipeline mode: deal rows (1,000 at most, held in memory, never stored) to weighted, commit, best and worst case by month. Outbound mode: sends per month to meetings, pipeline and revenue on benchmark rates.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Sales forecast calculator.
curl https://ken.so/api/free/v1/calculate/forecast \
-H "Content-Type: application/json" \
-d '{"mode":"outbound","sendsPerMonth":20000,"months":6,"dealSize":12000,"salesCycleMonths":2}'{
"mode": "outbound",
"months": [
{
"month": 1,
"sends": 20000,
"contacts": 5000,
"meetingsBooked": 3.5,
"meetingsHeld": 2.8,
"pipelineCreated": 16800,
"revenue": 0
},
{
"month": 2,
"sends": 20000,
"contacts": 5000,
"meetingsBooked": 3.5,
"meetingsHeld": 2.8,
"pipelineCreated": 16800,
"revenue": 0
},
{
"month": 3,
"sends": 20000,
"contacts": 5000,
"meetingsBooked": 3.5,
"meetingsHeld": 2.8,
"pipelineCreated": 16800,
"revenue": 3360
},
{
"month": 4,
…POST/calculate/infrastructureInboxes and domains
Emails a month (or a meetings goal) to inboxes, sending domains, warmup weeks and the monthly cost on each provider and on Ken. Ken's prices come from pricing.ts.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Cold email inbox calculator.
curl https://ken.so/api/free/v1/calculate/infrastructure \
-H "Content-Type: application/json" \
-d '{"provider":"google","emailsPerMonth":30000}'{
"emailsPerMonth": 30000,
"emailsPerDay": 1364,
"volumeSource": {
"kind": "assumption",
"source": "The volume you entered."
},
"inboxes": 55,
"domains": 19,
"dailyLimitPerInbox": 25,
"warmupWeeks": 2,
"provider": "google",
"options": [
{
"provider": "google",
"label": "Google Workspace",
"inboxes": 55,
"domains": 19,
"monthlyCost": 408.75,
"breakdown": [
{
"label": "55 inboxes x $7",
"monthly": 385
},
{
"label": "19 domains x $15 a year",
"monthly": 23.75
}
],
"priceSource": {
"usd": 7,
"kind": "list-price",
…POST/calculate/warmup-scheduleWarmup schedule
The day-by-day ramp for one inbox: warmup and cold sends per day until full volume, with Ken's 7-day cold hold. The CSV export stays on the page.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Email warmup calculator.
curl https://ken.so/api/free/v1/calculate/warmup-schedule \
-H "Content-Type: application/json" \
-d '{"provider":"microsoft","inboxAgeDays":0,"targetDaily":30}'{
"days": [
{
"day": 1,
"inboxAge": 0,
"warmup": 4,
"cold": 0,
"total": 4,
"phase": "warmup-only"
},
{
"day": 2,
"inboxAge": 1,
"warmup": 6,
"cold": 0,
"total": 6,
"phase": "warmup-only"
},
{
"day": 3,
"inboxAge": 2,
"warmup": 8,
"cold": 0,
"total": 8,
"phase": "warmup-only"
},
{
"day": 4,
"inboxAge": 3,
"warmup": 10,
"cold": 0,
"total": 10,
…POST/calculate/rateEmail rates
Bounce, spam complaint, open, reply, positive reply or click rate, with its band, the thresholds and their sources, Ken's and the industry's benchmark, and what to fix.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Email rate calculator.
curl https://ken.so/api/free/v1/calculate/rate \
-H "Content-Type: application/json" \
-d '{"rate":"bounce","numerator":64,"denominator":2400}'{
"rate": "bounce",
"name": "Bounce rate",
"percent": 2.67,
"formula": "bounce rate = bounced / sent x 100",
"numeratorLabel": "Emails that bounced",
"denominatorLabel": "Emails sent",
"band": "watch",
"verdict": "2.67% is over the 2% healthy ceiling and under the 4% line (ken pauses sending). Fix it before it climbs.",
"thresholds": [
{
"label": "Healthy ceiling",
"percent": 2,
"kind": "external-guideline",
"source": "Common deliverability guidance: keep hard bounces under 2%."
},
{
"label": "Ken pauses sending",
"percent": 4,
"kind": "ken-system",
"source": "Ken stops an inbox sending when its hard bounces pass 4% (sequencer send block, ken-backend SequencerSendBlockOptions.InboxRateThreshold)."
}
],
"benchmark": null,
"comparison": null,
"advice": "Stop sending to that list. Verify every address before the next send, remove the bounced ones, and check that the domain's SPF, DKIM and DMARC pass.",
"fix": {
"slug": "email-verifier",
"label": "Email verifier"
},
"warnings": [],
"source_url": "https://ken.so/tools/email-rate-calculator"
…POST/calculate/ab-testA/B test
Sample size per variant for a two-proportion test, or the significance of a finished test with a plain verdict and the stop rule.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as A/B test calculator.
curl https://ken.so/api/free/v1/calculate/ab-test \
-H "Content-Type: application/json" \
-d '{"mode":"significance","a":{"sent":1200,"successes":24},"b":{"sent":1180,"successes":41}}'{
"mode": "significance",
"ok": true,
"rateA": 0.02,
"rateB": 0.034746,
"difference": 1.4746,
"relativeLift": 0.7373,
"zScore": 2.2068,
"pValue": 0.027331,
"alpha": 0.05,
"significant": true,
"confidenceInterval": {
"low": 0.1634,
"high": 2.7858
},
"winner": "b",
"smallSample": false,
"stillCollecting": false,
"verdict": "B wins: 3.47% against 2% (+73.7% relative), p = 0.027. Switch to B and test the next idea.",
"stopRule": "Fix the sample size before you start. Send to both variants at the same time, stop only when each has reached it, and then read the result once. A significant result before that point is not a result.",
"source_url": "https://ken.so/tools/ab-test-calculator"
}POST/calculate/agency-pricingAgency pricing
What to charge each client: Ken's real Platform bill split across clients, your labor, the retainer for your target margin and the price per meeting.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as Agency pricing calculator.
curl https://ken.so/api/free/v1/calculate/agency-pricing \
-H "Content-Type: application/json" \
-d '{
"clients": 8,
"leadsPerClient": 2000,
"channels": {
"email": true,
"linkedin": true
},
"hoursPerClient": 10,
"targetMargin": 0.5
}'{
"kenCostTotal": 1340,
"kenCostPerClient": 167.5,
"laborCostPerClient": 500,
"costPerClient": 667.5,
"recommendedRetainer": 1335,
"pricePerMeeting": 953.57,
"meetingsPerClient": 1.4,
"meetingsSource": {
"kind": "ken-published",
"source": "Ken's published 7 meetings per 10,000 contacts. What is possible, not a promise."
},
"profitPerClient": 667.5,
"profitTotal": 5340,
"marginAtRecommended": 0.5,
"marginAtCurrent": null,
"warnings": [],
"source_url": "https://ken.so/tools/agency-pricing-calculator"
}POST/calculate/linkedin-limitsLinkedIn weekly limits
Safe weekly ranges for connection requests, messages, InMails and profile views by account type and age, never above Ken's own caps, with sources and a disclaimer.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as LinkedIn limits calculator.
curl https://ken.so/api/free/v1/calculate/linkedin-limits \
-H "Content-Type: application/json" \
-d '{
"accountType": "sales-navigator",
"accountAgeMonths": 30,
"ssi": 62,
"acceptanceRate": 0.35,
"pendingInvites": 420
}'{
"accountType": "sales-navigator",
"ranges": [
{
"action": "connectionRequests",
"label": "Connection requests",
"low": 60,
"high": 75,
"kenWeeklyLimit": 100,
"sources": [
{
"kind": "community-estimate",
"source": "LinkedIn does not publish weekly limits. Range reflects what practitioners report as safe for this account type, kept at or under Ken's cap."
},
{
"kind": "ken-system",
"source": "Ken's LinkedIn sender enforces 20 connection requests, 50 messages and 80 profile visits per account per day (the LinkedIn outreach page), 5 sending days a week."
}
]
},
{
"action": "messages",
"label": "Messages",
"low": 200,
"high": 250,
"kenWeeklyLimit": 250,
"sources": [
{
"kind": "community-estimate",
"source": "LinkedIn does not publish weekly limits. Range reflects what practitioners report as safe for this account type, kept at or under Ken's cap."
},
{
…Domain
GET/domain-healthDomain health grade
The A to F grade from the page's DNS checks (SPF, DKIM, DMARC, MX, DMARC reports, reverse DNS, MTA-STS, TLS-RPT, primary domain, bulk sender rules, BIMI) with the record to paste for each fix. The blacklists row comes back skipped and out of the score: GET /blacklist checks them, under its own limits. About 30 DNS queries, counted as one domain. With a key, up to 20 domains a call (comma separated).
Anonymous: 20 requests an hour, 100 domains a day per IP. Free key: 20 requests a minute, 2,000 domains a day per account.
Same engine as Domain health check.
curl "https://ken.so/api/free/v1/domain-health?domain=stripe.com"
GET/spfCheck SPF
The SPF record and its full include tree, with the RFC 7208 lookup and void counts worst-case across the tree, loops, macros and +all, plus a flattened record when it helps.
Anonymous: 20 requests an hour, 100 domains a day per IP. Free key: 20 requests a minute, 2,000 domains a day per account.
Same engine as SPF checker.
curl "https://ken.so/api/free/v1/spf?domain=stripe.com"
POST/spf/flattenFlatten SPF
Resolves a domain's SPF includes to ip4 and ip6 ranges and chains _spf1, _spf2 records past 450 characters. Flattened records go stale when a provider changes its ranges: re-run before you publish.
Anonymous: 20 requests an hour, 100 domains a day per IP. Free key: 20 requests a minute, 2,000 domains a day per account.
Same engine as SPF flattener.
curl https://ken.so/api/free/v1/spf/flatten \
-H "Content-Type: application/json" \
-d '{"domain":"stripe.com"}'GET/dkimCheck DKIM
Looks up the selectors you name, or sweeps 20 common ones (one domain either way): key size, revoked, testing and weak keys, CNAME-delegated keys and who owns each selector.
Anonymous: 20 requests an hour, 100 domains a day per IP. Free key: 20 requests a minute, 2,000 domains a day per account.
Same engine as DKIM checker.
curl "https://ken.so/api/free/v1/dkim?domain=stripe.com&selector=google"
GET/dmarcCheck DMARC
The DMARC record with every tag and its implied default, the organizational-domain fallback, the external rua authorization check and the next step up the policy ladder.
Anonymous: 20 requests an hour, 100 domains a day per IP. Free key: 20 requests a minute, 2,000 domains a day per account.
Same engine as DMARC checker.
curl "https://ken.so/api/free/v1/dmarc?domain=stripe.com"
GET/bimiCheck BIMI
The BIMI record, the SVG Tiny PS logo checked against the profile (fetched with a 1 MB cap), the VMC or CMC certificate and whether DMARC is strict enough.
Anonymous: 20 requests an hour, 100 domains a day per IP. Free key: 20 requests a minute, 2,000 domains a day per account.
Same engine as BIMI checker.
curl "https://ken.so/api/free/v1/bimi?domain=stripe.com"
GET/mta-stsCheck MTA-STS
The _mta-sts record, the policy file over HTTPS and whether it covers the domain's live MX hosts.
Anonymous: 20 requests an hour, 100 domains a day per IP. Free key: 20 requests a minute, 2,000 domains a day per account.
Same engine as MTA-STS checker.
curl "https://ken.so/api/free/v1/mta-sts?domain=stripe.com"
GET/tls-rptCheck TLS-RPT
The _smtp._tls record and where TLS failure reports go.
Anonymous: 20 requests an hour, 100 domains a day per IP. Free key: 20 requests a minute, 2,000 domains a day per account.
Same engine as TLS-RPT checker.
curl "https://ken.so/api/free/v1/tls-rpt?domain=stripe.com"
GET/rdapRDAP domain lookup
Registration and expiry dates and the registrar from the registry's RDAP server, or whether the domain is available.
Anonymous: 20 requests an hour, 100 domains a day per IP. Free key: 20 requests a minute, 2,000 domains a day per account.
Same engine as RDAP domain lookup.
curl "https://ken.so/api/free/v1/rdap?domain=stripe.com"
DNS records
GET/dnsDNS lookup
A, AAAA, MX, TXT, CNAME, NS and SOA records for a name, or PTR for an IPv4 or IPv6 address. resolvers=all asks Cloudflare, Google, Quad9 and OpenDNS the same question and counts as 4 lookups. With a key, up to 100 names a call.
Anonymous: 20 requests an hour, 100 domains a day per IP. Free key: 20 requests a minute, 2,000 domains a day per account.
Same engine as DNS lookup.
curl "https://ken.so/api/free/v1/dns?name=stripe.com&type=MX,TXT"
POST/spf/generateGenerate an SPF record
An SPF record for the senders you use, with an estimated lookup count and notes per sender. Check it live with GET /spf after you publish.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as SPF record generator.
curl https://ken.so/api/free/v1/spf/generate \
-H "Content-Type: application/json" \
-d '{"domain":"northwind-outbound.com","senders":["google","hubspot"],"all":"~"}'{
"record": {
"type": "TXT",
"host": "@",
"name": "northwind-outbound.com",
"value": "v=spf1 include:_spf.google.com ~all",
"ttl": 3600
},
"lookups": 1,
"notes": [
"HubSpot gives each account its own include (like 1234567.spf01.hubspotemail.net). Copy it from Settings > Domains & URLs > Email sending domains and add it as a custom include."
],
"issues": [],
"source_url": "https://ken.so/tools/spf-generator"
}POST/dmarc/generateGenerate a DMARC record
A DMARC record to paste at _dmarc: policy, subdomain policy, report addresses and alignment.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as DMARC record generator.
curl https://ken.so/api/free/v1/dmarc/generate \
-H "Content-Type: application/json" \
-d '{
"domain": "northwind-outbound.com",
"policy": "quarantine",
"rua": [
"[email protected]"
]
}'{
"record": {
"type": "TXT",
"host": "_dmarc",
"name": "_dmarc.northwind-outbound.com",
"value": "v=DMARC1; p=quarantine; rua=mailto:[email protected]",
"ttl": 3600
},
"source_url": "https://ken.so/tools/dmarc-generator"
}POST/bimi/generateGenerate a BIMI record
The default._bimi record for your SVG logo and VMC or CMC certificate, with what is missing.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as BIMI checker.
curl https://ken.so/api/free/v1/bimi/generate \
-H "Content-Type: application/json" \
-d '{
"domain": "northwind-outbound.com",
"logoUrl": "https://northwind-outbound.com/bimi/logo.svg"
}'{
"record": {
"type": "TXT",
"host": "default._bimi",
"name": "default._bimi.northwind-outbound.com",
"value": "v=BIMI1; l=https://northwind-outbound.com/bimi/logo.svg; a=",
"ttl": 3600
},
"issues": [
{
"code": "bimi_no_cert",
"severity": "info",
"message": "Gmail shows the logo only with a VMC or CMC certificate. Yahoo shows it without one."
}
],
"source_url": "https://ken.so/tools/bimi-checker"
}POST/mta-sts/generateGenerate MTA-STS
The _mta-sts TXT record and the policy file to host at mta-sts.<domain>/.well-known/mta-sts.txt, with MX patterns collapsed to one-label wildcards.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as MTA-STS checker.
curl https://ken.so/api/free/v1/mta-sts/generate \
-H "Content-Type: application/json" \
-d '{
"domain": "northwind-outbound.com",
"mx": [
"aspmx.l.google.com",
"alt1.aspmx.l.google.com",
"alt2.aspmx.l.google.com"
],
"mode": "testing"
}'{
"txt": {
"type": "TXT",
"host": "_mta-sts",
"name": "_mta-sts.northwind-outbound.com",
"value": "v=STSv1; id=20261019T1448",
"ttl": 3600
},
"policy": {
"url": "https://mta-sts.northwind-outbound.com/.well-known/mta-sts.txt",
"body": "version: STSv1\r\nmode: testing\r\nmx: aspmx.l.google.com\r\nmx: *.aspmx.l.google.com\r\nmax_age: 604800\r\n",
"contentType": "text/plain"
},
"patterns": [
"aspmx.l.google.com",
"*.aspmx.l.google.com"
],
"source_url": "https://ken.so/tools/mta-sts-checker"
}POST/tls-rpt/generateGenerate TLS-RPT
The _smtp._tls record that sends TLS failure reports to your address or HTTPS endpoint.
Anonymous: 60 requests an hour, 1,000 items a day per IP. Free key: 60 requests a minute, 10,000 items a day per account.
Same engine as TLS-RPT checker.
curl https://ken.so/api/free/v1/tls-rpt/generate \
-H "Content-Type: application/json" \
-d '{"domain":"northwind-outbound.com","rua":["[email protected]"]}'{
"record": {
"type": "TXT",
"host": "_smtp._tls",
"name": "_smtp._tls.northwind-outbound.com",
"value": "v=TLSRPTv1; rua=mailto:[email protected]",
"ttl": 3600
},
"source_url": "https://ken.so/tools/tls-rpt-checker"
}Probe
GET/blacklistBlacklist check
Checks a domain or IPv4 address against the DNS blocklists whose terms allow automated lookups, from Ken's own resolver, with what each listing means and where to delist. Lists that don't allow it come back under skipped with a link to check by hand.
Anonymous: 10 requests an hour, 10 items a day per IP. Free key: 10 requests a minute, 100 items a day per account. 2,000 a day across the API.
Same engine as Blacklist checker.
curl "https://ken.so/api/free/v1/blacklist?target=stripe.com"
POST/smtp-testSMTP server test
Connects to a mail server from Ken's non-sending probe box: banner, EHLO, STARTTLS, the certificate, reverse DNS and timings, with the transcript. It never sends a message. Key only: an anonymous SMTP probe gets used for scanning.
Key only. Free key: 2 requests a minute, 10 items a day per account. 2,000 a day across the API. 5 a day against any one target.
Same engine as SMTP test.
curl https://ken.so/api/free/v1/smtp-test \
-H "Content-Type: application/json" \
-d '{"domain":"stripe.com","port":25}'Use it in Clay
In your table, add an enrichment and pick HTTP API.
Method POST, the endpoint URL below, header Content-Type: application/json, and Authorization: Bearer <key> for the key limits.
Write the JSON body and insert your column where the value goes (type / to pick it).
Run it on a few rows, then map results[0].name (or any field) to a new column.
POST https://ken.so/api/free/v1/clean/company-name
Content-Type: application/json
Authorization: Bearer <your key>
{ "name": "<Company Name column>" }Use it from an AI agent
Agents that read OpenAPI (Custom GPT actions, n8n, most agent frameworks) can load the document above and call every endpoint as a tool.
Ken's MCP server already gives Claude, Cursor and other MCP clients your Ken workspace. The free tools are coming to it as their own group, counted per Ken account like a key.
Errors
Every error is JSON witherror, message and docs_url.bad_requestissues lists each field.invalid_keykey_requiredai: true, bulk lists or the SMTP test.not_foundmethod_not_allowedAllow names the right one.payload_too_largerate_limitedRetry-After says when it opens.global_limitbudget_exhaustedresets_at and start_free come with it.unavailabletimeoutinternal_errorQuestions
Is the API really free?
What do I need a key for?
ai: true. Everything else works without one.Do you store what I send?
ai: true, the values the rules leave unsure go to a model provider for that call.Why did my call get a 429?
rate_limited for yours, global_limit for the API-wide day) and Retry-After says when it opens. Bulk calls count each item, so a 100-name call takes 100 items.What does ai: true do?
ai: true and a key, the names or titles the rules leave unsure go to a model. If the model budget for the month is spent, you still get the rules result, with ai.skipped saying why.Can I publish results from the API?
source_url, the tool page that made it. Link it where you show the result.