Add block
Append a new main-section block, or insert at a specific position. Only permitted when project is inactive. This endpoint does not create outro blocks; use PUT /script for controlled outro updates.
Request
- Base URL: https://api.subo.ai
- URL: https://api.subo.ai/v1/communities/{communityId}/projects/{projectId}/script/blocks
- Auth: API key in header X-API-Key
Path parameters
Community ID (Discord guild snowflake, serialized as string)
Project ID
Request body
Variable token name for this block. Used in pipe variables ([q_name]), precondition expressions (NOT((q_name="value"))), and calculated formulas. Auto-assigned as q0, q1, … (by position) when omitted. Must be unique within the script.
Block section. intro blocks are shown before the survey begins (editable and deletable). outro blocks are returned only when GET /script?expand=outro is used and are read-only in script write endpoints.
How answer options are displayed. full_text: labelled buttons; emoji_only: keycap emoji buttons; select_menu: dropdown. Applies to single_punch and multi_punch blocks, to ranking (which takes full_text or emoji_only only), and to the scale family (rating / opinion_scale / nps), which accept only buttons (default) or select_menu — a scale's point rendering is set with scale.icon, not here. A select menu is the better widget from six labeled points up, where a button row wraps. Sending full_text or emoji_only on a scale returns 400 invalid_request. Null inherits the project default. For Discord-delivered projects, full_text and select_menu reject options that exceed the Discord character limit (40 for buttons, 50 for select menus) or carry more than one emoji that needs rendering (a button/select label has a single emoji slot) — the request returns 400 invalid_request with a violations array. Use emoji_only (its answer list renders every emoji), shorten the option, or remove the extra emoji.
Discord embed accent color as a hex string without the leading # (e.g. e1287e). Applies to content_block and action_block embeds when the project is Discord-delivered. Requires Premium tier. Ignored on read if community is on the Basic tier; blocks authored via the API will still persist the value, but it will not render until the community upgrades.
Image displayed above the question prompt. Requires Premium tier to persist via the editor; readable by all tiers.
Thumbnail image displayed top-right of the Discord embed. Available on all block types. Requires Premium tier to persist via the editor; readable by all tiers.
Min selections (multi_punch) or min value (open_numeric)
Max selections (multi_punch) or max value (open_numeric)
Whether a response is required to advance
Raw skip-logic hide expression: when it evaluates to true the block is hidden; when false (or null) it is shown. Prefer the structured show_when / hide_when fields below — they compile to this and avoid its quoting/operator/casing pitfalls. Reference a prior block by its name (matched case-sensitively against the stored, title-cased name, e.g. a block named NotifyPref is referenced as Notifypref) or by position as q1, q2, … qN; named references are recommended because positions shift when blocks are added or removed. Operators: = (or ==), !=, <, >, >=, <=, in (membership/substring), AND, OR, NOT. String literals use double quotes. To show only when a condition holds, wrap it: NOT((Notifypref = "Other")). Invalid expressions (unknown variable, syntax error) are rejected with 400 invalid_request at write time rather than silently failing open. See the Script tag description for the full reference.
Required for action_block. Null for all other block types.
Canonical correct-answer field. Array of real option.id values that are correct. Single-element today (MVP single-select grading); array type future-proofs multi-select. Survives option reorder because ids are stable. Only meaningful when scoring_enabled is true on the project.
Deprecated — use correct_answer_ids instead. 0-based position into the current options array of the first correct answer. Still accepted on input (translated to the option's id at write time) and emitted on output for back-compat, but breaks when options are reordered. Only meaningful when scoring_enabled is true.
Message shown to the respondent immediately after they answer correctly. Only meaningful when correct_answer_ids is set. Supports template variables: [UserName], [answer] (their response), [score], [max_score], [score_correct], [max_score_correct], [correct_answers], [max_correct_answers], [score_<bucket>], [max_score_<bucket>], [score_correct_<bucket>], [max_score_correct_<bucket>], and answer-pipe tokens [BlockLabel]. score_correct counts only points earned on correctly-answered graded questions; correct_answers / max_correct_answers count graded questions right vs total.
Message shown to the respondent immediately after they answer incorrectly. Only meaningful when correct_answer_ids is set. Supports the same template variables as when_correct.
Shuffle the option order per respondent, so the list a participant sees is not the order you authored. Valid on single_punch, multi_punch and ranking; sending it on rating / opinion_scale / nps returns 400 invalid_request — a scale is ordered by definition and its points are never shuffled.
It matters most on ranking, where a fixed order is not a cosmetic default but a measurement bias: whichever item sits first gets tapped first, and that bias lands in the average rank the results report.
The shuffle is seeded per respondent per session, so revisiting a question does not reorder it mid-answer. Options carrying anchor_position: "last" are appended after the shuffle in their stored order. Defaults to false. Discord poll embeds are out of scope — one embed renders for every viewer, so there is no per-respondent order to vary.
open_text only: send this block's answers for AI summary. null (or absent on read) follows the project's settings.text_analysis. Without an explicit value, a block whose question asks for personal data (name, email, phone, address...) is not summarized. Whatever this says, respondents are sent as pseudonyms, personal data in answers (emails, phone numbers, ids...) is removed before sending, and a block whose answers are mostly personal data is not summarized at all. Sending true/false on another block type returns 400 invalid_request. On update: omit to leave it, send null to follow the project again.
Ranking only: how many items the respondent is asked to put in order ("rank your top 3"). Omit or null to have every item ranked. It has its own field rather than riding max, which means max SELECTIONS on a multi_punch.
A ranking submits complete or not at all — every item, or exactly the top N — so average ranks stay comparable across respondents. Each ranked item is stored as one response row whose value is the rank position (1 = first) and whose option_id is the item; unranked items in top-N mode have no row.
Ranking has one interaction model (tap in order) on both Discord and web, so its answer_style is only about how the items are drawn: full_text (default) or emoji_only, which puts the item names in a list above the buttons and is the way to fit long names on Discord. select_menu returns 400 invalid_request — a dropdown can't express an order. The item list is capped at 20 — a full grid of Discord buttons — and more than about 7 items is ranked unreliably, which is what rank_top_n is for.
Formula for calculated_block type. Evaluated in script order; earlier calculated blocks can be referenced by subsequent blocks via [BlockLabel]. Three expression types are supported:
-
argmax([score_a], [score_b], ...) — returns the display name of the bucket with the highest value.
-
if <cond> then <val> else <fallback> — keywords are case-insensitive. <cond> supports >=, <=, !=, ==, >, < (numeric). A bare numeric condition is truthy if non-zero.
-
Arithmetic: any expression using [variable] tokens, digits, +, -, *, /, (, ). Unknown variables resolve to 0.
Available variables: [score], [max_score], [score_correct], [max_score_correct], [correct_answers], [max_correct_answers], [score_<bucket>], [max_score_<bucket>], [score_correct_<bucket>], [max_score_correct_<bucket>], answer-pipe tokens [BlockLabel], and previously evaluated [CalcFieldName] tokens. score_correct / max_score_correct accumulate only from correctly-answered graded questions; correct_answers / max_correct_answers are question counts (right vs total gradeable).
Examples: argmax([score_gryffindor], [score_slytherin], [score_ravenclaw]) if [score] >= 15 then Excellent else Good [score] / [max_score] * 100 if [correct_answers] == [max_correct_answers] then Perfect! else [correct_answers] out of [max_correct_answers] [score_correct] / [max_score_correct] * 100
0-based position in the script. Omit to append.
Response
Updated script with new block
Changes
No recorded changes to this operation across all 1 revision of this API.