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/v1Authentication
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/contentReturns a paginated list of content items in feed format.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
admin | string | — | Set to true to list all tenant content (requires RESOURCE_MANAGE_TENANT privilege) |
tags | string | — | Filter by tag names, comma-separated |
templates | string | — | Filter by template name(s), comma-separated |
channels | string | — | Filter by channel ID(s), comma-separated |
status | string | all | Filter by status: all, published, draft, scheduled, expired |
limit | number | 25 | Items per page (max 100) |
offset | number | 0 | Pagination offset |
sort_by | string | created | Sort field: created, modified, published |
sort_order | string | DESC | Sort direction: ASC or DESC |
publish_start | string | — | Published on or after (ISO 8601) |
publish_end | string | — | Published on or before (ISO 8601) |
event_start | string | — | Event starts on or after (ISO 8601) |
event_end | string | — | Event starts on or before (ISO 8601) |
expire_start | string | — | Expires on or after (ISO 8601) |
expire_end | string | — | Expires on or before (ISO 8601) |
user_email | string | — | Filter by author email (requires RESOURCE_MANAGE_TENANT) |
curl -H "Authorization: Bearer fb_sk_a1b2c3d4..." \ "https://your-org.flarebuilder.com/api/v1/content?admin=true&limit=10"curl -H "Authorization: Bearer fb_sk_a1b2c3d4..." \ "https://your-org.flarebuilder.com/api/v1/content?admin=true&tags=featured,news"curl -H "Authorization: Bearer fb_sk_a1b2c3d4..." \ "https://your-org.flarebuilder.com/api/v1/content?admin=true&templates=event&status=published"curl -H "Authorization: Bearer fb_sk_a1b2c3d4..." \ "https://your-org.flarebuilder.com/api/v1/content?admin=true&event_start=2026-03-01T00:00:00Z&event_end=2026-03-31T23:59:59Z"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/:idReturns a single content item by UUID.
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/contentCreates 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.
| Field | Type | Required | Description |
|---|---|---|---|
template_id | string | Yes | UUID of the template to use |
sections | array | Yes | Array of { id, data } objects containing all field values |
tags | string[] | No | Array of tag names (created automatically if new) |
date_published | string | No | ISO 8601 publish date (omit or null = draft) |
date_expires | string | No | ISO 8601 expiration date |
channel_id | string | No | Channel UUID (null = public feed) |
timezone | string | No | IANA 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.
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"curl -X POST \ -H "Authorization: Bearer fb_sk_a1b2c3d4..." \ -H "Content-Type: application/json" \ -d '{ "template_id": "tmpl-uuid", "tags": ["events", "community"], "date_published": "2026-05-01T09:00:00Z", "timezone": "America/New_York", "sections": [ { "id": "content", "data": { "title": "Summer Festival 2026", "description": "Annual community festival" } }, { "id": "event", "data": { "event_start_date": "2026-07-04T10:00:00Z", "event_end_date": "2026-07-04T22:00:00Z" } }, { "id": "location", "data": { "location_name": "Central Park", "location_link": "https://maps.google.com/?q=Central+Park", "location_geo": { "lat": 40.7829, "lon": -73.9654 } } }, { "id": "details", "data": { "summary": "Join us for food, music, and fun.", "body": "<p>Full event details here...</p>", "registration_url": "https://example.com/register" } } ] }' \ "https://your-org.flarebuilder.com/api/v1/content"# Omit date_published to create a draftcurl -X POST \ -H "Authorization: Bearer fb_sk_a1b2c3d4..." \ -H "Content-Type: application/json" \ -d '{ "template_id": "tmpl-uuid", "sections": [ { "id": "content", "data": { "title": "Work in Progress", "body": "<p>Draft content...</p>" } } ] }' \ "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/:idUpdates 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 insidesections. - You only need to include the sections you want to change.
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"curl -X PUT \ -H "Authorization: Bearer fb_sk_a1b2c3d4..." \ -H "Content-Type: application/json" \ -d '{ "tags": ["news", "updated"], "date_published": "2026-03-15T12:00:00Z" }' \ "https://your-org.flarebuilder.com/api/v1/content/550e8400-e29b-41d4-a716-446655440000"curl -X PUT \ -H "Authorization: Bearer fb_sk_a1b2c3d4..." \ -H "Content-Type: application/json" \ -d '{ "tags": ["conference", "2026"], "sections": [ { "id": "content", "data": { "title": "Annual Conference 2026", "description": "Updated description" } }, { "id": "event", "data": { "event_start_date": "2026-09-10T09:00:00Z", "event_end_date": "2026-09-12T18:00:00Z" } } ] }' \ "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/:idPermanently deletes a content item and its associated tags and metadata.
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/contentApply 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
| Field | Type | Description |
|---|---|---|
action | string | "update" or "delete" |
content_ids | string[] | IDs of content items to act on (max 100) |
data | object | Fields 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.
| Field | Type | Notes |
|---|---|---|
title | string | |
description | string | |
feature_image | string | null | URL. Preview URLs are automatically promoted to permanent storage. |
date_published | string | null | ISO 8601. Pass null to unpublish. Requires publish permission. |
date_expires | string | null | ISO 8601. Pass null to clear. |
event_start_date | string | null | ISO 8601. |
event_end_date | string | null | ISO 8601. |
location_name | string | null | |
location_link | string | null | |
location_geo | object | null | { "lat": 51.5, "lon": -0.1, "alt": 0 }. Pass null to clear. |
channel_id | string | null | Must be an active channel in the same tenant. |
template_id | string | null | Must be an existing template in the same tenant. Pass null to assign the default template. |
timezone | string | IANA timezone for interpreting date fields (e.g. "America/New_York"). Defaults to UTC. |
tags | string[] | 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.
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"curl -X PATCH \ -H "Authorization: Bearer fb_sk_a1b2c3d4..." \ -H "Content-Type: application/json" \ -d '{ "action": "update", "content_ids": ["uuid-1", "uuid-2"], "data": { "date_published": null } }' \ "https://your-org.flarebuilder.com/api/v1/content"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": { "channel_id": "channel-uuid" } }' \ "https://your-org.flarebuilder.com/api/v1/content"curl -X PATCH \ -H "Authorization: Bearer fb_sk_a1b2c3d4..." \ -H "Content-Type: application/json" \ -d '{ "action": "delete", "content_ids": ["uuid-1", "uuid-2"] }' \ "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/searchFull-text search across content titles, descriptions, and indexed fields.
| Parameter | Type | Default | Description |
|---|---|---|---|
q | string | Required | Search query (min 2 characters) |
template_id | string | — | Filter to a specific template UUID |
template_names | string | — | Filter by template name(s), comma-separated |
tags | string | — | Filter by tags, comma-separated |
status | string | published | Filter by status (published, draft, all — admin only) |
sort | string | relevance | Sort order: relevance, created, published |
limit | number | 20 | Results per page (max 100) |
cursor | string | — | Opaque pagination cursor from previous response |
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/uploadUpload 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.
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"| Field | Type | Description |
|---|---|---|
image | binary | The image file (multipart form data) |
bucket | string | published (default) for direct permanent storage, or preview to stage before saving |
field_type | string | image (default) or media — controls storage path and allowed file types |
Storage behaviour
The bucket field controls when storage is counted against your plan:
bucket | URL type | Storage tracked | Allowed types |
|---|---|---|---|
published (default) | Public CDN (assets.flarebuilder.com/...) | Immediately | Images only (JPEG, PNG, WebP, GIF, SVG) |
preview | Auth-gated (your-org.flarebuilder.com/api/internal/preview/...) | At content-item save | Images 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:
| Storage | Fields | Purpose |
|---|---|---|
| Database columns | title, description, feature_image, event_start_date, event_end_date, location_name, location_link, location_geo_lat/lon/alt | Indexed for filtering, sorting, and geographic queries |
| JSON blob | All 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.datathat 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:
- The server reads the item’s field set to determine which sections and fields to include.
- For each field, it resolves the value from the correct storage location — database column or JSON blob.
- 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:
| Field | Source | Notes |
|---|---|---|
tenant_id | Authenticated context | Derived from your API token’s tenant — cannot be specified or changed |
field_set | Template schema | Auto-generated from template_id at creation time |
author_id | API token | Set to the user associated with the token |
id | System | UUID generated on creation |
date_created | System | Set once at creation |
Token Privileges
API tokens carry a subset of privileges that control what operations are allowed:
| Privilege | Description |
|---|---|
RESOURCE_CREATE_OWN | Create content items |
RESOURCE_UPDATE_OWN | Update content items created by this token |
RESOURCE_DELETE_OWN | Delete content items created by this token |
RESOURCE_PUBLISH_OWN | Publish/unpublish content |
RESOURCE_MANAGE_TENANT | Access and modify all tenant content (not just own) |
TEMPLATE_MANAGE_TENANT | Create, 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
| Status | Description |
|---|---|
200 | Success |
201 | Created |
400 | Validation error (missing fields, invalid data) |
401 | Missing, invalid, or expired API token |
403 | Insufficient privileges or plan limit reached |
404 | Content item or tenant not found |
409 | Conflict (e.g. duplicate name) |
500 | Server 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.