Skip to content

Content API

The Content API provides full CRUD access to your organization’s content items. All requests require a Bearer token created by a tenant admin.

Base URL

https://your-org.flarebuilder.com/api/v1

Authentication

Every request must include an API token in the Authorization header:

Authorization: Bearer fb_sk_a1b2c3d4e5f6...

Tokens are created by tenant admins in the FlareBuilder dashboard under Settings → API Tokens. Each token is shown once at creation — store it securely.

Response Format

All content items returned by the Content API use the feed format — the same structure as the public Feed API. This means your integration code can consume both the public feed and the authenticated Content API with the same data shape.

{
"id": "550e8400-e29b-41d4-a716-446655440000",
"template_id": "tmpl-uuid",
"template_name": "Event",
"title": "Quarterly Town Hall",
"tags": ["company", "quarterly"],
"channel_id": null,
"date_published": "2026-03-01T10:00:00.000Z",
"date_expires": null,
"date_created": "2026-02-28T08:00:00.000Z",
"date_modified": "2026-02-28T08:30:00.000Z",
"author": {
"id": "user-uuid",
"name": "Jane Smith"
},
"sections": [
{
"id": "content",
"label": "Content",
"data": {
"title": "Quarterly Town Hall",
"description": "All-hands meeting for Q1 results",
"body": "<p>Detailed agenda...</p>"
}
},
{
"id": "event",
"label": "Event",
"data": {
"event_start_date": "2026-03-15T14:00:00.000Z",
"event_end_date": "2026-03-15T16:00:00.000Z"
}
},
{
"id": "location",
"label": "Location",
"data": {
"location_name": "Main Auditorium",
"location_link": "https://maps.google.com/...",
"location_geo": { "lat": 40.7829, "lon": -73.9654 }
}
}
]
}

The sections array contains only the fields that were enabled in the template when the item was created. See Content Data Model for details.

Endpoints

List Content

GET /api/v1/content

Returns a paginated list of content items in feed format.

Query Parameters

ParameterTypeDefaultDescription
adminstringSet to true to list all tenant content (requires RESOURCE_MANAGE_TENANT privilege)
tagsstringFilter by tag names, comma-separated
templatesstringFilter by template name(s), comma-separated
channelsstringFilter by channel ID(s), comma-separated
statusstringallFilter by status: all, published, draft, scheduled, expired
limitnumber25Items per page (max 100)
offsetnumber0Pagination offset
sort_bystringcreatedSort field: created, modified, published
sort_orderstringDESCSort direction: ASC or DESC
publish_startstringPublished on or after (ISO 8601)
publish_endstringPublished on or before (ISO 8601)
event_startstringEvent starts on or after (ISO 8601)
event_endstringEvent starts on or before (ISO 8601)
expire_startstringExpires on or after (ISO 8601)
expire_endstringExpires on or before (ISO 8601)
user_emailstringFilter by author email (requires RESOURCE_MANAGE_TENANT)
Terminal window
curl -H "Authorization: Bearer fb_sk_a1b2c3d4..." \
"https://your-org.flarebuilder.com/api/v1/content?admin=true&limit=10"

Response

{
"items": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"template_id": "tmpl-uuid",
"template_name": "Event",
"title": "Quarterly Town Hall",
"tags": ["company", "quarterly"],
"channel_id": null,
"date_published": "2026-03-01T10:00:00.000Z",
"date_expires": null,
"date_created": "2026-02-28T08:00:00.000Z",
"date_modified": "2026-02-28T08:30:00.000Z",
"author": {
"id": "user-uuid",
"name": "Jane Smith"
},
"sections": [
{
"id": "content",
"label": "Content",
"data": {
"title": "Quarterly Town Hall",
"description": "All-hands meeting for Q1 results",
"body": "<p>Detailed agenda...</p>"
}
},
{
"id": "event",
"label": "Event",
"data": {
"event_start_date": "2026-03-15T14:00:00.000Z",
"event_end_date": "2026-03-15T16:00:00.000Z"
}
}
]
}
],
"total": 42,
"limit": 25,
"offset": 0
}

Get Content Item

GET /api/v1/content/:id

Returns a single content item by UUID.

Terminal window
curl -H "Authorization: Bearer fb_sk_a1b2c3d4..." \
"https://your-org.flarebuilder.com/api/v1/content/550e8400-e29b-41d4-a716-446655440000"

Response

{
"item": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"template_id": "tmpl-uuid",
"template_name": "Event",
"title": "Quarterly Town Hall",
"tags": ["company", "quarterly"],
"channel_id": null,
"date_published": "2026-03-01T10:00:00.000Z",
"date_expires": null,
"date_created": "2026-02-28T08:00:00.000Z",
"date_modified": "2026-02-28T08:30:00.000Z",
"author": {
"id": "user-uuid",
"name": "Jane Smith"
},
"sections": [
{
"id": "content",
"label": "Content",
"data": {
"title": "Quarterly Town Hall",
"description": "All-hands meeting for Q1 results",
"body": "<p>Detailed agenda...</p>"
}
}
]
}
}

Create Content Item

POST /api/v1/content

Creates a new content item. Requires RESOURCE_CREATE_OWN privilege on the token.

Request Body

All content data is provided through a sections array that mirrors the feed response format. Top-level fields control publishing metadata; everything else — titles, descriptions, dates, locations, and custom template fields — goes inside sections.

FieldTypeRequiredDescription
template_idstringYesUUID of the template to use
sectionsarrayYesArray of { id, data } objects containing all field values
tagsstring[]NoArray of tag names (created automatically if new)
date_publishedstringNoISO 8601 publish date (omit or null = draft)
date_expiresstringNoISO 8601 expiration date
channel_idstringNoChannel UUID (null = public feed)
timezonestringNoIANA timezone for interpreting date values (default: UTC)

Sections format

Each object in the sections array has an id matching a section in your template, and a data object containing field values for that section. Built-in fields (title, description, feature_image, event_start_date, event_end_date, location_name, location_link, location_geo) and custom template fields all live inside sections.data.

Use the Templates API to discover a template’s section IDs and field names.

Terminal window
curl -X POST \
-H "Authorization: Bearer fb_sk_a1b2c3d4..." \
-H "Content-Type: application/json" \
-d '{
"template_id": "tmpl-uuid",
"sections": [
{
"id": "content",
"data": {
"title": "New Blog Post"
}
}
]
}' \
"https://your-org.flarebuilder.com/api/v1/content"

Response (201)

{
"success": true,
"item": {
"id": "newly-created-uuid",
"template_id": "tmpl-uuid",
"template_name": "Event",
"title": "Summer Festival 2026",
"tags": ["events", "community"],
"channel_id": null,
"date_published": "2026-05-01T09:00:00.000Z",
"date_expires": null,
"date_created": "2026-02-24T12:00:00.000Z",
"date_modified": "2026-02-24T12:00:00.000Z",
"author": {
"id": "user-uuid",
"name": "Jane Smith"
},
"sections": [
{
"id": "content",
"label": "Content",
"data": {
"title": "Summer Festival 2026",
"description": "Annual community festival"
}
},
{
"id": "event",
"label": "Event",
"data": {
"event_start_date": "2026-07-04T10:00:00.000Z",
"event_end_date": "2026-07-04T22:00:00.000Z"
}
}
]
}
}

Update Content Item

PUT /api/v1/content/:id

Updates an existing content item. Only the fields you include are changed — omitted fields are left as-is.

  • To update publishing metadata (tags, date_published, channel_id), include them as top-level fields.
  • To update content fields (title, description, custom template fields, dates, location), include them inside sections.
  • You only need to include the sections you want to change.
Terminal window
curl -X PUT \
-H "Authorization: Bearer fb_sk_a1b2c3d4..." \
-H "Content-Type: application/json" \
-d '{
"sections": [
{
"id": "content",
"data": {
"title": "Updated Title"
}
}
]
}' \
"https://your-org.flarebuilder.com/api/v1/content/550e8400-e29b-41d4-a716-446655440000"

Response

{
"success": true,
"item": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"template_id": "tmpl-uuid",
"template_name": "Event",
"title": "Updated Title",
"tags": ["news", "updated"],
"channel_id": null,
"date_published": "2026-03-15T12:00:00.000Z",
"date_expires": null,
"date_created": "2026-02-28T08:00:00.000Z",
"date_modified": "2026-03-10T09:15:00.000Z",
"author": {
"id": "user-uuid",
"name": "Jane Smith"
},
"sections": [...]
}
}

Delete Content Item

DELETE /api/v1/content/:id

Permanently deletes a content item and its associated tags and metadata.

Terminal window
curl -X DELETE \
-H "Authorization: Bearer fb_sk_a1b2c3d4..." \
"https://your-org.flarebuilder.com/api/v1/content/550e8400-e29b-41d4-a716-446655440000"

Response

{
"success": true,
"message": "ContentItem deleted"
}

Bulk Operations

PATCH /api/v1/content

Apply the same update to multiple content items at once, or delete a set of items in a single request. Maximum 100 items per request.

Request body

FieldTypeDescription
actionstring"update" or "delete"
content_idsstring[]IDs of content items to act on (max 100)
dataobjectFields to update — required for update, omit for delete

Updatable fields

Bulk update supports the built-in column-stored fields. Template section fields (custom fields stored as JSON) are not affected by bulk update and are never modified.

FieldTypeNotes
titlestring
descriptionstring
feature_imagestring | nullURL. Preview URLs are automatically promoted to permanent storage.
date_publishedstring | nullISO 8601. Pass null to unpublish. Requires publish permission.
date_expiresstring | nullISO 8601. Pass null to clear.
event_start_datestring | nullISO 8601.
event_end_datestring | nullISO 8601.
location_namestring | null
location_linkstring | null
location_geoobject | null{ "lat": 51.5, "lon": -0.1, "alt": 0 }. Pass null to clear.
channel_idstring | nullMust be an active channel in the same tenant.
template_idstring | nullMust be an existing template in the same tenant. Pass null to assign the default template.
timezonestringIANA timezone for interpreting date fields (e.g. "America/New_York"). Defaults to UTC.
tagsstring[]Replaces the tag set on every matched item. Maximum 50 tags per request.

Only the fields you include are updated — unspecified fields are left unchanged on each item.

Partial success

Each item is evaluated independently. If a subset of items fail permission checks, those are reported in failed and the rest are still updated. The response always returns HTTP 200; check results.failed for per-item errors.

Terminal window
curl -X PATCH \
-H "Authorization: Bearer fb_sk_a1b2c3d4..." \
-H "Content-Type: application/json" \
-d '{
"action": "update",
"content_ids": ["uuid-1", "uuid-2", "uuid-3"],
"data": {
"date_published": "2026-03-15T12:00:00Z"
}
}' \
"https://your-org.flarebuilder.com/api/v1/content"

Response

{
"success": true,
"results": {
"success": [
{ "id": "uuid-1", "action": "updated" },
{ "id": "uuid-2", "action": "updated" }
],
"failed": [
{ "id": "uuid-3", "error": "Permission denied" }
]
}
}

Search Content

GET /api/v1/content/search

Full-text search across content titles, descriptions, and indexed fields.

ParameterTypeDefaultDescription
qstringRequiredSearch query (min 2 characters)
template_idstringFilter to a specific template UUID
template_namesstringFilter by template name(s), comma-separated
tagsstringFilter by tags, comma-separated
statusstringpublishedFilter by status (published, draft, all — admin only)
sortstringrelevanceSort order: relevance, created, published
limitnumber20Results per page (max 100)
cursorstringOpaque pagination cursor from previous response
Terminal window
curl -H "Authorization: Bearer fb_sk_a1b2c3d4..." \
"https://your-org.flarebuilder.com/api/v1/content/search?q=quarterly+report&limit=10"

Response

{
"results": [
{
"id": "uuid",
"title": "Quarterly Town Hall",
"template_name": "Event",
"date_published": "2026-03-01T10:00:00.000Z",
"tags": ["company", "quarterly"]
}
],
"nextCursor": "eyJzb3J0VmFsdWUiOiIyMDI2LTAzLTAxIiwiaWQiOiJ1dWlkIn0=",
"hasMore": true,
"query": "quarterly report"
}

Upload Image

POST /api/v1/upload

Upload an image for use as a feature_image or in a template image field. Returns a preview URL that becomes permanent when attached to a saved content item.

Terminal window
curl -X POST \
-H "Authorization: Bearer fb_sk_a1b2c3d4..." \
-F "image=@/path/to/image.jpg" \
-F "bucket=preview" \
"https://your-org.flarebuilder.com/api/v1/upload"
FieldTypeDescription
imagebinaryThe image file (multipart form data)
bucketstringpublished (default) for direct permanent storage, or preview to stage before saving
field_typestringimage (default) or media — controls storage path and allowed file types

Storage behaviour

The bucket field controls when storage is counted against your plan:

bucketURL typeStorage trackedAllowed types
published (default)Public CDN (assets.flarebuilder.com/...)ImmediatelyImages only (JPEG, PNG, WebP, GIF, SVG)
previewAuth-gated (your-org.flarebuilder.com/api/internal/preview/...)At content-item saveImages only

When you use bucket=preview, the file is held in temporary storage. When the preview URL appears in a feature_image field or an image-type section field and the content item is saved, FlareBuilder automatically copies it to permanent CDN storage, updates the URL, and records the bytes against your quota. If the content item is never saved, the preview file is orphaned — there is no automatic cleanup.

For API integrations, uploading directly to published (the default) is simpler: you get a permanent CDN URL immediately and can include it straight in the create request.

Response (both paths)

{
"success": true,
"url": "https://assets.flarebuilder.com/your-org/images/abc123.jpg",
"filename": "your-org/images/abc123.jpg",
"size": 204800,
"type": "image/jpeg"
}

For bucket=preview, the url will be https://your-org.flarebuilder.com/api/internal/preview/abc123.jpg instead.

Content Data Model

Understanding how FlareBuilder stores and serves content helps you write integrations that work correctly with both the Content API and the Feed API.

Two-Tier Storage

Content item data is stored in two places:

StorageFieldsPurpose
Database columnstitle, description, feature_image, event_start_date, event_end_date, location_name, location_link, location_geo_lat/lon/altIndexed for filtering, sorting, and geographic queries
JSON blobAll other template fields (text, rich_text, url, number, select, etc.)Flexible storage for template-specific custom fields

When creating or updating content via the API, all fields are provided through the sections array — you do not need to know which storage tier a field uses. The server automatically routes each field to the correct location based on its ID.

{
"template_id": "tmpl-uuid",
"tags": ["events", "community"],
"date_published": "2026-05-01T09:00:00Z",
"sections": [
{
"id": "content",
"data": {
"title": "Summer Festival",
"description": "Annual community event"
}
},
{
"id": "details",
"data": {
"body": "<p>Full details here...</p>",
"registration_url": "https://example.com/register"
}
}
]
}

In this example, title and description are column-stored fields that get indexed for search and filtering. body and registration_url are custom template fields stored in the JSON blob. Both are provided the same way in the request.

See the Field Types table in the Templates API to see which fields use column vs. JSON storage.

Field Set (Auto-Generated)

Every content item has an internal field set — a snapshot of which template fields were enabled at the time the item was created. You cannot specify or modify the field set directly; it is derived automatically from the template you assign via template_id.

The field set records each section and its enabled fields:

{
"sections": [
{
"id": "content",
"fields": {
"title": { "type": "text" },
"description": { "type": "multiline" },
"body": { "type": "rich_text" }
}
}
]
}

Disabled fields in the template are excluded from the field set. This means:

  • If a template has 10 fields but only 6 are enabled, the content item’s field set contains only those 6.
  • Even if you pass extra keys in sections.data that don’t match an enabled field, they are not surfaced in responses.

How Responses Are Assembled

When the Content API (or Feed API) returns a content item, it uses the field set as a whitelist to assemble the sections array:

  1. The server reads the item’s field set to determine which sections and fields to include.
  2. For each field, it resolves the value from the correct storage location — database column or JSON blob.
  3. Only fields present in the field set appear in the response. Disabled or unknown fields are omitted.

This is why the response’s sections structure mirrors the template’s section layout:

{
"id": "550e8400-...",
"title": "Summer Festival",
"sections": [
{
"id": "content",
"label": "Content",
"data": {
"title": "Summer Festival",
"description": "Annual community event",
"body": "<p>Full details here...</p>"
}
}
]
}

The top-level fields (id, template_id, template_name, title, tags, date_published, date_expires, date_created, date_modified, author, channel_id) are always included. The sections array contains only the template-defined fields that were enabled when the item was created.

Immutable Fields

Certain fields are set by the system and cannot be overridden via the API:

FieldSourceNotes
tenant_idAuthenticated contextDerived from your API token’s tenant — cannot be specified or changed
field_setTemplate schemaAuto-generated from template_id at creation time
author_idAPI tokenSet to the user associated with the token
idSystemUUID generated on creation
date_createdSystemSet once at creation

Token Privileges

API tokens carry a subset of privileges that control what operations are allowed:

PrivilegeDescription
RESOURCE_CREATE_OWNCreate content items
RESOURCE_UPDATE_OWNUpdate content items created by this token
RESOURCE_DELETE_OWNDelete content items created by this token
RESOURCE_PUBLISH_OWNPublish/unpublish content
RESOURCE_MANAGE_TENANTAccess and modify all tenant content (not just own)
TEMPLATE_MANAGE_TENANTCreate, update, and delete templates

By default, new tokens are created with all content privileges. Admins can restrict tokens to specific privileges at creation time.

Error Responses

StatusDescription
200Success
201Created
400Validation error (missing fields, invalid data)
401Missing, invalid, or expired API token
403Insufficient privileges or plan limit reached
404Content item or tenant not found
409Conflict (e.g. duplicate name)
500Server error

All errors return JSON with an error field:

{
"error": "Title is required"
}

Plan limit errors include additional context:

{
"error": "ContentItem limit reached. Your Spark plan allows 100 content. You currently have 100."
}

Rate Limits

API tokens default to 60 requests per minute. Rate-limited responses return 429 Too Many Requests.