ioZen Docs

Schema Items

How to read and handle intake bot schema items — questions and content blocks — from the API.

The GET /intake-bots/:id endpoint returns a schema object that describes all items in an intake bot. Items fall into two categories: fields (question items that collect user input) and content blocks (informational items that display content between questions).

Schema Response Shape

{
  "success": true,
  "data": {
    "id": "clxyz...",
    "name": "Onboarding Bot",
    "schema": {
      "fields": [
        {
          "id": "field_1",
          "name": "full_name",
          "label": "What's your full name?",
          "type": "short_text",
          "required": true
        },
        {
          "id": "cb_1",
          "kind": "content",
          "name": "intro_block",
          "label": "Welcome Message",
          "content_type": "static",
          "body": "Thanks **{{full_name}}**! Here's what to expect next..."
        },
        {
          "id": "field_2",
          "name": "company",
          "label": "What company are you with?",
          "type": "short_text",
          "required": false
        }
      ]
    }
  }
}

Distinguishing Item Types

Use the kind field to determine how to handle each item:

kind valueMeaningHas type?Accepts input?
"field" or absentQuestion / input fieldYesYes
"content"Content block (display only)NoNo

Backward compatibility: Fields created before content blocks were introduced do not have a kind property. Treat items without kind, or with kind: "field", as question fields.

for (const item of schema.fields) {
  if (item.kind === 'content') {
    // Display-only item — skip when building submission data
    continue;
  }

  // Regular question field
  console.log(item.name, item.type, item.required);
}

Content Block Fields

FieldTypeDescription
idstringUnique item ID
kind"content"Identifies this as a content block
namestringInternal slug name
labelstring | nullAdmin-facing display name
content_type"plain" | "rich" | "editor" | "ai_generated"Authoring mode — plain (text), rich/editor (Tiptap), ai_generated (runtime AI)
bodystring | nullContent for static types; AI prompt for ai_generated
template_variablesboolean | nullWhether body contains {{field_name}} references
continue_button_textstring | nullLabel for the "Continue" button (defaults to "Continue")
ctasarray | nullCall-to-action buttons (Pro plan only)

ai_generated content blocks

When content_type is "ai_generated", body contains the author's prompt, not the generated output. Generated content is produced at runtime per respondent and stored in the conversation history.

CTAs

Each CTA in the ctas array:

{
  "id": "cta_1",
  "label": "View Pricing",
  "style": "primary",
  "action": "modal",
  "url": "https://example.com/pricing"
}
FieldValuesDescription
idstringUnique CTA identifier
labelstringButton text
style"primary" | "secondary" | "link"Button style
action"modal" | "link"Opens in overlay or new tab
urlstring | nullTarget URL (may contain {{field_name}} references)

Submitting Data

Content blocks are never included in submission data. When creating a submission via the API (POST /intake-bots/:id/submissions), only provide values for field items (those without kind: "content"):

{
  "data": {
    "full_name": "Jane Doe",
    "company": "Acme Corp"
  }
}

Passing a content block name as a key in data has no effect and is silently ignored.

Conditional Logic

Content blocks support the same conditional_logic structure as fields. A content block with conditional logic may or may not appear in a given session depending on the respondent's answers. The schema always returns all items; evaluate conditional_logic client-side if you need to predict which items will be shown.

On this page