{ "openapi": "3.0.0", "info": { "title": "SpecStory Cloud API", "version": "0.1.0", "description": "\n## **Overview**\n\nSpecStory Cloud provides a REST API for core CRUD operations for projects and AI chat sessions, and a GraphQL API for querying.\n\n## **Authentication**\n\nAll REST and GraphQL requests require an [API key](/api-keys) be passed via a `Bearer` token in the `Authorization` header.\n\nManage your API keys [here](/api-keys).\n\n## **GraphQL**\n\nIn additional to the REST API for CRUD, a [GraphQL](https://graphql.org/) API is available for querying.\n\n- **GraphQL Endpoint**: via a `POST` request to `/api/v1/graphql` for querying with filtering and data selection\n- **GraphQL Explorer**: visit the [interactive GraphQL playground](/api/v1/graphql) in your browser\n\nGraphQL APIs are designed to be self-documenting through their strongly-typed schema system. Every GraphQL service exposes its complete schema through introspection, allowing clients to query the API itself to discover available types, fields, arguments, and their relationships. This introspection capability means that tools can automatically generate comprehensive, always up-to-date documentation directly from the schema definition.\n\nDevelopers should explore the API's capabilities in real-time through the [GraphQL Playground](/api/v1/graphql), which provide interactive documentation, auto-completion, and validation. By requiring explicit type definitions for every field and argument, GraphQL ensures that the API's structure, expected inputs, and return types are transparent and discoverable without needing separate documentation.\n\n## **When to Use REST or GraphQL?**\n\nEach interface has its own use cases:\n\n- **REST API**: [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) operations on projects and sessions, including basic retrievals\n- **GraphQL API**: Complex queries, advanced filtering, relationship queries, full-text search across multiple entities" }, "servers": [ { "url": "https://cloud.specstory.com", "description": "SpecStory Cloud Service" } ], "security": [ { "bearerAuth": [] } ], "tags": [ { "name": "Projects", "description": "Project management operations" }, { "name": "Sessions", "description": "Session management and content operations" }, { "name": "GraphQL", "description": "Advanced querying interface - visit the [GraphQL Explorer](/api/v1/graphql) for interactive exploration" } ], "components": { "securitySchemes": { "bearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT", "description": "API token obtained from the web UI" } }, "schemas": { "ErrorResponse": { "type": "object", "properties": { "success": { "type": "boolean" }, "error": { "type": "string" } }, "required": ["success", "error"], "description": "Error response for failed requests", "example": { "success": false, "error": "Invalid session token" } } } }, "paths": { "/api/v1/projects": { "get": { "summary": "List projects", "tags": ["Projects"], "description": "List all projects", "operationId": "listProjects", "security": [{"bearerAuth": []}], "responses": { "200": { "description": "Successfully listed projects", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": {"type": "boolean"}, "data": { "type": "object", "properties": { "projects": { "type": "array", "items": { "type": "object", "properties": { "id": {"type": "string", "description": "Project ID"}, "ownerId": {"type": "string", "description": "Owner ID"}, "name": {"type": "string", "description": "Workspace name"}, "icon": {"type": "string", "description": "Project icon identifier"}, "color": {"type": "string", "description": "Project color theme"}, "createdAt": {"type": "string", "description": "Creation timestamp"}, "updatedAt": {"type": "string", "description": "Last updated timestamp"} }, "required": ["id", "ownerId", "name", "icon", "color", "createdAt", "updatedAt"] } }, "total": {"type": "number"} }, "required": ["projects", "total"] } }, "required": ["success", "data"] } } } }, "401": { "description": "Unauthorized - missing or invalid JWT token", "content": { "application/json": { "schema": {"$ref": "#/components/schemas/ErrorResponse"} } } } } } }, "/api/v1/projects/{projectId}": { "patch": { "summary": "Update a project", "tags": ["Projects"], "description": "Update a project", "operationId": "updateProject", "security": [{"bearerAuth": []}], "parameters": [ { "schema": {"type": "string"}, "required": true, "name": "projectId", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "icon": { "type": "string", "enum": ["Code2", "Terminal", "Bot", "Brain", "Sparkles", "Database", "GitBranch", "Bug", "FolderKanban", "Folder", "Files", "Library", "BookOpen", "Briefcase", "Package", "Layers", "AppWindow", "Rocket", "Palette", "Paintbrush", "PenTool", "Lightbulb", "BarChart3", "Settings", "Globe"] }, "color": { "type": "string", "enum": ["rose", "pink", "orange", "amber", "emerald", "cyan", "blue", "purple", "slate", "gray"] }, "name": {"type": "string"} } } } } }, "responses": { "200": { "description": "Successfully updated project", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": {"type": "boolean"}, "data": { "type": "object", "properties": { "icon": {"type": "string"}, "color": {"type": "string"}, "name": {"type": "string"} } } }, "required": ["success", "data"] } } } }, "401": { "description": "Unauthorized - missing or invalid JWT token", "content": { "application/json": { "schema": {"$ref": "#/components/schemas/ErrorResponse"} } } }, "403": { "description": "Forbidden - user does not have permission to update project", "content": { "application/json": { "schema": {"$ref": "#/components/schemas/ErrorResponse"} } } } } }, "delete": { "summary": "Delete a project", "tags": ["Projects"], "description": "Delete a project", "operationId": "deleteProject", "security": [{"bearerAuth": []}], "parameters": [ { "schema": {"type": "string"}, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "Successfully deleted project", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": {"type": "boolean"}, "data": { "type": "object", "properties": { "deletedProject": { "type": "object", "properties": { "id": {"type": "string"}, "name": {"type": "string"} } }, "deletedAt": {"type": "string"} } } }, "required": ["success", "data"] } } } }, "401": { "description": "Unauthorized - missing or invalid JWT token", "content": { "application/json": { "schema": {"$ref": "#/components/schemas/ErrorResponse"} } } }, "403": { "description": "Forbidden - user does not have permission to delete project", "content": { "application/json": { "schema": {"$ref": "#/components/schemas/ErrorResponse"} } } } } } }, "/api/v1/sessions/recent": { "get": { "summary": "Get recent sessions", "tags": ["Sessions"], "description": "Get recent sessions", "operationId": "listRecentSessions", "security": [{"bearerAuth": []}], "parameters": [ { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 5 }, "required": false, "name": "limit", "in": "query", "description": "Number of sessions to return" } ], "responses": { "200": { "description": "Successfully listed sessions", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": {"type": "boolean"}, "data": { "type": "object", "properties": { "sessions": { "type": "array", "items": { "type": "object", "properties": { "id": {"type": "string", "format": "uuid"}, "projectId": {"type": "string"}, "name": {"type": "string"}, "markdownSize": {"type": "number"}, "rawDataSize": {"type": "number"}, "createdAt": {"type": "string"}, "updatedAt": {"type": "string"}, "metadata": { "type": "object", "properties": { "clientName": {"type": "string"}, "llmModels": {"type": "array", "items": {"type": "string"}}, "tags": {"type": "array", "items": {"type": "string"}} } } } } }, "total": {"type": "number"} } } }, "required": ["success", "data"] } } } }, "401": { "description": "Unauthorized - missing or invalid JWT token", "content": { "application/json": { "schema": {"$ref": "#/components/schemas/ErrorResponse"} } } } } } }, "/api/v1/projects/{projectId}/sessions": { "get": { "summary": "List sessions", "tags": ["Sessions"], "description": "List all sessions for a project", "operationId": "listSessions", "security": [{"bearerAuth": []}], "parameters": [ { "schema": {"type": "string"}, "required": true, "name": "projectId", "in": "path" } ], "responses": { "200": { "description": "Successfully listed sessions", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": {"type": "boolean"}, "data": { "type": "object", "properties": { "sessions": { "type": "array", "items": { "type": "object", "properties": { "id": {"type": "string", "format": "uuid"}, "projectId": {"type": "string"}, "name": {"type": "string"}, "markdownSize": {"type": "number"}, "rawDataSize": {"type": "number"}, "createdAt": {"type": "string"}, "updatedAt": {"type": "string"}, "metadata": { "type": "object", "properties": { "clientName": {"type": "string"}, "llmModels": {"type": "array", "items": {"type": "string"}}, "tags": {"type": "array", "items": {"type": "string"}} } }, "etag": {"type": "string"} } } }, "total": {"type": "number"}, "projectId": {"type": "string"} } } }, "required": ["success", "data"] } } } }, "401": { "description": "Unauthorized - missing or invalid JWT token", "content": { "application/json": { "schema": {"$ref": "#/components/schemas/ErrorResponse"} } } } } } }, "/api/v1/projects/{projectId}/sessions/{sessionId}": { "get": { "summary": "Read a session", "tags": ["Sessions"], "description": "Read a session with ETag support", "operationId": "readSession", "security": [{"bearerAuth": []}], "parameters": [ { "schema": {"type": "string"}, "required": true, "name": "projectId", "in": "path" }, { "schema": {"type": "string"}, "required": true, "name": "sessionId", "in": "path" }, { "schema": {"type": "string", "enum": ["application/json", "text/markdown"]}, "required": false, "name": "Accept", "in": "header" } ], "responses": { "200": { "description": "Successfully read session", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": {"type": "boolean"}, "data": { "type": "object", "properties": { "session": { "type": "object", "properties": { "id": {"type": "string"}, "name": {"type": "string"}, "markdownContent": {"type": "string"}, "markdownSize": {"type": "number"}, "metadata": { "type": "object", "properties": { "clientName": {"type": "string"}, "llmModels": {"type": "array", "items": {"type": "string"}}, "tags": {"type": "array", "items": {"type": "string"}} } }, "createdAt": {"type": "string"}, "project": { "type": "object", "properties": { "id": {"type": "string"}, "name": {"type": "string"}, "icon": {"type": "string"}, "color": {"type": "string"} } } } } } } }, "required": ["success", "data"] } } } }, "304": { "description": "Not Modified - session unchanged" }, "401": { "description": "Unauthorized - missing or invalid JWT token", "content": { "application/json": { "schema": {"$ref": "#/components/schemas/ErrorResponse"} } } }, "404": { "description": "Session not found", "content": { "application/json": { "schema": {"$ref": "#/components/schemas/ErrorResponse"} } } } } }, "head": { "summary": "Check session existence", "tags": ["Sessions"], "description": "Check if session exists and get metadata", "operationId": "headSession", "security": [{"bearerAuth": []}], "parameters": [ { "schema": {"type": "string"}, "required": true, "name": "projectId", "in": "path" }, { "schema": {"type": "string"}, "required": true, "name": "sessionId", "in": "path" } ], "responses": { "200": { "description": "Session exists" }, "304": { "description": "Not Modified" }, "401": { "description": "Unauthorized" }, "404": { "description": "Session not found" } } }, "delete": { "summary": "Delete a session", "tags": ["Sessions"], "description": "Delete a session", "operationId": "deleteSession", "security": [{"bearerAuth": []}], "parameters": [ { "schema": {"type": "string"}, "required": true, "name": "projectId", "in": "path" }, { "schema": {"type": "string"}, "required": true, "name": "sessionId", "in": "path" } ], "responses": { "200": { "description": "Successfully deleted session", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": {"type": "boolean"}, "data": { "type": "object", "properties": { "success": {"type": "boolean"} } } }, "required": ["success", "data"] } } } }, "401": { "description": "Unauthorized - missing or invalid JWT token", "content": { "application/json": { "schema": {"$ref": "#/components/schemas/ErrorResponse"} } } }, "403": { "description": "Forbidden - insufficient permissions", "content": { "application/json": { "schema": {"$ref": "#/components/schemas/ErrorResponse"} } } } } } }, "/api/v1/graphql": { "post": { "summary": "GraphQL Endpoint", "tags": ["GraphQL"], "description": "Advanced querying interface for complex operations", "operationId": "graphqlQuery", "security": [{"bearerAuth": []}], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "query": {"type": "string"}, "variables": {"type": "object"}, "operationName": {"type": "string"} }, "required": ["query"] } } } }, "responses": { "200": { "description": "GraphQL query executed successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": {"nullable": true}, "errors": { "type": "array", "items": {"nullable": true} } } } } } }, "400": { "description": "Invalid GraphQL query", "content": { "application/json": { "schema": {"$ref": "#/components/schemas/ErrorResponse"} } } }, "401": { "description": "Unauthorized - missing or invalid JWT token", "content": { "application/json": { "schema": {"$ref": "#/components/schemas/ErrorResponse"} } } } } } } } }