HTTP reference

Collections API

Collection routes are defined explicitly in routes/collections.php (not a Laravel Route::resource). Every route requires auth + verified. Most actions also use Spatie permission: middleware; bulk delete/restore/force-delete authorize in the FormRequest. Super-admin bypasses via Gate::before.

Authorization model

Collection schema and item CRUD are gated server-side with PermissionEnum (can-show-collections, can-create-collections, can-edit-collections, can-delete-collections, restore/force-delete). The React UI (useCan) and AI tools share the same names. Item read/write also applies CollectionPermissionEnforcer (role collection_permissions field ACL / item_filter). See Effective permissions.

Headless Public CMS API

For external websites and integrations, use /api/v1/collections... (not these session routes). Auth is anonymous public role or Bearer API keys, gated by the Collection access matrix. See Public CMS API and GraphQL. Runnable companion: externa-bruno (PublicApi + GraphQL). Session pack helpers also live under Bruno Admin/ (not public API).

Relevant permission names:

  • can-show-collections
  • can-create-collections
  • can-edit-collections
  • can-delete-collections
  • can-restore-collections
  • can-force-delete-collections

Collections

MethodPathRoute namePermission / notes
GET/collectionscollections.indexcan-show-collections (search, sort, direction, trashed)
POST/collectionscollections.storecan-create-collections
POST/collections/bulkcollections.bulkFormRequest: delete → delete; restore → restore; force_delete → force-delete
POST/collections/packs/{pack}collections.packs.applycan-create-collections (collection pack; auto-create deps)
GET/collections/{collection}collections.showcan-show-collections
PUT/collections/{collection}collections.updatecan-edit-collections (PUT only)
DELETE/collections/{collection}collections.destroycan-delete-collections (soft delete)
POST/collections/{collection}/restorecollections.restorecan-restore-collections
DELETE/collections/{collection}/forcecollections.force-deletecan-force-delete-collections
PUT/collections/{collection}/singleton-contentcollections.singleton-contentcan-edit-collections

Controller: ContentCollectionController. Bulk body: { action, ids } with actiondelete | restore | force_delete.

Fields

MethodPathRoute namePermission
GET/collections/{collection}/fieldscollections.fields.indexcan-show-collections
POST/collections/{collection}/fieldscollections.fields.storecan-edit-collections
POST/collections/{collection}/field-packs/{pack}collections.field-packs.applycan-edit-collections
PATCH/collections/{collection}/fields/{field}collections.fields.updatecan-edit-collections
DELETE/collections/{collection}/fields/{field}collections.fields.destroycan-edit-collections
POST/collections/{collection}/fields/reordercollections.fields.reordercan-edit-collections
POST/collections/{collection}/fields/{field}/duplicatecollections.fields.duplicatecan-edit-collections
POST/collections/{collection}/fields/{field}/toggle-form-visibilitycollections.fields.toggle-form-visibilitycan-edit-collections
POST/collections/{collection}/fields/{field}/layout-widthcollections.fields.update-layout-widthcan-edit-collections
PUT/collections/{collection}/form-layoutcollections.form-layout.updatecan-edit-collections

Controller: FieldController. Types: Field types. Packs: Field types — Field packs. Locales for labels: project content locales (Project settings).

Items

Helpers registered before {item} so new / options / export are not captured as IDs:

MethodPathRoute namePermission
GET/collections/{collection}/items/newcollections.items.newcan-create-collections
GET/collections/{collection}/items/optionscollections.items.field-optionscan-show-collections
GET/collections/{collection}/items/exportcollections.items.exportcan-show-collections (?format=csv|json)
PUT/collections/{collection}/list-columnscollections.items.list-columns.updatecan-edit-collections
POST/collections/{collection}/items/{item}/restorecollections.items.restorecan-restore-collections
DELETE/collections/{collection}/items/{item}/forcecollections.items.force-deletecan-force-delete-collections
GET/collections/{collection}/itemscollections.items.indexcan-show-collections
POST/collections/{collection}/itemscollections.items.storecan-create-collections
POST/collections/{collection}/items/bulkcollections.items.bulkFormRequest per action (same as collection bulk)
GET/collections/{collection}/items/{item}collections.items.showcan-show-collections
PUT/collections/{collection}/items/{item}collections.items.updatecan-edit-collections (PUT only)
DELETE/collections/{collection}/items/{item}collections.items.destroycan-delete-collections

Controller: ItemController. Data model: Collections data model. Product UX (filters, History, export): Collection items.

Item bulk also runs CollectionPermissionEnforcer::assertItemWritable for delete/force-delete (and skips restore). IDs from another collection are rejected.

Item revisions

MethodPathRoute namePermission
GET/collections/{collection}/items/{item}/revisionscollections.items.revisions.indexcan-show-collections
POST/collections/{collection}/items/{item}/revisions/{revision}/restorecollections.items.revisions.restorecan-edit-collections
GET/collections/{collection}/items/{item}/preview-as-rolecollections.items.preview-as-rolecan-show-collections

Snapshots are written on every CollectionItemValuesWriter::sync (create/update/restore). Soft-deleted items keep history. Preview-as-role is JSON (role_id or as_public=1) — see Collection items.

Imports via AI / webhook

Bulk import does not live on these REST routes. Use:

  • Authenticated AI tools (ImportCollectionCsv, ImportRemoteJson, …) under AI API
  • Token webhook POST /ai/webhooks/collection-import

Import job status: GET /ai/import-jobs/{jobId} (requires can-use-ai and can-create-collections).

Authorization

Verified users without the matching can-*-collections permission receive 403. Pest: tests/Feature/Collections/CollectionAuthorizationTest.php, tests/Feature/Collections/BulkActionsTest.php.

Advanced list filters

Admin items index: Search title + Filters popover (AND multi-field) write this dialect into the URL. Same operators for Public API + GraphQL filter:

  • ?filter[title]=hello — contains (LIKE), backward compatible
  • ?filter[status][_eq]=published
  • ?filter[status][_neq]=draft
  • ?filter[tags][_in]=a,b
  • ?filter[body][_null]=1 / [_nnull]=1
  • ?filter[price][_gte]=10 / [_lte] / [_gt] / [_lt]
  • ?filter[title][_contains]=hello

See also Public CMS API and GraphQL.

Previous
Admin & files API