I made my SaaS installable by AI agents. Here's what was broken. A developer made their SaaS product, Waitlister, installable and usable by AI agents, documenting the broken assumptions and fixes along the way. They found that AI agents often hit 404s, guessed wrong package names, and were blocked by vendor AI-bot protections, leading to silent failures. The developer published multiple package names, fixed status codes, and added an API for landing page management to enable end-to-end agent runs. Two weeks ago I watched an agent run a full product launch on Waitlister, my waitlist tool. It created the waitlist, generated and published a landing page, signed up a test address, checked the signup was real by fetching the public page unauthenticated, then unpublished and deleted everything it had made. Nobody touched the dashboard. The interesting part isn't that run. It's what I found while getting there, because almost none of it was visible from a browser. My users are pre-launch founders, which is exactly the group now building landing pages by prompting Claude, Cursor, or v0 instead of opening a site builder. "Add a waitlist to my site" is a normal thing to ask an agent to do, and increasingly nobody types my product name at all. The uncomfortable part is when an agent hits a 404 or installs a package that doesn't exist, it doesn't debug. It picks a different tool in the next sentence and never tells the user it switched. You lose without ever seeing a bounce. skill.md route. /openapi.json , all five endpoints, auth, rate limits, error shapes. Endpoint changes update the spec and the SDK types in the same PR or they don't merge. llms.txt and llms-full.txt Honest list. The file I wrote for agents was the one file agents couldn't read. My llms.txt is proxied from a vendor, the proxy forwards the caller's user-agent, and the vendor had AI-bot blocking switched on by default. Every AI crawler got a 403 on the document whose only purpose is being read by AI crawlers. I found it by requesting my own files with eight bot user-agents and diffing the status codes. One vendor toggle can put it back, silently, which is why the check now runs on a schedule. llms-full.txt is too big to be read at answer time. It's 961 KB and grows with every docs page. It serves from my side in about 1.3 seconds, and Claude's answer-time fetcher still timed out on it at 60 seconds. The small index is the one that actually gets read. I haven't fixed this yet; Agents guess your package name. waitlister-js , waitlister-sdk , waitlister-node , @waitlister/sdk . Instead of arguing with that, I published all four as real packages that re-export the SDK and carry a deprecation notice pointing at the canonical name. A wrong guess installs and self-corrects. My email validator rejected valid addresses. Agents test with plus-tags, because that's how you make a disposable address on an account you already own. My validator refused some of them. Human users with Gmail aliases had been hitting the same wall for as long as the rule existed. My 404s weren't 404s. Unknown doc slugs returned a soft page with a 200. An agent reading status codes concludes the page exists and that it guessed the URL right, then builds on it. Real 404s, plus a 301 from the old getting-started URL. The single page that would have saved five fetches was labeled for the wrong reader. In the first live test the agent's own friction report said the docs were split across pages with no single page giving the complete picture, so it fetched five. skill.md is that page, and /docs/api linked to it in a callout at the very top. The callout was headed "Integrating with an AI agent," which is a label about who it's for , and the agent was reading through a fetch-summarizer where that reads as a sidebar. Reframed as "Fastest path: complete single-page integration guide," it started landing. The link was never missing. It was filed under the wrong thing. Every run used to die at the same sentence. The agent could create a waitlist through the API and then had to say "now open the dashboard to build your landing page." That one gap ended the automated path every time, no matter how good the rest of the surface was. Creating, updating, and publishing a landing page over the API is what made an end-to-end run possible at all. Still open: there's no cheap endpoint for an agent to check whether its key is valid before spending a call that changes something. And /openapi.yaml returns 404 because only .json is served, while some agents guess .yaml first. Test with the real fetchers, not with curl. Every failure above lived in the gap between what my server sends and what an agent's toolchain actually receives: a user-agent rewritten in transit, a file that serves fine but times out at answer time, a status code that lies, a link that survives the fetch but not the summary. Curl told me everything was fine. It was, for curl. Where I've got to: four consecutive live runs with zero wrong guesses, a complete correct integration plan from public surfaces alone in about 90 seconds, and a waitlist created from an empty account in three minutes and eighteen seconds. All of it is live. If you want to see what an agent actually receives, point yours at waitlister.me/skill.md https://waitlister.me/skill.md and ask it to set up a waitlist. The same path written for a person is at waitlister.me/growth-hub/guides/set-up-waitlist-with-ai-agent https://waitlister.me/growth-hub/guides/set-up-waitlist-with-ai-agent .