Forms

Build public forms with the GraphQL API — create a form, configure its fields, and collect submissions that become records in a workspace.


A form is a public page that collects responses and turns each submission into a record in a workspace. Forms are Form objects scoped to a workspace (Project in the API); each visible input is a FormField, and a submission creates a Todo (record) in the form’s target list.

There are two sides to the API:

  • Building & managing forms (authenticated) — create a form, add and order its fields, theme it, and activate it. Requires project-level OWNER, ADMIN, or MEMBER.
  • Submitting a form (public) — submitForm is unauthenticated and rate-limited, so a respondent never needs an account or token header. This is what Blue’s hosted form page calls.

All authenticated examples use personal access token headers and target https://api.blue.app. See Authentication for how to generate a token.

List forms

forms returns a paginated list of the forms in one workspace.

query ListForms {
  forms(filter: { projectId: "project_123" }, sort: updatedAt_DESC, take: 20) {
    items {
      id
      title
      isActive
    }
  }
}
ArgumentTypeRequiredDescription
filterFormFilterInputNo{ projectId } — scope to one workspace (its id, a CUID).
sortFormSortNoupdatedAt_DESC (default) or title_ASC.
skipIntNoOffset for pagination. Default 0.
takeIntNoPage size. Default 20.

The result is a FormPagination with items (an array of Form) and pageInfo.

Get one form

form fetches a single form — including its ordered formFields — by id.

query GetForm {
  form(id: "form_123") {
    id
    title
    description
    isActive
    primaryColor
    formFields {
      id
      field
      name
      required
      position
    }
  }
}

Create a form

createForm creates an empty form in a workspace. Only projectId is needed to start; everything else has sensible defaults you can fill in later with updateForm.

mutation CreateForm {
  createForm(
    input: {
      projectId: "project_123"
      title: "Contact us"
      description: "Tell us how we can help."
      primaryColor: "#2563eb"
      hideBranding: false
    }
  ) {
    id
    title
    isActive
  }
}

CreateFormInput

FieldTypeRequiredDescription
projectIdStringYesWorkspace id (CUID) the form belongs to.
titleStringNoForm title shown to respondents.
descriptionStringNoIntro text under the title.
primaryColorStringNoAccent color, hex (e.g. #2563eb).
hideBrandingBooleanNoHide the “Powered by Blue” footer.
assigneeIds[String!]NoUsers auto-assigned to records this form creates.

A new form is not active until you set isActive: true with updateForm.

Add and update fields

A form’s inputs are FormField rows. upsertFormField both creates and edits a field: pass an existing formFieldId to update it, or a new id to create one. field selects what the input maps to — a built-in record property or a custom field.

mutation AddNameField {
  upsertFormField(
    input: {
      formId: "form_123"
      formFieldId: "field_new_1"
      field: title
      name: "Your name"
      placeholder: "Ada Lovelace"
      required: true
      position: 1
    }
  ) {
    id
    field
    name
    required
    position
  }
}

UpsertFormFieldInput

FieldTypeRequiredDescription
formIdString!YesThe form to add the field to.
formFieldIdString!YesExisting field id to update, or a new id to create.
fieldFormFieldsField!YesWhat the input maps to (see below).
customFieldIdStringWhen field: customThe workspace custom field this input writes to.
nameStringNoLabel shown above the input.
placeholderStringNoPlaceholder text inside the input.
positionFloatNoOrder within the form (ascending).
requiredBooleanNoWhether a response is mandatory.
hiddenBooleanNoHide the field from the public form (e.g. a pre-filled value).
addToDescriptionBooleanNoAppend the field’s value to the created record’s description.
extraInfoStringNoHelper text shown under the input.

field accepts: title, description, tags, assignees, startedAt, duedAt, or custom. Use custom together with customFieldId to collect a value for one of the workspace’s custom fields.

List a form’s fields with formFields:

query FormFields {
  formFields(filter: { formId: "form_123" }) {
    id
    field
    name
    required
    position
  }
}

Remove a field with deleteFormField(id: "field_123"), which returns Boolean.

Update a form

updateForm edits any form property and is how you activate a form (isActive: true) once its fields are in place.

mutation ActivateForm {
  updateForm(
    input: {
      id: "form_123"
      isActive: true
      submitText: "Send"
      responseText: "Thanks — we'll be in touch."
      redirectURL: "https://example.com/thank-you"
    }
  ) {
    id
    isActive
  }
}

UpdateFormInput covers the visible form: title, description, footerText, showFooter, submitText, responseText, theme, primaryColor, hideBranding, imageURL, redirectURL, isActive, plus assigneeIds, tagIds, and todoListId (the list new records land in).

Copy a form

copyForm duplicates a form — and its fields — into a workspace.

mutation CopyForm {
  copyForm(input: { formId: "form_123", projectId: "project_456", title: "Contact us (copy)" }) {
    id
    title
  }
}

projectId is required and may be the same workspace or a different one. title is optional; omit it to keep the source title.

Delete a form

deleteForm(id: "form_123") deletes a form and returns Boolean.

mutation DeleteForm {
  deleteForm(id: "form_123")
}

Submit a form

submitForm is public — no authentication header, rate-limited. Each submission creates a record in the form’s target list. This is the call Blue’s hosted form page makes; use it directly only when you render your own form UI.

mutation SubmitForm {
  submitForm(
    input: {
      formId: "form_123"
      formToken: "form_123_token"
      formFieldInput: [
        { formFieldId: "field_1", value: "Ada Lovelace" }
        { formFieldId: "field_2", value: "ada@example.com" }
      ]
    }
  )
}

SubmitFormInput

FieldTypeRequiredDescription
formIdString!YesThe form being submitted.
formTokenString!YesThe form’s submission token.
formFieldInput[SubmitFormFieldInput!]!YesOne entry per answered field.

Each SubmitFormFieldInput is { formFieldId, customFieldId, value }, where value is JSON (a string, number, or structured value matching the field). The mutation returns Booleantrue once the record is created.

Watch for changes

subscribeToForm streams create/update/delete events for the forms in a workspace.

subscription WatchForms {
  subscribeToForm(filter: { projectId: "project_123" }) {
    mutation
    node {
      id
      title
      isActive
    }
    updatedFields
  }
}

mutation is CREATED, UPDATED, or DELETED; node is the affected Form.

Permissions

OperationRequirement
form, forms, createForm, updateForm, copyForm, deleteForm, upsertFormFieldProject-level OWNER, ADMIN, or MEMBER on the workspace.
deleteFormFieldAny authenticated user.
submitFormPublic — no authentication, rate-limited.