Skip to main content
Hero image

I Launched the "Not Available" Message First

Open a terminal and run curl https://dominikgronkiewicz.com/api/yt-pulling. You get a 404. That is deliberate, and it has been deliberate since before the service behind that URL existed.

I am building a paid API that returns YouTube transcripts and metadata for AI agents. The product is not finished. The endpoint that describes it went live first, because an API that does not exist yet still gets probed, and a bare HTML 404 tells a machine nothing except to give up.

This post covers the three decisions behind that: which status code an unbuilt paid service should answer with, what belongs in the body when the answer is a refusal, and the two bugs my own 404 shipped with. Both bugs were in the part only a machine reads. Neither was caught by a test.


I built the endpoint before I built the product

What shipped this week is a landing page selling a YouTube transcript and metadata API, an email waitlist, and a status endpoint. The endpoint answers 404 today. When the service opens it answers 200 with the full index of paid endpoints, their parameters and their prices.

The service behind it does not exist yet. That is the point.

Publishing the endpoint first cost me one file. In exchange, any agent that probes the URL gets a machine-readable answer explaining what the service will be and how to be told when it opens. A human reading a launch date on a landing page has to trust me. An agent polling a status endpoint does not have to trust anything, it can check.

Flipping it live is an environment variable, YT_PULLING_STATUS, read at request time. No redeploy, no code change, and no window where the page says one thing and the API says another.

The product changed before I wrote a line of code

The original plan was a paid API for downloading YouTube video. Reading the legal position killed that version before any of it got built.

In early 2026 a federal magistrate in Cordova v. Huneault ruled that YouTube's rolling cipher counts as an access control under the DMCA, even though the videos it protects are free for anyone to watch. The Yout v. RIAA case went the same direction, with the court finding the stream-ripper had failed to show it was not circumventing YouTube's protections. Section 1201(a)(2) reaches past the act of circumventing an access control and out to trafficking in the tools that do it, and selling API access is trafficking under the plainest reading of that word.

That mattered more for me than it would for an anonymous seller on an API marketplace, because this would run on the same domain as my consulting work and my paid audit service. A registrar complaint does not politely stay inside one route.

So the scope moved to transcripts and metadata, with no media bytes anywhere in the system. The demand was in transcripts anyway. The buying trigger is the quota wall: a single search.list call against the official YouTube Data API costs 100 units out of a daily budget of 10,000, so 100 searches ends your day and every call after that returns 403 quotaExceeded until midnight Pacific. There is no credit card that lifts it. Google reviews quota extension requests by hand, and an agent workload is exactly the profile those reviews turn down.

What a useful 404 actually contains

Here is the body my endpoint returns today, trimmed for length:

{
  "status": "not_available",
  "service": "yt-pulling",
  "message": "404 not available",
  "waitlist_url": "https://dominikgronkiewicz.com/youtube-transcript-api/",
  "notify": {
    "method": "POST",
    "path": "/api/yt-pulling-waitlist",
    "body": { "email": "string" }
  },
  "checked_at": "2026-08-19T04:05:19.057Z"
}

Four things in there earn their place:

  • Content-Type: application/json in both states. An agent parsing an HTML error page is a wasted call and a wasted impression.
  • waitlist_url for humans, notify for machines. The same refusal serves both readers without either having to guess.
  • Cache-Control: no-store. When the service opens, the change is visible on the next request instead of whenever a cache decides to expire.
  • HEAD and OPTIONS answered, with permissive CORS. Agents probe before they commit, and a dead OPTIONS reads as a dead host.

404 or 402, and why the difference is not pedantry

A 404 says the resource does not exist. A 402 Payment Required says it exists and costs money. Those are different sentences, and the distinction decides whether a paying customer bounces.

While the service is unbuilt, 404 is honest. Once the service is live and an unauthenticated caller shows up, 404 becomes a lie that costs money, because it tells an agent to abandon something it was ready to buy. That case gets 402.

This is the same argument I made in Your API Isn't Ready for Agent Customers, applied to my own surface this time. 402 sat unused in the HTTP spec for two decades and is now the status the entire agent-payment stack is organised around. Answering the wrong code closes a door you are paying a hosting bill to keep open. If you want the broader business case, I covered where the money actually is in Agent Commerce Is Here.

My own 404 shipped with two bugs

Both of these were live. Both were in the machine-readable half of the API.

The 404 advertised a URL that did not exist. My spec said the notify.path was /api/yt-pulling/waitlist. The function shipped at /api/yt-pulling-waitlist, because Gatsby maps src/api/yt-pulling-waitlist.js to a flat route and a nested path needs a nested file. An agent following the instructions my own endpoint handed it would have posted into nothing.

I found it by curling the path the endpoint advertised, instead of the path I remembered writing. That is not what you do when you are the person who wrote both.

The 405 responses had no Allow header. RFC 9110 requires one on every 405 Method Not Allowed. Mine returned the permitted methods inside the JSON body and left the header off entirely. A well-behaved client that reads headers before bodies learned nothing about which verb to use.

That one surfaced because I opened the waitlist URL in a browser, which issues a GET, saw a 405, and stopped to ask whether that response was correct rather than assuming it was. Both endpoints now send Allow: POST and Allow: GET, HEAD, OPTIONS respectively.

The pattern behind both is worth stating plainly. No human clicks through the machine-readable half of an API, so nothing about it feels broken. The page rendered, the form submitted, the build passed, the tests were green. The parts that were wrong were the parts only an agent would ever read.

The small constraints nobody warns you about

Two more, cheap to fix and invisible until they bite.

Gatsby's Link cannot take a bare hash. The hero button pointing at #waitlist had to go through the plain anchor branch instead of the router. Thirty seconds of work, and the failure mode is a button that silently does nothing.

The prices in the live index are null on purpose. The landing page says the service is cheap per call without naming a figure, because I have not set pricing yet. An endpoint that invented a number so it would look finished would contradict the page it points at. Null is the accurate answer until it is not.

What I will be watching

My site already runs an endpoint that fingerprints AI crawler visits in production, so I can count how many agents reach a status endpoint that was never advertised to a single human.

Three things I want to know over the next few months: whether agents poll it at all, whether the notify route gets used by something that never rendered the page, and whether a machine-readable refusal published early converts better than a launch announcement published late. I have no numbers yet. The instrumentation is running, the endpoint is live, and I will publish what it says either way.

The short version

The endpoint is live. It answers 404 with a JSON body that tells you how to be notified, and it will answer 200 with a full endpoint index without a redeploy. You can check both claims yourself in about five seconds.

Building the refusal before the product cost almost nothing and made the unfinished thing addressable. The two bugs it shipped with are the more useful lesson: the machine-readable half of an API has no user to complain about it, so it fails quietly and stays failed.

If you are building APIs or MCP servers for agent customers and want to work through these decisions with senior devs shipping the same kind of infrastructure, that is what The Agentic Architect Lab is for.

And if you want to watch the status code flip in real time, the transcript API waitlist is at dominikgronkiewicz.com/youtube-transcript-api. Poll the endpoint instead of trusting my launch date.

Sources

Building with AI beyond this article?

I run The Agentic Architect Lab, live builds, agent workflows, and a playbook for technical founders shipping solo. No toy demos.

Join the Lab