Projects API
REST API reference for managing projects in Laizy CMS.
Projects API
Projects are the top-level container for content in Laizy CMS. Each project has its own content models, content entries, and access controls. Projects are scoped to an organization and can be shared with other organizations via role-based access.
Authentication
All project endpoints require an admin-scoped token:
Authorization: Bearer laizy_eyJhbGciOiJI...The organization context is resolved from the token itself (the orgId claim in the JWT). No x-laizy-project header is needed for project management endpoints -- these operate at the organization level.
| Endpoint | Required Access |
|---|---|
project.create | Org admin |
project.list | Org admin |
project.getById | Project admin |
project.getBySlug | Project admin |
project.update | Project admin |
project.archive | Project admin |
project.restore | Project admin |
project.share | Project admin |
project.revokeAccess | Project admin |
project.transfer | Project admin |
project.getAccess | Project admin |
project.hasAccess | Project admin |
project.getOrCreateDefault | Org admin |
project.create
Create a new project within the current organization.
Input
{
slug: string; // URL-safe identifier (lowercase, numbers, hyphens)
name: string; // Display name (1-100 characters)
description?: string; // Optional description (max 500 characters)
}Slug validation rules:
- 1-63 characters long
- Only lowercase letters, numbers, and hyphens (
^[a-z0-9-]+$) - Must be unique within the organization
Response
{
id: string;
name: string;
slug: string;
description: string | null;
organizationId: string;
status: 'active' | 'archived';
createdByMemberId: string;
createdAt: Date;
updatedAt: Date;
}Example with ManagementClient
const project = await client.createProject({
name: 'Marketing Website',
slug: 'marketing-website',
description: 'Content for the main marketing site',
});
console.log(project.id); // "proj_abc123"
console.log(project.slug); // "marketing-website"Errors
| Code | Cause |
|---|---|
BAD_REQUEST | Invalid slug format or slug already taken |
UNAUTHORIZED | Token does not have org admin access |
project.list
List all projects accessible to the current organization.
Input
{
includeArchived?: boolean; // Default: false
}Response
Returns an array of projects. By default, archived projects are filtered out.
[
{
id: string;
name: string;
slug: string;
description: string | null;
organizationId: string;
status: 'active' | 'archived';
createdAt: Date;
updatedAt: Date;
}
]Example with ManagementClient
// Active projects only
const projects = await client.listProjects();
// Include archived
const allProjects = await fetch(
'https://laizycms.com/api/trpc/project.list?input={"includeArchived":true}',
{
headers: { 'Authorization': `Bearer ${apiToken}` },
},
);project.getById
Fetch a single project by its unique ID.
Input
{
id: string; // Project ID
}Response
Returns the full project object or throws NOT_FOUND.
Example with ManagementClient
const project = await client.getProject('proj_abc123');
console.log(project.name); // "Marketing Website"Errors
| Code | Cause |
|---|---|
NOT_FOUND | Project does not exist or organization has no access |
project.getBySlug
Fetch a project by its slug. Optionally specify a different organization to look up shared projects.
Input
{
slug: string;
organizationId?: string; // Defaults to current org
}Response
Returns the full project object or throws NOT_FOUND. If looking up a project in another organization, the endpoint verifies that the current organization has been granted access.
Example
const response = await fetch(
'https://laizycms.com/api/trpc/project.getBySlug?input={"slug":"marketing-website"}',
{
headers: { 'Authorization': `Bearer ${apiToken}` },
},
);Errors
| Code | Cause |
|---|---|
NOT_FOUND | Project does not exist |
FORBIDDEN | Organization does not have access to this project |
project.update
Update a project's metadata. Supports partial updates -- only include the fields you want to change.
Input
{
id: string;
data: {
name?: string; // 1-100 characters
slug?: string; // URL-safe identifier
description?: string; // Max 500 characters
};
}Response
Returns the updated project.
Example with ManagementClient
const updated = await client.updateProject('proj_abc123', {
name: 'Main Marketing Website',
description: 'Updated description',
});Errors
| Code | Cause |
|---|---|
NOT_FOUND | Project does not exist |
BAD_REQUEST | Invalid slug format or slug conflict |
FORBIDDEN | Insufficient permissions |
project.archive
Soft-delete a project by setting its status to archived. The project and its content are preserved but hidden from default list queries.
Input
{
id: string; // Project ID to archive
}Response
Returns the archived project with status: 'archived'.
Example
const archived = await fetch(
'https://laizycms.com/api/trpc/project.archive',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${apiToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ id: 'proj_abc123' }),
},
);Errors
| Code | Cause |
|---|---|
FORBIDDEN | Only the owning organization can archive a project |
project.restore
Restore an archived project back to active status.
Input
{
id: string; // Project ID to restore
}Response
Returns the restored project with status: 'active'.
Errors
| Code | Cause |
|---|---|
FORBIDDEN | Only the owning organization can restore a project |
project.share
Share a project with another organization by granting them a role.
Input
{
projectId: string;
targetOrgId: string; // Organization to share with
role: 'owner' | 'editor' | 'content_editor'; // Access level to grant
}Roles
| Role | Permissions |
|---|---|
owner | Full access including delete, share, and transfer |
editor | Manage content models and content data |
content_editor | Create and edit content entries only |
Response
Returns the created access record:
{
id: string;
projectId: string;
organizationId: string;
role: string;
grantedByMemberId: string;
createdAt: Date;
}Example
const access = await fetch(
'https://laizycms.com/api/trpc/project.share',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${apiToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
projectId: 'proj_abc123',
targetOrgId: 'org_xyz789',
role: 'editor',
}),
},
);Errors
| Code | Cause |
|---|---|
FORBIDDEN | Only the owning organization can share a project |
project.revokeAccess
Remove another organization's access to a project.
Input
{
projectId: string;
targetOrgId: string; // Organization to remove
}Response
{
success: boolean;
}Errors
| Code | Cause |
|---|---|
FORBIDDEN | Only the owning organization can revoke access |
BAD_REQUEST | Cannot revoke the owning organization's access |
You cannot revoke the owning organization's access to a project. To change ownership, use project.transfer instead.
project.transfer
Transfer project ownership to another organization. The original owner loses their owner role.
Input
{
projectId: string;
newOrganizationId: string; // New owner organization
}Response
Returns the updated project with the new organizationId.
Errors
| Code | Cause |
|---|---|
FORBIDDEN | Only the current owner can transfer ownership |
project.getAccess
List all organizations that have access to a project, including their roles.
Input
{
projectId: string;
}Response
Returns an array of access records:
[
{
organizationId: string;
role: 'owner' | 'editor' | 'content_editor';
grantedByMemberId: string;
createdAt: Date;
}
]Errors
| Code | Cause |
|---|---|
FORBIDDEN | Current organization does not have access to this project |
project.hasAccess
Check whether the current organization has access to a project, optionally verifying a specific role.
Input
{
projectId: string;
requiredRole?: 'owner' | 'editor' | 'content_editor';
}Response
{
hasAccess: boolean;
}project.getOrCreateDefault
Get the default project for the organization, creating one if it does not exist. This is used during onboarding to ensure every organization has at least one project.
Input
No additional input required. The organization is resolved from the token.
Response
Returns the default project (created if necessary).
Next Steps
- Authentication -- Token types and scopes
- Content Models API -- Managing schemas within a project
- Content Data API -- CRUD operations scoped to a project