Laizy CMS
API Reference

Content Models API

REST API reference for managing content models in Laizy CMS.

Content Models API

Content model endpoints manage the schema definitions that structure your content. Each content model maps to a model block in your .laizy schema file and defines the fields, types, and constraints for a category of content.

Authentication

All content model endpoints require authentication via the Authorization header and project context via the x-laizy-project header:

Authorization: Bearer laizy_eyJhbGciOiJI...
x-laizy-project: <project-id>
EndpointRequired Scope
contentModel.listcontent:read or admin
contentModel.getcontent:read or admin
contentModel.existscontent:read or admin
contentModel.createadmin
contentModel.updateadmin
contentModel.deleteadmin
contentModel.createFromSchemaadmin

contentModel.list

List all content models in the current project.

Input

{
  // No additional input required
  // Project is resolved from the x-laizy-project header
}

Response

Returns an array of content models:

[
  {
    id: string;
    name: string;                     // "BlogPost"
    schemaAST: ModelDefinition;       // Parsed schema structure
    projectId: string;
    createdAt: Date;
    updatedAt: Date;
  }
]

The schemaAST contains the full parsed model definition:

interface ModelDefinition {
  type: 'model';
  name: string;
  fields: Array<{
    name: string;
    fieldType: 'String' | 'Int' | 'Float' | 'Boolean' | 'DateTime';
    constraints: {
      required?: boolean;
      unique?: boolean;
      default?: string | number | boolean;
      maxLength?: number;
      minLength?: number;
    };
  }>;
}

Example with ManagementClient

const models = await client.listContentModels();

for (const model of models) {
  console.log(`${model.name}: ${model.schemaAST.fields.length} fields`);
}

Example with fetch

const response = await fetch(
  'https://laizycms.com/api/trpc/contentModel.list?input={}',
  {
    headers: {
      'Authorization': `Bearer ${apiToken}`,
      'x-laizy-project': projectId,
      'Content-Type': 'application/json',
    },
  },
);

const { result } = await response.json();
const models = result.data;

contentModel.get

Fetch a single content model by name.

Input

{
  name: string;    // Required -- model name (e.g. "BlogPost")
}

Response

Returns the content model or throws NOT_FOUND:

{
  id: string;
  name: string;
  schemaAST: ModelDefinition;
  projectId: string;
  createdAt: Date;
  updatedAt: Date;
}

Example with ManagementClient

const model = await client.getContentModel('BlogPost');

if (model) {
  console.log(`Fields: ${model.schemaAST.fields.map(f => f.name).join(', ')}`);
  // Fields: title, content, status, slug
} else {
  console.log('Model not found');
}

Errors

CodeCause
NOT_FOUNDModel does not exist in the project
UNAUTHORIZEDInvalid or missing authentication

contentModel.create

Create a new content model by providing a model name and its schema AST.

Input

{
  name: string;                // Model name (must match schemaAST.name)
  schemaAST: ModelDefinition;  // Full parsed model definition
}

Response

Returns the created content model:

{
  id: string;
  name: string;
  schemaAST: ModelDefinition;
  projectId: string;
  createdAt: Date;
  updatedAt: Date;
}

Example

const model = await fetch(
  'https://laizycms.com/api/trpc/contentModel.create',
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiToken}`,
      'x-laizy-project': projectId,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      name: 'Product',
      schemaAST: {
        type: 'model',
        name: 'Product',
        fields: [
          {
            name: 'title',
            fieldType: 'String',
            constraints: { required: true, maxLength: 200 },
          },
          {
            name: 'price',
            fieldType: 'Float',
            constraints: { required: true },
          },
          {
            name: 'inStock',
            fieldType: 'Boolean',
            constraints: { default: true },
          },
        ],
      },
    }),
  },
);

Errors

CodeCause
CONFLICTA model with this name already exists
BAD_REQUESTSchema AST name does not match the provided name
UNAUTHORIZEDToken does not have admin scope

In practice, you rarely call contentModel.create directly. The laizy sync command handles model creation as part of the schema synchronization workflow, which also manages updates and deletions.

contentModel.update

Update an existing content model's schema definition.

Input

{
  name: string;                // Existing model name
  schemaAST: ModelDefinition;  // Updated model definition
}

Response

Returns the updated content model.

Errors

CodeCause
NOT_FOUNDModel does not exist
BAD_REQUESTSchema AST name does not match the provided name
UNAUTHORIZEDToken does not have admin scope

contentModel.delete

Delete a content model and its associated metadata. Content data associated with the model is not automatically deleted by this endpoint.

Input

{
  name: string;    // Model name to delete
}

Response

{
  success: boolean;
}

Errors

CodeCause
NOT_FOUNDModel does not exist
UNAUTHORIZEDToken does not have admin scope

Deleting a content model removes its schema definition. The laizy sync command handles model deletion as part of the full diff workflow and includes impact analysis to warn you about content entries that will be affected.

contentModel.exists

Check whether a content model exists in the current project without fetching its full definition.

Input

{
  name: string;    // Model name to check
}

Response

{
  exists: boolean;
}

contentModel.createFromSchema

Create a content model from a raw .laizy schema string instead of a pre-parsed AST. The server parses the schema and creates the model.

Input

{
  schemaContent: string;   // Raw .laizy schema text
}

Example

const model = await fetch(
  'https://laizycms.com/api/trpc/contentModel.createFromSchema',
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiToken}`,
      'x-laizy-project': projectId,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      schemaContent: `model Product {
  title: String {
    required: true
    maxLength: 200
  }
  price: Float {
    required: true
  }
}`,
    }),
  },
);

Errors

CodeCause
BAD_REQUESTSchema parsing failed, empty schema, or multiple models in input
CONFLICTModel already exists
UNAUTHORIZEDToken does not have admin scope

This endpoint currently supports only single-model schemas. If the schema string contains multiple model blocks, it returns a BAD_REQUEST error.

Schema Sync vs. Direct API

Most content model management is handled through the laizy sync command, which uses the SchemaSyncOrchestrator under the hood. Direct API calls are useful for:

  • Building custom tooling that manages schemas programmatically
  • CI/CD pipelines that need to verify model state
  • Admin dashboards that display schema information

For standard development workflows, prefer laizy sync over direct API calls -- it handles diffing, impact analysis, and safe migration in a single command.

Next Steps

On this page