Skip to content

Channel entries have dynamic custom fields defined per channel. Simple types (string, integer, float, boolean, date, email, json) are sent as primitive values. This page documents the wire format for complex field types: files, references, galleries, and selects.

All examples use the create entry and update entry endpoints:

POST   /channels/{channel_id}/entries
PUT    /channels/{channel_id}/entries/{entry_id}

File Fields

File fields accept uploads as base64-encoded data inside a JSON object with __type: "File".

Upload a file

json
{
  "document": {
    "__type": "File",
    "filename": "report.pdf",
    "attachment": "JVBERi0xLjQKJ..."
  }
}
KeyTypeRequiredDescription
__typestringyesMust be "File"
filenamestringyesName with extension — used to detect content type
attachmentstringyesRaw base64-encoded file content (no data: URI prefix)

Remove a file

json
{
  "document": {
    "__type": "File",
    "remove": true
  }
}

Preserve an existing file

When updating an entry, omit the file field entirely to keep the current file. If you send back the response object as-is (with url but no attachment), the API also preserves the existing file.

Response format

Without X-Nimbu-Client-Version header:

json
{
  "document": {
    "filename": "report.pdf",
    "url": "https://cdn.nimbu.io/files/report.pdf",
    "content_type": "application/pdf"
  }
}

With X-Nimbu-Client-Version header set:

json
{
  "document": {
    "__type": "File",
    "filename": "report.pdf",
    "url": "https://cdn.nimbu.io/files/report.pdf",
    "content_type": "application/pdf",
    "size": 204800,
    "width": null,
    "height": null,
    "version": "abc123",
    "checksum": "def456"
  }
}

For image files, width and height are populated with pixel dimensions.

Code examples

bash
# Encode file and send as base64
curl -X PUT "https://api.nimbu.io/channels/blog/entries/ENTRY_ID" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "document": {
      "__type": "File",
      "filename": "report.pdf",
      "attachment": "'"$(base64 -i report.pdf)"'"
    }
  }'
javascript
import fs from "fs";

const body = {
  document: {
    __type: "File",
    filename: "report.pdf",
    attachment: fs.readFileSync("report.pdf").toString("base64"),
  },
};

const res = await fetch(
  `https://api.nimbu.io/channels/blog/entries/${entryId}`,
  {
    method: "PUT",
    headers: {
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(body),
  }
);
ruby
require "net/http"
require "json"
require "base64"

body = {
  document: {
    __type: "File",
    filename: "report.pdf",
    attachment: Base64.strict_encode64(File.binread("report.pdf"))
  }
}

uri = URI("https://api.nimbu.io/channels/blog/entries/#{entry_id}")
req = Net::HTTP::Put.new(uri)
req["Authorization"] = "Bearer #{token}"
req["Content-Type"] = "application/json"
req.body = body.to_json

Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
python
import requests
import base64

with open("report.pdf", "rb") as f:
    encoded = base64.b64encode(f.read()).decode("utf-8")

body = {
    "document": {
        "__type": "File",
        "filename": "report.pdf",
        "attachment": encoded,
    }
}

requests.put(
    f"https://api.nimbu.io/channels/blog/entries/{entry_id}",
    headers={"Authorization": f"Bearer {token}"},
    json=body,
)

Single Reference Fields

Single reference fields (belongs_to) link an entry to one entry in another channel.

Set by ID

Pass the entry ID as a plain string:

json
{
  "author": "507f1f77bcf86cd799439011"
}

Set by reference object

json
{
  "author": {
    "__type": "Reference",
    "className": "authors",
    "id": "507f1f77bcf86cd799439011"
  }
}
KeyTypeRequiredDescription
__typestringyesMust be "Reference"
classNamestringyesChannel slug of the referenced channel
idstringyes*Entry ID (*either id or slug required)
slugstringyes*Entry slug (*either id or slug required)

Set by slug

json
{
  "author": {
    "__type": "Reference",
    "className": "authors",
    "slug": "john-doe"
  }
}

Clear a reference

json
{
  "author": null
}

Response format

Default (pointer):

json
{
  "author": {
    "__type": "Reference",
    "className": "authors",
    "id": "507f1f77bcf86cd799439011"
  }
}

With ?include_slugs=true:

json
{
  "author": {
    "__type": "Reference",
    "className": "authors",
    "id": "507f1f77bcf86cd799439011",
    "slug": "john-doe"
  }
}

With ?resolve=author:

json
{
  "author": {
    "__type": "Object",
    "className": "authors",
    "id": "507f1f77bcf86cd799439011",
    "name": "John Doe",
    "slug": "john-doe"
  }
}

Multi Reference Fields

Multi reference fields (belongs_to_many) link an entry to multiple entries in another channel.

Replace all references

Pass an array of IDs:

json
{
  "tags": ["507f1f77bcf86cd799439011", "507f1f77bcf86cd799439012"]
}

Or use reference objects:

json
{
  "tags": {
    "objects": [
      { "__type": "Reference", "className": "tags", "id": "507f1f77bcf86cd799439011" },
      { "__type": "Reference", "className": "tags", "id": "507f1f77bcf86cd799439012" }
    ]
  }
}

Add references

Append to existing references without removing current ones:

json
{
  "tags": {
    "__op": "AddReference",
    "objects": [
      { "__type": "Reference", "className": "tags", "id": "507f1f77bcf86cd799439011" }
    ]
  }
}

Remove references

Remove specific references while keeping the rest:

json
{
  "tags": {
    "__op": "RemoveReference",
    "objects": [
      { "__type": "Reference", "className": "tags", "id": "507f1f77bcf86cd799439011" }
    ]
  }
}

Batch operations

Combine add and remove in a single request:

json
{
  "tags": {
    "__op": "Batch",
    "operations": [
      {
        "__op": "AddReference",
        "objects": [
          { "__type": "Reference", "className": "tags", "id": "new-tag-id" }
        ]
      },
      {
        "__op": "RemoveReference",
        "objects": [
          { "__type": "Reference", "className": "tags", "id": "old-tag-id" }
        ]
      }
    ]
  }
}

Response format

json
{
  "tags": {
    "__type": "Relation",
    "className": "tags",
    "objects": [
      { "__type": "Reference", "className": "tags", "id": "507f1f77bcf86cd799439011" },
      { "__type": "Reference", "className": "tags", "id": "507f1f77bcf86cd799439012" }
    ]
  }
}

Gallery fields hold ordered collections of images with optional captions.

json
{
  "photos": {
    "__type": "Gallery",
    "images": [
      {
        "__type": "GalleryImage",
        "file": {
          "__type": "File",
          "filename": "hero.jpg",
          "attachment": "/9j/4AAQSkZJRg..."
        },
        "caption": "Hero image",
        "position": 0
      },
      {
        "__type": "GalleryImage",
        "file": {
          "__type": "File",
          "filename": "detail.jpg",
          "attachment": "/9j/4AAQSkZJRg..."
        },
        "caption": "Detail shot",
        "position": 1
      }
    ]
  }
}

Each GalleryImage accepts:

KeyTypeRequiredDescription
__typestringyesMust be "GalleryImage"
fileFile objectfor new imagesFile upload (same format as file fields)
captionstringnoImage caption text
positionintegernoSort order (0-based)
idstringfor existingID of an existing gallery image

Update an existing image

Include the id of the existing image and only the fields you want to change:

json
{
  "photos": {
    "__type": "Gallery",
    "images": [
      {
        "__type": "GalleryImage",
        "id": "existing-image-id",
        "caption": "Updated caption"
      }
    ]
  }
}
json
{
  "photos": {
    "__type": "Gallery",
    "images": [
      {
        "__type": "GalleryImage",
        "id": "image-to-delete",
        "remove": true
      }
    ]
  }
}

Response format

json
{
  "photos": [
    {
      "id": "img-001",
      "caption": "Hero image",
      "position": 0,
      "file": {
        "filename": "hero.jpg",
        "url": "https://cdn.nimbu.io/galleries/hero.jpg",
        "content_type": "image/jpeg"
      }
    }
  ]
}

With X-Nimbu-Client-Version header, each image file includes size, width, height, version, and checksum.

Select & Multi-Select Fields

Select (single)

Pass the option ID as a string:

json
{
  "status": "published"
}

Multi-Select

Pass an array of option IDs:

json
{
  "categories": ["news", "featured", "technology"]
}

Response Metadata

The X-Nimbu-Client-Version request header controls how much metadata the API returns for file and gallery fields.

Without the header, file fields return a compact object:

json
{ "filename": "photo.jpg", "url": "https://...", "content_type": "image/jpeg" }

With the header set (any value), file fields return full metadata:

json
{
  "__type": "File",
  "filename": "photo.jpg",
  "url": "https://...",
  "content_type": "image/jpeg",
  "size": 245760,
  "width": 1920,
  "height": 1080,
  "version": "v1a2b3",
  "checksum": "sha256..."
}

TIP

Set X-Nimbu-Client-Version to any value (e.g. "1") to get the richest response format. This is recommended for API integrations that need file dimensions or checksums.

Resolving References

When fetching entries, use query parameters to control how references are returned:

ParameterExampleEffect
include_slugs?include_slugs=trueAdds slug to each reference pointer
resolve?resolve=authorInlines the full referenced object
resolve?resolve=author,tagsResolves multiple fields (comma-separated)

Example — fetch an entry with resolved author:

GET /channels/blog/entries/ENTRY_ID?resolve=author

Complete Example

Creating an entry with multiple field types combined:

json
{
  "title": "New Blog Post",
  "body": "Article content here...",
  "published": true,
  "publish_date": "2025-03-15",
  "hero_image": {
    "__type": "File",
    "filename": "hero.jpg",
    "attachment": "/9j/4AAQSkZJRg..."
  },
  "author": {
    "__type": "Reference",
    "className": "authors",
    "slug": "john-doe"
  },
  "tags": {
    "objects": [
      { "__type": "Reference", "className": "tags", "slug": "javascript" },
      { "__type": "Reference", "className": "tags", "slug": "tutorial" }
    ]
  },
  "gallery": {
    "__type": "Gallery",
    "images": [
      {
        "__type": "GalleryImage",
        "file": {
          "__type": "File",
          "filename": "screenshot-1.png",
          "attachment": "iVBORw0KGgo..."
        },
        "caption": "Step 1",
        "position": 0
      }
    ]
  },
  "status": "published",
  "related_topics": ["news", "featured"]
}
bash
curl -X POST "https://api.nimbu.io/channels/blog/entries" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d @entry.json
javascript
const res = await fetch("https://api.nimbu.io/channels/blog/entries", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${token}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(entryData),
});
ruby
uri = URI("https://api.nimbu.io/channels/blog/entries")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{token}"
req["Content-Type"] = "application/json"
req.body = entry_data.to_json

Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
python
requests.post(
    "https://api.nimbu.io/channels/blog/entries",
    headers={"Authorization": f"Bearer {token}"},
    json=entry_data,
)

Common Gotchas

  • __type is required on File, GalleryImage, and Gallery objects. For references, __type is required when using the object format — but single references also accept a plain ID string.
  • Base64 must be raw — do not include data:image/png;base64, prefixes. Send only the base64 string.
  • className is the channel slug — use the human-readable channel identifier (e.g. "authors", "blog-posts"), not an internal class name.
  • Multi-reference semantics — sending an array of IDs replaces all references. Use AddReference/RemoveReference to modify incrementally.
  • Gallery image ordering — set position explicitly. Images without a position may appear in arbitrary order.
  • File size limits — base64 encoding increases payload size by ~33%. For very large files, consider using the standalone upload endpoint first, then reference the upload.
  • Omit unchanged fields — when updating an entry, only include fields you want to change. Omitted fields are preserved. Sending a file field without attachment preserves the existing file.