Skip to main content
CMS content records and library files are separate resources. Deleting a record preserves its files; deleting a library asset removes the stored file and asset record. Use both operations when your pipeline owns both resources and no other consumer needs the file. All paths below are relative to https://api.sapt.ai and accept Authorization: ApiKey <key> or an OAuth bearer token.

Content endpoints

The content type must already exist. content must match that type’s schema. Create and update use the same validation and permissions as the dashboard: ordinary content requires cms_items:write, and reads require cms_items:read. Create/update also read the type definition using cms_types:read. Meta planner content uses its own meta_planner permissions.

Create content

This example assumes an existing clip content type with a title field. Replace the type slug and content fields with your project’s schema.
Returns HTTP 201 with { "item": { ... } }. Store item.id for future mutations. Creating content does not schedule a social-platform post. Use the social publishing API for that.

Update content

Returns HTTP 200 with { "item": { ... } }. Omitted fields stay unchanged. Nested content objects merge according to the content schema; arrays and scalar values replace. The content type cannot be changed through this endpoint. scheduledAt and publishedAt accept ISO 8601 timestamps or null. Clearing scheduledAt returns a scheduled CMS item to draft. These are CMS publishing dates, separate from a social post’s schedule. Responses serialize dates as ISO strings. Invalid content returns 400 with field errors in error.details.errors; slug conflicts and concurrent edits return 409.

Delete content

Returns HTTP 200 with { "success": true }. A missing item returns 404. This removes only the CMS record. Library assets and scheduled-post records remain; delete them through their own endpoints when appropriate.

Find library assets

Returns { "assets": [...], "total": 90 }. Each asset contains id, url, filename, mimeType, sizeBytes, feature, assetType, tags, and createdAt. Use id for updates and deletion. search matches filenames and tags; untagged=true selects files with no tags. limit is 1–100, default 50. Collect the complete set of IDs before deleting a paginated batch: deleting while advancing offset can skip records as the remaining pages shift. Read one asset with GET /projects/{projectId}/assets/{assetId}; it returns { "asset": { ... } } or 404. Both reads require assets:read.

Update library assets

PATCH /projects/{projectId}/assets/{assetId} updates feature or tags and returns { "asset": { ... } }. It does not replace the file bytes.
tagOperation supports replace (default), add, and remove. Updates require assets:write; changing another uploader’s asset also requires assets:manage.

Delete library assets

Requires assets:manage. Returns HTTP 200 with { "deletedCount": 1 } after deleting the origin file and asset record, or { "deletedCount": 0 } if the ID is already absent from this project. A failed storage deletion leaves the record available for retry. CDN or browser caches may continue serving previously cached bytes after origin deletion.
Asset deletion does not check shared references. Confirm that other content, pending posts, and retries no longer need the file. Existing content and post records are preserved, so their references can become unavailable. Published email delivery images are protected and return 400 if deletion is attempted.
For the full clip lifecycle, including a cleanup job 24 hours after publication, see Media retention and cleanup.