Create a NEW site (a 'roost') and return its public URL in one call. Returns `{ hatchId, slug, url, apex, promo, uploads? }` — show `url` to the user and remember `hatchId`. NEVER call hatch twice for the same site — use `convert` to rename, change tier, or set Promo, and `upload`/`deploy` for content updates.
Pick `apex` from the user's intent (homes / estate / land / wedding / events / agency / site / omit for theroost.dev). Do NOT invent other apexes.
Ways to call it:
• `html` (PREFERRED for n8n / a single review page) → one self-contained HTML string published at /. Do not also pass site/manifest/script.
• Omit `html`, `manifest`, `site`, and `script` → a placeholder page is published instantly.
• Pass `manifest` (file list with sizes) → returns presigned `uploads[]`; you PUT each file's bytes directly to its URL. PREFER this for any project with images, fonts, video, or more than a few KB of HTML.
• Pass `site` (inline files map) → small text-only sites only. File keys must be paths like `index.html` (n8n may send `index`; that is accepted as `index.html`).
• Pass `script` → advanced: full server-side code as one ES module (1.5 MiB max, text only — NEVER base64-embed binaries here).
Optional `promo` (boolean). `true` lists this hatch on the public carousel even when its tier would hide it, if the hatch is active, has a public slug, and is not expired, and forces the Powered By chip on. A password still keeps it off the carousel. `false` unmarks Promo and returns the normal carousel and chip rules. Omit `promo` to leave an existing hatch unchanged, or to create one under the normal rules. To change Promo later, call `convert` with `promo` — do not hatch again.
Do not send empty strings for optional fields (hatchId, preferredSlug, apex, html, site). Omit them.