---
title: "Get project"
method: GET
path: "/v1/communities/{communityId}/projects/{projectId}"
tags: ["Projects"]
---

# Get project

`GET /v1/communities/{communityId}/projects/{projectId}`

## Request

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

Get full details for a single project. Pass `?expand=script` to include `script.blocks` in the response.

## Path parameters

- `communityId` string, required
- `projectId` string, required

## Query parameters

- `expand` 'script'

## Response `200`

Project details. Includes `data.script.blocks` when `?expand=script` is passed.

- object
  - `data` Project
    - `id` string
    - `community_id` string
    - `name` string
    - `status` 'active' | 'inactive': Lifecycle state. `POST /open` → `active` (accepting responses). `POST /close` → `inactive` (closed). Projects start `inactive` on creation.
    - `info` object: Core identity and aggregate counts for this project
      - `type` 'convo' | 'poll'
      - `created_at` string, date-time, nullable
      - `block_count` integer
      - `is_cloneable` boolean: Whether this project may be cloned by other communities (read-only opt-out flag)
      - `author_id` string, nullable: DB user ID of the project creator
      - `author_name` string, nullable: Display name of the project creator
      - `completion_count` integer: Number of participant sessions that reached the end of the project (i.e. `saveFinalStatus` was called). For polls this equals the number of votes cast; for convos it counts only fully-completed runs. Decremented when a poll voter retracts their answer.
      - `response_count` integer: Running total of individual question-answer rows written across all participants. Each block a participant answers increments this by 1. For a 5-block convo with 10 completions this can reach 50. To count distinct participant sessions use the `total` field from `GET /responses`.
    - `settings` object: Participation rules and result visibility for this project
      - `privacy_mode` 'transparent' | 'semi-private' | 'anonymous', nullable: Controls response visibility and identity disclosure. - **`transparent`** — All community members can see exactly who answered what for every question. - **`semi-private`** — Only the project creator and community admins can view individual responses (who answered what). The rest of the community sees aggregated results only if the creator chooses to share them. - **`anonymous`** — Respondent identity is hidden from everyone, including the creator and admins. Data is pseudo-anonymous: answers are recorded but not linked to a user ID or display name, unless a respondent volunteers that information in an open-text answer. **Caveat:** XP and achievements can still be granted in anonymous projects, so participation is not entirely hidden — this is especially relevant in small communities where deduction is easier.
      - `max_completes_per_user` integer, nullable
      - `change_poll` boolean, nullable: Allow respondents to change their poll answer after submission
      - `poll_results_mode` 'public' | 'voters_only' | 'hidden', nullable: `public`: results visible in the poll embed; `voters_only`: only voters can see results; `hidden`: results hidden until poll closes
      - `reveal_results` boolean, nullable: Post a results summary to the results channel when the project closes
      - `text_analysis` boolean, nullable: Send this project's open-text answers for AI summary. A new project starts with the community's text analysis setting (`general.text_analysis`) written on it; a clone keeps the source's value only when the destination community has text analysis on, and starts off otherwise. `null` (projects created before 2026-10) follows the community setting. A block can still override it, and an `open_text` block whose question asks for personal data (name, email, phone...) is off by default. On update: omit to leave it, send `null` to go back to the community setting.
    - `delivery` object, nullable
      - `opening` object
        - `mode` 'manual' | 'scheduled'
        - `time` string, date-time, nullable
      - `closing` object
        - `mode` 'manual' | 'scheduled'
        - `time` string, date-time, nullable
      - `audience` object
        - `participation` 'private' | 'open_web'
        - `response_channel` 'discord' | 'web'
        - `required_role_ids` string[]
        - `verified_source_ids` integer[]
      - `answer_surfaces` string[], nullable: Ordered fallback chain of surfaces a Convo is attempted on, first to last. `null` means no override: the project follows Subo's default rules, which are resolved at press time and can differ between two posts of the same project in different channels. Send `null` to clear an override; an empty array is rejected.
      - `clear_conversation` boolean: Purge the respondent's thread transcript once they COMPLETE the Convo. Never fires on a timeout: a timed-out Convo is resumable and the respondent returns to it. Defaults to false. Only honored on a thread: Subo can bulk-delete in a thread but only its own messages in a DM, so a project with this on AND a `dm` step in `answer_surfaces` fails script validation and will not open. A web Convo carries no durable transcript, so the flag is inert there.
      - `share_url` string, nullable: The link respondents use to answer on the web, for `open_web` and `private` + `web` projects; null for a project answered in Discord. Share it as given: its shape may change (community vanity URLs).
      - `invitation` object, nullable
        - `post_channel_id` string, nullable: Where the invitation embed is posted; null means nowhere.
        - `message` string, nullable
        - `thumbnail_url` string, uri, nullable
        - `image_url` string, uri, nullable
        - `border_color` string, nullable: Hex colour without '#' for the embed border while the project is open (e.g. `e1287e`)
        - `border_color_closed` string, nullable: 6-digit hex colour without '#' for the embed border when the project is closed (e.g. `745399`). A leading '#' is accepted and removed. Premium only.
        - `footer` string, nullable: Text shown below the invitation embed. Premium only.
        - `embed_config` object, nullable: Invitation embed layout — whether project info shows inline (`embed`) or behind a button, plus per-row visibility toggles
          - `info_display` 'embed' | 'button', nullable
          - `rows` object: Per-row visibility toggles for the invitation embed (open map, e.g. status/privacyMode/roles/xpReward)
        - `answer_button_label` string, nullable: Custom label for the answer/vote button. Premium only.
        - `answer_button_color` integer, nullable: Discord button style for the answer button (1 primary, 2 secondary, 3 success, 4 danger). Premium only.
    - `rewards` object, nullable
      - `discord_role_id` string, nullable
      - `achievement_id` string, nullable
      - `use_xp` boolean, nullable
      - `achievement_enabled` boolean, nullable: True if this project grants an achievement on completion
      - `achievement_image_url` string, uri, nullable: Badge image URL for the achievement
      - `achievement_name` string, nullable: Custom achievement name; null uses the computed default
      - `achievement_role_id` string, nullable: Discord role snowflake granted alongside the achievement
    - `presentation` object, nullable
      - `theme_id` integer, nullable
      - `interviewer_id` integer, nullable
      - `branding` string, nullable
      - `chart_emoji` string, nullable: Emoji used as the bar character in poll result embeds
    - `scoring` object, nullable: Quiz and scoring configuration for this project
      - `enabled` boolean: When true, blocks may carry `correct_answer_index`, `when_correct`, `when_incorrect`, and per-option `score_values` for quiz scoring. Enable via `POST /projects` or `PUT /projects/{projectId}` with `scoring_enabled: true`.
      - `buckets` object[]: Score dimensions defined for this project. Each bucket's `name` (lowercased, spaces replaced with underscores) is the key used in `score_values` on block options and in template variables such as `[score_gryffindor]`. Empty when `enabled` is false.
        - `name` string: Display name of the bucket (e.g. `Gryffindor`). Variable key is this value lowercased with spaces replaced by underscores.
        - `order` integer: Display order (0-based).

## Other responses

- `401`: Invalid or missing API key
- `403`: Forbidden
- `404`: Resource not found
- `429`: Rate limit exceeded — wait `retry_after` seconds before retrying. The same value appears in the `Retry-After` header.

---

[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)
