Skip to Content
ConnectItems API

Items API

The Items API is the primary interface for reading and writing data in any collection. It supports full CRUD with filtering, sorting, pagination, field selection, aggregation, and deep relational reads.

GET /api/items/:collection POST /api/items/:collection GET /api/items/:collection/:id PATCH /api/items/:collection/:id PUT /api/items/:collection/:id DELETE /api/items/:collection/:id PATCH /api/items/:collection (batch update) DELETE /api/items/:collection (batch delete)

Replace :collection with the name of any table in your database (e.g., posts, products). Permissions are enforced per collection — a request will 403 if the user’s role doesn’t have the required permission.

List Items

GET /api/items/:collection

Query Parameters

ParameterDescriptionExample
fieldsComma-separated field names to return?fields=id,title,author
filterFilter rules (see Filter Rules)?filter[status][_eq]=published
sortField to sort by. Prefix with - for descending?sort=-created_at
limitNumber of items to return (default 25, always applied)?limit=20
pagePage number for pagination (default 1)?page=2
searchSubstring search across string fields (ILIKE)?search=hello
aggregateAggregate functions?aggregate[count]=*
groupByGroup results by one or more fields (comma-separated). Requires aggregate?groupBy=status&aggregate[count]=*

Example

curl "https://your-domain.com/api/items/posts?fields=id,title,status&filter[status][_eq]=published&sort=-created_at&limit=10" \ -H "Authorization: Bearer <token>"

Response:

{ "data": [ { "id": 1, "title": "Hello World", "status": "published" }, { "id": 2, "title": "Second Post", "status": "published" } ], "meta": { "total_count": 42, "total": 42, "page": 1, "limit": 25 } }

Get Single Item

GET /api/items/:collection/:id
curl "https://your-domain.com/api/items/posts/1?fields=*,author.*" \ -H "Authorization: Bearer <token>"

The fields=*,author.* pattern includes all top-level fields plus all fields from the related author record (deep read).

Pass ?version=<key> to retrieve the item with a specific content version’s delta merged in (e.g., ?version=draft).

Create Item

POST /api/items/:collection
curl -X POST "https://your-domain.com/api/items/posts" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"title": "New Post", "status": "draft", "body": "Hello!"}'

Returns the created item with its generated id and status 201 Created.

Upsert Item

PUT /api/items/:collection/:id

Creates the item if it doesn’t exist, or replaces it entirely if it does. Unlike PATCH (partial update), PUT requires all writable fields in the request body — any omitted fields will be set to null.

curl -X PUT "https://your-domain.com/api/items/posts/1" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"title": "Updated Title", "status": "published", "body": "Full content"}'

Update Item (Partial)

PATCH /api/items/:collection/:id

Only the fields included in the request body are updated (partial update).

curl -X PATCH "https://your-domain.com/api/items/posts/1" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"status": "published"}'

Delete Item

DELETE /api/items/:collection/:id

Returns 200 with { data: { deleted: true, id } } on success.

Batch Operations

The filter parameter is required for batch update and batch delete. Omitting it returns 400 with { "error": "Filter parameter required for batch update" }.

Batch update

Update multiple items matching a filter. The filter query parameter must be JSON-encoded:

curl -X PATCH "https://your-domain.com/api/items/posts?filter=%7B%22status%22%3A%7B%22_eq%22%3A%22draft%22%7D%7D" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"status": "archived"}'

Or pass the filter as a JSON string in the URL:

# URL-decoded for readability: ?filter={"status":{"_eq":"draft"}} curl -X PATCH "https://your-domain.com/api/items/posts" \ -G --data-urlencode 'filter={"status":{"_eq":"draft"}}' \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"status": "archived"}'

Batch delete

Delete multiple items matching a filter. The filter query parameter must be JSON-encoded:

curl -X DELETE "https://your-domain.com/api/items/posts" \ -G --data-urlencode 'filter={"status":{"_eq":"archived"}}' \ -H "Authorization: Bearer <token>"

Batch update response (200):

{ "data": { "updated": 3, "keys": [1, 5, 12] } }

Batch delete response (200):

{ "data": { "deleted": 2, "keys": [8, 15] } }

The MAX_BATCH_MUTATION environment variable controls the maximum number of items that can be mutated in a single batch request (default: 100).

Aggregates

GET /api/items/posts?aggregate[count]=*&aggregate[avg]=views&groupBy=status
{ "data": [ { "count": { "*": 15 }, "avg": { "views": 243.6 }, "status": "published" }, { "count": { "*": 8 }, "avg": { "views": 12.1 }, "status": "draft" } ] }

Supported functions: count, countDistinct, countAll, sum, sumDistinct, avg, avgDistinct, min, max.

  • count / countDistinct: Counts non-null values of a specific field (e.g., ?aggregate[count]=id).
  • countAll: Counts all rows regardless of field values (e.g., ?aggregate[countAll]=*). Use * as the field argument.

Relational Data

Fetch related items inline using dot notation in fields:

?fields=id,title,author.name,author.email,tags.tag_id.name
  • author.name — M2O: the author’s name
  • tags.tag_id.name — M2M junction: the tag name through the junction table

Use the * wildcard to include all fields from a related collection:

?fields=*,author.*

This returns all top-level fields plus all fields from the author relation.

Error Responses

Errors return a JSON body with at least an error key, and some errors include a code field for programmatic handling:

{ "error": "Not authenticated" } { "error": "Item not found", "code": "NOT_FOUND" }

Common HTTP status codes:

CodeMeaning
400Bad request (invalid parameters, missing required filter)
401Not authenticated
403Forbidden (insufficient permissions)
404Item or collection not found
500Internal server error

Scope & Multi-tenancy

Every request is scoped to a resource URI via the X-Resource-URI header or a cookie. This header controls which tenant/project the request operates within. Omitted or invalid resource URIs result in authorization errors.

Delegation

Service accounts can act on behalf of other users by setting the X-On-Behalf-Of header to the target user ID. This is useful for automation and background jobs.

Authentication

Requests can be authenticated using either:

  • Bearer token: Authorization: Bearer <token> header
  • Cookie-based auth: Browser clients with an active session cookie

Field-Level Permissions

Non-admin users receive filtered response objects — fields they don’t have permission to read are stripped from the response. Admins see all fields.

PATCH vs PUT

MethodBehavior
PATCHPartial update — only the fields in the request body are changed
PUTUpsert — creates the item if it doesn’t exist, or fully replaces it. Omitted fields are set to null
Last updated on