Skip to main content

Custom Collections API

Custom Collections are the most flexible content type in Adapto CMS. They allow you to define your own data structures with custom field schemas — team members, products, testimonials, FAQs, documentation pages, or any structured content your application needs.

Endpoints Overview

MethodEndpointDescription
GET/public/custom-collectionsList collections (paginated)
GET/public/custom-collections/{collection_id}Get collection by ID
GET/public/custom-collections/by-slug/{slug}Get collection by slug
GET/public/custom-collections/{collection_id}/itemsList collection items (paginated)
GET/public/custom-collections/{collection_id}/items/previewList item previews (lightweight)
GET/public/custom-collections/{collection_id}/items/{item_id}Get item by ID
GET/public/custom-collections/{collection_id}/items/by-slug/{slug}Get item by slug

Collection Data Model

A Custom Collection defines a schema (via fields) and contains items that conform to that schema. Understanding this structure is key to working with collections effectively.

Collection Object

When you fetch a collection, you get back its schema definition including the fields array that describes what data each item can hold:

{
  "id": "coll-001",
  "name": "Team Members",
  "slug": "team-members",
  "description": "Our team directory",
  "language": "en",
  "fields": [
    {
      "name": "role",
      "label": "Role",
      "type": "text",
      "required": true,
      "multiple": false,
      "description": "Job title or position",
      "default_value": null,
      "related_collection": null,
      "options": null,
      "validation": null
    },
    {
      "name": "department",
      "label": "Department",
      "type": "select",
      "required": true,
      "multiple": false,
      "options": [
        {"value": "engineering", "label": "Engineering"},
        {"value": "design", "label": "Design"},
        {"value": "marketing", "label": "Marketing"}
      ]
    },
    {
      "name": "bio",
      "label": "Biography",
      "type": "rich_text",
      "required": false,
      "multiple": false
    }
  ],
  "status": "published",
  "created_at": "2026-01-08T10:00:00",
  "updated_at": "2026-01-08T10:00:00"
}

Collection Item Object

Each item's data field is a flat object where keys match the field name values from the collection schema, and values conform to the field's type:

{
  "id": "item-001",
  "collection_id": "coll-001",
  "title": "Jane Doe",
  "slug": "jane-doe",
  "data": {
    "role": "Lead Engineer",
    "department": "engineering",
    "bio": "<p>Jane has 10 years of experience...</p>"
  },
  "language": "en",
  "status": "published",
  "created_at": "2026-01-09T10:00:00",
  "updated_at": "2026-01-09T10:00:00",
  "published_at": "2026-01-09T12:00:00",
  "media_objects_placements": [
    {
      "placement_key": "avatar",
      "media_object": {
        "id": "mo-001",
        "title": "Jane headshot",
        "description": null,
        "file_id": "file-001",
        "url": "https://media.adaptocms.com/tenants/.../jane.jpg",
        "type": "image",
        "created_at": "2026-01-09T10:00:00",
        "updated_at": "2026-01-09T10:00:00"
      },
      "caption": "Jane Doe, Lead Engineer",
      "alt_text": "Photo of Jane Doe",
      "meta_data": null
    }
  ],
  "translation_of_id": null,
  "meta_data": null,
  "file_urls": {"file-001": "https://media.adaptocms.com/tenants/.../jane.jpg"}
}

Field Types Reference

Every collection defines its schema through an array of fields. Each field has a type that determines what values can be stored in the item's data object. Here are all 15 available field types with the data values they produce:

TypeData ValueDescriptionExample Value
textstringSingle-line text input"Lead Engineer"
textareastringMulti-line text input"A longer description\nwith line breaks"
rich_textstring (HTML)Rich text content with formatting"<p>Bold <strong>text</strong></p>"
numbernumberInteger or decimal value42 or 99.99
datestring (ISO 8601)Single date value"2026-03-15"
date_rangeobjectStart and end date pair{"start": "2026-03-01", "end": "2026-03-31"}
booleanbooleanTrue/false toggletrue
selectstringSingle value from predefined options"engineering"
multi_selectstring[]Multiple values from predefined options["frontend", "backend"]
referencestring (UUID)ID pointing to an item in another collection"a1b2c3d4-..."
imagestring (UUID)Media object ID for an image file"mo-img-001"
filestring (UUID)Media object ID for any file type"mo-file-001"
urlstringURL value"https://example.com"
emailstringEmail address"jane@example.com"
colorstringColor value (typically hex)"#0369a1"

Field Definition Properties

Each field in the collection's fields array has these properties:

PropertyTypeRequiredDescription
namestringYesField identifier — used as the key in item data
labelstringYesHuman-readable display label
typestringYesOne of the 15 field types above
requiredbooleanNoWhether the field must be populated (default: false)
multiplebooleanNoWhether the field holds a list of values (default: false)
descriptionstring | nullNoHelp text shown in the CMS UI
default_valueany | nullNoDefault value when creating items
related_collectionstring | nullNoRequired for reference type: the target collection UUID
optionsobject[] | nullNoRequired for select/multi_select: array of {"value": "...", "label": "..."}
validationobject | nullNoAdditional validation rules

Multiple Values

When multiple is true, the data value becomes an array of the field's base type. For example, a text field with multiple: true stores ["value1", "value2"] instead of "value1".

Not allowed on: boolean, multi_select, rich_text, date_range (these types already handle multiplicity internally or don't support it).

Select/Multi-Select Options

Fields of type select or multi_select require an options array. Each option is an object with value (stored in data) and label (displayed in UI):

{
  "name": "priority",
  "label": "Priority",
  "type": "select",
  "options": [
    {"value": "low", "label": "Low"},
    {"value": "medium", "label": "Medium"},
    {"value": "high", "label": "High"},
    {"value": "critical", "label": "Critical"}
  ]
}

// Item data stores the value:
{"priority": "high"}

Reference Fields

Fields of type reference store the UUID of an item in another collection. The related_collection property specifies which collection is the target:

{
  "name": "author",
  "label": "Author",
  "type": "reference",
  "related_collection": "coll-team-members-uuid"
}

// Item data stores the referenced item's ID:
{"author": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}

To resolve the reference, make a separate API call to fetch the referenced item by its ID.


Media Objects & Placements

Every collection item can have media attached via media_objects_placements — an array of placement objects that associate media (images, videos, documents) with named slots on the item.

MediaObjectPlacement

FieldTypeDescription
placement_keystringNamed slot identifier (e.g., "hero", "thumbnail", "gallery_1")
media_objectMediaObjectThe media object details (see below)
captionstring | nullCaption text for the media
alt_textstring | nullAlt text for accessibility (images)
meta_datastring | nullFree-form metadata (JSON string)

MediaObject

FieldTypeDescription
idstringUnique identifier (UUID)
titlestring | nullMedia title
descriptionstring | nullMedia description
file_idstringID of the underlying file in storage
urlstringDirect CDN URL to the file
typestringMedia type (see MediaType values below)
created_atstring | nullCreation timestamp
updated_atstring | nullLast update timestamp

MediaType Values

ValueDescription
imageImage files (JPEG, PNG, GIF, WebP, AVIF, SVG, HEIC)
videoVideo files (MP4, WebM, MOV, etc.)
audioAudio files (MP3, WAV, AAC, FLAC, etc.)
documentDocuments (PDF, DOC, DOCX, CSV, XLS, XLSX)
youtubeYouTube video embed
vimeoVimeo video embed
tiktokTikTok video embed
instagram_reelInstagram Reel embed
instagram_postInstagram Post embed
otherAny other file type

The file_urls Convenience Field

Each item response also includes a file_urls object — a flat map of file_id → CDN URL for every file referenced by the item's media placements. This saves you from having to extract URLs from nested placement objects:

{
  "file_urls": {
    "file-001": "https://media.adaptocms.com/tenants/.../photo.jpg",
    "file-002": "https://media.adaptocms.com/tenants/.../document.pdf"
  }
}

Working with Media Placements

// JavaScript: Extract the hero image from placements
const item = await fetch(`${API}/public/custom-collections/${collId}/items/${itemId}`, {
  headers: { 'x-api-key': API_KEY }
}).then(r => r.json());

// Find a specific placement by key
const heroPlacement = item.media_objects_placements
  .find(p => p.placement_key === 'hero');

if (heroPlacement) {
  const imageUrl = heroPlacement.media_object.url;
  const altText = heroPlacement.alt_text || heroPlacement.media_object.title;
  // Use in your template
}

// Or use file_urls for a quick lookup by file_id
const thumbnailUrl = item.file_urls['file-123'];

List Collections

GET /public/custom-collections

Returns a paginated list of custom collections defined in your tenant.

Query Parameters

ParameterTypeRequiredDescription
statusstringNoFilter by status
languagestringNoFilter by language code
fieldstringNoSort field
orderstringNoSort order: asc or desc
pageintegerNoPage number
limitintegerNoItems per page

Example Request

curl -X GET "https://api.adaptocms.com/public/custom-collections?language=en" \
  -H "x-api-key: YOUR_API_KEY"

Example Response

{
  "items": [
    {
      "id": "coll-001",
      "name": "Team Members",
      "slug": "team-members",
      "description": "Our team directory",
      "language": "en",
      "fields": [
        {
          "name": "role",
          "label": "Role",
          "type": "text",
          "required": true,
          "multiple": false
        },
        {
          "name": "bio",
          "label": "Biography",
          "type": "rich_text",
          "required": false,
          "multiple": false
        },
        {
          "name": "avatar",
          "label": "Avatar",
          "type": "image",
          "required": false,
          "multiple": false
        }
      ],
      "status": "published",
      "created_at": "2026-01-08T10:00:00",
      "updated_at": "2026-01-08T10:00:00"
    }
  ],
  "total": 3,
  "page": 1,
  "limit": 20,
  "pages": 1
}

Get Collection by ID

GET /public/custom-collections/{collection_id}

Path Parameters

ParameterTypeRequiredDescription
collection_idstring (UUID)YesThe unique identifier of the collection

Returns the full collection object including the fields schema definition. Use this to understand the structure of items in the collection before fetching them.

Example Request

curl -X GET "https://api.adaptocms.com/public/custom-collections/coll-001" \
  -H "x-api-key: YOUR_API_KEY"

Get Collection by Slug

GET /public/custom-collections/by-slug/{slug}

Path Parameters

ParameterTypeRequiredDescription
slugstringYesThe URL-friendly slug of the collection

Example Request

curl -X GET "https://api.adaptocms.com/public/custom-collections/by-slug/team-members" \
  -H "x-api-key: YOUR_API_KEY"

List Collection Items

GET /public/custom-collections/{collection_id}/items

Returns a paginated list of items in a collection.

Query Parameters

ParameterTypeRequiredDescription
statusstringNoFilter by status
languagestringNoFilter by language code
translation_of_idstringNoFilter by translation source ID
fieldstringNoSort field
orderstringNoSort order
pageintegerNoPage number
limitintegerNoItems per page

Example Request

curl -X GET "https://api.adaptocms.com/public/custom-collections/coll-001/items?language=en&status=published" \
  -H "x-api-key: YOUR_API_KEY"

Example Response

{
  "items": [
    {
      "id": "item-001",
      "collection_id": "coll-001",
      "title": "Jane Doe",
      "slug": "jane-doe",
      "data": {
        "role": "Lead Engineer",
        "bio": "<p>Jane has 10 years of experience...</p>"
      },
      "language": "en",
      "status": "published",
      "created_at": "2026-01-09T10:00:00",
      "updated_at": "2026-01-09T10:00:00",
      "published_at": "2026-01-09T12:00:00",
      "media_objects_placements": [
        {
          "placement_key": "avatar",
          "media_object": {
            "id": "mo-001",
            "title": "Jane headshot",
            "description": null,
            "file_id": "file-001",
            "url": "https://media.adaptocms.com/tenants/.../jane.jpg",
            "type": "image",
            "created_at": "2026-01-09T10:00:00",
            "updated_at": "2026-01-09T10:00:00"
          },
          "caption": "Jane Doe, Lead Engineer",
          "alt_text": "Photo of Jane Doe",
          "meta_data": null
        }
      ],
      "translation_of_id": null,
      "meta_data": null,
      "file_urls": {"file-001": "https://media.adaptocms.com/tenants/.../jane.jpg"}
    }
  ],
  "total": 5,
  "page": 1,
  "limit": 20,
  "pages": 1
}

List Collection Items Preview

GET /public/custom-collections/{collection_id}/items/preview

Returns a lightweight list without the data, file_urls, or media_objects_placements fields. Use this for listing pages where you only need titles and metadata.

Accepts the same query parameters as the full items list endpoint.

Example Response

{
  "items": [
    {
      "id": "item-001",
      "collection_id": "coll-001",
      "title": "Jane Doe",
      "slug": "jane-doe",
      "language": "en",
      "status": "published",
      "created_at": "2026-01-09T10:00:00",
      "updated_at": "2026-01-09T10:00:00",
      "published_at": "2026-01-09T12:00:00",
      "translation_of_id": null,
      "meta_data": null
    }
  ],
  "total": 5,
  "page": 1,
  "limit": 20,
  "pages": 1
}

Get Item by ID

GET /public/custom-collections/{collection_id}/items/{item_id}

Path Parameters

ParameterTypeRequiredDescription
collection_idstring (UUID)YesThe collection ID
item_idstring (UUID)YesThe item ID

Get Item by Slug

GET /public/custom-collections/{collection_id}/items/by-slug/{slug}

Path Parameters

ParameterTypeRequiredDescription
collection_idstring (UUID)YesThe collection ID
slugstringYesThe URL-friendly slug of the item

Use Case: Dynamic Collection Pages

// Astro example: src/pages/team/[slug].astro
---
const collectionSlug = 'team-members';

// First, resolve collection ID from slug
const collection = await fetch(
  `${import.meta.env.ADAPTO_URL}/public/custom-collections/by-slug/${collectionSlug}`,
  { headers: { 'x-api-key': import.meta.env.ADAPTO_API_KEY } }
).then(r => r.json());

// Then fetch item by slug
const member = await fetch(
  `${import.meta.env.ADAPTO_URL}/public/custom-collections/${collection.id}/items/by-slug/${Astro.params.slug}`,
  { headers: { 'x-api-key': import.meta.env.ADAPTO_API_KEY } }
).then(r => r.json());
---

<h1>{member.title}</h1>
<p>{member.data.role}</p>
<div set:html={member.data.bio} />

{/* Render media placements */}
{member.media_objects_placements
  .filter(p => p.media_object.type === 'image')
  .map(p => (
    <img
      src={p.media_object.url}
      alt={p.alt_text || p.media_object.title}
    />
  ))
}