Skip to content
CalabDocs

Board forms

Intake forms on a board — create, change, preview and submit answers as a bot.

A board form is a questionnaire whose answers become tasks. A bot can manage a board's forms (create, change, delete, validate a definition in preview) and submit answers to a form by its code — for example, to carry requests over from an external system.

ActionPermission
list, create, change, delete forms, previewVIEW_BOARD and MANAGE_BOARD
open and submit a formaccess by the form's settings (for a private form, the bot is in allowedUserIds)

Forms per board: Team — 5, Business — 20, a self-hosted installation — as configured (0 = unlimited). The board's “Forms” feature switched off gives 409 FEATURE_DISABLED.

Routes

MethodPathWhat it does
GET/api/boards/{id}/formsThe board's forms → {forms}
POST/api/boards/{id}/formsCreate a form {definition} → {form}
PUT/api/boards/{id}/forms/{fid}Replace the definition {definition, revision} → {form}
DELETE/api/boards/{id}/forms/{fid}Delete a form: its link stops working, tasks stay
POST/api/boards/{id}/forms/previewValidate an unsaved definition and answers without creating a task
GET/api/forms/{code}The form as a respondent sees it → {title, description, fields, revision}
POST/api/forms/{code}/submissionsSubmit answers → {receiptId}

The anonymous GET /api/public/forms/{code} and POST /api/public/forms/{code}/submissions are public link access for people without an account; enforced workspace SSO closes them. Bots use the authenticated /api/forms/{code}….

Form definition

BoardFormDefinition:

FieldDescription
title, descriptionThe form's title and description
fieldsFields: id (UUID), type, label, hint, placeholder, required, options
titleFieldIdOptional single-value field used as the task title (not CHECKBOX or MULTISELECT)
statusId, priorityStatus and priority of the created tasks
isPrivate, allowedUserIdsA private form and who may submit it

Field types (with the BOARD_FORM_FIELD_TYPE_ prefix in JSON): TEXT, PARAGRAPH, EMAIL, NUMBER, DATE, SELECT, CHECKBOX, PHONE, URL, MULTISELECT.

curl -s -X POST $CALAB/api/boards/$BOARD/forms \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{
  "definition": {
    "title": "Support request",
    "fields": [
      {"id": "6f1c2b0e-8a4d-4e3b-9c1a-2d3e4f5a6b7c", "type": "BOARD_FORM_FIELD_TYPE_TEXT", "label": "Subject", "required": true},
      {"id": "7a2d3c1f-9b5e-4f4c-8d2b-3e4f5a6b7c8d", "type": "BOARD_FORM_FIELD_TYPE_EMAIL", "label": "Reply-to email"},
      {"id": "8b3e4d20-ac6f-4a5d-9e3c-4f5a6b7c8d9e", "type": "BOARD_FORM_FIELD_TYPE_MULTISELECT", "label": "Team", "options": ["Design", "Support", "Sales"]}
    ],
    "titleFieldId": "6f1c2b0e-8a4d-4e3b-9c1a-2d3e4f5a6b7c",
    "priority": "TASK_PRIORITY_MEDIUM"
  }}'

The answer is {form: {id, boardId, url, definition, revision, createdBy, createdAt, updatedAt}}. PUT replaces the whole definition and requires the current revision.

Submit answers

POST /api/forms/{code}/submissions {revision, nonce, answers: [{fieldId, value}]} → {receiptId}, without task details.

  • Values are strings; a checkbox is "true" or "false".
  • MULTISELECT uses {fieldId, values: ["Design", "Support"]} with no value; other types use only value.
  • Unknown and duplicate options are rejected; the order of chosen options does not affect idempotency.
  • PHONE keeps formatting and leading zeroes: 7–15 digits, up to 64 characters, an optional leading +, spaces, parentheses, dots and hyphens.
  • URL is an absolute HTTP/HTTPS URL without credentials or whitespace; the server never fetches it.
  • The task title comes from the titleFieldId answer: collapsed to one line and cut to 200 characters; the full value stays in the task description. No such field, or no answer — the form title.
curl -s -X POST $CALAB/api/forms/$CODE/submissions \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{
  "revision": 3,
  "nonce": "3b0f6c1e-2a4d-4b8e-9f10-6a7b8c9d0e1f",
  "answers": [
    {"fieldId": "6f1c2b0e-8a4d-4e3b-9c1a-2d3e4f5a6b7c", "value": "Email does not arrive"},
    {"fieldId": "8b3e4d20-ac6f-4a5d-9e3c-4f5a6b7c8d9e", "values": ["Support"]}
  ]}'
# → {"receiptId": "0192c9…", "preview": false}

Preview

POST /api/boards/{id}/forms/preview {definition, answers} (SDK bot.forms.preview) validates an unsaved definition and answers without creating tasks, task numbers or webhook deliveries. The answer is {receiptId: "", preview: true}, or a validation error.

Errors

All errors below are 409 CONFLICT with the given reason; field errors are 422 VALIDATION with field.

reasonMeaning
FORM_CHANGEDThe form changed — reload revision
NONCE_CONFLICTThe nonce was already used for different content
FORM_TARGET_UNAVAILABLEThe status the form creates tasks in was removed
PLAN_LIMITThe plan's form limit per board
FEATURE_DISABLEDThe “Forms” feature is off on the board

Request and response types come from @calaba/protocol. The common error format is described in Errors and limits.