# Hosting

> Deploy a folder to <slug>.vibiz.app. Production by default, previews on request, instant promote and rollback.

Every project has an address, `https://<slug>.vibiz.app`, and the `hosting` resource builds and serves the app there. Deploying works by content hash: files the host already has are never uploaded twice, and every deployment keeps its file manifest, so any production deployment can be switched back to instantly.

## Pricing

Hosting is not charged today: builds and live sites are recorded in usage at $0. Pricing is not decided.

## Limits

- 30 builds per project per UTC day (`rate_limited` after that; `GET /v1/usage` shows `builds_today`).
- Files: up to 10,000 per deployment, 50 MB each.
- Never uploaded by the CLI: `node_modules`, `.git`, `.next`, `dist`, `.vercel`, `.turbo`, `vibiz.json`, `.env*` files, and key or credential files (`*.pem`, `id_rsa`, `.npmrc`…). It refuses to deploy a home or config folder.
- Deleting a project takes the site offline at once; its data is kept for 7 days and `restore` brings it back.

## Deploy

```bash
vibiz deploy               # build and go live
vibiz deploy ./site --preview
vibiz promote dep_…        # a preview is rebuilt as production; a production deployment switches instantly
vibiz rollback             # back to the previous production deployment, instantly
vibiz status               # resources and the latest deployments
```

Over HTTP it is three steps: ask which files are missing, upload them, deploy the manifest.

```bash
SHA=$(shasum -a 1 index.html | cut -d' ' -f1)
curl https://app.vibiz.app/v1/files/missing -H "Authorization: Bearer $VIBIZ_API_KEY" \
  -H 'content-type: application/json' -d "{\"shas\":[\"$SHA\"]}"
# → { "missing": ["…"] }
curl -X PUT https://app.vibiz.app/v1/files/$SHA -H "Authorization: Bearer $VIBIZ_API_KEY" \
  --data-binary @index.html
# → 204
curl https://app.vibiz.app/v1/projects/$PROJECT/deployments -H "Authorization: Bearer $VIBIZ_API_KEY" \
  -H 'content-type: application/json' \
  -d "{\"files\":[{\"path\":\"index.html\",\"sha\":\"$SHA\",\"size\":$(wc -c < index.html)}]}"
# → 202 { "deployment": { "id": "dep_…", "status": "queued", "target": "production" }, "operation": { … } }
```

Poll `GET /v1/deployments/:id` until `status` is `ready` (or `failed`, with `error`). `target: "preview"` builds at a separate URL.

From an agent: `vibiz_deploy { project_id, path, target? }` (waits for the build), `vibiz_promote`, `vibiz_rollback`.

## Your own domain

Every app keeps its free `<slug>.vibiz.app` address. A domain the business already owns (`shop.example.com`, or `example.com`) can be connected on top of it, with HTTPS that turns on by itself.

```bash
vibiz domains add shop.example.com     # prints the DNS records to add
vibiz domains                          # every domain, its status and records
vibiz domains verify shop.example.com  # check again now
vibiz domains remove shop.example.com
```

Then add the records at the company where you bought the domain. It usually takes a few minutes; HTTPS turns on by itself.

| You connect | Record to add | Name | Value |
| --- | --- | --- | --- |
| a subdomain, `shop.example.com` | `CNAME` | `shop` | `cname.vibiz.app` |
| the domain itself, `example.com` | `A` | `@` | the address `records_to_set` shows |
| …and its `www` | `CNAME` | `www` | `cname.vibiz.app` |

- **`www` comes along.** Connecting `example.com` also connects `www.example.com` as a permanent redirect to it, so both work and search engines see one site. Its record is in the list. To serve `www` as the main address instead, connect `www.example.com` (a subdomain) and leave the apex out.
- **Ownership.** Sometimes (the domain was used on another site before) one more `TXT` record is listed: add it as shown, name and value exactly.
- **Names** in `records_to_set` are relative to `zone`: `@` is the domain itself. Some DNS providers want the full name (`shop.example.com`); both mean the same.
- **Trusted for sign-in.** A domain an owner adds, one our hosting serves, or one [bought through Vibiz](https://app.vibiz.app/docs/domains) is trusted for sign-in. One an agent adds counts analytics and replay at once and shows `trusted_for_sign_in: false` with a `trust_record` until it is proven: add that TXT record where the domain's DNS is managed (`_vibiz.shop.example.com` = `vibiz-verify=…`, name and value exactly), then `vibiz domains verify shop.example.com`. It is also looked up every hour for a week, so nobody has to poll. Or the owner confirms it in the console (Domains ▸ *Trust for sign-in*).
- **Status**: `pending_dns` (add the records), `verifying` (they're in; ownership and HTTPS are being settled), `active` (live with HTTPS), `error` (read `error`). Status is checked when you look, at most every 20 seconds; `verify` checks right away.
- A domain belongs to one project at a time: another project's answers `409 domain_taken`. Removing it frees it; deleting the project frees it after the 7-day restore window.
- No domain yet? [Buy one](https://app.vibiz.app/docs/domains) from your credits: it serves on the app at once, with no records to add.

Over HTTP: `POST /v1/projects/:id/domains { "domain": "shop.example.com" }` → `201` with `domain.records_to_set`; `GET /v1/projects/:id/domains`; `POST /v1/projects/:id/domains/shop.example.com/verify`. Each domain has a `console_url` that opens the console's Domains page on it. From an agent: `vibiz_domains`.

## Running somewhere else

A project doesn't need Vibiz hosting: create it with `--resources auth,ai` (sign-in brings the database), add the app's domain (`vibiz domains add app.example.com`: without Vibiz hosting it is only trusted) and give the host its env (connected host or `VIBIZ_APP_KEY`). A project that has Vibiz hosting but also runs on another host at a domain adds it with `--elsewhere` (`hosting: "elsewhere"`): status `external`, no records, sign-in and analytics accept it. See [Keys and environments](https://app.vibiz.app/docs/keys#getting-the-production-env-to-the-app), and [Use one service](https://app.vibiz.app/docs/use-one) for each service on its own.

## What agents can and can't do

Agents may deploy to production or preview, promote, roll back, delete and restore a project, read domain status and check a domain again. Agents may add the app's own domains: analytics and replay count one at once, and sign-in trusts it once it is proven (`trusted_for_sign_in: false` until then). An agent that can edit the domain's DNS adds the TXT record in `trust_record` and calls `verify`; otherwise the owner confirms it in the console. A domain our hosting serves is trusted as soon as its DNS checks out, and one bought through Vibiz (or a name under it) at once. Removing a domain and connecting a host are the owner's (`403 owner_only`): they decide where the app answers and where production secrets go. An agent gives the person the domain's `console_url` or the command.

## Errors

| Code | Status | When | Next step |
| --- | --- | --- | --- |
| `rate_limited` | 429 | 30 builds today for this project | wait for `details.resets_at` |
| `invalid_request` | 400 | a bad manifest (absolute path, `..`, bad sha) or a file that doesn't match its sha | fix the file list |
| `dependency_not_ready` | 409 | hosting isn't ready yet | poll the project |
| `domain_taken` | 409 | the slug or domain belongs to another project or app | pick another, or remove it there first |
| `not_found` | 404 | no such project or deployment | check the id |
| `deployment_failed` (MCP) | | the build failed | read the deployment's `error`, fix, deploy again |
