---
title: "Create a site from an approved AI plan"
method: POST
path: "/api/v1/sites/generate/from-plan"
tags: ["sites-ai"]
---

# Create a site from an approved AI plan

`POST /api/v1/sites/generate/from-plan`

## Request

- Base URL: `https://slatehut.com`
- URL: `https://slatehut.com/api/v1/sites/generate/from-plan`
- Auth: HTTP bearer

Runs SlateHut block generation from a `plan` returned by `POST /api/v1/sites/generate/plan` (optionally edited), then persists like `POST /api/v1/sites/generate`. **Still consumes AI credits** — if your agent already has full block JSON, use `POST /api/v1/sites` with `pages[]` instead.

## Request body

- GenerateSiteFromPlanRequest: Body for `POST /api/v1/sites/generate/from-plan`. Optional `subdomain` matches `CreateSiteRequest.subdomain`.
  - `plan` GeneratedSitePlan, required: Structured site plan from the LLM. `pages` has 1–6 rows (home first, then optional secondary slugs). Navbar `links` need at least one item.
    - `title` string, required
    - `description` string
    - `theme` SiteTheme, required: Global fonts, corner radius, section spacing, and palette. Sending a subset on `PUT /api/v1/sites/{subdomain}` merges with the current theme (same as the editor).
      - `fontPreset` 'inter' | 'poppins' | 'roboto' | 'open-sans' | 'lato' | 'montserrat' | 'raleway' | 'dm-sans' | 'space-grotesk' | 'outfit' | 'plus-jakarta-sans' | 'playfair-display' | 'merriweather' | 'libre-baskerville' | 'source-code-pro'
      - `headingFontPreset` 'inter' | 'poppins' | 'roboto' | 'open-sans' | 'lato' | 'montserrat' | 'raleway' | 'dm-sans' | 'space-grotesk' | 'outfit' | 'plus-jakarta-sans' | 'playfair-display' | 'merriweather' | 'libre-baskerville' | 'source-code-pro': Optional; defaults to body font when omitted.
      - `borderRadius` 'none' | 'sm' | 'md': Corner rounding for themed UI. `PUT` accepts legacy `lg`, `xl`, and `pill`; they are normalized to `md`. `GET` returns only `none`, `sm`, or `md`.
      - `sectionSpacing` 'compact' | 'default' | 'spacious'
      - `primary` string: CSS hex color, e.g. #27272a
      - `primaryForeground` string: CSS hex color, e.g. #27272a
      - `background` string: CSS hex color, e.g. #27272a
      - `foreground` string: CSS hex color, e.g. #27272a
      - `muted` string: CSS hex color, e.g. #27272a
      - `mutedForeground` string: CSS hex color, e.g. #27272a
      - `border` string: CSS hex color, e.g. #27272a
      - `heroFrom` string: CSS hex color, e.g. #27272a
      - `heroTo` string: CSS hex color, e.g. #27272a
      - `heroForeground` string: CSS hex color, e.g. #27272a
      - `footerBackground` string: CSS hex color, e.g. #27272a
      - `footerForeground` string: CSS hex color, e.g. #27272a
      - `footerMuted` string: CSS hex color, e.g. #27272a
    - `navbar` NavbarBlockProps, required
      - `brandLabel` string, required
      - `logoUrl` string: Public image URL (e.g. from POST /api/v1/media/upload).
      - `logoIcon` string: Lucide icon id when logoUrl is empty (e.g. sparkles). Prefer for API-generated sites without a logo asset.
      - `variant` 'standard' | 'minimal' | 'elevated' | 'dense' | 'splitCentered' | 'withPromoStrip': Layout: standard (default bar), minimal (no border), elevated (shadow), dense (compact), splitCentered (nav centered between brand and CTA on md+), withPromoStrip (announcement strip above bar).
      - `promoStripText` string
      - `secondaryCtaLabel` string
      - `secondaryCtaHref` string
      - `links` NavLinkItem[], required
        - `label` string, required
        - `href` string, required
      - `ctaLabel` string
      - `ctaHref` string
      - `ctaIcon` string: Lucide icon id (optional).
    - `footer` FooterBlockProps, required
      - `brand` string, required
      - `tagline` string, required
      - `copyrightYear` integer
      - `variant` 'default' | 'illustratedBand': illustratedBand: bottom illustration band with watermark brand.
      - `illustrationImageUrl` string
      - `watermarkText` string
      - `legalLinks` FooterLink[]
        - `label` string, required
        - `href` string, required
      - `columns` FooterColumn[]
        - `title` string, required
        - `links` FooterLink[], required
          - `label` string, required
          - `href` string, required
      - `socialLinks` SocialLink[]
        - `platform` 'twitter' | 'github' | 'linkedin' | 'instagram' | 'youtube' | 'facebook' | 'website', required
        - `href` string, required
    - `pages` GeneratedSitePlanPage[], required
      - `slug` string, required: Home page is empty string `""`.
      - `title` string: Optional page title.
      - `purpose` string, required: One line: sections and blocks to generate on this page.
  - `subdomain` string: Optional; random `site-xxxxxxxx` if omitted.

## Response `201`

Created

- object
  - `subdomain` string, required
  - `url` string, required
  - `generationWarnings` string[]: Optional post-generation quality hints (e.g. low block-type diversity). Site is still persisted.

## Other responses

- `400`: Validation or conflict error
- `401`: Missing or invalid credentials
- `402`: AI Gateway budget cap reached. Update billing limits and try again. `reason = budget_exceeded`.
- `409`: Validation or conflict error
- `422`: Model could not produce valid output. Try a shorter or clearer prompt. `reason = invalid_output`.
- `429`: AI provider is rate-limited right now. `reason = rate_limited`.
- `502`: AI provider is temporarily unavailable, credentials are misconfigured, or the request failed. `reason = upstream_unavailable | unauthorized | upstream_error | unknown`.
- `503`: AI provider is temporarily unavailable, credentials are misconfigured, or the request failed. `reason = upstream_unavailable | unauthorized | upstream_error | unknown`.
- `504`: AI provider timed out. Try again in a moment. `reason = upstream_timeout`.

---

[API](https://skmtc.dev/slatehut/apis/slatehut-api.md) · [All operations](https://skmtc.dev/slatehut/apis/slatehut-api/llms.txt) · [OpenAPI document](https://skmtc.dev/slatehut/apis/slatehut-api/revisions/32dae277550c?raw)
