{"openapi":"3.0.0","info":{"title":"SoloRecall API Documentation","version":"1.0.0","description":"API documentation for SoloRecall backend services","contact":{"name":"API Support","url":"https://solorecall.com/support"}},"servers":[{"url":"http://localhost:5024","description":"Development server"},{"url":"https://api.solorecall.com","description":"Production server"}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"},"ApiKeyAuth":{"type":"apiKey","in":"header","name":"Authorization"}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string","description":"Error message"},"details":{"type":"object","description":"Additional error details"}}},"SuccessResponse":{"type":"object","properties":{"success":{"type":"boolean","description":"Indicates if the operation was successful"},"message":{"type":"string","description":"Success message"}}},"Block":{"type":"object","required":["id","type"],"properties":{"id":{"type":"string"},"type":{"type":"string","description":"Unified block type, including editor blocks plus page-like `page`, `database`, and `database_row`."},"parent_id":{"type":"string","nullable":true},"database_id":{"type":"string","nullable":true},"teamspace_id":{"type":"string","nullable":true},"properties":{"type":"object","additionalProperties":true,"description":"JSON properties payload. Titles, icons, covers, database values, and custom fields live here."},"content":{"nullable":true},"position":{"type":"number","nullable":true},"archived":{"type":"boolean"},"in_trash":{"type":"boolean"},"created_by":{"type":"string","nullable":true},"last_edited_by":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"CreateBlockRequest":{"type":"object","required":["type"],"properties":{"id":{"type":"string","description":"Optional caller-supplied block ID."},"type":{"type":"string"},"properties":{"type":"object","additionalProperties":true,"default":{}},"parent_id":{"type":"string","nullable":true},"parentId":{"type":"string","nullable":true},"database_id":{"type":"string","nullable":true},"databaseId":{"type":"string","nullable":true},"content":{"nullable":true},"position":{"type":"number"}}},"UpdateBlockRequest":{"type":"object","properties":{"type":{"type":"string"},"properties":{"type":"object","additionalProperties":true},"parent_id":{"type":"string","nullable":true},"database_id":{"type":"string","nullable":true},"teamspace_id":{"type":"string","nullable":true},"content":{"nullable":true},"position":{"type":"number"},"archived":{"type":"boolean"},"in_trash":{"type":"boolean"}}}},"parameters":{"BlockId":{"in":"path","name":"id","required":true,"schema":{"type":"string"},"description":"Unified block ID."}}},"tags":[{"name":"Auth","description":"Authentication endpoints"},{"name":"AI","description":"AI model integration endpoints"},{"name":"Blocks","description":"Unified SoLoDocs blocks API"},{"name":"Comments","description":"SoLoDocs block and page comments"},{"name":"Mentions","description":"SoLoDocs inline mentions"},{"name":"Backlinks","description":"SoLoDocs backlinks"},{"name":"Synced Blocks","description":"SoLoDocs synced block metadata"},{"name":"Media","description":"SoLoDocs media storage wrappers"},{"name":"Pages","description":"Page-like block compatibility endpoints"},{"name":"Transcription","description":"Audio transcription endpoints"},{"name":"Notion","description":"Notion integration endpoints"},{"name":"Stripe","description":"Payment and subscription endpoints"},{"name":"System","description":"System health and information endpoints"}],"paths":{"openapi":{"0":"3","1":".","2":"0","3":".","4":"0"},"info":{"title":"AI API","description":"API documentation for various AI integrations","version":"1.0.0"},"servers":{"0":{"url":"http://localhost:3024/api/ai","description":"Local server"}},"/openai":{"post":{"tags":["AI"],"summary":"Make OpenAI API request","description":"Send a prompt to OpenAI API and get response","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prompt":{"type":"string","description":"The prompt to send to OpenAI","example":"Translate the following text into French."},"model":{"type":"string","description":"The OpenAI model to use","example":"text-davinci-003"},"apiKey":{"type":"string","description":"OpenAI API key","example":"your-api-key"}}}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"response":{"type":"string"}}}}}},"500":{"description":"API error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/claude":{"post":{"tags":["AI"],"summary":"Make Claude API request","description":"Send a prompt to Anthropic's Claude API","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prompt":{"type":"string","example":"Explain the concept of entropy."},"model":{"type":"string","example":"claude-v1"},"apiKey":{"type":"string","example":"your-api-key"}}}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"response":{"type":"string"}}}}}},"500":{"description":"API error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/gemini":{"post":{"tags":["AI"],"summary":"Make Google Gemini API request","description":"Send a prompt to Google's Gemini API","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prompt":{"type":"string","example":"Summarize the latest tech trends."},"model":{"type":"string","example":"gemini-model"},"apiKey":{"type":"string","example":"your-api-key"}}}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"response":{"type":"string"}}}}}},"500":{"description":"API error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/mistral":{"post":{"tags":["AI"],"summary":"Make Mistral API request","description":"Send a prompt to Mistral AI API","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prompt":{"type":"string","example":"Generate a poem about the sea."},"model":{"type":"string","example":"mistral-v1"},"apiKey":{"type":"string","example":"your-api-key"}}}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"response":{"type":"string"}}}}}},"500":{"description":"API error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/openrouter":{"post":{"tags":["AI"],"summary":"Make OpenRouter API request","description":"Send a prompt to OpenRouter API","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prompt":{"type":"string","example":"Describe the lifecycle of a butterfly."},"model":{"type":"string","example":"router-model"},"apiKey":{"type":"string","example":"your-api-key"}}}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"response":{"type":"string"}}}}}},"500":{"description":"API error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/auth/complete":{"post":{"tags":["Auth"],"summary":"Complete authentication process","description":"Completes the authentication process and returns session data","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sessionId":{"type":"string","description":"Session ID from Supabase"}}}}}},"responses":{"200":{"description":"Authentication completed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"sessionData":{"type":"object"}}}}}},"400":{"description":"Invalid session"},"500":{"description":"Server error"}}}},"/api/v1/blocks":{"get":{"tags":["Blocks"],"summary":"List blocks","description":"Lists visible unified blocks for the authenticated user. Results include blocks owned by the user and shared blocks where `created_by` is null.","security":[{"BearerAuth":[]}],"parameters":[{"in":"query","name":"q","schema":{"type":"string"},"description":"Optional full-text search query against `search_vector`."},{"in":"query","name":"type","schema":{"type":"string"},"description":"Optional block type filter, such as `paragraph`, `page`, `database`, or `database_row`."},{"in":"query","name":"parent_id","schema":{"type":"string"},"description":"Optional parent block ID filter."},{"in":"query","name":"database_id","schema":{"type":"string"},"description":"Optional database block ID filter for database rows."},{"in":"query","name":"limit","schema":{"type":"integer","default":50,"maximum":100},"description":"Maximum number of blocks to return."},{"in":"query","name":"offset","schema":{"type":"integer","default":0},"description":"Zero-based offset."},{"in":"query","name":"sortBy","schema":{"type":"string","enum":["position","updated_at","created_at"],"default":"updated_at"},"description":"Sort column."},{"in":"query","name":"sortOrder","schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"description":"Sort direction."}],"responses":{"200":{"description":"Visible blocks.","headers":{"X-Total-Count":{"schema":{"type":"integer"},"description":"Total matching row count when available."},"X-Pagination-Limit":{"schema":{"type":"integer"}},"X-Pagination-Offset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Block"}}}}},"401":{"description":"Missing or invalid authentication."}}},"post":{"tags":["Blocks"],"summary":"Create block","description":"Creates a unified block owned by the authenticated user.","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBlockRequest"}}}},"responses":{"201":{"description":"Created block.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Block"}}}},"400":{"description":"`type` is required."},"401":{"description":"Missing or invalid authentication."}}}},"/api/v1/blocks/{id}":{"get":{"tags":["Blocks"],"summary":"Get block","description":"Fetches one active visible block by ID.","security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/BlockId"}],"responses":{"200":{"description":"Block found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Block"}}}},"404":{"description":"Block not found or access denied."}}},"patch":{"tags":["Blocks"],"summary":"Update block","description":"Updates an owned block. Ownership and creation fields are server-controlled.","security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/BlockId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlockRequest"}}}},"responses":{"200":{"description":"Updated block.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Block"}}}},"404":{"description":"Block not found or access denied."}}},"delete":{"tags":["Blocks"],"summary":"Permanently delete block","description":"Permanently deletes an owned block.","security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/BlockId"}],"responses":{"200":{"description":"Delete confirmation."}}}},"/api/v1/blocks/{id}/children":{"get":{"tags":["Blocks"],"summary":"List child blocks","description":"Lists active visible direct children of a block, ordered by `position` ascending.","security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/BlockId"}],"responses":{"200":{"description":"Direct child blocks.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Block"}}}}}}}},"/api/v1/blocks/{id}/hierarchy":{"get":{"tags":["Blocks"],"summary":"Get block hierarchy","description":"Fetches a visible block with nested children up to the requested depth.","security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/BlockId"},{"in":"query","name":"depth","schema":{"type":"integer","default":10,"maximum":25}}],"responses":{"200":{"description":"Block hierarchy."}}}},"/api/v1/blocks/{id}/duplicate":{"post":{"tags":["Blocks"],"summary":"Duplicate block","description":"Duplicates a visible block for the authenticated user. Child duplication is enabled by default.","security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/BlockId"}],"responses":{"201":{"description":"Duplicated block."}}}},"/api/v1/blocks/{id}/convert":{"post":{"tags":["Blocks"],"summary":"Convert block type","description":"Updates an owned block's type and properties.","security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/BlockId"}],"responses":{"200":{"description":"Converted block."}}}},"/api/v1/blocks/{id}/archive":{"post":{"tags":["Blocks"],"summary":"Archive block","description":"Sets the `archived` flag on an owned block.","security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/BlockId"}],"responses":{"200":{"description":"Archived block."}}}},"/api/v1/blocks/{id}/trash":{"post":{"tags":["Blocks"],"summary":"Move block to trash","description":"Sets `in_trash` to true for an owned block.","security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/BlockId"}],"responses":{"200":{"description":"Trashed block.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Block"}}}},"404":{"description":"Block not found or access denied."}}}},"/api/v1/blocks/{id}/restore":{"post":{"tags":["Blocks"],"summary":"Restore block","description":"Clears `in_trash` and `archived` for an owned block.","security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/BlockId"}],"responses":{"200":{"description":"Restored block.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Block"}}}},"404":{"description":"Block not found or access denied."}}}},"/api/v1/blocks/{id}/move":{"post":{"tags":["Blocks"],"summary":"Move block","description":"Updates a block's parent, teamspace, or position.","security":[{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/BlockId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"parent_id":{"type":"string","nullable":true},"parentId":{"type":"string","nullable":true},"teamspace_id":{"type":"string","nullable":true},"teamspaceId":{"type":"string","nullable":true},"position":{"type":"number"}}}}}},"responses":{"200":{"description":"Moved block.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Block"}}}},"404":{"description":"Block not found or access denied."}}}},"/":{"get":{"tags":["System"],"summary":"Get API status","description":"Returns the current status of the API and environment information","responses":{"200":{"description":"API status information","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"API is running"},"environment":{"type":"string","example":"development"},"isVercel":{"type":"boolean","example":false}}}}}}}}},"/test":{"get":{"tags":["System"],"summary":"Test endpoint","description":"Simple endpoint to verify server functionality","responses":{"200":{"description":"Server status","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Server is running correctly"}}}}}}}}},"/notion":{"post":{"tags":["Notion"],"summary":"Create Notion page","description":"Create a new page in Notion with transcription text","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"transcriptionText":{"type":"string","description":"Text to be added to Notion"},"title":{"type":"string","description":"Title of the Notion page"}}}}}},"responses":{"200":{"description":"Data sent to Notion successfully"},"400":{"description":"No transcription text in request"},"500":{"description":"Failed to send data to Notion"}}}},"/api/v1/comments/block/{blockId}":{"get":{"tags":["Comments"],"summary":"List block comments","security":[{"BearerAuth":[]}],"parameters":[{"in":"path","name":"blockId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Comments for the block."}}}},"/api/v1/comments/page/{pageId}":{"get":{"tags":["Comments"],"summary":"List page comments","security":[{"BearerAuth":[]}],"parameters":[{"in":"path","name":"pageId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Comments for the page."}}}},"/api/v1/comments":{"post":{"tags":["Comments"],"summary":"Create comment","security":[{"BearerAuth":[]}],"responses":{"201":{"description":"Created comment."}}}},"/api/v1/comments/{id}":{"patch":{"tags":["Comments"],"summary":"Update comment","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Updated comment."}}},"delete":{"tags":["Comments"],"summary":"Delete comment","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Delete confirmation."}}}},"/api/v1/comments/{id}/resolve":{"post":{"tags":["Comments"],"summary":"Resolve comment","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Resolved comment."}}}},"/api/v1/comments/{id}/unresolve":{"post":{"tags":["Comments"],"summary":"Unresolve comment","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Unresolved comment."}}}},"/api/v1/mentions/block/{blockId}":{"get":{"tags":["Mentions"],"summary":"List block mentions","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Mentions in the block."}}}},"/api/v1/mentions/page/{pageId}":{"get":{"tags":["Mentions"],"summary":"List page mentions","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Mentions on the page."}}}},"/api/v1/mentions":{"post":{"tags":["Mentions"],"summary":"Create mention","security":[{"BearerAuth":[]}],"responses":{"201":{"description":"Created mention."}}}},"/api/v1/mentions/sync":{"post":{"tags":["Mentions"],"summary":"Sync block mentions","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Sync result."}}}},"/api/v1/mentions/{id}":{"patch":{"tags":["Mentions"],"summary":"Update mention","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Updated mention."}}},"delete":{"tags":["Mentions"],"summary":"Delete mention","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Delete confirmation."}}}},"/api/v1/backlinks/{targetPageId}":{"get":{"tags":["Backlinks"],"summary":"List backlinks","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Backlinks pointing to the target page."}}}},"/api/v1/backlinks/{targetPageId}/count":{"get":{"tags":["Backlinks"],"summary":"Count backlinks","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Backlink count."}}}},"/api/v1/synced-blocks/source/{sourceBlockId}":{"get":{"tags":["Synced Blocks"],"summary":"List synced block instances","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Synced block instances."}}}},"/api/v1/synced-blocks/instance/{instanceBlockId}":{"get":{"tags":["Synced Blocks"],"summary":"Get synced block metadata","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Synced block metadata."}}}},"/api/v1/synced-blocks":{"post":{"tags":["Synced Blocks"],"summary":"Create synced block metadata","security":[{"BearerAuth":[]}],"responses":{"201":{"description":"Created synced block metadata."}}}},"/api/v1/synced-blocks/source/{sourceBlockId}/propagate":{"post":{"tags":["Synced Blocks"],"summary":"Propagate synced block changes","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Propagation result."}}}},"/api/v1/synced-blocks/instance/{instanceBlockId}/unlink":{"post":{"tags":["Synced Blocks"],"summary":"Unlink synced block instance","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Unlink result."}}}},"/api/v1/media":{"get":{"tags":["Media"],"summary":"List media","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Media files."}}}},"/api/v1/media/upload":{"post":{"tags":["Media"],"summary":"Upload media","security":[{"BearerAuth":[]}],"responses":{"201":{"description":"Uploaded media."}}}},"/api/v1/media/search":{"get":{"tags":["Media"],"summary":"Search media","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Matching media files."}}}},"/api/v1/media/{id}/url":{"get":{"tags":["Media"],"summary":"Get media URL","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Public media URL."}}}},"/api/v1/media/{id}/metadata":{"get":{"tags":["Media"],"summary":"Get media metadata","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Media metadata."}}},"patch":{"tags":["Media"],"summary":"Update media metadata","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Updated media metadata."}}}},"/api/v1/media/{id}":{"delete":{"tags":["Media"],"summary":"Delete media","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Delete confirmation."}}}},"/api/v1/pages/{id}/export":{"get":{"tags":["Pages"],"summary":"Export page","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Page export in markdown, HTML, or JSON."}}}},"/api/v1/pages/export/batch":{"get":{"tags":["Pages"],"summary":"Batch export pages","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Batch page export."}}}},"/stripe/webhook":{"post":{"tags":["Stripe"],"summary":"Handle Stripe webhooks","description":"Process various Stripe webhook events","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Webhook processed successfully"},"400":{"description":"Invalid webhook signature"}}}},"/stripe/cancel-subscription":{"post":{"tags":["Stripe"],"summary":"Cancel subscription","description":"Cancel a user's subscription","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Subscription cancelled successfully"},"400":{"description":"Invalid request"},"500":{"description":"Failed to cancel subscription"}}}},"/api/transcription/transcribe":{"post":{"tags":["Transcription"],"summary":"Transcribe audio file","description":"Upload and transcribe an audio file","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"audio":{"type":"string","format":"binary","description":"Audio file to transcribe"}}}}}},"responses":{"200":{"description":"Successful transcription","content":{"application/json":{"schema":{"type":"object","properties":{"transcriptionData":{"type":"string"}}}}}},"400":{"description":"No audio file uploaded"},"500":{"description":"Transcription failed"}}}}}}