> ## Documentation Index
> Fetch the complete documentation index at: https://cactal.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Websites

> The website resource: its fields, the create-edit-publish-serve lifecycle, renaming, soft delete and restore, and transferring a website to another organization.

A website is the unit of work in Cactal: one deployable site with its own source code, CMS, assets, domains, and version history, owned by one organization.

## Opening a site

While Cactal resolves your site and access, it shows a loading indicator. Inside the editor, Content Management, Assets, Context, Analytics, Activity, and Settings use loading layouts that match the selected tab. Settings shows an abstract skeleton until its initial data loads. These placeholders indicate that the page is still loading, not that the site or its content is empty.

## The website resource

`GET /v1/websites/find?websiteId=...` returns the full resource:

```json theme={null}
{
  "id": "V1StGXR8_Z5jdHi6B-myT",
  "organizationId": "kX9dQ2mNpL4wRt7vYc3Ub",
  "name": "Acme Marketing Site",
  "slug": "acme-marketing-site",
  "customDomainsEnabled": true,
  "headVersion": 42,
  "publishedVersion": 40,
  "createdAt": "2026-06-01T12:00:00.000Z",
  "updatedAt": "2026-07-08T09:30:00.000Z",
  "canManageSchema": true,
  "canManageDomains": true,
  "faviconUrl": "https://assets.cactal.ai/website-assets/aB3cD5eF7gH9iJ1kL2mN4"
}
```

| Field                                  | Type           | Meaning                                                                                                                                                                              |
| -------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id`                                   | string         | Stable identifier, used in every website-scoped request                                                                                                                              |
| `organizationId`                       | string         | Owning organization                                                                                                                                                                  |
| `name`                                 | string         | Display name, 1–200 characters                                                                                                                                                       |
| `slug`                                 | string         | URL-safe identifier, unique among active websites in the organization; used for slug-based addressing and dashboard URLs                                                             |
| `customDomainsEnabled`                 | boolean        | Whether custom domains are enabled. Enabling is owner-only and makes the website a billable site; custom domains can only be attached while `true`. See [Domains](/docs/concepts/domains) |
| `headVersion`                          | number         | Current draft version; starts at `1`, advances with every source edit                                                                                                                |
| `publishedVersion`                     | number or null | Version the live site serves; `null` until the first publish                                                                                                                         |
| `createdAt` / `updatedAt`              | timestamp      | Creation and last-modification times                                                                                                                                                 |
| `canManageSchema` / `canManageDomains` | boolean        | Whether the caller can manage the CMS schema and domains                                                                                                                             |
| `faviconUrl`                           | string or null | Public URL of the current favicon image; `null` when none is configured. Change it with `PUT /v1/websites/{websiteId}/favicon`                                                       |

List responses (`GET /v1/websites`) carry `faviconUrl` too and add three fields per item: `primaryHostname`, the primary custom domain hostname when one is set, otherwise the platform hostname; `organizationSlug`, the owning organization's URL slug; and `shared`, `true` when your access comes from a direct editor grant outside your organization memberships. Trash listings (`GET /v1/websites?status=deleted`) instead add `deletedAt` (when the website entered the trash) and `purgeEligibleAt` (when it becomes permanently purgeable) to each item.

## Lifecycle

<Steps>
  <Step title="Create">
    `POST /v1/websites` accepts either `{ "organizationId": "...", "name": "..." }` or a creation `prompt`, plus an optional `slug`. Prompt-based creation returns immediately as `Untitled site`; after an agent run is accepted, the dashboard requests a name in the background and retries after later accepted runs while the temporary name remains. An explicit brand or project name in the brief is preserved; otherwise Cactal chooses a generic description from the stated purpose instead of inventing a brand. The first generated name atomically aligns the display name, an available organization slug, and an available platform hostname. The hostname uses the slug when globally available or adds a short suffix when needed. The website starts at `headVersion: 1` and `publishedVersion: null`. Creating websites is free on every plan.
  </Step>

  <Step title="Edit">
    Source edits go through an [edit lease](/docs/concepts/source-code) and advance `headVersion`. Drafts are visible on the `draft--` preview host, never on the live site.
  </Step>

  <Step title="Publish">
    `POST /v1/websiteSourceCode/head/publish` runs the quality gate and build, then sets `publishedVersion`. Publishing to the platform domain is free on every plan. See [Publishing](/docs/concepts/publishing).
  </Step>

  <Step title="Serve">
    The published version always serves on the platform subdomain, free on every plan, and on every `active` custom domain. A site counts toward your plan when an organization owner enables custom domains for it. See [Domains](/docs/concepts/domains).
  </Step>
</Steps>

## Listing and searching

`GET /v1/websites` paginates with `cursor` and `limit` (default `20`, maximum `100`) and returns `{ items, nextCursor }`. Optional parameters:

| Parameter        | Values                                     | Behavior                                                                                                                                                                                                                                                         |
| ---------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `organizationId` | organization id                            | Scope the list to one organization                                                                                                                                                                                                                               |
| `scope`          | `shared`, `all`                            | `shared` (no `organizationId`) lists only websites shared with you through direct editor grants outside your organization memberships; `all` (requires `organizationId`) combines that organization's accessible websites with those shared websites in one page |
| `sort`           | `createdAt` (default), `updatedAt`, `name` | `createdAt`/`updatedAt` sort newest first; `name` sorts A–Z                                                                                                                                                                                                      |
| `search`         | up to 200 characters                       | Case-insensitive substring match on `name`                                                                                                                                                                                                                       |

Keys without organization-wide access only see the websites they are scoped to.

## Addressing a website by slug

Every website has a `slug`, and its organization has a slug too, so you can resolve a website from the two slugs instead of its id:

```bash theme={null}
curl "https://api.cactal.ai/v1/websites/find?organizationSlug=acme&websiteSlug=marketing-site" \
  -H "Authorization: Bearer $CACTAL_API_KEY"
```

`GET /v1/websites/find` accepts either `websiteId` or the `organizationSlug` + `websiteSlug` pair and returns the website along with `canManageSchema` and `canManageDomains` flags for the caller, or `404` when either slug does not match an active website you can access. Slugs are lowercase, may contain letters, digits, and hyphens, and stay unique among active websites in the organization.

## Rename

`PATCH /v1/websites/{websiteId}` updates the display `name` and, when you include a `slug`, the URL slug. Names are trimmed and must be 1–200 characters. After the first automatic naming step, renaming changes nothing about hostnames, versions, or content: the platform subdomain remains stable unless it is changed separately in domain settings.

## Soft delete and restore

`DELETE /v1/websites/{websiteId}` moves the website to the trash for 30 days; the deletion time and purge deadline appear as `deletedAt` and `purgeEligibleAt` in `GET /v1/websites?status=deleted`. The delete marks the website alone. Its CMS content, assets, source history, and deployments keep their existing lifecycle state but become inaccessible through the deleted parent. The site stops serving immediately: visitors get a `404`, and the website disappears from `GET /v1/websites`.

Custom domains are the exception: trashing a website disables custom domains automatically, which disconnects each domain, stops its charge, and releases each hostname for another website to claim. The platform subdomain is untouched.

Deleted websites remain listable through `GET /v1/websites?status=deleted` (requires `organizationId`) during the restore window. They stop appearing once the deadline passes, even if permanent cleanup is waiting for a retry. Deleting an already-deleted website returns `404`. `POST /v1/websites/{websiteId}/restore` returns the website to the active list before the deadline; restoration is rejected once the restore window expires. An hourly cleanup job permanently removes expired websites, CMS records, source history, domains, deployments, asset records, references, and blobs. This cleanup is irreversible.

<Note>
  Restoring the website makes all previously active child content available again without reviving collections, items, or assets that were deleted independently before the website entered trash. Custom domains do not come back either: the website is restored with custom domains disabled, so nothing silently re-bills. It serves on its platform subdomain until an owner re-enables custom domains, after which you add and verify domains again from scratch. See [Domains](/docs/concepts/domains).
</Note>

## Transfer between organizations

`POST /v1/websites/{websiteId}/transfer` with `{ "targetOrganizationId": "..." }` moves the website — content, versions, domains, and history — to another organization. The target must be a different, active organization.

If the website has custom domains enabled, the target organization must have active billing and unused paid capacity; otherwise the transfer fails with `403` (`Billing must be active to receive this website` or `This organization has reached its website capacity`). Websites with custom domains disabled transfer without a billing check, even when published. See [Plans and limits](/docs/platform/plans-and-limits).

<Warning>
  Transfer removes all website-scoped editor grants on the website. Website-scoped API keys and invited editors lose access; the receiving organization's members gain access through their roles. Re-grant editors after the transfer if they still need access. See [Transfer a website](/docs/guides/transfer-a-website).
</Warning>

## Constraints

| Constraint      | Value                                                                                                                       |
| --------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `name` length   | 1–200 characters                                                                                                            |
| `slug`          | Lowercase letters, digits, and hyphens; unique among active websites in the organization                                    |
| List page size  | default `20`, maximum `100`                                                                                                 |
| `search` length | maximum 200 characters                                                                                                      |
| Delete          | Parent-owned soft delete; child lifecycle state is preserved, except custom domains, which are disabled and disconnected    |
| Restore window  | 30 days from `deletedAt`                                                                                                    |
| Restore         | Only websites still within the restore window; websites come back with custom domains disabled and domains are not restored |
| Transfer target | Different active organization; unused paid capacity required when the website has custom domains enabled                    |

## Next steps

<Columns cols={2}>
  <Card title="Source code" icon="file-code" href="/docs/concepts/source-code">
    The file model and edit leases behind `headVersion`.
  </Card>

  <Card title="Publishing" icon="rocket" href="/docs/concepts/publishing">
    How head becomes the published version, and how to roll back.
  </Card>
</Columns>
