# Zucms

## RESTful API

> Category: API

---

## Pages

- [Introduction](https://docs.zucms.co/introduction)

### API

- [RESTful API](https://docs.zucms.co/api/rest)

---

# RESTful API

This document explains how to use the LWAPI entry endpoints.

## Base URL

Use the LWAPI server base URL and append the routes below:

```text
/api/models/{modelKey}/entries
```

Example:

```text
/api/models/articles/entries
```

## Authentication

Every request to `/api/*` requires an API key.

Use one of these headers:

```http
Authorization: Bearer <api-key>
```

or

```http
x-api-key: <api-key>
```

The tenant is resolved automatically from the organization behind the API key.

## Entry Object

All entry responses use this shape:

```json
{
	"id": "680dff1d8f1b3c1f1a6f7a12",
	"tenantId": "tenant_123",
	"modelKey": "articles",
	"data": {
		"title": "Hello world",
		"status": "published"
	},
	"createdAt": "2025-01-01T10:00:00.000Z",
	"updatedAt": "2025-01-01T10:00:00.000Z"
}
```

`data` contains the model fields. Relation fields are also returned inside `data`.

## Endpoints

### 1. List entries

```http
GET /api/models/{modelKey}/entries
```

Returns paginated entries for one model.

Supported query parameters:

- `page`: Integer, default `1`
- `pageSize`: Integer, default `25`, max `100`
- `sort`: Comma-separated fields, for example `title,-createdAt`
- `search`: Full text search across serialized `data`
- `fields`: Comma-separated projection of `data` fields
- `include`: Comma-separated relation field names to resolve
- `filter[field][operator]`: Field filters

Supported filter operators:

- `eq`
- `ne`
- `contains`
- `startsWith`
- `endsWith`
- `in`
- `nin`
- `gt`
- `gte`
- `lt`
- `lte`
- `exists`

Example request:

```http
GET /api/models/articles/entries?page=1&pageSize=10&sort=-createdAt&search=hello&fields=title,status,author&include=author&filter[status][eq]=published
```

Example response:

```json
{
	"data": [
		{
			"id": "680dff1d8f1b3c1f1a6f7a12",
			"tenantId": "tenant_123",
			"modelKey": "articles",
			"data": {
				"title": "Hello world",
				"status": "published",
				"author": {
					"id": "680dff1d8f1b3c1f1a6f7b45",
					"tenantId": "tenant_123",
					"modelKey": "authors",
					"data": {
						"name": "Jane Doe"
					},
					"createdAt": "2025-01-01T09:00:00.000Z",
					"updatedAt": "2025-01-01T09:00:00.000Z"
				}
			},
			"createdAt": "2025-01-01T10:00:00.000Z",
			"updatedAt": "2025-01-01T10:00:00.000Z"
		}
	],
	"meta": {
		"tenantId": "tenant_123",
		"modelKey": "articles",
		"page": 1,
		"pageSize": 10,
		"total": 1,
		"totalPages": 1,
		"sort": ["-createdAt"],
		"filters": {
			"status": {
				"eq": "published"
			}
		},
		"search": "hello",
		"fields": ["title", "status", "author"],
		"include": ["author"]
	}
}
```

Notes:

- If `fields` is used, only selected keys from `data` are returned.
- Included relation fields are automatically added to the projection.
- `include` only resolves relation fields that exist on the model.

### 2. Get a single entry

```http
GET /api/models/{modelKey}/entries/{entryId}
```

Returns one entry by ID.

Example request:

```http
GET /api/models/articles/entries/680dff1d8f1b3c1f1a6f7a12
```

Example response:

```json
{
	"data": {
		"id": "680dff1d8f1b3c1f1a6f7a12",
		"tenantId": "tenant_123",
		"modelKey": "articles",
		"data": {
			"title": "Hello world",
			"status": "published"
		},
		"createdAt": "2025-01-01T10:00:00.000Z",
		"updatedAt": "2025-01-01T10:00:00.000Z"
	}
}
```

### 3. Create an entry

```http
POST /api/models/{modelKey}/entries
```

Request body:

```json
{
	"data": {
		"title": "New article",
		"status": "draft"
	}
}
```

Current status:

`POST` is routed and documented in the API, but the repository implementation is not available yet. At the moment this endpoint will fail on the server side.

### 4. Update an entry

```http
PATCH /api/models/{modelKey}/entries/{entryId}
```

Request body:

```json
{
	"data": {
		"status": "published"
	}
}
```

Current status:

`PATCH` is routed and documented in the API, but the repository implementation is not available yet. At the moment this endpoint will fail on the server side.

### 5. Delete an entry

```http
DELETE /api/models/{modelKey}/entries/{entryId}
```

Success response shape:

```json
{
	"data": {
		"id": "680dff1d8f1b3c1f1a6f7a12",
		"deleted": true
	}
}
```

Current status:

`DELETE` is routed and documented in the API, but the repository implementation is not available yet. At the moment this endpoint will fail on the server side.

## Error Format

Errors use this format:

```json
{
	"error": {
		"code": "VALIDATION_ERROR",
		"message": "Invalid request payload",
		"details": {}
	}
}
```

Common error codes:

- `UNAUTHORIZED`
- `VALIDATION_ERROR`
- `NOT_FOUND`
- `INTERNAL_SERVER_ERROR`

