Skip to content

Object Types API

The Object Types API allows organizations to define custom object types with specific schemas and behaviors.

Register Object Type

Registers a new custom object type for the organization. This enables the creation of specialized objects on boards with custom schemas and behaviors.

  • URL: /object-types
  • Method: POST
  • Headers:
    • X-API-Key: Organization API key (Required)
  • Body:
json
{
  "typeName": "vocabulary-card",
  "displayName": "Vocabulary Card",
  "category": "educational", // Optional
  "schema": {
    "type": "object",
    "properties": {
      "word": { "type": "string", "minLength": 1 },
      "translation": { "type": "string", "minLength": 1 },
      "pronunciation": { "type": "string", "format": "uri" },
      "image_url": { "type": "string", "format": "uri" }
    },
    "required": ["word", "translation"]
  },
  "renderConfig": {
    "component": "VocabularyCard",
    "defaultProps": { "width": 200, "height": 150 },
    "previewTemplate": "<div>{{word}} - {{translation}}</div>"
  },
  "interactions": { // Optional
    "draggable": true,
    "resizable": true,
    "editable": true
  }
}

Response (201 Created)

json
{
  "id": "uuid",
  "name": "vocabulary-card",
  "schema": { ... },
  "organization_id": "org-uuid",
  "created_at": "2025-11-17T10:00:00.000Z"
}

Get All Object Types

Retrieves all custom object types registered for the authenticated organization.

  • URL: /object-types
  • Method: GET
  • Headers:
    • X-API-Key: Organization API key (Required)

Response

json
[
  {
    "id": "uuid",
    "name": "vocabulary-card",
    "schema": { ... },
    "organization_id": "org-uuid",
    "created_at": "2025-11-17T10:00:00.000Z"
  }
]

Get Object Type by Name

Retrieves a specific custom object type by its name.

  • URL: /object-types/:typeName
  • Method: GET
  • Headers:
    • X-API-Key: Organization API key (Required)

Response

json
{
  "id": "uuid",
  "name": "vocabulary-card",
  "schema": { ... },
  "organization_id": "org-uuid",
  "created_at": "2025-11-17T10:00:00.000Z"
}

When to Use Object Types

Object Types are best for structured data cards that need validation but don't require complex interactivity.

Object Types vs Components SDK

Choose Object Types when:

  • You need simple, validated data structures
  • Data is primarily displayed, not interactive
  • You want server-side rendering templates
  • Use case: vocabulary cards, task cards, simple quizzes

Choose Components SDK when:

  • You need complex UI and interactions
  • State management across participants is required
  • You want full control over rendering
  • Use case: Planning Poker, collaborative diagrams, games

Comparison Table

FeatureObject TypesComponents SDK
RenderingServer templateCustom iframe
InteractivityRead-only displayFull JavaScript control
State SynccustomData onlyShared storage (CRDT-like)
ValidationJSON SchemaCustom logic
DevelopmentRegister via APICLI + local dev server
PerformanceLightweightHeavier (iframe)
Use CasesData cards, simple objectsInteractive apps, games

JSON Schema Examples

Example 1: Vocabulary Card

Perfect for language learning platforms.

json
{
  "typeName": "vocabulary-card",
  "displayName": "Vocabulary Card",
  "category": "educational",
  "schema": {
    "type": "object",
    "properties": {
      "word": {
        "type": "string",
        "minLength": 1,
        "maxLength": 100,
        "description": "The word to learn"
      },
      "translation": {
        "type": "string",
        "minLength": 1,
        "maxLength": 100,
        "description": "Translation in target language"
      },
      "pronunciation": {
        "type": "string",
        "format": "uri",
        "description": "URL to audio pronunciation file"
      },
      "image_url": {
        "type": "string",
        "format": "uri",
        "description": "Visual aid image URL"
      },
      "example_sentence": {
        "type": "string",
        "maxLength": 500,
        "description": "Example usage in sentence"
      },
      "difficulty": {
        "type": "string",
        "enum": ["beginner", "intermediate", "advanced"],
        "description": "Difficulty level"
      },
      "tags": {
        "type": "array",
        "items": { "type": "string" },
        "maxItems": 10,
        "description": "Topic tags (e.g., 'food', 'travel')"
      }
    },
    "required": ["word", "translation"]
  },
  "renderConfig": {
    "component": "VocabularyCard",
    "defaultProps": {
      "width": 300,
      "height": 200,
      "showPronunciation": true
    },
    "previewTemplate": "<div class='vocab-card'><h3>{{word}}</h3><p>{{translation}}</p></div>"
  },
  "interactions": {
    "draggable": true,
    "resizable": false,
    "editable": true
  }
}

Use Case: EdTech platforms creating vocabulary lessons. Teachers generate hundreds of cards via AI or import from spreadsheets.


Example 2: Task Card (Project Management)

Kanban-style task tracking.

json
{
  "typeName": "task-card",
  "displayName": "Task Card",
  "category": "productivity",
  "schema": {
    "type": "object",
    "properties": {
      "title": {
        "type": "string",
        "minLength": 1,
        "maxLength": 200,
        "description": "Task title"
      },
      "description": {
        "type": "string",
        "maxLength": 2000,
        "description": "Detailed task description"
      },
      "status": {
        "type": "string",
        "enum": ["todo", "in_progress", "review", "done"],
        "default": "todo"
      },
      "priority": {
        "type": "string",
        "enum": ["low", "medium", "high", "critical"],
        "default": "medium"
      },
      "assignee": {
        "type": "string",
        "description": "Participant ID of assignee"
      },
      "dueDate": {
        "type": "string",
        "format": "date-time",
        "description": "ISO 8601 deadline"
      },
      "estimatedHours": {
        "type": "number",
        "minimum": 0,
        "maximum": 999
      },
      "tags": {
        "type": "array",
        "items": { "type": "string" },
        "maxItems": 5
      },
      "attachments": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "fileId": { "type": "string" },
            "filename": { "type": "string" }
          }
        },
        "maxItems": 10
      }
    },
    "required": ["title", "status"]
  },
  "renderConfig": {
    "component": "TaskCard",
    "defaultProps": {
      "width": 280,
      "height": 180,
      "showAssignee": true,
      "colorByPriority": true
    },
    "previewTemplate": "<div class='task-card'><strong>{{title}}</strong><span class='status'>{{status}}</span></div>"
  }
}

Use Case: Agile teams managing sprints. Each column in Kanban is a Frame, cards move between statuses.


Example 3: Quiz Question

Interactive assessment tool.

json
{
  "typeName": "quiz-question",
  "displayName": "Quiz Question",
  "category": "educational",
  "schema": {
    "type": "object",
    "properties": {
      "question": {
        "type": "string",
        "minLength": 5,
        "maxLength": 500,
        "description": "The question text"
      },
      "questionType": {
        "type": "string",
        "enum": ["multiple_choice", "true_false", "short_answer", "essay"],
        "description": "Type of question"
      },
      "options": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "id": { "type": "string" },
            "text": { "type": "string" },
            "isCorrect": { "type": "boolean" }
          },
          "required": ["id", "text"]
        },
        "minItems": 2,
        "maxItems": 6,
        "description": "Answer options (for multiple choice)"
      },
      "correctAnswer": {
        "type": "string",
        "description": "Correct answer (for short answer/essay)"
      },
      "explanation": {
        "type": "string",
        "maxLength": 1000,
        "description": "Explanation shown after answering"
      },
      "points": {
        "type": "number",
        "minimum": 1,
        "maximum": 100,
        "default": 10,
        "description": "Points awarded for correct answer"
      },
      "difficulty": {
        "type": "string",
        "enum": ["easy", "medium", "hard"]
      },
      "topic": {
        "type": "string",
        "description": "Subject topic"
      },
      "timeLimit": {
        "type": "number",
        "minimum": 10,
        "maximum": 600,
        "description": "Time limit in seconds"
      }
    },
    "required": ["question", "questionType"]
  },
  "renderConfig": {
    "component": "QuizQuestion",
    "defaultProps": {
      "width": 400,
      "height": 300,
      "showFeedback": true
    }
  }
}

Use Case: Online exams with instant feedback. Each question is isolated in a Student Zone for academic integrity.


Best Practices for Schema Design

1. Keep Schemas Focused

Each object type should represent one clear concept. Don't create "universal" objects with dozens of optional fields.

Good:

  • vocabulary-card - language learning
  • task-card - task management
  • quiz-question - assessments

Bad:

  • generic-card - can be anything (too vague)

2. Use Descriptive Property Names

Property names should be self-explanatory and use camelCase.

json
// Good
{
  "firstName": "...",
  "emailAddress": "...",
  "phoneNumber": "..."
}

// Bad
{
  "fn": "...",
  "email": "...",
  "phone": "..."
}

3. Set Reasonable Constraints

Use minLength, maxLength, minimum, maximum to prevent abuse and ensure data quality.

json
{
  "title": {
    "type": "string",
    "minLength": 1,    // Prevent empty strings
    "maxLength": 200   // Prevent excessive data
  }
}

4. Leverage Enums for Fixed Options

Use enum instead of free-form strings when options are limited.

json
{
  "status": {
    "type": "string",
    "enum": ["draft", "published", "archived"]
  }
}

This enables:

  • Frontend dropdowns
  • Validation
  • Filtering and search

5. Use Standard Formats

JSON Schema supports formats like uri, email, date-time.

json
{
  "website": {
    "type": "string",
    "format": "uri"
  },
  "dueDate": {
    "type": "string",
    "format": "date-time"  // ISO 8601
  }
}

6. Provide Descriptions

Always include description fields for documentation.

json
{
  "difficulty": {
    "type": "string",
    "enum": ["beginner", "intermediate", "advanced"],
    "description": "Difficulty level for content targeting"
  }
}

Validation

Server-Side Validation

All object creation and updates are validated against the registered schema:

  1. Schema Syntax Check - When registering object type
  2. Data Validation - When creating/updating objects
  3. Type Enforcement - customData must match schema

Validation Errors

Example Request:

bash
POST /boards/:uuid/objects
{
  "type": "vocabulary-card",
  "customData": {
    "word": "",  // Too short (minLength: 1)
    "translation": "hello"
  }
}

Response (400 Bad Request):

json
{
  "statusCode": 400,
  "message": "Validation failed",
  "errors": [
    {
      "field": "customData.word",
      "constraint": "minLength",
      "message": "Property 'word' must have minimum length of 1"
    }
  ]
}

Client-Side Validation

Fetch schema before creating objects to validate on frontend:

typescript
// Fetch schema
const schema = await fetch('/api/v1/object-types/vocabulary-card', {
  headers: { 'X-API-Key': apiKey }
}).then(r => r.json());

// Use schema for form validation
import Ajv from 'ajv';
const ajv = new Ajv();
const validate = ajv.compile(schema.schema);

const isValid = validate({
  word: formData.word,
  translation: formData.translation
});

if (!isValid) {
  console.error(validate.errors);
}

Error Handling

Common Errors

409 Conflict - Object Type Already Exists

json
{
  "statusCode": 409,
  "message": "Object type \"vocabulary-card\" already exists"
}

Solution: Use a different typeName or update existing type (if supported).


400 Bad Request - Invalid Schema

json
{
  "statusCode": 400,
  "message": "Invalid JSON Schema",
  "errors": [
    {
      "message": "Property 'type' is required in schema"
    }
  ]
}

Solution: Ensure schema follows JSON Schema Draft 7 specification.


402 Payment Required - Quota Exceeded

json
{
  "statusCode": 402,
  "message": "Object type quota exceeded",
  "current": 10,
  "limit": 10,
  "upgradeRequired": true
}

Solution: Upgrade plan or delete unused object types.


404 Not Found - Object Type Not Found

json
{
  "statusCode": 404,
  "message": "Object type \"task-card\" not found"
}

Solution: Check typeName spelling or register the type first.


Quota Limits

Object types are subject to plan limits:

PlanMax Object TypesDescription
Starter3Basic types only
Professional10Most common use cases
Business50Multi-product platforms
EnterpriseUnlimitedCustom limits

Check current usage:

bash
GET /quota/usage

Tips and Tricks

Versioning Schemas

Object type schemas are immutable after creation. To evolve:

  1. Additive Changes - Add optional properties (backward compatible)
  2. New Type - Create vocabulary-card-v2 for breaking changes
  3. Migration - Update existing objects to new type via API

Reusing Schemas

Store common schema fragments in your codebase:

typescript
// schemas/common.ts
export const personSchema = {
  type: "object",
  properties: {
    name: { type: "string" },
    email: { type: "string", format: "email" }
  }
};

// Compose in object types
const taskSchema = {
  type: "object",
  properties: {
    title: { type: "string" },
    assignee: personSchema  // Reuse
  }
};

Testing Schemas

Before registering in production, test with sample data:

typescript
import Ajv from 'ajv';

const schema = { /* your schema */ };
const testData = { /* sample object */ };

const ajv = new Ajv();
const validate = ajv.compile(schema);
const isValid = validate(testData);

console.log(isValid ? 'Valid' : validate.errors);