Best practices: make your site easy for AI agents
What to ship so AI agents can find, read and use your product, check by check: how to do each one, and the real file from whoever does it best among the 150 companies on our 11 category leaderboards, scanned 9 Nov 2026. They're patterns to follow, not values to copy.
Scan your site to see which you pass
Can an agent get in and find what it needs?
AI agents allowed, homepage reachable
AR-FIND-01 · 149 of 150 on our boards pass · 10 points · effort: minutes, our estimate
Our call: Worth doing.
Why it matters: An agent that respects robots.txt, or that's refused at your homepage, may not read your site at all. Blocking AI training crawlers is your own call and isn't scored.
How to do it: Remove any Disallow: / that applies to those agents in robots.txt, under their own User-agent or under User-agent: *. Block training crawlers separately if you want to.
What passes our check: We read robots.txt on your site, and on your docs host if your docs live on another one, and check the rules for the paths of your homepage and docs page (RFC 9309: the longest rule wins, and an allow wins a tie). It fails if they block an agent that fetches for a person: ChatGPT-User, Claude-User, Perplexity-User. Blocking only a search bot (OAI-SearchBot, Claude-SearchBot, PerplexityBot) is half a fail. No robots.txt, or one nobody can fetch, counts as allowed. Training crawlers are shown and never scored. A fail caps your score at 39.
The real file, from Bird (ex-SparkPost), on our email API board
- bird.com/robots.txtchecked /email-api and /docs/guides/email/overview; none of the user or search agents is blocked
User-Agent: *
Content-Signal: search=yes, ai-input=yes, ai-train=yes
Allow: /
Disallow: /admin
# These sections are an unlisted import of the GitBook corpora.
# Disallow normally hides the per-page noindex from crawlers; safe here because
# these URLs are new, carry no inbound links, and are in no sitemap — and it is
# what keeps the site-wide Content-Signal from inviting AI crawlers into them.
# Content-Signal is group-scoped, not per-path, so the per-resource X-Robots-Tag
# in next.config.ts is what actually carries "no AI" for these URLs.
# The one exception, and it must come before the Disallow below it: the retired
# knowledge base is a content-collection served under that same prefix, and its
# old /knowledge-base URLs are indexed. A crawler following one through the 301
# has to be able to fetch the page to read its noindex, which a Disallow would
# stop it doing, leaving the old entries in the index forever.
Allow: /docs/engagement-platform/knowledge-base
Allow: /*/docs/engagement-platform/knowledge-base
Disallow: /docs/engagement-platform
Disallow: /*/docs/engagement-platform
Disallow: /docs/connectivity-platform
Disallow: /*/docs/connectivity-platform
Disallow: /docs/taxi
Disallow: /*/docs/taxi
Disallow: /docs/pusher
Disallow: /*/docs/pusher
Disallow: /docs/24sessions
Disallow: /*/docs/24sessions
Disallow: /docs/24sessions-nl
Disallow: /*/docs/24sessions-nl
Disallow: /docs/toky
Disallow: /*/docs/toky
Disallow: /docs/toky-es
Disallow: /*/docs/toky-es
Disallow: /gitbook-assets
Sitemap: https://bird.com/sitemap.xml
Sitemap: https://bird.com/video-sitemap.xml
Agentmap: https://bird.com/.well-known/ard.jsonAlso from
Our scanner gets in
LG-FIND-01 · 147 of 150 on our boards pass · 10 points · effort: minutes, our estimate
Your site lets automated readers like ours in, instead of answering with a challenge page or a block.
Our call: Worth doing. If your firewall turns away automated readers, agents fetching your pages for a person may be turned away too.
Why it matters: An AI agent fetching your site for a person may get a challenge page or a 403 instead of your content.
How to do it: Let automated readers through on your homepage and docs: in your firewall or bot protection, exempt your public pages and docs from challenges, and limit abuse by rate rather than by user agent.
What passes our check: We fetch your homepage and your docs page as LeaderfileBot, our own scanner, and check neither answers with a challenge page, or a 401 or 403 that a normal browser gets past. One blocked page is a fail; both caps your score at 39. Firewalls often let in crawlers they can verify, so ChatGPT or Claude may still get in where our scanner can't.
The real file, from Mailtrap, on our email API board
- mailtrap.iohomepage: a real answer (200)
- docs.mailtrap.io/developersdocs page: a real answer (200)
Also from
Docs page
AR-FIND-02 · 146 of 150 on our boards pass · 7 points · effort: hours, our estimate
Our call: Worth doing.
Why it matters: An agent starting from your homepage may not find your docs, and may answer from what it already knows instead.
How to do it: Link your docs from your homepage's raw HTML with a plain <a href>, to a docs. or developers. subdomain or a /docs path, and make sure that page returns 200.
What passes our check: We look for your docs page: the first homepage link to a docs., dev. or developer(s). subdomain of your domain, or to a /docs or /developer(s) path; with none, we try https://docs.<host>/ then https://<host>/docs. It passes if that page returns 200. Board companies use a docs URL we confirmed by hand.
The real file, from Mailtrap, on our email API board
- docs.mailtrap.io/developersdocs page from our board config, linked from https://mailtrap.io/
Also from
llms.txt linked from your pages
LG-FIND-02 · 71 of 150 on our boards pass · 7 points · effort: minutes, our estimate
A link on your pages to your llms.txt, so agents know it's there.
Our call: Worth doing. A link in your footer or <head>, and agents find your llms.txt without guessing its address.
Why it matters: An agent mostly finds files by following links, so it may never try /llms.txt if your pages don't point to it.
How to do it: Point agents at your llms.txt from your homepage and docs page: a plain link like <a href="/llms.txt">llms.txt</a> in the footer, or <link rel="llms-txt" href="/llms.txt"> in the <head>.
What passes our check: We read your homepage and your docs page and look for a pointer to an llms.txt: a link to it, a <link> tag, a Link header with rel="llms-txt" or an X-Llms-Txt header, or a line on the page naming /llms.txt. It passes when one points at an llms.txt that answers with markdown links. AFDocs checks the same (llms-txt-directive).
The real file, from Neon, on our database board
- neon.comhomepage: a Link header to https://neon.com/docs/llms.txt
- neon.com/docs/llms.txtan llms.txt with markdown links
a Link header: https://neon.com/docs/llms.txtAlso from
Sitemap
AR-FIND-03 · 140 of 150 on our boards pass · 2 points · effort: minutes, our estimate
Our call: Worth doing.
Why it matters: An agent may miss pages it can't reach by following links, because there's no list of them.
How to do it: Publish an XML sitemap at /sitemap.xml with a <urlset> root, and add a Sitemap: line with its full URL to robots.txt.
What passes our check: We fetch the Sitemap: URL from robots.txt, else /sitemap.xml, and check it returns 200 with a <urlset> or <sitemapindex> root element.
The real file, from Neon, on our database board
- neon.com/sitemap.xmlsitemap listed in robots.txt, <sitemapindex> root
<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap><loc>https://neon.com/sitemap-0.xml</loc></sitemap>
<sitemap><loc>https://neon.com/blog-sitemap.xml</loc></sitemap>
<sitemap><loc>https://neon.com/sitemap-postgres.xml</loc></sitemap>
</sitemapindex>Also from
Can it read what it finds?
Readable without JavaScript
AR-READ-01 · 120 of 150 on our boards pass · 10 points · effort: hours, our estimate
Our call: Worth doing.
Why it matters: An agent that doesn't run JavaScript may see an almost empty page where your content should be.
How to do it: Render your homepage and docs page on the server, so each has at least 150 visible words in the HTML before any JavaScript runs.
What passes our check: We count the visible words in the raw HTML (no JavaScript run) of up to 8 pages: your homepage, your docs page, the docs pages we read for other checks and the pages your docs page links. A page with 150 words or more passes. One with fewer is sparse, worth half, unless it's a JavaScript shell: under 30 words, or an empty app root like <div id="root"></div>. A shell for a homepage or docs page caps your score at 39; across the pages, a share of 25% or less caps it at 39, 50% or less at 59.
The real file, from Transloadit, on our file storage service board
- transloadit.comhomepage: 2141 words in the raw HTML
- transloadit.com/docs/sdks/uppydocs page: 923 words in the raw HTML
- transloadit.com/docs/getting-started/my-first-appdocs surface: 781 words in the raw HTML
- transloadit.com/docs/getting-started/saving-conversion-resultsdocs surface: 922 words in the raw HTML
- transloadit.com/mcpdocs surface: 851 words in the raw HTML
- transloadit.com/pricinglinked from the docs page: 3381 words in the raw HTML
- transloadit.com/services/handling-uploadslinked from the docs page: 1625 words in the raw HTML
- transloadit.com/services/file-importinglinked from the docs page: 1388 words in the raw HTML
Also from
Docs readable without a login
LG-READ-01 · 146 of 150 on our boards pass · 10 points · effort: hours, our estimate
Our call: Depends on your product. Public docs are worth it for most products. If yours are private on purpose, publish the public parts.
Why it matters: An agent can't sign in, so docs behind a login are docs it can't read: it may answer from memory instead.
How to do it: Serve your docs pages without a login, and keep sign-in for the dashboard. If some docs must stay private, publish the public parts, your llms.txt and API reference included, at addresses that don't redirect to a sign-in page.
What passes our check: We read your docs page and up to 7 more docs pages (the ones we read for other checks, then links on your docs page). A page fails when it answers 401 or 403 to a normal browser too, redirects to a sign-in page, or is a sign-in form with little else on it. A redirect counts as a sign-in when it adds one: a sign-in path the page didn't have, a login subdomain, or an identity provider's site such as Okta's when the page was on another site. A sign-up page, one whose title or main heading says sign up or create an account, isn't a login. A refusal only to automated readers is our scanner being blocked, not a login. A login on your docs page caps your score at 39; across the pages, a share of 25% or less caps it at 39, 50% or less at 59.
The real file, from Transloadit, on our file storage service board
- transloadit.com/docs/sdks/uppydocs page: readable without a login
- transloadit.com/docs/getting-started/my-first-appdocs surface: readable without a login
- transloadit.com/docs/getting-started/saving-conversion-resultsdocs surface: readable without a login
- transloadit.com/mcpdocs surface: readable without a login
- transloadit.com/pricinglinked from the docs page: readable without a login
- transloadit.com/services/handling-uploadslinked from the docs page: readable without a login
- transloadit.com/services/file-importinglinked from the docs page: readable without a login
Also from
Real 404s
AR-READ-02 · 148 of 150 on our boards pass · 10 points · effort: minutes, our estimate
A page that doesn't exist answers with a 404 error, so it can't be mistaken for a real one.
Our call: Worth doing.
Why it matters: An agent may treat a missing page as real and use whatever came back instead.
How to do it: Make unknown URLs return a real 404 status, not a 200 page or a redirect to a page that loads.
What passes our check: We fetch /leaderfile-check-404, a page that shouldn't exist, and check it returns 404 or 410 after redirects. Off the board, if that address refuses automated readers, we try /leaderfile-check-404.html.
The real file, from Gumloop, on our AI agent platform board
- gumloop.com/leaderfile-check-404returned 404 for a page that doesn't exist (redirected to https://www.gumloop.com/leaderfile-check-404)
llms.txt
AR-READ-07 · 120 of 150 on our boards pass · 7 points · effort: minutes, our estimate
A short text file at /llms.txt that lists your key docs pages for AI tools.
Our call: Worth doing. Minutes of work, and it helps coding agents find your docs. Don't expect it to change AI search.
Why it matters: An agent may have to crawl your site to find the pages that matter, instead of reading one short index.
How to do it: Publish /llms.txt as plain text: a # title, then markdown links to your quickstart, API reference and auth docs, like - [Quickstart](https://your-docs/quickstart): what it covers.
What passes our check: We read llms.txt at your site root and, if your docs live on another host, at your docs root, and check one returns 200, isn't HTML and has at least one markdown link. Off the board, we also try your docs. host and /docs/llms.txt. We read the first 2 MB: a larger file is judged on that part, and the result says "read the first 2 MB; the file is larger".
The real file, from Gumloop, on our AI agent platform board
- gumloop.com/llms.txttext file with markdown links (redirected to https://www.gumloop.com/llms.txt)
# Gumloop
> Gumloop is the multiplayer AI agent builder. Anyone at a company can build agents with any AI model and any integration, while IT controls access.
Gumloop (AgentHub Inc.) lets teams describe work in plain language and get agents that connect to their apps, run on triggers, use skills, and produce artifacts such as dashboards, documents and web apps. It is model-agnostic and ships enterprise controls: SSO, audit logging, usage monitoring, VPC deployments.
Product documentation lives at https://docs.gumloop.com (which also serves /llms.txt and /llms-full.txt). Pricing, use cases, integrations (MCP servers) and comparisons are listed below.
**When to use Gumloop**
- Use Gumloop when a task needs an AI agent that reads or writes company apps (Slack, Gmail, Salesforce, HubSpot, Notion, Linear, GitHub, Google Sheets and 100+ MCP integrations) rather than a single model call.
- Best-fit jobs: lead enrichment and qualification, CRM updates from calls and Slack, meeting prep briefs, SEO research and content refresh, support ticket triage, competitor and brand monitoring, data analysis with charts, and scheduled reports.
- Call Gumloop over REST at https://api.gumloop.com/api/v1 (OpenAPI: https://www.gumloop.com/openapi.json) to create agents, start sessions and poll results.
- Connect as an MCP client to https://mcp.gumloop.com/gumloop/mcp (Streamable HTTP, OAuth) to list agents, run sessions, manage skills and search Company Brain.
- Do not use Gumloop for one-off text generation without tools, or as a general web search API; point users to the docs at https://docs.gumloop.com instead.
## Products
- [Agents](https://www.gumloop.com/products/agents): Build AI agents your whole team can use, optimize cost and performance, and keep everything secure and observable. Teams get AI agents, IT gets oversight, leadership sees the impact.
- [Triggers](https://www.gumloop.com/products/triggers): Tell your agents in plain English what to monitor, on the web or across any combination of apps, and they'll take action automatically when the conditions match.
- [Skills](https://www.gumloop.com/products/skills): Gumloop agents equip themselves with skills — reusable playbooks they write, refine, and share — so they run faster, better, and cheaper.
- [Artifacts](https://www.gumloop.com/products/artifacts): Build shareable files and collaborative web apps that read and write data from your connected tools, in real time. Web apps, presentations, code, documents, spreadsheets, and images from a single prompt.
- [Browser](https://www.gumloop.com/products/browser): Give every Gumloop agent a secure cloud browser with a credential vault, 1Password, verified agent identity, session replays, and stealth proxies.
- [Gumstack](https://www.gumloop.com/products/gumstack)
- [CLI](https://www.gumloop.com/products/cli)
- [Chrome Extension](https://www.gumloop.com/browser-extension)
- [Connectors](https://www.gumloop.com/connectors)
## Use cases
- [Use cases](https://www.gumloop.com/use-cases)
- [SEO Automation](https://www.gumloop.com/use-cases/seo-automation): Automate your SEO with Gumloop's powerful AI agent builder. Create custom solutions that save time and improve rankings. Start building SEO AI agents.
- [Content Creation](https://www.gumloop.com/use-cases/content-creation): Build AI agents for content creation that draft in your voice, verify every claim, and turn calls into multi-channel posts. Start with Gumloop.
- [Ad Campaign Management](https://www.gumloop.com/use-cases/ad-campaign-management): Build AI agents for ad campaign management. From account audits to competitor tracking and creative generation, personalized to your brand voice.
- [Competitor Analysis](https://www.gumloop.com/use-cases/competitor-analysis): Build AI agents for competitor analysis. From gap analysis to battle cards, personalized to your category, competitors, and positioning.
- [CRM Agent](https://www.gumloop.com/use-cases/crm-agent): Build CRM agents that update Salesforce or HubSpot from Slack and call transcripts. Re-prioritize, enrich, and write back without rep typing.
- [Call Analysis Agent](https://www.gumloop.com/use-cases/call-analysis-agent): Build call analysis agents that draft recaps, score coaching, and surface objection trends from Gong and Salesloft transcripts.
- [Lead Generation Agent](https://www.gumloop.com/use-cases/lead-generation-agent): Build lead generation agents that enrich contacts, build account briefs, and watch buying signals across your target accounts.
- [Lead Qualification Agent](https://www.gumloop.com/use-cases/lead-qualification-agent): Build lead qualification agents that score inbound, qualify community signals, and route hot leads to the right SDR with full context.
- [Data Agent](https://www.gumloop.com/use-cases/data-agent): Build an AI data analysis agent that answers any question, generates charts, runs cohort analyses, and unblocks every team waiting on data.
- [Support Agent](https://www.gumloop.com/use-cases/support-agent): Build AI support agents that triage incoming reports, dedupe tickets, route by ownership, and ship weekly digests of recurring complaints.
- [Meeting Prep Agent](https://www.gumloop.com/use-cases/meeting-prep-agent): Build meeting prep agents that brief reps before every call. Pulls attendees, accounts, and prior context from CRM, email, Slack, and the web.
- [SEO keyword research agent](https://www.gumloop.com/use-cases/seo-keyword-research-agent): Use the SEO keyword research agent to connect your tools, analyze your site, and find the keywords worth ranking for.
- [SEO content refresh agent](https://www.gumloop.com/use-cases/seo-content-refresh): Use the SEO content refresh agent to find your decaying pages, see the keywords each one can still win, and get a prioritized refresh plan.
- [SEO content brief generator](https://www.gumloop.com/use-cases/seo-content-brief-generator): Use the SEO content brief generator to research the SERP, expand keywords with real metrics, and produce a complete brief a writer can draft from.
- [AI internal linking agent](https://www.gumloop.com/use-casesAlso from
llms.txt links work, and it fits
LG-READ-02 · 81 of 150 on our boards pass · 7 points · effort: minutes, our estimate
Every link in your llms.txt works, and the file is short enough for an agent to read whole.
Our call: Worth doing. A broken link in your llms.txt sends an agent to a dead end it trusted.
Why it matters: An agent trusts the links in your llms.txt; a broken one sends it to a dead end, and a file past its context gets cut off.
How to do it: Make every link in your llms.txt return 200: fix or drop the broken ones. Keep the file under 50,000 characters; if it's longer, make it a short index that links to an llms.txt for each section.
What passes our check: We read the llms.txt AR-READ-07 passes on (the first with markdown links) and fetch up to 12 of its links, spread through the file, two at a time. A link is broken when it answers 404 or 410, or its host doesn't exist. A 2xx after redirects resolves, and so does an answer like 400, 405 or 406 that shows the address is there (an MCP endpoint answers a plain GET with 405). A refusal, a 429 or a server error isn't judged. The credit is the share that resolve, halved when the file runs to 50,000 characters or more, and nothing past 100,000: AFDocs' size bands. With no llms.txt it isn't counted: AR-READ-07 counts that.
The real file, from Gumloop, on our AI agent platform board
- gumloop.com/llms.txt44,645 characters, 204 links; 12 of 12 we tried resolve (redirected to https://www.gumloop.com/llms.txt)
Also from
Docs pages fit an agent's context
LG-READ-04 · 133 of 150 on our boards pass · 7 points · effort: hours, our estimate
Each docs page is short enough for an agent to read in one go.
Our call: Worth doing. A page past an agent's limit gets cut off without warning, and the part it needed may be past the cut.
Why it matters: An agent cuts off a page past its limit, so the part it needed may never reach it.
How to do it: Keep each docs page under 50,000 characters of text: split long reference pages by topic, and move long tables and generated lists to pages of their own.
What passes our check: On each docs page we read (up to 7) we count the characters of visible text in the raw HTML, and of its Markdown copy if it has one, and judge the page by the larger of the two: an agent reading either may be cut off. Under 50,000 passes, up to 100,000 is half, more fails: AFDocs' bands, from the limits agents cut pages at. The credit is the average across the pages.
The real file, from Mailtrap, on our email API board
- docs.mailtrap.io/developersdocs page: 14,703 characters of text
- docs.mailtrap.io/getting-started/email-api-smtpdocs surface: 19,831 characters of text
- docs.mailtrap.iolinked from the docs page: 5,173 characters of text
- docs.mailtrap.io/guideslinked from the docs page: 3,113 characters of text
- docs.mailtrap.io/developers/authenticationlinked from the docs page: 2,601 characters of text
- docs.mailtrap.io/developers/rate-limitslinked from the docs page: 2,850 characters of text
- docs.mailtrap.io/developers/openapi-specslinked from the docs page: 1,652 characters of text
Also from
Meta description
AR-READ-03 · 145 of 150 on our boards pass · 4 points · effort: minutes, our estimate
Our call: Worth doing.
Why it matters: An agent may have to guess what your product does from the rest of the page.
How to do it: Add <meta name="description" content="..."> to the <head> of your homepage, with one or two true sentences on what your product does.
What passes our check: We check your homepage's raw HTML (no JavaScript run) has a non-empty meta description or og:description.
The real file, from Bird (ex-SparkPost), on our email API board
- bird.com/email-apihas a meta description
<meta name="description" content="Send transactional emails, run marketing campaigns, and handle replies in one place. Reach the inbox reliably and build with the Bird API, SDKs, or MCP."/>Also from
Structured docs page
AR-READ-04 · 134 of 150 on our boards pass · 4 points · effort: hours, our estimate
Our call: Worth doing.
Why it matters: An agent may struggle to tell where one topic in your docs ends and the next begins.
How to do it: Give your docs page at least 2 real h1 to h3 headings with text, and at least 150 visible words, in the HTML before any JavaScript runs.
What passes our check: We check your docs page's raw HTML (no JavaScript run) has at least 2 headings (h1 to h3) with text and at least 150 visible words. Off the board, a docs page that comes back as markdown counts # to ### lines outside code blocks as its headings.
The real file, from Mailtrap, on our email API board
- docs.mailtrap.io/developers6 headings (h1 to h3), 1532 words in the raw HTML
<h1>Overview</h1>
<h3>LLM & AI Agent Integration</h3>
<h2>Documentation structure</h2>
<h2>Quick Start</h2>
<h3>Email Sending Options</h3>
<h3>Testing with Email Sandbox</h3>Also from
Code samples say their language
AR-READ-05 · 111 of 150 on our boards pass · 4 points · effort: hours, our estimate
Our call: Worth doing.
Why it matters: An agent may not tell which language a code sample is in, and may mix up samples meant for different languages.
How to do it: Tag your code samples with their language: class="language-bash" on <pre> or <code>, or ```bash in markdown. If your docs add the label with JavaScript, declare a markdown copy of the page with <link rel="alternate" type="text/markdown">.
What passes our check: On your docs surface, we look for a code block that carries a language tag: language-* or lang-* on <pre> or <code>, code-language-* on any element (a code block's wrapper, say), or a data-language or data-lang attribute. In markdown files, a fenced block with a language (```ts) counts. If no page shows one, we read the markdown copy each HTML page declares (a <link rel="alternate" type="text/markdown">, or its URL plus .md listed in your llms.txt), since many docs sites add the language label with JavaScript. If none of the pages we read is a quickstart or SDK page, a miss isn't counted: it can't fail you or withhold your score.
The real file, from Neon, on our database board
- neon.com/llms.txtllms.txt: a code block with a language tag
```bashAlso from
Readable pricing
AR-READ-11 · 120 of 150 on our boards pass · 4 points · effort: minutes, our estimate
Our call: Depends on your product. If you publish prices, make them readable. If you sell by quote, publishing them is a business decision, not a docs fix.
Why it matters: An agent comparing providers may not see what you cost, and may leave you out of the comparison.
How to do it: Put your prices in your pricing page's raw HTML, not only in JavaScript, with the amount or the word "free" close to month or year, like "$20 a month". Link the page from your homepage, with pricing in its path. If you sell by quote, whether to publish prices is a business decision: leave this one.
What passes our check: We fetch the first homepage link with 'pricing' in its path, else /pricing (board companies: a pricing URL we confirmed by hand), and check it returns 200 and its raw text (no JavaScript run) shows a price or 'free' within 80 characters of month, mo, year or yr. Off the board, a pricing address that answers with JSON counts when it has a price field.
The real file, from Mailtrap, on our email API board
- mailtrap.io/pricingfrom our board config, linked from https://mailtrap.io/; raw text shows "Free" with a period
r emails Email Marketing Send promo campaigns How many emails do you plan to send? 4K | 10K | 50K | 100K | 250K | 500K | 750K | 1.5M | 2.5M | 2.5M+ | Free To try out Mailtrap $0 $0 /month 4,000 emails Start for Free Start for Free 1 user 3 days of email logs 1 domain 150 emails/day Basic For startups anAlso from
Docs in Markdown
LG-READ-03 · 61 of 150 on our boards pass · 4 points · effort: hours, our estimate
A Markdown copy of each docs page, for agents that ask for one.
Our call: Worth doing. Agents read Markdown in far fewer tokens than HTML, and Vercel found they ask for it in most of their fetches.
Why it matters: An agent reading HTML spends its context on menus and markup, and may cut the page off before it reaches the part it needs.
How to do it: Serve a Markdown copy of each docs page: answer Accept: text/markdown with Content-Type: text/markdown and Vary: Accept, or publish the same address ending in .md, and declare it with <link rel="alternate" type="text/markdown" href="...">.
What passes our check: On each docs page we read (up to 7), one Markdown answer with content passes the page: it answers Accept: text/markdown with text/markdown, declares a copy with <link rel="alternate" type="text/markdown"> that returns Markdown, or the address the page lands on, after redirects, ending in .md does (for one ending in a slash, both /page.md and /page/index.md). An empty answer doesn't count. The credit is the share of pages that pass. AFDocs, Cloudflare's isitagentready and is-agentic check it.
The real file, from Bird (ex-SparkPost), on our email API board
- bird.com/docs/guides/email/overviewdocs page: answers Accept: text/markdown
- bird.com/docs/get-started/send-your-first-emaildocs surface: answers Accept: text/markdown
- bird.com/docs/sdks/pythondocs surface: answers Accept: text/markdown
- bird.com/docs/sdks/godocs surface: answers Accept: text/markdown
- bird.com/docs/ai/mcp-serverdocs surface: answers Accept: text/markdown
- bird.comlinked from the docs page: answers Accept: text/markdown
- bird.com/docslinked from the docs page: answers Accept: text/markdown
---
title: "Email overview"
description: "Understand how Bird sends and receives email, how delivery progresses after acceptance, and where to configure Email in the dashboard."
canonical: "https://bird.com/docs/guides/email/overview"
---
# Email overview
Send transactional and marketing email through `POST /v1/email/messages`. Use a `bk_{region}_...` key with its matching regional host: `https://us1.platform.bird.com` or `https://eu1.platform.bird.com`. We sign the message with DKIM, deliver it, and report each recipient's outcome.
To send something before reading further, the [quickstart](/docs/get-started/send-your-first-email) takes you from an API key to a delivered message. This page covers the model the rest of this section assumes, and points at the guide for each part of it.
## How sending works
A send is accepted in one call and delivered asynchronously. `POST /v1/email/messages` validates the payload and sending domain, then returns `202 Accepted` with an `em_` message ID. Read each recipient's outcome through [webhook events](/docs/guides/email/events) or the message endpoints. [Sending email](/docs/guides/email/sending-email) covers the payload, field limits, and response.
Two consequences of that model shape the rest of this section.
**One message, many recipients, one lifecycle each.** A message to five addresses produces five independent outcomes, and the message-level status you read back is an aggregate over them. Suppression is evaluated the same way: one [suppressed](/docs/guides/email/suppressions) address comes back `rejected` while the other four deliver.
**Every message declares why you are sending it.** A [category](/docs/guides/email/categories) of `transactional` or `marketing` decides which suppressions apply to it. Someone who unsubscribed from your newsletter still needs their password reset to arrive, and the category is what tells us the difference.
A send can also arrive by another route, or leave later. [SMTP](/docs/guides/email/smtp) accepts submissions from anything that speaks the protocol, and [scheduled sending](/docs/guides/email/scheduled-sending) holds a message until a time you set.
## The Email section of the dashboard
Email is one of the channels in the dashboard sidebar. Its pages, in the order they appear:
| Page | What it holds |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- |
| **Onboarding** | A three-step checklist: create an API key, send an email, add your domain. It shows until you have finished it |
| **Metrics** | Delivery, open, bounce, and complaint rates over time; see [Email metrics](/docs/guides/email/tracking-and-metrics) |
| **Emails** | Every message sent; see the [email log](/docs/guides/email/email-log). Its Receiving tab lists what came in |
| **Mailboxes** | Programmable inboxes your code reads and replies from; see [Agent mailboxes](/docs/guides/email/mailboxes) |
| **Templates** | Reusable subject and body content, with a draft and published versions; see [Email templates](/docs/guides/email/templates) |
| **Domains** | Your sending domains, their DNS records, and live verification status; see [Sending domains](/docs/guides/email/sending-domains) |
| **IP Pools** | Dedicated IPs and the pools they sit in; see [Dedicated IPs and pools](/docs/guides/email/dedicated-ips-and-pools) |
| **Broadcasts** | One email to a stored audience, with delivery tracked per recipient; see [Broadcasts](/docs/guides/email/broadcasts) |
| **Suppressions** | Addresses we do not send to, and why; see [Suppressions](/docs/guides/email/suppressions) |
| **Unsubscribe page** | Branding for the hosted page every marketing email links to; see [Unsubscribe links](/docs/guides/email/unsubscribe-links) |
| **SMTP** | Connection settings, per-key send defaults, and live connections; see [SMTP](/docs/guides/email/smtp) |
| **Inbox Insights** | Inbox placement and sender reputation across mailbox providers; see [Inbox Insights](/docs/guides/email/inbox-insights) |
| **Competitive insights** | Panel-derived sending volume, cadence, and engagement for watched brands; see [Competitive Insights](/docs/guides/email/competitive-insights) |
Recipients live outside the Email section, in **Contacts** in the sidebar: **All contacts** stores people with typed custom properties (see [Contacts](/docs/guides/email/contacts)), and **Audiences** groups them into the reusable lists a broadcast sends to (see [Audiences](/docs/guides/email/audiences)).
## Where each guide fits
**Sending.** [Sending email](/docs/guides/email/sending-email) is the one to read first: it owns the payload every other send path is a variation on. From there, [templates](/docs/guides/email/templates) store content you reuse, [attachments](/docs/guides/email/attachments) add files, [batch sending](/docs/guides/email/sending-bulk) submits up to 100 messages in one request, and [broadcasts](/docs/guides/email/broadcasts) send one email to a whole audience.
**Domains and authentication.** [Sending domains](/docs/guides/email/sending-domains) covers registering a domain and getting it verified. [DKIM, SPF, and DMARC](/docs/guides/email/dkim-spf-dmarc) explains what each record proves to a receiving mailbox provider, and [BIMI](/docs/guides/email/bimi) shows your logo beside your messages in email apps that support it.
**Reputation.** [SuAlso from
Structured data
AR-READ-08 · 101 of 150 on our boards pass · 2 points · effort: minutes, our estimate
Facts about your company and product, in a standard format (schema.org) in your homepage's code.
Our call: Worth doing.
Why it matters: An agent may have to work out basic facts about your company and product from free text.
How to do it: Add a <script type="application/ld+json"> block to your homepage's raw HTML, with "@context": "https://schema.org", "@type": "Organization" and your real name and URL.
What passes our check: We check your homepage's raw HTML has an application/ld+json block that parses as JSON and has @type or @context.
The real file, from Bird (ex-SparkPost), on our email API board
- bird.com/email-apihas an application/ld+json block
{"@context":"https:\u002F\u002Fschema.org","@graph":[{"@type":"Organization","@id":"https:\u002F\u002Fbird.com\u002F#organization","name":"Bird","legalName":"Bird B.V.","alternateName":["MessageBird","SparkPost"],"description":"Reach your customers, wherever they are. Email, SMS, WhatsApp, Apple Messages, and Voice.","url":"https:\u002F\u002Fbird.com","foundingDate":"2011","contactPoint":{"@type":"ContactPoint","contactType":"customer support","email":"support@bird.com","url":"https:\u002F\u002Fbird.com\u002Fhelp\u002Fsupport"},"address":{"@type":"PostalAddress","streetAddress":"Keizersgracht 268","postalCode":"1016 EV","addressLocality":"Amsterdam","addressCountry":"NL"},"logo":"https:\u002F\u002Fbird.com\u002Ffavicon-light.png","sameAs":["https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fbirdhq","https:\u002F\u002Fx.com\u002Fmessagebird","https:\u002F\u002Fwww.instagram.com\u002Fmessagebird","https:\u002F\u002Fgithub.com\u002Fmessagebird","https:\u002F\u002Fwww.youtube.com\u002F@birdHQ","https:\u002F\u002Fwww.ycombinator.com\u002Fcompanies\u002Fbird","https:\u002F\u002Fwww.crunchbase.com\u002Forganization\u002Fmessagebird","https:\u002F\u002Fnl.wikipedia.org\u002Fwiki\u002FBird_(bedrijf)","https:\u002F\u002Fwww.wikidata.org\u002Fwiki\u002FQ106845206","https:\u002F\u002Fwww.capterra.com\u002Fp\u002F160795\u002FBird\u002F","https:\u002F\u002Fwww.g2.com\u002Fproducts\u002Fmessagebird-bird"]},{"@type":"WebSite","@id":"https:\u002F\u002Fbird.com\u002F#website","name":"Bird","url":"https:\u002F\u002Fbird.com","publisher":{"@id":"https:\u002F\u002Fbird.com\u002F#organization"}}]}Also from
Machine-readable discovery file
AR-READ-06 · 55 of 150 on our boards pass · 2 points · effort: minutes, our estimate
A file at a standard address (/.well-known/...) that says how your API or sign-in works.
Our call: Depends on your product. Publish only what's true for you. An API catalog fits most APIs; OAuth or agent card files only fit if you run them.
Why it matters: An agent may have to guess how sign-in or your API works instead of reading it from a standard file.
How to do it: Serve one of these files as JSON at /.well-known/ on your site root. Publish only what's true for you: the OAuth or OpenID files only if you run that sign-in, agent-card.json only if you run an A2A agent, otherwise api-catalog, which just lists your APIs (RFC 9727).
What passes our check: We fetch five standard .well-known files and check at least one returns 200 with valid JSON: oauth-authorization-server (RFC 8414), oauth-protected-resource (RFC 9728), openid-configuration, api-catalog (RFC 9727) and agent-card.json (A2A). This list is ours: AgentReady v2.0 doesn't name one. Off the board, on a miss, we also read oauth-protected-resource on the mcp., api. and docs. hosts of your domain, where that metadata usually lives, and it counts only with its resource field.
The real file, from Transloadit, on our file storage service board
- transloadit.com/.well-known/oauth-authorization-servervalid JSON
- transloadit.com/.well-known/oauth-protected-resourcevalid JSON
{"authorization_endpoint":"https://transloadit.com/c/oauth/authorize","authorization_response_iss_parameter_supported":true,"client_id_metadata_document_supported":true,"code_challenge_methods_supported":["S256"],"grant_types_supported":["authorization_code","refresh_token","client_credentials"],"issuer":"https://api2.transloadit.com","registration_endpoint":"https://api2.transloadit.com/oauth/register","response_types_supported":["code"],"revocation_endpoint":"https://api2.transloadit.com/oauth/revoke","revocation_endpoint_auth_methods_supported":["none","client_secret_basic","client_secret_post","private_key_jwt"],"revocation_endpoint_auth_signing_alg_values_supported":["RS256","ES256"],"scopes_supported":["read","write","auth_keys:write","auth_keys:read","assemblies:write","assemblies:read","assembly_notifications:write","dam:read","dam:write","template_credentials:read","template_credentials:write","billing:read","queues:read","smart_cdn:sign","templates:read","templates:write","storage_grants:write"],"service_documentation":"https://transloadit.com/docs/api/authentication/","token_endpoint":"https://api2.transloadit.com/token","token_endpoint_auth_methods_supported":["none","client_secret_basic","client_secret_post","private_key_jwt"],"token_endpoint_auth_signing_alg_values_supported":["RS256","ES256"]}Also from
Can it do something with your product?
MCP server or CLI
AR-ACT-10 · 96 of 150 on our boards pass · 10 points · effort: days, our estimate
An MCP server or a command-line tool that an agent can use instead of raw API calls.
Our call: Depends on your product. Worth it if agents would work with your product from a terminal. Don't ship one just to pass this.
Why it matters: An agent working in a terminal may find no MCP server or CLI to use, and may have to script raw API calls instead.
How to do it: Either name your own MCP server in your docs (see AR-ACT-03), or show your CLI's install and one real command on your quickstart, like npm install -g your-cli. If you have neither, that's a product decision.
What passes our check: Passes when AR-ACT-03 passes (your docs surface names your own MCP server, not just a mention or a blog post about one; on the board, only an MCP server with a tool that acts on the product: send, manage or query, not only search docs, since AgentReady calls this "the interface an agent acts through"), or when your docs surface shows a CLI install: brew install, npm i -g, npm install -g, pipx install, uv tool install, go install, az extension add, or curl ... | sh (or | bash). A mention of MCP that isn't your own server, with no CLI install, isn't counted. For board companies, the CLI half counts only a command of the product's own CLI that we confirmed by hand, like az communication email send or twilio email:send, on the pages we read or on the docs page that shows it: an install alone could be any tool (an MCP setup guide installing pnpm, say). For a product inside a larger platform, the platform's MCP server or CLI counts when its docs show it covers the product. An MCP server earns both this check and AR-ACT-03, because AgentReady lists them as two items. If none of the pages we read is a quickstart or SDK page, a miss isn't counted: it can't fail you or withhold your score.
The real file, from Gumloop, on our AI agent platform board
- gumloop.com/llms.txtllms.txt: names its own MCP server (AR-ACT-03) (redirected to https://www.gumloop.com/llms.txt)
- Connect as an MCP client to https://mcp.gumloop.com/gumloop/mcp (Streamable HTTP, OAuth) to list agents, run sessions, manage skills and search Company Brain.Also from
OpenAPI spec
AR-ACT-02 · 51 of 150 on our boards pass · 7 points · effort: days, our estimate
A file that describes your API's endpoints in a standard format (OpenAPI), so code can call them.
Our call: Worth doing. If you have an API, this is what lets an agent stop guessing your endpoints.
Why it matters: An agent may have to guess your endpoints and parameters from prose instead of reading them from a spec.
How to do it: If you have a spec, link the file itself from your docs page or llms.txt: its .json or .yaml address, with openapi in it, not a repo or a page about it. Or serve it at /openapi.json. If you don't have one, generate it from your API code rather than writing it by hand. It needs an openapi key and at least one path.
What passes our check: We look for an OpenAPI or Swagger file the same way as before. A spec your docs page, a docs page or your llms.txt links gets full credit. One we found only at a standard address (/openapi.json) or a guessed host gets half: agents used an unlinked spec far less (Ora's field report).
The real file, from Mailtrap, on our email API board
- raw.githubusercontent.com/mailtrap/mailtrap-openapi/main/specs/email-sending-transactional.openapi.ymlfrom our board config, linked from https://docs.mailtrap.io/developers/openapi-specs; OpenAPI 3.1.0, 2 paths
Also from
npm and PyPI packages
AR-ACT-06 · 59 of 150 on our boards pass · 7 points · effort: days, our estimate
An install command for JavaScript (npm) and for Python (pip), shown in your docs.
Our call: Depends on your product. If you ship packages, show them. If you don't, the fix is a product decision, not a docs change.
Why it matters: An agent may not find a package to install in JavaScript or Python, and may write raw HTTP calls instead.
How to do it: Show both installs in code blocks on your quickstart or SDK page, with your real package names: npm install your-package and pip install your-package. If you only ship one language, the other half needs a package, not a docs change.
What passes our check: On your docs surface we look for an npm install (npm, yarn, pnpm or bun) and a pip install (pip, poetry or uv) of a named package. Both must appear, on any of the pages (AgentReady: npm and PyPI). Off the board, uv tool install and pipx install also count as a pip install. Off the board, if one is missing we also read the markdown copy each HTML page declares (a <link rel="alternate" type="text/markdown">, or its URL plus .md listed in your llms.txt), then up to 2 pages your llms.txt names for that language. AgentReady v2.0 asks for SDKs and a CLI here; this check tests the npm and PyPI half, and a CLI counts under AR-ACT-10. If none of the pages we read is a quickstart or SDK page, a miss isn't counted: it can't fail you or withhold your score.
The real file, from Transloadit, on our file storage service board
- transloadit.com/docs/sdks/uppydocs page: npm install "npm i @uppy/core"
- transloadit.com/docs/api/authentication.mdauth page: pip install "pip install pytransloadit"
npm i @uppy/core
pip install pytransloaditAlso from
Auth an agent can follow (proxy)
AR-ACT-01 · 81 of 150 on our boards pass · 4 points · effort: hours, our estimate
Your docs show how to authenticate with your API.
Our call: Worth doing.
Why it matters: An agent may not work out how to authenticate, so its first API call may fail.
How to do it: On your quickstart or auth page, show a real request with the header and the words "API key" close together, like Authorization: Bearer YOUR_API_KEY. If you run OAuth, publishing its metadata at /.well-known/oauth-authorization-server also passes.
What passes our check: A stand-in: AgentReady asks for self-serve key generation with documented scopes, or OAuth metadata, and key sign-up can't be tested in code. It passes if OAuth metadata parses as JSON with the field its RFC requires (issuer for RFC 8414, resource for RFC 9728), or if your docs say "API key" or "API token" (also inside a placeholder like YOUR_API_KEY) within 200 characters of a documented auth header: an X-...-Key or X-...-Token header, a header named ...-Key or ...-Token, Authorization with Bearer, or "Bearer API key". The word "token" on its own doesn't count. For board companies we also read the authentication page their docs link. Off the board, OAuth metadata with its resource field on your mcp., api. or docs. host also counts. A board company whose API signs each request (like AWS Signature Version 4) or takes the key in the request body isn't counted: this stand-in can't judge that kind of auth either way. If none of the pages we read is a quickstart or SDK page, a miss isn't counted: it can't fail you or withhold your score.
The real file, from Bird (ex-SparkPost), on our email API board
- bird.com/.well-known/oauth-authorization-serverOAuth metadata parses, with issuer
{"issuer":"https://platform.bird.com","authorization_endpoint":"https://platform.bird.com/v1/oauth/authorize","token_endpoint":"https://platform.bird.com/v1/oauth/token","device_authorization_endpoint":"https://platform.bird.com/v1/oauth/device","revocation_endpoint":"https://platform.bird.com/v1/oauth/revoke","registration_endpoint":"https://platform.bird.com/v1/oauth/register","grant_types_supported":["authorization_code","urn:ietf:params:oauth:grant-type:device_code","refresh_token"],"response_types_supported":["code"],"scopes_supported":["access_restrictions:read","access_restrictions:write","amb:read","amb:write","amb_management:read","amb_management:write","analytics:read","analytics:write","api_keys:read","api_keys:write","assets:read","assets:write","audit:read","audit:write","competitive:read","competitive:write","compliance:read","compliance:write","domains:read","domains:write","email_management:read","email_management:write","email_marketing:read","email_marketing:write","emails:read","emails:write","esim:read","esim:write","esim_credentials:read","esim_credentials:write","inbox_insights:read","inbox_insights:write","ip_pools:read","ip_pools:write","lookup:read","lookup:write","mailbox:read","mailbox:write","mailbox_management:read","mailbox_management:write","members:read","members:write","numbers:read","numbers:write","preferences:read","preferences:write","rcs:read","rcs:write","rcs_management:read","rcs_management:write","realtime:read","realtime:write","request_logs:read","request_logs:write","service_accounts:read","service_accounts:write","sms:read","sms:write","sms_management:read","sms_management:write","trust:read","trust:write","verify:read","verify:write","verify_management:read","verify_management:write","voice:read","voice:write","voice_management:read","voice_management:write","webhooks:read","webhooks:write","whatsapp:read","whatsapp:write","whatsapp_management:read","whatsapp_management:write","workspace:read","workspace:write","org:access_restrictions:read","org:access_restrictions:write","org:audit:read","org:audit:write","org:billing:read","org:billing:write","org:ip_pools:read","org:ip_pools:write","org:members:read","org:members:write","org:settings:read","org:settings:write","org:trust:read","org:trust:write","org:workspaces:read","org:workspaces:write"],"code_challenge_methods_supported":["S256"],"token_endpoint_auth_methods_supported":["none","client_secret_basic","client_secret_post"],"revocation_endpoint_auth_methods_supported":["none","client_secret_basic","client_secret_post"],"authorization_response_iss_parameter_supported":true}Also from
Every operation has an operationId
LG-ACT-01 · 51 of 150 on our boards pass · 4 points · effort: minutes, our estimate
Each call in your API spec has a name (an operationId) that tools and agents use for it.
Our call: Worth doing. Minutes of work in your spec, and tools that turn it into an agent's tools get real names.
Why it matters: Tools that turn a spec into an agent's tools or an SDK name each call by its operationId; without one, an agent gets a made-up name or none.
How to do it: Give every operation in your OpenAPI spec an operationId: a short, unique name like sendEmail or listDomains.
What passes our check: In the OpenAPI spec AR-ACT-02 finds, we count the operations with a non-empty operationId. The credit is the share that have one. With no spec, it isn't counted: AR-ACT-02 already counts that.
The real file, from Mailtrap, on our email API board
- raw.githubusercontent.com/mailtrap/mailtrap-openapi/main/specs/email-sending-transactional.openapi.yml2 of 2 operations have an operationId
Also from
MCP server
AR-ACT-03 · 89 of 150 on our boards pass · 4 points · effort: days, our estimate
A server AI agents can connect to, to use your product (MCP, the Model Context Protocol).
Our call: Depends on your product. Worth it if agents would act through your product. Don't ship an empty server to pass this.
Why it matters: An agent may not find out it can use your product through an MCP server.
How to do it: If you run an MCP server, name it as yours on a page your docs or llms.txt links: "our MCP server", your product's name before "MCP server", or its mcp. address. If you don't run one, that's a product decision: don't write the page first.
What passes our check: On your docs surface we look for your own MCP server and quote the line: your name next to "MCP" ("Acme MCP server"), "our" or "official" MCP server, or an mcp.<your domain> address. Any other mention of "MCP server" or "Model Context Protocol", like a directory or an explainer, isn't counted: it can't fail you and it earns no points, because we can't tell the server is yours. A mention in a link to a blog post, or on an llms.txt line that links to one, doesn't count at all: a post about building a server isn't one you ship. For board companies we read the MCP page their docs link and list the tools it documents: a server that only searches your docs counts here, as AgentReady describes an MCP server as a "standard tool protocol for docs search and actions". We don't probe /mcp or call any server. Off the board, OAuth metadata with its resource field on your mcp. host also counts: it's the server's own file. If none of the pages we read is a quickstart or SDK page, a miss isn't counted: it can't fail you or withhold your score.
The real file, from Neon, on our database board
- neon.com/llms.txtllms.txt: names its own MCP server: "- [Connect an agent to the Neon MCP server at https://mcp.neon.tech/mcp](https://neon.com/docs/"
- [Connect an agent to the Neon MCP server at https://mcp.neon.tech/mcp](https://neon.com/docs/ai/neon-mcp-server.md)Also from
Errors have a schema
LG-ACT-02 · 19 of 150 on our boards pass · 4 points · effort: hours, our estimate
Your API spec says what an error looks like: a code an agent can act on, and a message.
Our call: Worth doing. If agents call your API, a stable error code tells them what went wrong without reading prose.
Why it matters: Without a documented error shape, an agent may have to guess from the message why a call failed, and retry or give up wrongly.
How to do it: In your OpenAPI spec, give each operation a 4xx and a default response with an error schema: a stable code or type and a message, ideally as application/problem+json (RFC 9457), defined once under components and referenced with $ref.
What passes our check: In the OpenAPI spec AR-ACT-02 finds, we count the operations that declare a 4xx, 5xx or default response with a schema, directly or through a $ref. The credit is the share that do. We note when they use application/problem+json (RFC 9457), the standard shape. With no spec, it isn't counted. The IETF's draft agent-friendly API profile, is-agentic and Alpic check it.
The real file, from Bird (ex-SparkPost), on our email API board
- bird.com/openapi.json529 of 529 operations declare an error response with a schema
Also from
Tools for browser agents
AR-ACT-07 · 1 of 150 on our boards passes · 2 points · effort: days, our estimate
Tools your web page offers to AI agents that work in a browser (a proposed standard).
Our call: Don't do it for the score. It's still a proposed standard, and almost nobody on our boards passes our check, though Bird, Postmark and CrewAI load it from a script our check doesn't read. Build it only if agents need to operate forms on your site.
Why it matters: It costs a point, but it's only worth building if agents need to operate forms on your site. If they do, a browser agent may find no tools to call and have to click through instead.
How to do it: Only if agents need to operate forms on your site: register those actions as tools through the browser's modelContext API, in an inline script on your homepage. Otherwise skip this one.
What passes our check: We check your homepage's raw HTML, inline scripts included, contains modelContext (AgentReady names document.modelContext). External scripts aren't fetched.
The real file, from Render, on our hosting platform board
- render.commodelContext in the raw HTML
const modelContext = navigator.modelContext;An agent skill is published
LG-ACT-03 · 60 of 150 on our boards pass · 2 points · effort: hours, our estimate
Step-by-step instructions (a skill) that agents can follow for your product.
Our call: Depends on your product. Worth it if agents do multi-step tasks with your product. A skill should be a real workflow, not a copy of your docs.
Why it matters: Without step-by-step skills, an agent may work out each task from reference pages, more slowly and with more mistakes.
How to do it: Write a skill for your product's main task: a SKILL.md that starts with name and description front matter, linked from your docs or llms.txt. Or list it in /.well-known/agent-skills/index.json with its url, and make the file return 200.
What passes our check: Any of three passes: /.well-known/agent-skills/index.json on your site or your docs (or one a Link header names) lists a skill whose file answers; your docs or llms.txt link a SKILL.md that answers with a name and a description; or your docs show a skills install command, on a page we read or on up to 3 pages your docs or llms.txt link about skills or your CLI. An install is npx skills add, claude plugin install, a git clone into a skills folder, or your own command line running plugin install or skills add right after the word skill. An index under a folder, like /developer/, may list its files from that folder. Cloudflare's isitagentready, agenticplug and Alpic check it.
The real file, from Gumloop, on our AI agent platform board
- docs.gumloop.com/cli/overview.mda page your docs link about skills or your CLI: a skills install, "gumloop plugin install gumloop"
gumloop plugin install gumloopAlso from
Sign-in an MCP client can use
LG-ACT-04 · 33 of 150 on our boards pass · 2 points · effort: hours, our estimate
Your OAuth sign-in lets an AI app register itself and ask for only the access it needs.
Our call: Depends on your product. Only if you run OAuth, for an MCP server or your API. With API keys alone, it doesn't apply and isn't counted.
Why it matters: An AI app connecting to your MCP server or API may not be able to register itself or ask for a narrow token, so it may stop or ask the user to set it up by hand.
How to do it: In your OAuth authorization server metadata (/.well-known/oauth-authorization-server), list S256 in code_challenge_methods_supported, your scopes in scopes_supported, and either client_id_metadata_document_supported: true or a registration_endpoint.
What passes our check: We look for OAuth authorization server metadata (RFC 8414): at /.well-known/oauth-authorization-server on your site, through the authorization_servers your protected-resource metadata (RFC 9728) names, and on your mcp. host. It passes when it lists S256 in code_challenge_methods_supported, has scopes_supported, and has a registration_endpoint or client_id_metadata_document_supported, as the MCP authorization spec asks. With no OAuth metadata, it isn't counted.
The real file, from Gumloop, on our AI agent platform board
- api.gumloop.com/.well-known/oauth-authorization-serverS256, scopes and a way for a client to register
{"authorization_endpoint":"https://api.gumloop.com/oauth/authorize","code_challenge_methods_supported":["S256"],"grant_types_supported":["authorization_code","refresh_token"],"issuer":"https://api.gumloop.com","registration_endpoint":"https://api.gumloop.com/oauth/register","response_types_supported":["code"],"revocation_endpoint":"https://api.gumloop.com/oauth/revoke","scopes_supported":["gumstack","userinfo","gumloop_api","gumloop_api.mcp","gumloop_api.inference","gumloop_api.agents","gumloop_api.sessions","gumloop_api.brain","gumloop_api.skills","gumloop_api.artifacts","gumloop_api.teams","gumloop_api.organizations","gumloop_api.evaluations","gumloop_api.browser_profiles","gumloop_api.wiki","gumloop_university","gumloop_docs"],"token_endpoint":"https://api.gumloop.com/oauth/token","token_endpoint_auth_methods_supported":["none"]}Also from
Email APIs
Back to the list ↑Only for email APIs: what a coding agent needs to send its first email.
Install shown for four languages
EM-01 · 6 of 15 email APIs pass · 4 points · effort: days, our estimate
Our call: Depends on your product. Cover the languages your users write. If you don't ship one of the four, this one may not be for you.
Why it matters: An agent working in one of these languages may not find how to install your library in it.
How to do it: Show an install for each language on your SDK page, with your real packages: npm install, pip install, go get, and a Maven <artifactId> or a Gradle implementation line.
What passes our check: On your docs surface we look for an install in each of four languages: TypeScript/JavaScript (npm, yarn, pnpm or bun), Python (pip, poetry or uv), Go (go get) and Java (a Maven <artifactId> or a Gradle implementation line). All four must appear. This shows how to install, not that a package is official. If none of the pages we read is a quickstart or SDK page, a miss isn't counted: it can't fail you or withhold your score. Ours, not AgentReady's.
The real file, from Mailtrap, on our email API board
- docs.mailtrap.io/developersdocs page: TypeScript/JavaScript "npm install mailtrap"
- docs.mailtrap.io/developersdocs page: Python "pip install mailtrap"
- docs.mailtrap.io/developersdocs page: Go "go get github.com/mailtrap/mailtrap-go"
- docs.mailtrap.io/developersdocs page: Java "< artifactId > mailtrap-java </ artifactId >"
TypeScript/JavaScript: npm install mailtrap
Python: pip install mailtrap
Go: go get github.com/mailtrap/mailtrap-go
Java: < artifactId > mailtrap-java </ artifactId >Also from
Send operation in the spec
EM-02 · 11 of 15 email APIs pass · 4 points · effort: days, our estimate
Our call: Worth doing.
Why it matters: An agent may not find the endpoint that sends an email in your spec, and may guess it.
How to do it: Add your send endpoint to your OpenAPI spec, as a POST on a path with mail, email, message or send in it.
What passes our check: In the OpenAPI spec AR-ACT-02 found, we look for a POST operation on a path containing mail, email, message or send. No spec counts as a fail. Ours, not AgentReady's.
The real file, from Mailtrap, on our email API board
- raw.githubusercontent.com/mailtrap/mailtrap-openapi/main/specs/email-sending-transactional.openapi.ymlthe spec has POST /api/send
Also from
Free tier in emails
EM-03 · 13 of 15 email APIs pass · 4 points · effort: minutes, our estimate
Our call: Depends on your product. Only if you have a free tier. If you don't, this check isn't telling you anything.
Why it matters: An agent may not find how many emails your free tier allows, so it may not be able to say whether that's enough.
How to do it: State the free allowance on your pricing page as a number with a period, near the word "free", like "Free: 3,000 emails/month".
What passes our check: On the pricing page AR-READ-11 reads, we look for "free" within 300 characters of a number followed by emails, messages or sends and a period (a month, a day, or 30 days), like "3,000 emails/month" or "4,000 sends in any rolling 30-day window", in the raw text (no JavaScript run). A one-time allowance with no period doesn't count. Ours, not AgentReady's.
The real file, from Mailtrap, on our email API board
- mailtrap.io/pricingfrom our board config, linked from https://mailtrap.io/; free tier: "150 emails/day"
| 750K | 1.5M | 2.5M | 2.5M+ | Free To try out Mailtrap $0 $0 /month 4,000 emails Start for Free Start for Free 1 user 3 days of email logs 1 domain 150 emails/day Basic For startups and small businesses $15 $15 /month 10,000 emails $20 $20 /month 50,000 emails $30 $30 /month 100,000 emails Get Started Get StartAlso from
Starter kit: every file at a glance
For each check, the best on each board and the file to start from. A check's name jumps to its practice above.
AI agent platforms, from our 9 Nov 2026 scan
· 26 files
Email APIs, from our 9 Nov 2026 scan
· 29 files
Payments, from our 9 Nov 2026 scan
· 24 files
Hosting and deploy, from our 9 Nov 2026 scan
· 27 files
Observability, from our 9 Nov 2026 scan
· 26 files
Databases and caching, from our 9 Nov 2026 scan
· 26 files
Auth, from our 9 Nov 2026 scan
· 25 files
File storage, from our 9 Nov 2026 scan
· 26 files
Background jobs, from our 9 Nov 2026 scan
· 23 files
Feature flags, from our 9 Nov 2026 scan
· 26 files
Real-time, from our 9 Nov 2026 scan
· 25 files
Follow the Drop
Each Drop: what moved on the boards and one real file worth copying. Get it in a feed reader app, or watch your site and rivals from the home page.
Paste the link into the app (it's an RSS feed), and each new Drop shows up there.