---
title: "Generate script from intent"
method: POST
path: "/v1/communities/{communityId}/projects/generate"
tags: ["Script"]
---

# Generate script from intent

`POST /v1/communities/{communityId}/projects/generate`

## Request

- Base URL: `https://api.subo.ai`
- URL: `https://api.subo.ai/v1/communities/{communityId}/projects/generate`
- Auth: API key in header `X-API-Key`

Draft a complete script from a description of the conversational goal. Does not create a project. The draft uses every block type (rating, NPS, ranking, calculated fields, action blocks), scoring and `show_when`; it is fixed in code, failing blocks get one repair call, and blocks that still fail are dropped and listed in `dropped` (except a misspelled score bucket: that block is kept and listed in `flagged`). The returned `blocks` pass `PUT /script` as they are. Typical workflow: (1) POST /projects/generate; (2) read `author_notes`; (3) POST /projects with `script: {blocks}` (and `scoring_enabled: true` when `scoring.enabled`). Or use POST /projects with `intent` to draft and write in one call. Optionally call POST /projects/generate/plan first. Every model call is charged, repairs included. Returns 402 if the balance is below the chosen quality's floor.

## Path parameters

- `communityId` string, required

## Request body

- object
  - `intent` string, required: The goal or purpose of the convo in plain language
  - `type` 'convo' | 'poll': `poll` asks for a one-question poll. Omit to let the intent decide.
  - `quality` 'quick' | 'deep': Draft quality. `quick` is a fast, low-cost model; `deep` is a stronger model that costs far more credits (typically ~24,000-48,000 versus ~700) and needs a balance of at least its floor to start. Defaults to `deep` on any paid plan, `quick` otherwise.
  - `question_count` integer: How many questions to draft (intro, content and action blocks not counted). Capped by the plan's limit. Omit to let the model choose what the goal needs.
  - `max_blocks` integer: Deprecated alias of `question_count`.
  - `language` string: Language respondents will read: any language's name (`French`, `Tagalog`) or a locale code (`fr`, `pt-BR`, `ja`). Defaults to a language the intent names ("a poll in Tagalog"), else the community's. Only a value that is not a language name or code is a 400.
  - `admin_language` string: Language the plan and `author_notes` are written in for you (the author): any language's name or a locale code. It never sets the project's language. When omitted it is inferred from the intent, and the response's `notices` say so.
  - `facts` string: Facts the model cannot know and must use as given: dates, line-ups, results, odds. The model's knowledge has a cutoff, so pass anything current here.
  - `plan` DraftPlan: What the AI understood and what it would like to know before drafting.
    - `kind` 'survey' | 'poll'
    - `title` string
    - `question_count` integer, nullable
    - `outline` string[]: One line per planned block.
    - `questions` object[]: Questions for the author. Answer them in `answers` by `id`; unanswered ones are left to the model. A question with `id` `language` comes when the intent is written in a language that is neither yours (`admin_language`) nor the project's: its 4 suggestions, in order, keep the project's language, write the project in the intent's language, write only `author_notes` in it, or both. Answer with the suggestion's text.
      - `id` string
      - `question` string
      - `suggestions` string[]
    - `facts_needed` string: Facts the draft needs from you (pass them in `facts`); empty when none.
    - `notes` string
    - `request_language` string: The language the intent is written in, as the model read it.
    - `named_language` string: The language respondents should read when the intent names one ("a poll in Tagalog"); empty otherwise.
  - `answers` object: Your answers to the plan's questions: plan question `id` -> answer text.
  - `session_id` string: The `session_id` from `POST /projects/generate/plan`, so the plan and the draft are recorded as one exchange. Optional.
  - `locale` string: Deprecated alias of `language`.

## Response `200`

The draft: `blocks` (pass to `PUT /script` or `POST /projects` as they are) and what came with it

- object
  - `data` DraftInfo: What came back with an AI draft, beside its blocks.
    - `name` string, nullable: A suggested project name.
    - `kind` 'convo' | 'poll'
    - `scoring` object: When `enabled`, create the project with `scoring_enabled: true`; the buckets are created from the blocks' `score_values`.
      - `enabled` boolean
      - `buckets` string[]
    - `author_notes` string: What a person must check before the project opens: facts the model was unsure of, estimated odds, unconfirmed correct answers. Empty when nothing needs checking. Never shown to respondents.
    - `dropped` object[]: Blocks removed because they still failed validation after one repair.
      - `name` string, nullable
      - `type` string, nullable
      - `prompt` string
      - `problems` string[]
    - `flagged` object[]: Blocks kept in the draft that a person must fix before opening. Today one rule: `unlisted_bucket`, points or a `[score_<bucket>]` token under a name that is not one of `scoring.buckets` (a misspelled outcome), still wrong after the repair. Writing the script creates that name as an extra bucket: move its points to the right bucket, then delete it.
      - `name` string, nullable
      - `type` string, nullable
      - `prompt` string
      - `rule` 'unlisted_bucket'
      - `keys` string[]: The bucket names used that are not listed.
      - `buckets` string[]: The listed buckets.
      - `problems` string[]
    - `quality` 'quick' | 'deep'
    - `model` string, nullable: The model that wrote the draft.
    - `credits_used` integer: Every model call is charged: the draft and, when needed, its repair.
    - `session_id` string
    - `language` string: The language respondents read: the one you passed, else one the intent names ("a poll in Tagalog", read by the plan or, without a plan, by the draft), else the community's.
    - `admin_language` string, nullable: The language `author_notes` are written in; null when it was neither given nor read from a plan (then: the intent's).
    - `notices` string[]: Non-blocking notes in English. When `admin_language` was not given, one says which language it was inferred as and how to choose another.

## Other responses

- `400`: Bad request
- `401`: Invalid or missing API key
- `402`: Insufficient bot credits for the chosen quality
- `429`: Rate limit exceeded — wait `retry_after` seconds before retrying. The same value appears in the `Retry-After` header.
- `500`: No usable draft. Calls already made are charged; `credits_used` says how much.

---

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