Build and share an API
Put a small service online that other people call from their own code — they send a request to your URL and get data back, in their script, their notebook, their app. You write a tiny FastAPI app (Python), deploy it, and it ships with an interactive docs page so callers see exactly how to use it. Lock it with an API key so only people you've handed a key to can call it.
Time: ~2 min to your agent to write the app; then your real cost is the deploy (a host account + card, once). You'll need: Claude Code, a deploy host account, and a clear idea of the one thing the API should return. Last verified: 2026-06-07 · code and routes checked against fastapi.tiangolo.com, deploy against Fly's and Vercel's own docs.
[confirmed]New to all this? Do Set up Claude Code first (~10 min once), then come back. Want people to call a tool from inside their agent, not their code? Build an MCP server instead. Just showing a finished thing people click? Deploy a website.
Before you begin
- Claude Code running in an empty folder — ~10 min once. It writes the app, installs FastAPI, and runs it locally so you can see the docs page before you ship.
- One clear thing the API returns. Name the single job: "look up a country's risk score", "score this text for toxicity", "return today's forecast as JSON". One app can hold several routes, but start with one.
[confirmed] - A deploy host account. The default here is Fly.io — it runs a real server and sleeps to ~$0 when idle. The un-delegable bit is the account + a card on file (anti-abuse, not a charge).
[confirmed] - Whatever the job needs — often an API key or database URL for the thing you're wrapping. Keep it out of the code (see Secrets).
New to handing setup to an agent? Read How to ask your agent — one screen, then come back.
What "an API" buys you here
A website hands a person a page to look at. An API hands a program an answer it can use — your recipient writes requests.get("https://your-app.../score?text=...") in their own code and gets back JSON. That's the whole point: they automate against you, no copy-paste, no UI. [confirmed]
FastAPI is the standout for this. It turns a normal Python function into a route from its type hints, and — for free, no extra work — generates an interactive docs page at /docs (Swagger UI) plus a machine-readable spec (OpenAPI) every caller's tools can read. So you don't write a manual: the docs are the code. [confirmed]
The default: ask your agent to write it
With Claude Code running in an empty folder, say:
Write a small FastAPI app in Python. Give it one GET route, /score, that
takes a "text" query parameter and returns JSON {"text": ..., "score": ...}.
Protect every route except the docs with an API key sent in an X-API-Key
header, using fastapi.security.APIKeyHeader — read the valid key from an
environment variable, never hard-code it, and return 401 if the key is
missing or wrong. Add a requirements.txt. Then run it locally and open
http://localhost:8000/docs so I can try it.
Swap in your own route — its path, what it takes in, what it returns. Your agent installs FastAPI, writes main.py, wires the key check in as a dependency, and starts the server (fastapi dev or uvicorn). Open http://localhost:8000/docs and you'll see a live page listing your route with a try-it-out button and an Authorize box for the key. That page proves it works before you ship. [confirmed]
The APIKeyHeader scheme shows up in /docs as that Authorize box automatically — callers paste their key there and try real requests in the browser. [confirmed]
Deploy it
A FastAPI app is a running server, so deploy it the way you'd deploy any backend — Deploy to Fly.io is the full walkthrough (account, card, fly launch, sleep-to-zero, secrets). The short version, once Fly's set up, is one sentence to your agent:
Deploy this FastAPI app to Fly. Set the API key as a Fly secret named
API_KEY, not in the code. Pick the lhr region. Give me the live URL at the end.
You get back a https://your-app.fly.dev URL. Your callable API lives at that URL; the docs at https://your-app.fly.dev/docs. [confirmed]
Keep the key out of the code. It rides as a host secret (fly secrets set API_KEY=...), encrypted, never in your files — the same Fly secrets pattern. [confirmed]
Brief alternative — Vercel. If you'd rather connect a GitHub repo and never touch a server, Vercel deploys a FastAPI app zero-config: it finds a FastAPI instance named
appatmain.py(orapp/,api/,src/), reads yourrequirements.txt, and runs it as one serverless function.[confirmed]Tell your agent "deploy this FastAPI app to Vercel." Catch: it's serverless, so a cold first request after idle is a bit slower, and the whole app must fit Vercel's 500 MB function bundle.[confirmed](Vercel FastAPI docs)
How a recipient calls it
Hand them two things: the URL and their key. That's the whole share. From their own code:
import requests
r = requests.get(
"https://your-app.fly.dev/score",
params={"text": "some input"},
headers={"X-API-Key": "the-key-you-gave-them"},
)
print(r.json())
The same call works from any language, curl, or a notebook — it's a plain HTTPS request with a header. To explore first, they open https://your-app.fly.dev/docs, click Authorize, paste the key, and try every route in the browser. No install, no account on your service — just the URL and the key. [confirmed]
Want named logins instead of one shared key — per-person sign-in, a members area? Put a login wall in front and skip the key. [confirmed]
You're done when
Your deployed /docs page loads, you click Authorize, paste the key, and a try-it-out request comes back 200 with your JSON — and the same request without the key comes back 401. If that round-trip works for you at the live URL, it works for anyone you hand the URL and key to. [confirmed]
If it doesn't work
- Caller's browser app gets a CORS error ("blocked by CORS policy" / "No 'Access-Control-Allow-Origin' header") → the recipient is calling from JavaScript in a web page, and your API hasn't allowed their origin. Server-to-server calls (
requests,curl) never hit this — it's browser-only. Tell your agent "add FastAPI's CORSMiddleware and allow these origins: …" with their site's URL (or["*"]to allow any, fine for a public read-only API).[confirmed] - Caller gets 401 with a valid-looking key → the header name or the key doesn't match. The request header must be exactly what
APIKeyHeader(name=...)expects (e.g.X-API-Key, case-insensitive but spelled right), and the key must equal the one in yourAPI_KEYhost secret. Re-check the secret is set on the host (fly secrets list), not only in your local.env.[confirmed] - First request after a quiet spell is slow (~1–2 s) → that's a cold start: a sleep-to-zero Fly app (or any Vercel function) wakes on the first hit. Normal, and the price of ~$0 idle cost. To kill it, keep one machine always on (
min_machines_running = 1) — but then it's no longer free when idle.[confirmed] - "Where are the docs?" → the interactive page is at
/docs(Swagger UI) and an alternative read-only view at/redoc; the raw machine spec is at/openapi.json. All three are generated for you — you don't write them.[confirmed] /docsloads but every real call 401s, even yours → you protected the docs route too, or the Authorize box is empty. The docs UI itself shouldn't need the key (only the data routes should); paste your key into Authorize before hitting try-it-out.[confirmed]- Deploy fails / app won't start → that's a deploy problem, not a FastAPI one — see the Deploy to Fly FAQ (port mismatch, missing dependency, card needed). Paste the full error to your agent.
[confirmed]
Prefer to do it by hand?
No agent — just you and the official tutorial. The short version:
- Install it. In an empty folder:
uv add "fastapi[standard]"(orpip install "fastapi[standard]").[confirmed] - Write
main.py— one route, plus the key check as a dependency:import os from fastapi import FastAPI, Depends, HTTPException, Security from fastapi.security import APIKeyHeader app = FastAPI() api_key_header = APIKeyHeader(name="X-API-Key") def check_key(key: str = Security(api_key_header)): if key != os.environ["API_KEY"]: raise HTTPException(status_code=401, detail="Bad or missing API key") @app.get("/score") def score(text: str, _=Depends(check_key)): return {"text": text, "score": len(text)} # your logic here - Run it.
API_KEY=test fastapi dev main.py, then openhttp://localhost:8000/docs— the route, the Authorize box, and try-it-out are all there.[confirmed] - Deploy it the same as any server — Fly (or Vercel), with
API_KEYas a host secret, never in the file.[confirmed]
Watch / read
YouTube blocked transcript pulls from this machine on 2026-06-07, so these aren't verified line-by-line — judged on title, length, and channel; lean on the written tutorial below if a video drifts.
- Build a REST API in 15 Minutes — pixegami, 15:16. Writes a small FastAPI app from scratch and shows the auto-generated
/docspage. Why this one: the clearest short build of exactly the app on this page, docs page included. - FastAPI Deployed on Fly — Bytes Of Py, 1:31. The deploy step alone, very short. Why this one: shows the
fly launch→ live URL arc in 90 seconds. (unofficial — community channel, seen 2026-06-07) - API Authentication EXPLAINED: OAuth vs JWT vs API Keys — SoftsWeb, 9:42. The concepts behind protecting an API. Why this one: explains when an API key is the right lock vs a full login, the choice this page makes for you. (unofficial — community channel, seen 2026-06-07)
Best written walkthrough: FastAPI's own First Steps — the minimal app, running it, and the /docs page — then Security – First Steps for the key check. The authoritative source the code here was checked against. [confirmed]
Sources
- FastAPI — First Steps — minimal
@app.getapp,fastapi dev, the auto/docs(Swagger UI),/redoc,/openapi.json - FastAPI — features (OpenAPI / interactive docs) — auto-generated OpenAPI schema + two doc UIs
- FastAPI — Security reference (
APIKeyHeader) — read a key from a named header (X-API-Key), 401 by default, shows in OpenAPI/Swagger Authorize box - FastAPI — Security First Steps —
Security/Depends, automatic 401 on missing credentials - FastAPI — CORS (CORSMiddleware) —
allow_origins,["*"], browser-only preflight - Deploy a FastAPI app on Vercel — zero-config,
appinstance atmain.py/app//api/,requirements.txt, single Vercel Function, 500 MB limit - Deploy to Fly.io — account + card,
fly launch, sleep-to-zero, secrets (sibling tutorial)
Good to know
- The
/docspage is free and live. FastAPI generates an interactive Swagger UI at/docs, a read-only ReDoc view at/redoc, and the raw OpenAPI spec at/openapi.json— from your code, updated every deploy, no manual writing. It's the cheapest way to tell callers how to use your API.[confirmed] - An API key is a shared secret, not per-person identity. Everyone you hand the key to is indistinguishable, and a leaked key works until you rotate it (change the host secret, redeploy, hand out the new one). For named, revocable, per-person access, use a login wall instead.
[confirmed] - A
*.fly.devURL is public — the key is the only lock. Anyone who finds the URL can hit/docs; only a valid key gets past the routes. Don't put anything you wouldn't want a leaked key to reach behind a single shared key alone. See Who can see it? and Can you trust the company?.[confirmed] - Serve docs vs lock docs. By default
/docsis open so callers can read it; the data routes need the key. If even the API's shape is sensitive, tell your agent to gate or disable the docs route too.[confirmed]