Documentation

Contents

Overview

Each content source in Seclai produces content versions — individual indexed items such as articles, uploaded files, or custom documents. The Contents API lets you inspect, replace, and delete these items, as well as view the embedding chunks generated for semantic search.

Key concepts:

  • Content Version — A single indexed document tied to a source connection.
  • Embeddings — Chunked vector representations used for knowledge base retrieval. Each content version may have many embedding chunks.
  • Inline Text — Small text payloads (up to 8 KB) that can replace an existing content version without a file upload.
  • Extracted media — When the source has media indexing enabled, the images and video in a web page's main content become attachments of the page's item. So do the images inside a PDF, Word, PowerPoint or Excel file (.docx, .pptx, .xlsx), without that setting. Both are listed by GET /contents/{id}/attachments, as are the files of an RSS item that its source chose to attach. extracted_media_count reports how many were attached to the item on this source; a file over the per-file size limit is listed as a failed attachment and not counted. extracted_media_capped is true when extraction stopped with media still unread — a web page that listed more media than is read from one page or ran out of the budget for fetching remote media, or a page or file that could not be read to the end. Media search will not match anything past the cut. A null count means there is no media record for the item; treat it as unknown, not as zero.
  • Awaiting re-index — awaiting_reindex is true for an item that is linked and reports completed but whose contents are not searchable yet, because they still sit under the index the source used before an embedding migration switched it. Anything added while a migration was running can land in this state. Semantic and content search will not match the item until it is re-embedded; a search on its title can still return it, so it may appear in results while its body finds nothing. It clears on its own once the item is re-embedded under the new configuration — typically within minutes of the migration finishing, and a daily sweep retries anything still outstanding, so a large backlog can take more than one sweep to drain. That re-embedding is not charged to your account: it is repair work caused by the migration's timing rather than by anything you did. An item that is simply still indexing is not flagged this way; content_status covers that.

API Access

Content items can be managed via the Public API using your API key. All endpoints are scoped to your account.

The CONTENT_VERSION_ID these endpoints take is the source_connection_content_version_id, which only exists once an item has finished indexing. Where you get it depends on how the upload came back:

  • status: "uploaded" — a new item. The upload returns source_connection_content_version_id: null, because it does not have one yet. Poll GET /sources/{id}/contents/{content_version_id} with the content_version_id the upload returned, and use the source_connection_content_version_id it reports once the item is indexed. An item that reports held_for_review: true was blocked by a governance policy and has no id to use unless a reviewer releases it.
  • status: "duplicate" — this exact file is already on the source. The upload returns the existing item's source_connection_content_version_id directly, and content_version_id: null. It is already indexed, so use it here straight away — there is nothing to poll.

See Track Indexing Progress Per Item.

Get Content Details

Retrieve the extracted text and metadata for a content version. Use start and end to page through large documents.

CONTENT_VERSION_ID=...

curl "https://api.seclai.com/contents/$CONTENT_VERSION_ID?start=0&end=5000" \
  -H "X-API-Key: $SECLAI_API_KEY"

The response carries extracted_media_count — how many images or video clips media indexing attached to the item from this web page's main content, or, for a PDF or Office file, how many images inside it were attached to the item. The count is for this source. It has three meanings and they are not interchangeable:

ValueMeaning
nullThere is no media record — the item is neither a web page nor a PDF or Office file, media indexing is off for a web page's source, the embedding model can't index the kinds involved, the item was read and nothing indexable was found in it, or the content was indexed before this was recorded
0Extraction of the page was cut short before anything was indexed, so extracted_media_capped is true
> 0That many images or videos attached

A count above zero is shown on the content detail page in the app, and the field is on the get_source_content_text MCP tool. If you expected pictures and the count is null, see Media Indexing Found No Images.

Delete Content

Permanently remove a content version and its embeddings.

CONTENT_VERSION_ID=...

curl -X DELETE "https://api.seclai.com/contents/$CONTENT_VERSION_ID" \
  -H "X-API-Key: $SECLAI_API_KEY"

List Content Embeddings

View the embedding chunks for a content version. Useful for debugging chunking and indexing.

CONTENT_VERSION_ID=...

curl "https://api.seclai.com/contents/$CONTENT_VERSION_ID/embeddings?page=1&limit=20" \
  -H "X-API-Key: $SECLAI_API_KEY"

List Content Attachments

List the files attached to a content item: those an agent's write content attachment step wrote, those sent with a message to an email content source, the images and video in a web page's main content on a source with media indexing on, and the images extracted from a PDF, Word, PowerPoint or Excel file (.docx, .pptx, .xlsx) that is the item or one of its attachments, on a source whose embedding model indexes images. Each entry carries a metadata object, where an image from a PDF has its page_number and one from a web page its source_url, alt_text and position, along with indexing_status (pending, completed or failed, or null when indexing was not asked for) and, when it failed, indexing_error saying why.

CONTENT_VERSION_ID=...

curl "https://api.seclai.com/contents/$CONTENT_VERSION_ID/attachments?page=1&limit=20" \
  -H "X-API-Key: $SECLAI_API_KEY"

Open a Content Attachment

Each entry in the list has an id. Use it to open one attachment: its status and metadata with the text it is indexed by, the embeddings it is indexed by, and the file itself. In the app, the same view opens from a file's name in an item's Attachments list.

ATTACHMENT_ID=...

# Details and the text indexed from the file (page long text with start and end)
curl "https://api.seclai.com/contents/$CONTENT_VERSION_ID/attachments/$ATTACHMENT_ID?start=0&end=5000" \
  -H "X-API-Key: $SECLAI_API_KEY"

# The chunks search can match
curl "https://api.seclai.com/contents/$CONTENT_VERSION_ID/attachments/$ATTACHMENT_ID/embeddings?page=1&limit=20" \
  -H "X-API-Key: $SECLAI_API_KEY"

# The file's bytes
curl "https://api.seclai.com/contents/$CONTENT_VERSION_ID/attachments/$ATTACHMENT_ID/file" \
  -H "X-API-Key: $SECLAI_API_KEY" -o attachment.bin

A file with no completed index has no text and no embeddings; for one that failed, indexing_error says why. file_withheld is null when the file can be downloaded. Otherwise the download answers 403 and the field says why: blocked_by_governance_policy, redacted_by_governance_policy (any text returned is the redacted text, and the original file is not served), or pending_screening for a file that arrived from outside and is still being indexed.

Replace Content with Inline Text

Replace the text backing an existing content version with a small inline payload (max 8 KB UTF-8).

CONTENT_VERSION_ID=...

curl -X PUT "https://api.seclai.com/contents/$CONTENT_VERSION_ID" \
  -H "X-API-Key: $SECLAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Updated article text...",
    "content_type": "text/plain",
    "title": "Updated Article",
    "metadata": {"category": "docs"}
  }'

Replace Content with File Upload

Upload a new file to replace the content for an existing content version.

CONTENT_VERSION_ID=...

curl -X POST "https://api.seclai.com/contents/$CONTENT_VERSION_ID/upload" \
  -H "X-API-Key: $SECLAI_API_KEY" \
  -F "file=@updated-doc.pdf" \
  -F "title=Updated Document" \
  -F 'metadata={"category":"reports"}'

Both replace endpoints keep the same CONTENT_VERSION_ID, so you can reuse it for later replacements, reads and deletes. The replacement is indexed in the background: until it finishes, reads return the previous content rather than an empty result, and a replacement that fails to index leaves the previous content in place.

Next Steps