# Deploy a serverless API from your AI agent, without a Cloudflare account

Your agent writes a JavaScript, TypeScript or Hono API and [chorus.host, web hosting for AI agents](/), runs it on Cloudflare's network at `https://your-api.worker.chorus.host`. You need a free chorus.host account, not a Cloudflare account.

| | |
|---|---|
| Needs | A free chorus.host account. You read one 6-digit code from your email; it works in a headless agent session with no browser login. |
| Doesn't need | A Cloudflare account, a browser OAuth step, or a credit card. |
| URL lifetime | Until you delete it. |

## Can an agent deploy a serverless function with no account at all? {#compare}

Checked 1 October 2026 against [Cloudflare's claim-deployments docs](https://developers.cloudflare.com/workers/platform/claim-deployments/) and [Netlify's AI quickstart](https://docs.netlify.com/start/quickstarts/deploy-from-ai-code-generation-tool/).

| | chorus.host Workers | Cloudflare `npx wrangler@latest deploy --temporary` | Netlify `netlify deploy --allow-anonymous` | Your own Cloudflare account |
|---|---|---|---|---|
| Before the first deploy | A 6-digit email code, once | Nothing (Wrangler 4.102.0 or later; you accept Cloudflare's terms and a proof-of-work runs automatically) | Nothing | Sign up, then `wrangler login` or an API token |
| URL lifetime with no human step | Until deleted | 60 minutes unless a person claims it | 1 hour unless claimed | Until deleted |
| Server code | Yes, JavaScript modules; the CLI bundles TypeScript, npm packages and Hono | Yes | No: Netlify says "sites or apps that use serverless functions or edge functions will require an account" | Yes |
| Storage | None built in | KV, D1 (1 database, 100 MB), Durable Objects, Queues | n/a | All of it |
| Static files on the same origin | No; pair it with a site at `<name>.chorus.host` | Static Assets, 1,000 files of up to 5 MiB | Static only | Yes |
| Secrets | Yes, and they stay set across redeploys and rollbacks | Not in Cloudflare's list of supported resources | n/a | Yes |
| Cron triggers | Not yet | Not in the list | n/a | Yes |

Vercel's agent skill also has a no-auth fallback that returns a preview URL and a claim URL; how long an unclaimed deploy lasts isn't documented. here.now hosts static files only and its docs say not to use it for backend code: see [chorus.host vs here.now](/vs/here-now).

## Deploy a plain JavaScript Worker

### 1. Write the Worker

Save this as `worker.js`. It answers `GET /api/hello` with JSON that any web page can fetch.

```js
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    if (url.pathname === "/api/hello") {
      return Response.json(
        { message: "hello from chorus.host", time: new Date().toISOString() },
        { headers: { "Access-Control-Allow-Origin": "*" } },
      );
    }
    return new Response("Not found", { status: 404 });
  },
};
```

### 2. Get an API key

Signing up and signing in are the same step. With the CLI:

```bash
curl -fsSL https://chorus.host/install.sh -o install-beacon.sh && sh install-beacon.sh
beacon login --email you@example.com
beacon login --email you@example.com --code 123456
```

The first `login` emails you a 6-digit code; the second saves your key to `~/.config/beacon/config.json`. Without the CLI, see [sign in from a headless agent](#headless).

### 3. Deploy

From the folder that holds `worker.js`:

```bash
beacon deploy --slug my-api --pretty
```

Or with two HTTP calls, one to create the Worker and one to upload the code:

```bash
curl -sS https://chorus.host/v1/workers \
  -H "Authorization: Bearer $BEACON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"slug":"my-api"}'
curl -sS https://chorus.host/v1/workers/my-api/deploy \
  -H "Authorization: Bearer $BEACON_API_KEY" \
  -F 'metadata={"entryPoint":"worker.js","compatibilityDate":"2026-09-01"}' \
  -F "file=@worker.js"
```

Then try it:

```bash
curl -sS https://my-api.worker.chorus.host/api/hello
```

Redeploy the same way after every change. The URL stays the same.

## Deploy a Hono app {#hono}

```bash
curl -fsSL https://chorus.host/install.sh -o install-beacon.sh && sh install-beacon.sh
beacon init my-api --template hono
cd my-api && npm install && npm i -D esbuild
beacon login --email you@example.com              # then: --code 123456
beacon deploy --pretty
```

The template's `index.ts` is a normal Hono app. To let a web page on another host call it, add CORS:

```ts
import { Hono } from 'hono'
import { cors } from 'hono/cors'

const app = new Hono()
app.use('/api/*', cors())
app.get('/api/hello', (c) => c.json({ message: 'Hello from chorus.host!' }))

export default app
```

`beacon deploy` bundles `index.ts` and its npm imports with esbuild and serves it at `https://my-api.worker.chorus.host`. Secrets are `c.env.NAME`. Claude Code, Codex and Cursor can run these commands as they are.

## Sign in from a headless agent {#headless}

No browser window, OAuth redirect or token page. The agent sends a code to the user's email, asks the user for it, and gets an API key:

```bash
curl -sS https://chorus.host/v1/auth/send-otp \
  -H "Content-Type: application/json" -d '{"email":"you@example.com"}'
# the user reads the 6-digit code from the email (valid for 10 minutes)
curl -sS https://chorus.host/v1/auth/verify-otp \
  -H "Content-Type: application/json" -d '{"email":"you@example.com","code":"123456"}'
# {"apiKey":"chk_...","account":{...}}
```

Keep the key in `BEACON_API_KEY` (the CLI also reads `~/.config/beacon/config.json`). Five wrong tries cancel a code.

## Secrets

```bash
printf '%s' "sk-your-token" | beacon secret set UPSTREAM_TOKEN - --slug my-api
```

```bash
curl -sS -X PUT https://chorus.host/v1/workers/my-api/secrets/UPSTREAM_TOKEN \
  -H "Authorization: Bearer $BEACON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"value":"sk-your-token"}'
```

Your code reads it as `env.UPSTREAM_TOKEN`. Set secrets after the first deploy; they stay set across redeploys and rollbacks. Names use capital letters, digits and underscores. chorus.host stores only the names; the values are kept by Cloudflare and can't be read back.

## Watch the logs

```bash
beacon logs my-api
```

This streams one JSON line per request, including anything your code passes to `console.log`. Over HTTP, `GET /v1/workers/my-api/logs/tail` returns a WebSocket URL to read the same stream from.

## Give a static site an API {#static-site-api}

**Option A: two hosts.** Publish the site to `my-app.chorus.host` and the Worker to `my-app-api.worker.chorus.host` (a site and a Worker can't share a name). The page calls the API with `fetch`, and the Worker sends `Access-Control-Allow-Origin`, as the example in step 1 does:

```js
const res = await fetch("https://my-app-api.worker.chorus.host/api/hello");
const data = await res.json();
```

`beacon init my-app --template fullstack` scaffolds both halves: a React frontend in `frontend/` for `my-app.chorus.host` and a Hono API in `backend/` for `my-app-api.worker.chorus.host`.

**Option B: one origin, no CORS.** For a small page, let the Worker serve the HTML too:

```js
const page = `<!doctype html>
<title>Counter</title>
<p id="out">Loading…</p>
<script>
  fetch("/api/hello").then((r) => r.json()).then((d) => (out.textContent = d.message));
</script>`;

export default {
  async fetch(request) {
    const { pathname } = new URL(request.url);
    if (pathname.startsWith("/api/")) {
      return Response.json({ message: "hello from the same origin" });
    }
    return new Response(page, { headers: { "Content-Type": "text/html; charset=utf-8" } });
  },
};
```

## Roll back

```bash
curl -sS -X POST https://chorus.host/v1/workers/my-api/rollback \
  -H "Authorization: Bearer $BEACON_API_KEY"
```

This puts the previous deploy back. To pick an older one, send `{"deploymentId":"..."}` with an id from `GET /v1/workers/my-api/deployments`.

## Free tier and limits {#limits}

Free, with no credit card. These are the limits today:

| Limit | Value |
|---|---|
| Code per deploy | 3 MB total, up to 100 files |
| Language | JavaScript ES modules. For npm imports or TypeScript, the CLI bundles with esbuild or runs your `npm run build`. |
| Secret values | 5 KB each |
| New Workers | 10 per hour |
| Deploys and rollbacks | 20 per hour |
| Log sessions | 5 per hour |
| Scheduled (cron) runs | Not available yet |
| Storage (KV, Durable Objects) | Not available. Keep data in a service you call with `fetch`. |
| Outbound requests | Public HTTP and HTTPS only. Private and internal addresses are blocked. |
| Without an account | Not available. Workers need an API key; static sites don't. |

Receiving webhooks? Follow the [GitHub and Stripe webhook receiver guide](/guides/deploy-webhook-from-agent).

## Questions

### Can my agent add an API backend to a static site?

Yes. Publish the site to `<name>.chorus.host` and deploy the API as a Worker at `<name>-api.worker.chorus.host`, then call it from the page with `fetch`, sending an `Access-Control-Allow-Origin` header from the Worker. Or serve the page from the Worker itself and skip CORS.

### Can my agent deploy a webhook endpoint?

Yes. A Worker gets a public HTTPS URL as soon as it deploys, so it can receive webhooks from GitHub, Stripe or any other service. Keep the signing secret as a Worker secret. Step by step: [deploy a GitHub or Stripe webhook receiver](/guides/deploy-webhook-from-agent).

### Does it support TypeScript and npm packages?

With the CLI, yes: if your entry file imports packages, `beacon deploy` bundles it with esbuild (`npm i -D esbuild`), or runs your `npm run build` if `package.json` has one. The HTTP API takes JavaScript modules as they are, so bundle TypeScript before uploading.

### Can I deploy a Hono app from Claude Code or Codex to a public URL?

Yes. `beacon init my-api --template hono`, `npm install`, then `beacon deploy`. The agent signs in with a code from your email, so no browser is needed, and the app is live at `https://my-api.worker.chorus.host`.

### How long does a chorus.host Worker URL stay up?

Until you delete it. There's no claim window and no expiry for Workers.

### Is chorus.host Workers free?

Yes. There are no paid plans and no credit card. The limits above apply, including 20 deploys an hour.

### Do I need a Cloudflare account?

No. chorus.host runs the Worker on its own Cloudflare account. If you only need it for an hour, Cloudflare's `wrangler deploy --temporary` also works without an account; it's deleted after 60 minutes unless someone claims it.
