API Reference

Resource Model

The API operates on three core resource types:

ResourcePath prefixDescription
Project/v1/projectsContainer for items and files
Item/v1/projects/{project_key}/itemsInline text or file upload
Search/v1/projects/{project_key}/searchFull-text search across items

Items are the canonical resource type. Each item has a content_type indicating whether it stores inline text (inline) or an uploaded file (file). Both types share the same endpoint surface.

Authentication

All API requests require a Bearer token in the Authorization header. API keys are prefixed ctxme_ and validated against stored prefixes/hashes.

curl -H "Authorization: Bearer $API_KEY" https://api.ctx.me/v1/projects

Endpoints

Health

MethodPathDescription
GET/healthService health check

Auth

MethodPathDescription
GET/v1/auth/meCurrent user + account context

Projects

MethodPathDescription
GET/v1/projectsList projects for current account
GET/v1/projects/{project_key}Get a single project
POST/v1/projectsCreate a new project
PUT/v1/projects/{project_key}Update a project (ETag required)
DELETE/v1/projects/{project_key}Delete a project (ETag required)

List Projects

Returns a paginated list of projects for the current account.

{
  "projects": [ ... ],
  "next_cursor": "eyJ...",
  "has_more": true
}

Query parameters:

  • limit: Max projects per page (1-200, default 50)
  • cursor: Opaque cursor from previous response's next_cursor

Create Project

Returns 201 Created with Location and ETag headers.

HTTP/1.1 201 Created
Location: /v1/projects/my-project
ETag: "v1:2026-02-07T..."

Get Project

Supports conditional GET via If-None-Match header. Returns 304 Not Modified when the ETag matches.

Update Project

Full replacement of project metadata. Requires If-Match header.

Delete Project

Soft-deletes a project. Requires If-Match header. Returns 409 Conflict if the project still contains items.

Items

The unified items endpoint handles both inline text content and file uploads through a single API surface.

MethodPathDescription
GET/v1/projects/{project_key}/itemsList items in a project
GET/v1/projects/{project_key}/items/{item_key}Get a single item
POST/v1/projects/{project_key}/itemsCreate item (JSON or multipart)
PUT/v1/projects/{project_key}/items/{item_key}Replace an inline item (full update)
PATCH/v1/projects/{project_key}/items/{item_key}Patch item metadata (partial update)
DELETE/v1/projects/{project_key}/items/{item_key}Delete an item

Creating Items

Items can be created in two ways:

Inline Content (JSON):

curl -X POST -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"key": "my-item", "title": "My Item", "data": "content here"}' \
  https://api.ctx.me/v1/projects/myproject/items

File Upload (multipart/form-data):

curl -X POST -H "Authorization: Bearer $API_KEY" \
  -F "file=@document.docx" \
  -F "key=my-document" \
  https://api.ctx.me/v1/projects/myproject/items

For file uploads, the key is optional — if omitted, it's derived from the filename. Supported upload formats are .txt, .md/.markdown, .pdf, .docx, .csv, .tsv, .html, and .htm. File uploads return 202 Accepted while asynchronous extraction runs.

PUT — Replace Inline Item

Full replacement of an inline item's content and metadata. Requires If-Match header. File items cannot be replaced via PUT — use PATCH to update metadata, or delete and re-upload.

PATCH — Partial Metadata Update

Partially updates item metadata. Requires If-Match header. Accepted fields (at least one required):

  • title (optional): New title (1-255 characters)
  • mime_type (optional): New MIME type (not changeable for file items)
  • tags (optional): New tags array

Content Types

Items have a content_type field indicating the storage type:

  • inline: Text content stored directly in the database
  • file: Binary content stored in object storage

Processing Status

Items have a processing_status field:

  • ready: Content is fully indexed and searchable
  • processing: Async extraction in progress (file uploads)
  • failed: Processing failed (check processing_error field)

List Items Query Parameters

  • content_type: Filter by type (inline or file)
  • content_sha256: Filter by content hash for deduplication lookup
  • created_via: Filter by provenance (ui, cli, mcp, unknown)
  • limit: Max items per page (1-200, default 50)
  • cursor: Opaque cursor from previous response's next_cursor
MethodPathDescription
GET/v1/search?q=<query>Search context items

Query parameters:

  • q (required): Search query (2-256 chars)
  • project_key: Scope search to a single project. Omit to search all projects.
  • tags: Comma-separated tags (AND semantics)
  • include_pending: Include items with non-ready processing status (default false)
  • created_via: Filter by provenance (ui, cli, mcp, unknown)
  • limit: Results per page (1-50, default 20)
  • cursor: Opaque cursor from previous response's next_cursor

Pagination

List endpoints use cursor-based pagination for stable, efficient paging through results.

  1. Make the initial request (optionally with limit).
  2. The response includes has_more (boolean) and next_cursor (string or null).
  3. If has_more is true, pass next_cursor as the cursor query parameter in the next request.
  4. Repeat until has_more is false.
# First page
curl -H "Authorization: Bearer $API_KEY" \
  "https://api.ctx.me/v1/projects/myproject/items?limit=10"

# Next page (using next_cursor from previous response)
curl -H "Authorization: Bearer $API_KEY" \
  "https://api.ctx.me/v1/projects/myproject/items?limit=10&cursor=eyJ..."

Conditional Requests and ETags

Optimistic Concurrency (If-Match)

Write operations that modify existing resources require the If-Match header to prevent lost updates. The value must match the resource's current etag.

# 1. Fetch the resource and capture its ETag
curl -i -H "Authorization: Bearer $API_KEY" \
  https://api.ctx.me/v1/projects/myproject/items/my-item

# 2. Update with If-Match
curl -X PUT -H "Authorization: Bearer $API_KEY" \
  -H 'If-Match: "v1:2026-02-07T12:00:00Z"' \
  -H "Content-Type: application/json" \
  -d '{"title": "Updated", "data": "new content", "mime_type": "text/plain", "tags": []}' \
  https://api.ctx.me/v1/projects/myproject/items/my-item

Conditional GET (If-None-Match)

Read operations support the If-None-Match header to avoid re-downloading unchanged resources. Returns 304 Not Modified when the ETag matches.

Errors

Error responses follow a consistent envelope format:

{
  "error": {
    "code": "string",
    "message": "Human-readable detail",
    "details": {}
  }
}

Common error codes:

StatusCodeDescription
400validation_errorInvalid request (e.g., PUT on file items)
401unauthorizedInvalid or missing API key
403forbiddenInsufficient permissions
404not_foundResource not found
409conflictDuplicate key or content
412precondition_failedETag mismatch (If-Match failed)
422validation_errorRequest validation failed
428precondition_requiredMissing required If-Match header
429too_many_requestsRate limited

Versioning

All endpoints are prefixed with /v1/. The current API version is v1. Breaking changes within /v1/ are avoided where possible. Deprecated endpoints remain functional and will be announced before removal.