{
"openapi": "3.0.3",
"info": {
"title": "Cedros Data API",
"version": "0.1.0",
"description": "Multi-site Postgres-backed content and custom data storage"
},
"servers": [
{
"url": "http://localhost:8080",
"description": "Local development server"
}
],
"security": [
{
"BearerAuth": []
}
],
"tags": [
{ "name": "DATA", "description": "Entry upsert, query, and collection registration" },
{ "name": "ADMIN", "description": "Admin operations for collections, pages, and bootstrap" },
{ "name": "SCHEMA", "description": "Custom schema and contract operations" },
{ "name": "STORAGE", "description": "Media upload, asset management, and storage config (optional feature)" },
{ "name": "SITE", "description": "Site registration, migration, import/export, and config" },
{ "name": "DISCOVERY", "description": "AI discovery endpoints (no auth required)" }
],
"paths": {
"/entries/upsert": {
"post": {
"operationId": "upsertEntry",
"summary": "Upsert an entry",
"description": "Insert or update an entry in a collection. The entry is identified by collection_name + entry_key. Payload must be a JSON object. Contracts are verified on write.",
"tags": ["DATA"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/UpsertEntryRequest" }
}
}
},
"responses": {
"200": {
"description": "Upserted entry record",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/EntryRecord" }
}
}
},
"400": { "$ref": "#/components/responses/BadRequest" },
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"404": { "$ref": "#/components/responses/NotFound" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/entries/query": {
"post": {
"operationId": "queryEntries",
"summary": "Query entries from a collection",
"description": "Retrieve entries by collection name, optionally filtered by entry_keys, a JSONB contains filter, and pagination. When visitor_id is provided, metered content gating is applied.",
"tags": ["DATA"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/QueryEntriesRequest" }
}
}
},
"responses": {
"200": {
"description": "Array of matching entry records",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": { "$ref": "#/components/schemas/EntryRecord" }
}
}
}
},
"400": { "$ref": "#/components/responses/BadRequest" },
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"404": { "$ref": "#/components/responses/NotFound" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/collections": {
"post": {
"operationId": "registerCollection",
"summary": "Register a collection",
"description": "Register a new collection with the specified mode (jsonb or typed). Optionally set table_name for typed collections and a strict_contract.",
"tags": ["DATA"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/RegisterCollectionRequest" }
}
}
},
"responses": {
"200": {
"description": "Registered collection",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/Collection" }
}
}
},
"400": { "$ref": "#/components/responses/BadRequest" },
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/custom-schema": {
"post": {
"operationId": "registerCustomSchema",
"summary": "Register a custom schema",
"description": "Apply a custom schema definition with types and tables. Returns a report of applied changes, generated SQL, and any breaking changes detected.",
"tags": ["SCHEMA"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/RegisterCustomSchemaRequest" }
}
}
},
"responses": {
"200": {
"description": "Schema apply report",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/CustomSchemaApplyReport" }
}
}
},
"400": { "$ref": "#/components/responses/BadRequest" },
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/contract/verify": {
"post": {
"operationId": "verifyContract",
"summary": "Verify a contract against sample data",
"description": "Check whether sample payloads are compatible with the stored contract for a collection. Returns a report with passes/failures and any breaking or additive changes.",
"tags": ["SCHEMA"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/VerifyContractRequest" }
}
}
},
"responses": {
"200": {
"description": "Contract verification report",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ContractVerificationReport" }
}
}
},
"400": { "$ref": "#/components/responses/BadRequest" },
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/site/export": {
"get": {
"operationId": "exportSite",
"summary": "Export complete site data",
"description": "Export the entire site including site metadata, collections, contracts, custom schema, and all entries.",
"tags": ["SITE"],
"responses": {
"200": {
"description": "Full site export",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/SiteExport" }
}
}
},
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"404": { "$ref": "#/components/responses/NotFound" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/import": {
"post": {
"operationId": "importSite",
"summary": "Import site data",
"description": "Import a previously exported site payload. Optionally overwrite existing contracts.",
"tags": ["SITE"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ImportSiteRequest" }
}
}
},
"responses": {
"200": {
"description": "Import result summary",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ImportResult" }
}
}
},
"400": { "$ref": "#/components/responses/BadRequest" },
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/site": {
"post": {
"operationId": "registerSite",
"summary": "Register a site",
"description": "Register or update the site with a display name and optional metadata object.",
"tags": ["SITE"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/RegisterSiteRequest" }
}
}
},
"responses": {
"200": {
"description": "Registered site",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/Site" }
}
}
},
"400": { "$ref": "#/components/responses/BadRequest" },
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/migrate": {
"post": {
"operationId": "runMigrations",
"summary": "Run database migrations",
"description": "Apply any pending database migrations.",
"tags": ["SITE"],
"responses": {
"200": {
"description": "Migration success",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/OkResponse" }
}
}
},
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/site/config/{key}": {
"get": {
"operationId": "getPublicSiteConfig",
"summary": "Get public site config by key",
"description": "Retrieve a publicly accessible site configuration entry. Allowed keys: global, tipping, monetization. No authentication required.",
"tags": ["SITE"],
"security": [],
"parameters": [
{
"name": "key",
"in": "path",
"required": true,
"description": "Config key (global, tipping, or monetization)",
"schema": {
"type": "string",
"enum": ["global", "tipping", "monetization"]
}
}
],
"responses": {
"200": {
"description": "Config payload object. Returns {\"enabled\": false} if key has no stored value.",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
},
"404": { "$ref": "#/components/responses/NotFound" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/admin/bootstrap": {
"post": {
"operationId": "bootstrapSite",
"summary": "Bootstrap site with defaults",
"description": "Seed default collections and entries for the site.",
"tags": ["ADMIN"],
"responses": {
"200": {
"description": "Bootstrap report",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/SiteBootstrapReport" }
}
}
},
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/admin/collections": {
"get": {
"operationId": "listCollections",
"summary": "List all collections",
"description": "Retrieve all registered collections for the site.",
"tags": ["ADMIN"],
"responses": {
"200": {
"description": "Array of collections",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": { "$ref": "#/components/schemas/Collection" }
}
}
}
},
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"500": { "$ref": "#/components/responses/InternalError" }
}
},
"post": {
"operationId": "createCollection",
"summary": "Create a collection (admin)",
"description": "Create a new collection via the admin endpoint. Mode defaults to jsonb if omitted.",
"tags": ["ADMIN"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/RegisterSiteCollectionRequest" }
}
}
},
"responses": {
"200": {
"description": "Created collection",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/Collection" }
}
}
},
"400": { "$ref": "#/components/responses/BadRequest" },
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/admin/pages": {
"get": {
"operationId": "listPages",
"summary": "List all pages",
"description": "Retrieve all default page entries for the site.",
"tags": ["ADMIN"],
"responses": {
"200": {
"description": "Array of page entry records",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": { "$ref": "#/components/schemas/EntryRecord" }
}
}
}
},
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/admin/pages/{page_key}": {
"put": {
"operationId": "upsertPage",
"summary": "Upsert a page",
"description": "Insert or update a page entry by page_key.",
"tags": ["ADMIN"],
"parameters": [
{
"name": "page_key",
"in": "path",
"required": true,
"description": "Page entry key",
"schema": { "type": "string" }
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/UpsertPageRequest" }
}
}
},
"responses": {
"200": {
"description": "Upserted page entry",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/EntryRecord" }
}
}
},
"400": { "$ref": "#/components/responses/BadRequest" },
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/admin/default-pages": {
"get": {
"operationId": "getDefaultPages",
"summary": "Get default page templates",
"description": "Retrieve the built-in default page templates with key, title, route, and section.",
"tags": ["ADMIN"],
"responses": {
"200": {
"description": "Array of default page templates",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": { "$ref": "#/components/schemas/DefaultPageTemplate" }
}
}
}
},
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/admin/media/upload": {
"post": {
"operationId": "uploadMedia",
"summary": "Upload media file",
"description": "Upload an image file via multipart form data. The file is processed into variants and stored in S3-compatible storage. Requires the 'storage' feature.",
"tags": ["STORAGE"],
"requestBody": {
"required": true,
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"required": ["file"],
"properties": {
"file": {
"type": "string",
"format": "binary",
"description": "Image file to upload"
}
}
}
}
}
},
"responses": {
"200": {
"description": "Uploaded asset with variants",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/Asset" }
}
}
},
"400": { "$ref": "#/components/responses/BadRequest" },
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"503": { "$ref": "#/components/responses/ServiceUnavailable" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/admin/media/assets": {
"get": {
"operationId": "listMediaAssets",
"summary": "List media assets",
"description": "Retrieve a paginated list of media assets.",
"tags": ["STORAGE"],
"parameters": [
{
"name": "limit",
"in": "query",
"description": "Maximum number of assets to return (default 50)",
"schema": { "type": "integer", "format": "int64", "default": 50 }
},
{
"name": "offset",
"in": "query",
"description": "Number of assets to skip (default 0)",
"schema": { "type": "integer", "format": "int64", "default": 0 }
}
],
"responses": {
"200": {
"description": "Array of assets",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": { "$ref": "#/components/schemas/Asset" }
}
}
}
},
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/admin/media/assets/{asset_id}": {
"get": {
"operationId": "getMediaAsset",
"summary": "Get a media asset",
"description": "Retrieve a single media asset by ID.",
"tags": ["STORAGE"],
"parameters": [
{
"name": "asset_id",
"in": "path",
"required": true,
"description": "Asset UUID",
"schema": { "type": "string", "format": "uuid" }
}
],
"responses": {
"200": {
"description": "Asset record",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/Asset" }
}
}
},
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"404": { "$ref": "#/components/responses/NotFound" },
"500": { "$ref": "#/components/responses/InternalError" }
}
},
"put": {
"operationId": "updateMediaAsset",
"summary": "Update a media asset",
"description": "Update asset metadata (alt_text, metadata) by ID.",
"tags": ["STORAGE"],
"parameters": [
{
"name": "asset_id",
"in": "path",
"required": true,
"description": "Asset UUID",
"schema": { "type": "string", "format": "uuid" }
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/UpdateAssetRequest" }
}
}
},
"responses": {
"200": {
"description": "Updated asset record",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/Asset" }
}
}
},
"400": { "$ref": "#/components/responses/BadRequest" },
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"404": { "$ref": "#/components/responses/NotFound" },
"500": { "$ref": "#/components/responses/InternalError" }
}
},
"delete": {
"operationId": "deleteMediaAsset",
"summary": "Delete a media asset",
"description": "Delete an asset and all its S3 objects (original + variants) by ID.",
"tags": ["STORAGE"],
"parameters": [
{
"name": "asset_id",
"in": "path",
"required": true,
"description": "Asset UUID",
"schema": { "type": "string", "format": "uuid" }
}
],
"responses": {
"200": {
"description": "Deletion confirmation",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/OkResponse" }
}
}
},
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"404": { "$ref": "#/components/responses/NotFound" },
"503": { "$ref": "#/components/responses/ServiceUnavailable" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/admin/storage/config": {
"get": {
"operationId": "getStorageConfig",
"summary": "Get storage configuration",
"description": "Returns whether storage is enabled and a redacted summary of the config (bucket, region, endpoint, CDN, path prefix, redacted access key).",
"tags": ["STORAGE"],
"responses": {
"200": {
"description": "Storage config status",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/StorageConfigResponse" }
}
}
},
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/admin/storage/test": {
"post": {
"operationId": "testStorage",
"summary": "Test storage connectivity",
"description": "Verify that the S3-compatible storage connection is working by issuing a HEAD-bucket request.",
"tags": ["STORAGE"],
"responses": {
"200": {
"description": "Storage connection test passed",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/OkResponse" }
}
}
},
"401": { "$ref": "#/components/responses/Unauthorized" },
"403": { "$ref": "#/components/responses/Forbidden" },
"503": { "$ref": "#/components/responses/ServiceUnavailable" },
"500": { "$ref": "#/components/responses/InternalError" }
}
}
},
"/ai.txt": {
"get": {
"operationId": "getAiTxt",
"summary": "AI discovery text",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "AI discovery text",
"content": { "text/plain": { "schema": { "type": "string" } } }
}
}
}
},
"/llms.txt": {
"get": {
"operationId": "getLlmsTxt",
"summary": "LLM documentation (summary)",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "LLM summary documentation",
"content": { "text/plain": { "schema": { "type": "string" } } }
}
}
}
},
"/llms-full.txt": {
"get": {
"operationId": "getLlmsFullTxt",
"summary": "LLM documentation (full)",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "Full LLM documentation",
"content": { "text/plain": { "schema": { "type": "string" } } }
}
}
}
},
"/llms-admin.txt": {
"get": {
"operationId": "getLlmsAdminTxt",
"summary": "LLM documentation (admin)",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "Admin-focused LLM documentation",
"content": { "text/plain": { "schema": { "type": "string" } } }
}
}
}
},
"/skill.md": {
"get": {
"operationId": "getSkillMd",
"summary": "Skill index (Markdown)",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "Skill index in Markdown",
"content": { "text/markdown": { "schema": { "type": "string" } } }
}
}
}
},
"/skill.json": {
"get": {
"operationId": "getSkillJson",
"summary": "Skill index (JSON)",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "Skill index in JSON",
"content": { "application/json": { "schema": { "type": "object" } } }
}
}
}
},
"/skills/data.md": {
"get": {
"operationId": "getSkillDataMd",
"summary": "Data skill documentation",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "Data skill Markdown",
"content": { "text/markdown": { "schema": { "type": "string" } } }
}
}
}
},
"/skills/admin.md": {
"get": {
"operationId": "getSkillAdminMd",
"summary": "Admin skill documentation",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "Admin skill Markdown",
"content": { "text/markdown": { "schema": { "type": "string" } } }
}
}
}
},
"/skills/schema.md": {
"get": {
"operationId": "getSkillSchemaMd",
"summary": "Schema skill documentation",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "Schema skill Markdown",
"content": { "text/markdown": { "schema": { "type": "string" } } }
}
}
}
},
"/skills/storage.md": {
"get": {
"operationId": "getSkillStorageMd",
"summary": "Storage skill documentation",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "Storage skill Markdown",
"content": { "text/markdown": { "schema": { "type": "string" } } }
}
}
}
},
"/skills/site.md": {
"get": {
"operationId": "getSkillSiteMd",
"summary": "Site skill documentation",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "Site skill Markdown",
"content": { "text/markdown": { "schema": { "type": "string" } } }
}
}
}
},
"/agent.md": {
"get": {
"operationId": "getAgentMd",
"summary": "Agent integration guide",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "Agent integration guide in Markdown",
"content": { "text/markdown": { "schema": { "type": "string" } } }
}
}
}
},
"/heartbeat.md": {
"get": {
"operationId": "getHeartbeatMd",
"summary": "Health check (Markdown)",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "Health status in Markdown",
"content": { "text/markdown": { "schema": { "type": "string" } } }
}
}
}
},
"/heartbeat.json": {
"get": {
"operationId": "getHeartbeatJson",
"summary": "Health check (JSON)",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "Health status in JSON",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": { "type": "string" },
"version": { "type": "string" }
}
}
}
}
}
}
}
},
"/.well-known/ai-discovery.json": {
"get": {
"operationId": "getAiDiscoveryJson",
"summary": "AI discovery index manifest",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "AI discovery index",
"content": { "application/json": { "schema": { "type": "object" } } }
}
}
}
},
"/.well-known/ai-plugin.json": {
"get": {
"operationId": "getAiPluginJson",
"summary": "OpenAI plugin manifest",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "OpenAI plugin manifest",
"content": { "application/json": { "schema": { "type": "object" } } }
}
}
}
},
"/.well-known/agent.json": {
"get": {
"operationId": "getAgentJson",
"summary": "A2A agent manifest",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "A2A agent manifest",
"content": { "application/json": { "schema": { "type": "object" } } }
}
}
}
},
"/.well-known/mcp": {
"get": {
"operationId": "getMcpDiscovery",
"summary": "MCP discovery endpoint",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "MCP discovery document",
"content": { "application/json": { "schema": { "type": "object" } } }
}
}
}
},
"/.well-known/skills.zip": {
"get": {
"operationId": "getSkillsBundle",
"summary": "Downloadable skills bundle",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "ZIP archive of all skill files",
"content": {
"application/zip": {
"schema": { "type": "string", "format": "binary" }
}
}
}
}
}
},
"/openapi.json": {
"get": {
"operationId": "getOpenApiSpec",
"summary": "OpenAPI specification",
"tags": ["DISCOVERY"],
"security": [],
"responses": {
"200": {
"description": "This OpenAPI 3.0 specification",
"content": { "application/json": { "schema": { "type": "object" } } }
}
}
}
}
},
"components": {
"securitySchemes": {
"BearerAuth": {
"type": "http",
"scheme": "bearer",
"description": "Bearer token passed via Authorization header. When cedros-login-profile is enabled, the token is verified against the cedros-login service. The x-cedros-org-id header is also required for organization-scoped requests."
}
},
"schemas": {
"UpsertEntryRequest": {
"type": "object",
"required": ["collection_name", "entry_key", "payload"],
"properties": {
"collection_name": { "type": "string", "description": "Target collection name" },
"entry_key": { "type": "string", "description": "Unique key for the entry within the collection" },
"payload": { "type": "object", "description": "Entry data (must be a JSON object)" }
}
},
"QueryEntriesRequest": {
"type": "object",
"required": ["collection_name"],
"properties": {
"collection_name": { "type": "string", "description": "Collection to query" },
"entry_keys": {
"type": "array",
"items": { "type": "string" },
"default": [],
"description": "Optional filter by specific entry keys"
},
"contains": {
"type": "object",
"nullable": true,
"description": "Optional JSONB containment filter (@>) applied to payload"
},
"limit": {
"type": "integer",
"format": "int64",
"default": 100,
"minimum": 0,
"maximum": 1000,
"description": "Maximum entries to return"
},
"offset": {
"type": "integer",
"format": "int64",
"default": 0,
"minimum": 0,
"description": "Number of entries to skip"
},
"visitor_id": {
"type": "string",
"nullable": true,
"description": "Optional visitor ID for metered content gating"
}
}
},
"EntryRecord": {
"type": "object",
"required": ["entry_key", "payload", "updated_at"],
"properties": {
"entry_key": { "type": "string" },
"payload": { "type": "object" },
"updated_at": { "type": "string", "format": "date-time" }
}
},
"RegisterCollectionRequest": {
"type": "object",
"required": ["collection_name", "mode"],
"properties": {
"collection_name": { "type": "string" },
"mode": { "$ref": "#/components/schemas/CollectionMode" },
"table_name": { "type": "string", "nullable": true, "description": "Required for typed mode" },
"strict_contract": {
"nullable": true,
"allOf": [{ "$ref": "#/components/schemas/ContractSchema" }],
"description": "Optional strict contract enforced on all writes"
}
}
},
"RegisterSiteCollectionRequest": {
"type": "object",
"required": ["collection_name"],
"properties": {
"collection_name": { "type": "string" },
"mode": {
"nullable": true,
"allOf": [{ "$ref": "#/components/schemas/CollectionMode" }],
"description": "Defaults to jsonb if omitted"
},
"table_name": { "type": "string", "nullable": true },
"strict_contract": {
"nullable": true,
"allOf": [{ "$ref": "#/components/schemas/ContractSchema" }]
}
}
},
"Collection": {
"type": "object",
"required": ["collection_name", "mode"],
"properties": {
"collection_name": { "type": "string" },
"mode": { "$ref": "#/components/schemas/CollectionMode" },
"table_name": { "type": "string", "nullable": true },
"strict_contract": {
"nullable": true,
"allOf": [{ "$ref": "#/components/schemas/ContractSchema" }]
}
}
},
"CollectionMode": {
"type": "string",
"enum": ["jsonb", "typed"],
"description": "Storage mode: jsonb (default flexible JSON) or typed (Postgres-native table)"
},
"RegisterSiteRequest": {
"type": "object",
"required": ["display_name"],
"properties": {
"display_name": { "type": "string" },
"metadata": { "type": "object", "default": {}, "description": "Arbitrary site metadata" }
}
},
"Site": {
"type": "object",
"required": ["display_name", "metadata"],
"properties": {
"display_name": { "type": "string" },
"metadata": { "type": "object" }
}
},
"RegisterCustomSchemaRequest": {
"type": "object",
"required": ["definition"],
"properties": {
"definition": { "$ref": "#/components/schemas/CustomSchemaDefinition" }
}
},
"CustomSchemaDefinition": {
"type": "object",
"properties": {
"types": {
"type": "array",
"default": [],
"items": { "$ref": "#/components/schemas/CustomTypeDefinition" }
},
"tables": {
"type": "array",
"default": [],
"items": { "$ref": "#/components/schemas/CustomTableDefinition" }
}
}
},
"CustomTypeDefinition": {
"type": "object",
"required": ["kind", "name"],
"description": "Discriminated union tagged by 'kind'. Enum types have 'values'; composite types have 'fields'.",
"properties": {
"kind": {
"type": "string",
"enum": ["enum", "composite"]
},
"name": { "type": "string" },
"values": {
"type": "array",
"items": { "type": "string" },
"description": "Required for enum kind"
},
"fields": {
"type": "array",
"items": { "$ref": "#/components/schemas/CustomColumnDefinition" },
"description": "Required for composite kind"
}
}
},
"CustomTableDefinition": {
"type": "object",
"required": ["name"],
"properties": {
"name": { "type": "string" },
"columns": {
"type": "array",
"default": [],
"items": { "$ref": "#/components/schemas/CustomColumnDefinition" }
},
"primary_key": {
"type": "array",
"default": [],
"items": { "type": "string" }
},
"unique_constraints": {
"type": "array",
"default": [],
"items": { "$ref": "#/components/schemas/UniqueConstraintDefinition" }
},
"foreign_keys": {
"type": "array",
"default": [],
"items": { "$ref": "#/components/schemas/ForeignKeyDefinition" }
},
"indexes": {
"type": "array",
"default": [],
"items": { "$ref": "#/components/schemas/IndexDefinition" }
}
}
},
"CustomColumnDefinition": {
"type": "object",
"required": ["name", "data_type"],
"properties": {
"name": { "type": "string" },
"data_type": { "type": "string", "description": "Postgres data type expression" },
"nullable": { "type": "boolean", "default": false },
"default_sql": { "type": "string", "nullable": true, "description": "SQL default expression" }
}
},
"UniqueConstraintDefinition": {
"type": "object",
"required": ["columns"],
"properties": {
"name": { "type": "string", "nullable": true },
"columns": { "type": "array", "items": { "type": "string" } }
}
},
"ForeignKeyDefinition": {
"type": "object",
"required": ["columns", "ref_table", "ref_columns"],
"properties": {
"name": { "type": "string", "nullable": true },
"columns": { "type": "array", "items": { "type": "string" } },
"ref_table": { "type": "string" },
"ref_columns": { "type": "array", "items": { "type": "string" } },
"on_delete": { "type": "string", "nullable": true, "description": "e.g. CASCADE, SET NULL" }
}
},
"IndexDefinition": {
"type": "object",
"required": ["columns"],
"properties": {
"name": { "type": "string", "nullable": true },
"columns": { "type": "array", "items": { "type": "string" } },
"unique": { "type": "boolean", "default": false }
}
},
"CustomSchemaApplyReport": {
"type": "object",
"required": ["applied", "version", "additive_changes", "breaking_changes", "generated_sql"],
"properties": {
"applied": { "type": "boolean", "description": "Whether the schema was applied" },
"version": { "type": "integer", "format": "int32" },
"additive_changes": { "type": "array", "items": { "type": "string" } },
"breaking_changes": { "type": "array", "items": { "type": "string" } },
"generated_sql": { "type": "array", "items": { "type": "string" } }
}
},
"VerifyContractRequest": {
"type": "object",
"required": ["collection_name", "samples"],
"properties": {
"collection_name": { "type": "string" },
"samples": {
"type": "array",
"items": { "type": "object" },
"description": "Sample payloads to verify against the stored contract"
}
}
},
"ContractVerificationReport": {
"type": "object",
"required": ["passes", "additive_changes", "breaking_changes", "incoming_contract"],
"properties": {
"passes": { "type": "boolean" },
"additive_changes": { "type": "array", "items": { "type": "string" } },
"breaking_changes": { "type": "array", "items": { "type": "string" } },
"stored_contract": {
"nullable": true,
"allOf": [{ "$ref": "#/components/schemas/ContractSchema" }]
},
"incoming_contract": { "$ref": "#/components/schemas/ContractSchema" }
}
},
"ContractSchema": {
"type": "object",
"required": ["fields"],
"properties": {
"fields": {
"type": "array",
"items": { "$ref": "#/components/schemas/ContractField" }
}
}
},
"ContractField": {
"type": "object",
"required": ["path", "required", "types"],
"properties": {
"path": { "type": "string", "description": "Dot-separated path into the payload" },
"required": { "type": "boolean" },
"types": {
"type": "array",
"items": { "$ref": "#/components/schemas/ValueType" }
}
}
},
"ValueType": {
"type": "string",
"enum": ["string", "number", "boolean", "object", "array", "null"]
},
"SiteExport": {
"type": "object",
"required": ["site", "collections", "contracts", "entries"],
"properties": {
"site": { "$ref": "#/components/schemas/Site" },
"collections": {
"type": "array",
"items": { "$ref": "#/components/schemas/Collection" }
},
"custom_schema": {
"nullable": true,
"allOf": [{ "$ref": "#/components/schemas/CustomSchemaDefinition" }]
},
"contracts": {
"type": "array",
"items": { "$ref": "#/components/schemas/CollectionContractRecord" }
},
"entries": {
"type": "array",
"items": { "$ref": "#/components/schemas/CollectionEntriesExport" }
}
}
},
"CollectionEntriesExport": {
"type": "object",
"required": ["collection_name", "entries"],
"properties": {
"collection_name": { "type": "string" },
"entries": {
"type": "array",
"items": { "$ref": "#/components/schemas/EntryRecord" }
}
}
},
"CollectionContractRecord": {
"type": "object",
"required": ["collection_name", "version", "contract"],
"properties": {
"collection_name": { "type": "string" },
"version": { "type": "integer", "format": "int32" },
"contract": { "$ref": "#/components/schemas/ContractSchema" }
}
},
"ImportSiteRequest": {
"type": "object",
"required": ["export"],
"properties": {
"export": { "$ref": "#/components/schemas/SiteExport" },
"overwrite_contracts": {
"type": "boolean",
"default": false,
"description": "Whether to overwrite existing contracts during import"
}
}
},
"ImportResult": {
"type": "object",
"required": ["collections_imported", "entries_imported", "contracts_imported"],
"properties": {
"collections_imported": { "type": "integer" },
"entries_imported": { "type": "integer" },
"contracts_imported": { "type": "integer" }
}
},
"UpsertPageRequest": {
"type": "object",
"required": ["payload"],
"properties": {
"payload": { "type": "object", "description": "Page content payload" }
}
},
"DefaultPageTemplate": {
"type": "object",
"required": ["key", "title", "route", "section"],
"properties": {
"key": { "type": "string" },
"title": { "type": "string" },
"route": { "type": "string" },
"section": { "type": "string" }
}
},
"SiteBootstrapReport": {
"type": "object",
"required": ["collections_seeded", "entries_seeded"],
"properties": {
"collections_seeded": { "type": "integer" },
"entries_seeded": { "type": "integer" }
}
},
"Asset": {
"type": "object",
"required": ["id", "filename", "original_key", "content_type", "size_bytes", "variants", "metadata", "created_at", "updated_at"],
"properties": {
"id": { "type": "string", "format": "uuid" },
"filename": { "type": "string" },
"original_key": { "type": "string", "description": "S3 object key for the original file" },
"content_type": { "type": "string" },
"size_bytes": { "type": "integer", "format": "int64" },
"width": { "type": "integer", "format": "int32", "nullable": true },
"height": { "type": "integer", "format": "int32", "nullable": true },
"variants": {
"type": "array",
"items": { "$ref": "#/components/schemas/AssetVariant" },
"description": "Processed image variants (resized, WebP, etc.)"
},
"alt_text": { "type": "string", "nullable": true },
"metadata": { "type": "object" },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" }
}
},
"AssetVariant": {
"type": "object",
"required": ["suffix", "key", "url", "content_type", "width", "height"],
"properties": {
"suffix": { "type": "string", "description": "Variant identifier (e.g. 'sm', 'md', 'webp')" },
"key": { "type": "string", "description": "S3 object key" },
"url": { "type": "string", "format": "uri", "description": "Public URL for the variant" },
"content_type": { "type": "string" },
"width": { "type": "integer", "format": "int32" },
"height": { "type": "integer", "format": "int32" }
}
},
"UpdateAssetRequest": {
"type": "object",
"properties": {
"alt_text": { "type": "string", "nullable": true },
"metadata": { "type": "object", "nullable": true }
}
},
"StorageConfigResponse": {
"type": "object",
"required": ["enabled"],
"properties": {
"enabled": { "type": "boolean" },
"config": {
"type": "object",
"nullable": true,
"description": "Present when enabled=true. Contains redacted storage configuration.",
"properties": {
"bucket": { "type": "string" },
"region": { "type": "string" },
"endpoint": { "type": "string", "nullable": true },
"cdn_base_url": { "type": "string", "nullable": true },
"path_prefix": { "type": "string", "nullable": true },
"access_key": { "type": "string", "description": "Redacted access key (first 3 + last 3 chars)" }
}
}
}
},
"OkResponse": {
"type": "object",
"required": ["ok"],
"properties": {
"ok": { "type": "boolean", "enum": [true] }
}
},
"ErrorResponse": {
"type": "object",
"required": ["error"],
"properties": {
"error": { "type": "string", "description": "Human-readable error message" }
}
}
},
"responses": {
"BadRequest": {
"description": "Invalid request (validation error, breaking schema change, contract failure, etc.)",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
}
}
},
"Unauthorized": {
"description": "Missing or invalid authentication token",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
}
}
},
"Forbidden": {
"description": "Insufficient permissions for the requested operation",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
}
}
},
"NotFound": {
"description": "Site not configured or collection not found",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
}
}
},
"ServiceUnavailable": {
"description": "Storage feature is not enabled or external service is unreachable",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
}
}
},
"InternalError": {
"description": "Internal server error (database, I/O, or unexpected failure)",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
}
}
}
}
}
}