This guide is the human-readable companion to openapi.yaml. The examples use raw Authorization header values. Do not prefix JWTs or MCP tokens with Bearer.
GET /api/v1/private/projects/{project_id}/documents/{document_id}/overview returns version_count, endpoint_count, latest_version (the existing public version DTO or null), published_branch_ids, has_reviewed_draft, raw_size_bytes, and nullable raw_line_count. Counts and latest-version selection cover the whole document; published branch IDs and reviewed-draft evidence only include active branches. The response contains no document body or storage keys. Markdown statistics are stored at publication; older versions populate the derived metadata once on first overview access.
GET /api/v1/private/projects/{project_id}/documents/{document_id}/mcp-readiness returns nullable last_read_at. It searches successful published-content reads for the selected document across all history, using only the current user's active, unexpired tokens with a matching read scope. Archived parents or absence of matching evidence return null. Both endpoints require document read permission and keep the HTTP 200 envelope contract.
Summary polling reads only the target and its permission context. On startup and every minute, the worker marks a pending summary as failed if it has no matching durable job and has remained pending for at least five minutes. The grace period protects an older instance's in-flight generation; existing queued or leased jobs are preserved. Manual regeneration performs the same recovery check before reusing pending state.
| Surface | Base |
|---|---|
| Public REST | /api/v1/open |
| Private REST | /api/v1/private |
| OpenAPI document | /api/v1/open/docs/openapi.yaml |
| MCP JSON-RPC | /api/v1/open/mcp |
Public auth normally starts with login. Anonymous registration is disabled by default and must be explicitly enabled with VDOC_AUTH_ALLOW_REGISTRATION=true only for a trusted disposable or pilot environment. Private REST calls use the JWT returned in the Vdoc envelope. MCP calls use an MCP token created through the private REST API.
API_BASE="${API_BASE:-http://127.0.0.1:8080}"
PASSWORD="sample-password-change-me"
# This request requires VDOC_AUTH_ALLOW_REGISTRATION=true on the backend.
REGISTER_RESPONSE=$(curl -sS "$API_BASE/api/v1/open/auth/register" \
-H 'Content-Type: application/json' \
-d '{"email":"docs-admin@example.test","name":"Docs Admin","password":"sample-password-change-me"}')
ADMIN_USER_ID=$(printf '%s' "$REGISTER_RESPONSE" | jq -r '.detail.user.id')
JWT=$(printf '%s' "$REGISTER_RESPONSE" | jq -r '.detail.token')REST handlers return HTTP 200 for both success and application errors. The semantic result is inside the JSON body.
| Field | Meaning |
|---|---|
code |
Semantic status code such as 200, 400, 401, 403, 404, 409, or 500. |
status |
Semantic status text such as OK, INVALID_ARGUMENT, UNAUTHENTICATED, PERMISSION_DENIED, NOT_FOUND, or INTERNAL. |
detail |
Optional result body. |
total |
Optional list count on list endpoints. |
Private project APIs use SuperAdmin plus project Reader, Writer, and Admin roles. Reader can query, Writer can upload draft and submit, and Admin can approve or reject.
Projects directly own typed Documents. document_type is 1 for OpenAPI and 2 for Markdown. relative_path is the document path identity stored by Vdoc; display names can change without creating a second persisted path/name identity.
List routes accept the PRD filters used by the workbench: document lists accept ?document_type=1|2, while draft and version lists accept ?branch_id={branch_id}. Draft detail/list responses include review_comment after request-changes, reject, or approve review actions.
| Category | Purpose |
|---|---|
| Open | Health, login, opt-in registration, OpenAPI YAML, MCP JSON-RPC, and capability-authenticated public document shares. |
| Identity | Current JWT user identity. |
| System Users | SuperAdmin user lifecycle and user MCP token oversight. |
| Teams | Team lifecycle. |
| Projects | Project lifecycle and membership. |
| Documents | Project document lifecycle. |
| Branches | Document branch lifecycle. |
| Drafts | Draft creation, update, submission, review, and promotion. |
| Versions | Published document versions and stored raw/normalized or stable content. |
| Endpoints | Parsed endpoint list and detail from published versions. |
| Diffs | Semantic version comparison and summaries. |
| MCP Tokens | User MCP token lifecycle. |
| AI | Built-in Admin AI provider, prompt, AI summary, and page chat APIs. |
| Document Shares | Admin-managed public capability links and anonymous published-content access. |
The scriptable smoke path covers register/login, create project/document, upload draft, submit, approve, query endpoint, compare diff, create MCP token, MCP tools/list, and MCP tools/call.
TEAM_RESPONSE=$(curl -sS "$API_BASE/api/v1/private/teams" \
-H 'Content-Type: application/json' \
-H "Authorization: $JWT" \
-d '{"name":"Docs Team","description":"API docs smoke team"}')
TEAM_ID=$(printf '%s' "$TEAM_RESPONSE" | jq -r '.detail.id')
PROJECT_RESPONSE=$(curl -sS "$API_BASE/api/v1/private/projects" \
-H 'Content-Type: application/json' \
-H "Authorization: $JWT" \
-d "{\"team_id\":\"$TEAM_ID\",\"name\":\"Docs Project\",\"description\":\"API docs smoke project\",\"admin_user_id\":\"$ADMIN_USER_ID\"}")
PROJECT_ID=$(printf '%s' "$PROJECT_RESPONSE" | jq -r '.detail.id')
DOCUMENT_RESPONSE=$(curl -sS "$API_BASE/api/v1/private/projects/$PROJECT_ID/documents" \
-H 'Content-Type: application/json' \
-H "Authorization: $JWT" \
-d '{"name":"petstore","document_type":1,"relative_path":"apis/petstore.yaml","description":"Docs sample document"}')
DOCUMENT_ID=$(printf '%s' "$DOCUMENT_RESPONSE" | jq -r '.detail.id')
BRANCH_ID=$(curl -sS "$API_BASE/api/v1/private/projects/$PROJECT_ID/documents/$DOCUMENT_ID/branches" \
-H "Authorization: $JWT" | jq -r '.detail[] | select(.name=="dev") | .id')Document creation creates dev, test, and protected prod branches. Admins can add feature/* branches when needed.
Document lifecycle state is not patchable. PATCH /api/v1/private/projects/{project_id}/documents/{document_id} updates document metadata only; omit status (or send the unchanged active value for legacy clients). Archive a document only through POST /api/v1/private/projects/{project_id}/documents/{document_id}/archive. A rejected status change does not partially update the other fields.
Create a draft by posting OpenAPI 3.0 or 3.1 content as schema_content. Markdown documents use the same private REST draft routes and may post Markdown text as schema_content or content; MCP Markdown draft tools use markdown_content. content_kind accepts raw or normalized for OpenAPI content and raw or stable for Markdown content.
DRAFT_ONE_RESPONSE=$(curl -sS "$API_BASE/api/v1/private/projects/$PROJECT_ID/documents/$DOCUMENT_ID/drafts" \
-H 'Content-Type: application/json' \
-H "Authorization: $JWT" \
-d "{\"branch_id\":\"$BRANCH_ID\",\"version_name\":\"1.0.0\",\"schema_content\":$SCHEMA_V1}")
DRAFT_ONE_ID=$(printf '%s' "$DRAFT_ONE_RESPONSE" | jq -r '.detail.id')
curl -sS "$API_BASE/api/v1/private/projects/$PROJECT_ID/documents/$DOCUMENT_ID/drafts/$DRAFT_ONE_ID/content/raw" -H "Authorization: $JWT"
curl -sS "$API_BASE/api/v1/private/projects/$PROJECT_ID/documents/$DOCUMENT_ID/drafts/$DRAFT_ONE_ID/content/normalized" -H "Authorization: $JWT"
curl -sS "$API_BASE/api/v1/private/projects/$PROJECT_ID/documents/$DOCUMENT_ID/drafts/$DRAFT_ONE_ID/submit" -X POST -H "Authorization: $JWT"
VERSION_ONE_RESPONSE=$(curl -sS "$API_BASE/api/v1/private/projects/$PROJECT_ID/documents/$DOCUMENT_ID/drafts/$DRAFT_ONE_ID/approve" \
-X POST -H "Authorization: $JWT")
VERSION_ONE_ID=$(printf '%s' "$VERSION_ONE_RESPONSE" | jq -r '.detail.id')Other review and promotion calls use:
POST /api/v1/private/projects/{project_id}/documents/{document_id}/drafts/{draft_id}/request-changes
POST /api/v1/private/projects/{project_id}/documents/{document_id}/drafts/{draft_id}/reject
POST /api/v1/private/projects/{project_id}/documents/{document_id}/drafts/promote
Review actions accept an optional JSON comment, trim it, persist it on the draft, return it as review_comment, and include it in review audit metadata without placing it in the published version. Unknown review fields are rejected.
curl -sS "$API_BASE/api/v1/private/projects/$PROJECT_ID/documents/$DOCUMENT_ID/versions/$VERSION_ONE_ID/content/raw" -H "Authorization: $JWT"
curl -sS "$API_BASE/api/v1/private/projects/$PROJECT_ID/documents/$DOCUMENT_ID/versions/$VERSION_ONE_ID/content/normalized" -H "Authorization: $JWT"
ENDPOINTS_RESPONSE=$(curl -sS "$API_BASE/api/v1/private/projects/$PROJECT_ID/documents/$DOCUMENT_ID/versions/$VERSION_ONE_ID/endpoints?path=/pets" -H "Authorization: $JWT")
ENDPOINT_ID=$(printf '%s' "$ENDPOINTS_RESPONSE" | jq -r '.detail[0].id')
curl -sS "$API_BASE/api/v1/private/projects/$PROJECT_ID/documents/$DOCUMENT_ID/versions/$VERSION_ONE_ID/endpoints/$ENDPOINT_ID" -H "Authorization: $JWT"
DIFF_RESPONSE=$(curl -sS "$API_BASE/api/v1/private/projects/$PROJECT_ID/documents/$DOCUMENT_ID/diffs" \
-H 'Content-Type: application/json' \
-H "Authorization: $JWT" \
-d "{\"from_version_id\":\"$VERSION_ONE_ID\",\"to_version_id\":\"$VERSION_TWO_ID\"}")
DIFF_ID=$(printf '%s' "$DIFF_RESPONSE" | jq -r '.detail.id')
curl -sS "$API_BASE/api/v1/private/projects/$PROJECT_ID/documents/$DOCUMENT_ID/diffs/$DIFF_ID/summary" -H "Authorization: $JWT"OpenAPI summaries use added_endpoints, removed_endpoints, modified_endpoints, and breaking_changes. Markdown summaries set document_format: 3 and use added_lines, removed_lines, modified_lines, and modified_blocks; endpoint counts remain zero for Markdown.
Endpoint details resolve local references and apply operation-level parameter overrides by name + in; duplicate identities at the same level are rejected. OpenAPI 3.1 Schema $ref siblings remain active alongside the referenced schema (represented with allOf), while 3.0 Reference Object siblings remain ignored. Used security scheme definitions are included in normalized_operation.securitySchemes; unused definitions are omitted. Changes to these definitions emit security_changed items at securitySchemes with the previous and current definitions, using the existing warning severity for security changes. This is available through both REST endpoint detail and MCP get_endpoint_detail; tool arguments are unchanged.
On upgraded backends, legacy published endpoint indexes are refreshed from hash-verified immutable source content when read. Cached OpenAPI version comparisons are recalculated and persisted on first access, retaining the version, endpoint, and diff IDs. The original published document is unchanged; object storage must remain available for this refresh.
Creating a comparison requires an active Project and Document, and from_version_id must differ from to_version_id. Previously stored Diff records and summaries remain readable after their Project, Document, or target Branch is archived; only creation of a new comparison is blocked.
MCP_TOKEN_RESPONSE=$(curl -sS "$API_BASE/api/v1/private/mcp-tokens" \
-H 'Content-Type: application/json' \
-H "Authorization: $JWT" \
-d '{"name":"docs-agent","scopes":[1,2]}')
MCP_TOKEN=$(printf '%s' "$MCP_TOKEN_RESPONSE" | jq -r '.detail.token')
MCP_TOKEN_ID=$(printf '%s' "$MCP_TOKEN_RESPONSE" | jq -r '.detail.id')
curl -sS "$API_BASE/api/v1/open/mcp" \
-H 'Content-Type: application/json' \
-H "Authorization: $MCP_TOKEN" \
-d '{"jsonrpc":"2.0","id":"tools-list","method":"tools/list"}'
curl -sS "$API_BASE/api/v1/open/mcp" \
-H 'Content-Type: application/json' \
-H "Authorization: $MCP_TOKEN" \
-d "{\"jsonrpc\":\"2.0\",\"id\":\"endpoint-detail\",\"method\":\"tools/call\",\"params\":{\"name\":\"get_endpoint_detail\",\"arguments\":{\"project_id\":\"$PROJECT_ID\",\"document_id\":\"$DOCUMENT_ID\",\"version_id\":\"$VERSION_ONE_ID\",\"endpoint_id\":\"$ENDPOINT_ID\"}}}"
curl -sS "$API_BASE/api/v1/private/mcp-usage?token_id=$MCP_TOKEN_ID&limit=20" \
-H "Authorization: $JWT"The token value in .detail.token is returned on creation and may be revealed again by the token owner with GET /api/v1/private/mcp-tokens/{token_id} while the token remains active. List, revoked, and expired token responses stay redacted. Storage uses token_hash for authentication and encrypted token_ciphertext for owner reveal; neither storage field is exposed by the API.
GET /api/v1/private/mcp-usage returns newest-first sanitized mcp.tool_call evidence for the authenticated user's tokens. token_id selects one owned token; SuperAdmins may specify another user's token, but an omitted token_id always means the current user's own tokens. The response is capped at 200 records and retains only the tool, adapter, result/reason, token ID, and canonical project/document/branch/draft/version/endpoint/diff IDs. Entity IDs are recorded only after a successful tool call, so a failed request cannot turn caller-supplied IDs into entity evidence. Successful published-content reads use evidence_kind=published_content_read. Raw MCP secrets, request arguments, schema/Markdown content, IP addresses, and User-Agent values are not returned.
Current MCP tools include list_projects, list_documents, list_document_branches, list_api_endpoints, list_api_versions, list_doc_versions, get_latest_schema, get_endpoint_detail, compare_api_versions, get_change_summary, create_api_version_draft, update_api_version_draft, submit_api_version_draft, get_api_version_draft, get_latest_doc, compare_doc_versions, create_doc_draft, update_doc_draft, submit_doc_draft, and get_doc_draft. Direct publish tools are intentionally not exposed in v0.1. list_api_versions is retained for API-document clients; Markdown agents should use the discoverable list_doc_versions tool with a doc:read scope.
MCP discovery in the current source version: list_document_branches(project_id, document_id) returns branch IDs/names/default/protection/status even before publication and requires the target document type's read scope. list_api_endpoints(project_id, document_id, version_id, method?, path?) returns endpoint summaries with IDs; method is case-insensitive and path matches the exact OpenAPI template. Use a returned ID with get_endpoint_detail. Older deployments may lack these tools; inspect tools/list before use.
SuperAdmins alone can read, update, and test the system OpenAI-compatible provider and system prompts at /api/v1/private/ai/*. Project Admins and SuperAdmins can read, update, and test project provider and prompt configuration under /api/v1/private/projects/{project_id}/ai/*; Reader and Writer roles are denied those configuration APIs even though they may use page summaries and Chat where document permissions allow. Provider responses expose api_key_set and api_key_last4 only. AI summary and chat outputs are AI-generated helper text and cannot approve, request changes, reject, publish, or modify drafts or versions.
Provider payloads accept tuning fields alongside name, base_url, model, api_mode, api_key, and enabled. temperature defaults to 0.2 and accepts 0 through 2. timeout_ms defaults to 30000 and accepts 1000 through 120000. max_output_tokens defaults to 1000 and accepts 1 through 32000. Project provider endpoints use the same request and response shape as the system provider.
The provider timeout controls the complete AI HTTP request. The default backend server.write_timeout is 180s to allow a 120-second provider call and request/response processing. Existing deployments with an explicit shorter write timeout should update it (or set VDOC_SERVER_WRITE_TIMEOUT=180s) before using longer provider timeouts; external proxy/client timeouts must also allow the request. Admin connects to the configured backend origin directly. The current MCP adapter defaults VDOC_MCP_TIMEOUT_MS to 180000 and accepts 1 through 180000. Upgrade older adapters before setting this value, and allow at least the same duration in the agent host's tool timeout when waiting for long AI-assisted draft submissions.
Token-limit truncation and other explicit incomplete provider responses fail the AI generation instead of saving a successful partial summary. Draft submission/publication retains its business result when an automatic AI summary fails; the AI panel reports the failed summary so it can be retried after changing the output limit. Context previews disclose truncation and carry version/branch identity; semantic-diff prompts include original change flags and old/new values.
Provider tests accept an optional request body. Omitting the body tests the saved effective configuration; for a project without an enabled override, this deliberately tests the enabled system-provider fallback. Prompt update bodies contain system_prompt, user_prompt_template, and enabled; the path is the single source of truth for prompt_key. Both prompt strings must be non-blank, every user_prompt_template must contain the literal {{context}}, and page_chat must additionally contain {{message}}.
curl -sS "$API_BASE/api/v1/private/ai/provider" \
-X PUT \
-H 'Content-Type: application/json' \
-H "Authorization: $JWT" \
-d '{"name":"docs-ai","base_url":"https://api.openai.example","model":"gpt-4.1-mini","api_mode":"chat_completions","api_key":"sk-change-me","enabled":true,"temperature":0.2,"timeout_ms":30000,"max_output_tokens":1000}'Submitting a draft atomically saves its submitted state, pending AI summary, and background job. Approving a draft atomically publishes the version and its summary job. Provider calls run after the transaction in a background worker, so submit and approve responses do not wait for AI. OpenAPI and Markdown draft submit and approve paths both follow this rule. The summary attempt is helper work, not part of the approval decision.
Manual ai-summary/regenerate also queues work and returns pending; repeating it while pending reuses that generation. Poll the matching GET endpoint every two seconds until a terminal status, and stop polling on navigation or read errors. The latest in-flight generation is visible as pending. Skipped and failed automatic summaries are saved as non-blocking skipped or failed records. Missing providers and disabled prompts are stored as skipped; provider call errors are stored as failed. A completion is rejected if its target, permissions, provider, or prompt changed while the provider call was running. These records are visible through the same ai-summary read endpoints and do not roll back submit or publish.
AI chat sends a bounded window of the current session history. Each session uses a persisted generation token so an older provider response cannot overwrite a newer request, including when requests are handled by different Vdoc instances. The chat-session collection supports GET with required document_id, context_type, and context_id query parameters so clients can recover all sessions for the current page context, newest-updated first.
Archiving is a read-only boundary for AI history. Project provider and prompt configuration remains readable to Project Admins and SuperAdmins after Project archive, while provider update/test and prompt update are blocked. Reader and Writer roles still cannot read that configuration. Existing Summary records, Chat sessions, and Chat messages remain readable after Project, Document, or target Branch archive. Manual regeneration, new Chat session creation, and new Chat messages require an active Project, Document, and target Branch. Manual Summary regeneration additionally requires Project Admin or SuperAdmin permission; readable project members may use Chat while the context is active. A provider completion that returns after the context or relevant configuration became stale is discarded.
This produces the following archive boundary across the private APIs:
| Resource after parent archive | Read/list | New work | Remaining lifecycle action |
|---|---|---|---|
| Draft, Version, stored Diff | Allowed | Draft mutation and Compare blocked | None |
| AI provider/prompts | Project Admin/SuperAdmin only | Update and provider test blocked | None |
| AI Summary/Chat | Allowed | Regenerate, create session, and send blocked | None |
| Document share | List allowed | Create and reveal blocked | Revoke allowed |
AI audit metadata includes token usage fields when the provider returns them: prompt_tokens, completion_tokens, and total_tokens. API keys, JWTs, MCP tokens, and Authorization headers are not stored in AI audit metadata. Provider test calls, manual summary regeneration, automatic summaries, and chat calls are audited with status and non-secret context.
GET /api/v1/private/ai/provider
PUT /api/v1/private/ai/provider
POST /api/v1/private/ai/provider/test
GET /api/v1/private/projects/{project_id}/ai/provider
PUT /api/v1/private/projects/{project_id}/ai/provider
POST /api/v1/private/projects/{project_id}/ai/provider/test
GET /api/v1/private/ai/prompts
PUT /api/v1/private/ai/prompts/{prompt_key}
GET /api/v1/private/projects/{project_id}/ai/prompts
PUT /api/v1/private/projects/{project_id}/ai/prompts/{prompt_key}
GET /api/v1/private/projects/{project_id}/documents/{document_id}/drafts/{draft_id}/ai-summary
POST /api/v1/private/projects/{project_id}/documents/{document_id}/drafts/{draft_id}/ai-summary/regenerate
GET /api/v1/private/projects/{project_id}/documents/{document_id}/versions/{version_id}/ai-summary
POST /api/v1/private/projects/{project_id}/documents/{document_id}/versions/{version_id}/ai-summary/regenerate
GET /api/v1/private/projects/{project_id}/documents/{document_id}/diffs/{diff_id}/ai-summary
POST /api/v1/private/projects/{project_id}/documents/{document_id}/diffs/{diff_id}/ai-summary/regenerate
GET /api/v1/private/projects/{project_id}/ai/chat-sessions?document_id={document_id}&context_type={draft|version|diff}&context_id={context_id}
POST /api/v1/private/projects/{project_id}/ai/chat-sessions
GET /api/v1/private/projects/{project_id}/ai/chat-sessions/{session_id}
POST /api/v1/private/projects/{project_id}/ai/chat-sessions/{session_id}/messages
Only Project Admins and SuperAdmins can manage public links. A branch must be active and already contain at least one published version before a link can be created. version_scope is 1 for the moving latest published version and 2 for all published versions on the branch. expiry_preset accepts 1_month, 3_months, 6_months, 1_year, or permanent; Admin selects 3_months by default. password is optional and, when present, must be 12–72 UTF-8 bytes with no leading or trailing Unicode whitespace.
After the parent Project, Document, or Branch is archived, Admins can still list retained share history and revoke an active link. Creating a link and revealing its capability are blocked. Anonymous public access remains unavailable whenever a parent is inactive and deliberately does not reveal which lifecycle check failed.
SHARE_RESPONSE=$(curl -sS "$API_BASE/api/v1/private/projects/$PROJECT_ID/documents/$DOCUMENT_ID/shares" \
-H 'Content-Type: application/json' \
-H "Authorization: $JWT" \
-d "{\"branch_id\":\"$BRANCH_ID\",\"version_scope\":2,\"expiry_preset\":\"1_month\",\"password\":\"sample share password\"}")
SHARE_ID=$(printf '%s' "$SHARE_RESPONSE" | jq -r '.detail.share.id')
SHARE_SECRET=$(printf '%s' "$SHARE_RESPONSE" | jq -r '.detail.secret')The complete browser URL is built as /share/{share_id}#{secret}. The fragment must be removed from the current history entry before any network request. Anonymous API calls send Authorization: VdocShare {secret}, omit account cookies/JWT, and receive Cache-Control: no-store, Referrer-Policy: no-referrer, and X-Robots-Tag: noindex protections.
Password-protected shares exchange the password for a 15-minute, share-bound proof:
POST /api/v1/open/document-shares/{share_id}/unlock
GET /api/v1/open/document-shares/{share_id}
GET /api/v1/open/document-shares/{share_id}/versions
GET /api/v1/open/document-shares/{share_id}/versions/{version_id}/content
GET /api/v1/open/document-shares/{share_id}/versions/{version_id}/download
Send the proof as X-Vdoc-Share-Unlock. Invalid capabilities, passwords, proofs, revoked/expired links, and inactive parent resources all return the same public unavailable response. Downloads always pass through Vdoc authorization; object storage remains private. Markdown viewers must disable raw HTML, remote images, and unsafe links, while OpenAPI content is rendered only as escaped read-only text.
| Category | Methods | Path | Auth |
|---|---|---|---|
| Open | GET |
/api/v1/open/health |
Public |
| Open | GET |
/api/v1/open/auth/config |
Public |
| Open | POST |
/api/v1/open/auth/register |
Public |
| Open | POST |
/api/v1/open/auth/login |
Public |
| Open | GET |
/api/v1/open/docs/openapi.yaml |
Public |
| Open | POST |
/api/v1/open/mcp |
MCP token |
| Document Shares | GET |
/api/v1/open/document-shares/{share_id} |
Share capability |
| Document Shares | POST |
/api/v1/open/document-shares/{share_id}/unlock |
Share capability |
| Document Shares | GET |
/api/v1/open/document-shares/{share_id}/versions |
Share capability/proof |
| Document Shares | GET |
/api/v1/open/document-shares/{share_id}/versions/{version_id}/content |
Share capability/proof |
| Document Shares | GET |
/api/v1/open/document-shares/{share_id}/versions/{version_id}/download |
Share capability/proof |
| Identity | GET |
/api/v1/private/identity/me |
JWT |
| System Users | GET, POST |
/api/v1/private/system/users |
JWT |
| System Users | PATCH |
/api/v1/private/system/users/{user_id} |
JWT |
| System Users | GET |
/api/v1/private/system/users/{user_id}/mcp-tokens |
JWT |
| System Users | POST |
/api/v1/private/system/users/{user_id}/mcp-tokens/{token_id}/revoke |
JWT |
| Teams | GET, POST |
/api/v1/private/teams |
JWT; SuperAdmin |
| Teams | GET, PATCH |
/api/v1/private/teams/{team_id} |
JWT; SuperAdmin |
| Teams | POST |
/api/v1/private/teams/{team_id}/archive |
JWT; SuperAdmin |
| Projects | GET, POST |
/api/v1/private/projects |
JWT |
| Projects | GET, PATCH |
/api/v1/private/projects/{project_id} |
JWT |
| Projects | POST |
/api/v1/private/projects/{project_id}/archive |
JWT |
| Projects | GET, POST |
/api/v1/private/projects/{project_id}/members |
JWT |
| Projects | GET |
/api/v1/private/projects/{project_id}/member-candidates |
JWT; Project Admin or SuperAdmin |
| Projects | DELETE |
/api/v1/private/projects/{project_id}/members/{user_id} |
JWT |
| Projects | PATCH |
/api/v1/private/projects/{project_id}/members/{user_id}/role |
JWT |
| Documents | GET, POST |
/api/v1/private/projects/{project_id}/documents |
JWT |
| Documents | GET, PATCH |
/api/v1/private/projects/{project_id}/documents/{document_id} |
JWT |
| Documents | POST |
/api/v1/private/projects/{project_id}/documents/{document_id}/archive |
JWT |
| Document Shares | GET, POST |
/api/v1/private/projects/{project_id}/documents/{document_id}/shares |
JWT (Project Admin/SuperAdmin) |
| Document Shares | POST |
/api/v1/private/projects/{project_id}/documents/{document_id}/shares/{share_id}/reveal |
JWT (Project Admin/SuperAdmin) |
| Document Shares | POST |
/api/v1/private/projects/{project_id}/documents/{document_id}/shares/{share_id}/revoke |
JWT (Project Admin/SuperAdmin) |
| Branches | GET, POST |
/api/v1/private/projects/{project_id}/documents/{document_id}/branches |
JWT |
| Branches | GET, PATCH |
/api/v1/private/projects/{project_id}/documents/{document_id}/branches/{branch_id} |
JWT |
| Branches | POST |
/api/v1/private/projects/{project_id}/documents/{document_id}/branches/{branch_id}/archive |
JWT |
| Drafts | GET, POST |
/api/v1/private/projects/{project_id}/documents/{document_id}/drafts |
JWT |
| Drafts | GET, PATCH |
/api/v1/private/projects/{project_id}/documents/{document_id}/drafts/{draft_id} |
JWT |
| Drafts | GET |
/api/v1/private/projects/{project_id}/documents/{document_id}/drafts/{draft_id}/content/{content_kind} |
JWT |
| Drafts | POST |
/api/v1/private/projects/{project_id}/documents/{document_id}/drafts/{draft_id}/submit |
JWT |
| Drafts | POST |
/api/v1/private/projects/{project_id}/documents/{document_id}/drafts/{draft_id}/approve |
JWT |
| Drafts | POST |
/api/v1/private/projects/{project_id}/documents/{document_id}/drafts/{draft_id}/request-changes |
JWT |
| Drafts | POST |
/api/v1/private/projects/{project_id}/documents/{document_id}/drafts/{draft_id}/reject |
JWT |
| Drafts | POST |
/api/v1/private/projects/{project_id}/documents/{document_id}/drafts/promote |
JWT |
| Versions | GET |
/api/v1/private/projects/{project_id}/documents/{document_id}/versions |
JWT |
| Versions | GET |
/api/v1/private/projects/{project_id}/documents/{document_id}/versions/{version_id} |
JWT |
| Versions | GET |
/api/v1/private/projects/{project_id}/documents/{document_id}/versions/{version_id}/content/{content_kind} |
JWT |
| Endpoints | GET |
/api/v1/private/projects/{project_id}/documents/{document_id}/versions/{version_id}/endpoints |
JWT |
| Endpoints | GET |
/api/v1/private/projects/{project_id}/documents/{document_id}/versions/{version_id}/endpoints/{endpoint_id} |
JWT |
| Diffs | POST |
/api/v1/private/projects/{project_id}/documents/{document_id}/diffs |
JWT |
| Diffs | GET |
/api/v1/private/projects/{project_id}/documents/{document_id}/diffs |
JWT |
| Diffs | GET |
/api/v1/private/projects/{project_id}/documents/{document_id}/diffs/{diff_id} |
JWT |
| Diffs | GET |
/api/v1/private/projects/{project_id}/documents/{document_id}/diffs/{diff_id}/summary |
JWT |
| Audit Logs | GET |
/api/v1/private/audit-logs |
JWT; super admin or scoped project admin |
| AI | GET, PUT |
/api/v1/private/ai/provider |
JWT; SuperAdmin |
| AI | POST |
/api/v1/private/ai/provider/test |
JWT; SuperAdmin |
| AI | GET, PUT |
/api/v1/private/projects/{project_id}/ai/provider |
JWT; Project Admin or SuperAdmin |
| AI | POST |
/api/v1/private/projects/{project_id}/ai/provider/test |
JWT; Project Admin or SuperAdmin |
| AI | GET |
/api/v1/private/ai/prompts |
JWT; SuperAdmin |
| AI | PUT |
/api/v1/private/ai/prompts/{prompt_key} |
JWT; SuperAdmin |
| AI | GET |
/api/v1/private/projects/{project_id}/ai/prompts |
JWT; Project Admin or SuperAdmin |
| AI | PUT |
/api/v1/private/projects/{project_id}/ai/prompts/{prompt_key} |
JWT; Project Admin or SuperAdmin |
| AI | GET |
/api/v1/private/projects/{project_id}/documents/{document_id}/drafts/{draft_id}/ai-summary |
JWT |
| AI | POST |
/api/v1/private/projects/{project_id}/documents/{document_id}/drafts/{draft_id}/ai-summary/regenerate |
JWT |
| AI | GET |
/api/v1/private/projects/{project_id}/documents/{document_id}/versions/{version_id}/ai-summary |
JWT |
| AI | POST |
/api/v1/private/projects/{project_id}/documents/{document_id}/versions/{version_id}/ai-summary/regenerate |
JWT |
| AI | GET |
/api/v1/private/projects/{project_id}/documents/{document_id}/diffs/{diff_id}/ai-summary |
JWT |
| AI | POST |
/api/v1/private/projects/{project_id}/documents/{document_id}/diffs/{diff_id}/ai-summary/regenerate |
JWT |
| AI | GET, POST |
/api/v1/private/projects/{project_id}/ai/chat-sessions |
JWT |
| AI | GET |
/api/v1/private/projects/{project_id}/ai/chat-sessions/{session_id} |
JWT |
| AI | POST |
/api/v1/private/projects/{project_id}/ai/chat-sessions/{session_id}/messages |
JWT |
| MCP Tokens | GET, POST |
/api/v1/private/mcp-tokens |
JWT |
| MCP Tokens | GET |
/api/v1/private/mcp-usage |
JWT; owner-scoped unless SuperAdmin supplies token_id |
| MCP Tokens | GET |
/api/v1/private/mcp-tokens/{token_id} |
JWT |
| MCP Tokens | POST |
/api/v1/private/mcp-tokens/{token_id}/revoke |
JWT |
- Version and endpoint lists accept
page_size=1..200,offset=0..1000000, andsearch(up to 256 UTF-8 bytes). Version search matches the version name. Endpoint search matches method, path, summary, operation ID and tags. Responses includetotalandhas_more. Omittingpage_sizepreserves the legacy list contract. - Audit queries accept
limit(default 100, maximum 200),cursor, and RFC3339from(inclusive) /to(exclusive). The response includeshas_moreand, when available,next_cursor. Repeat the same filters with that cursor to continue beyond 200 records. Cursor pages omit a global total; project authorization is checked for every page. - Example:
GET /api/v1/private/projects/{project_id}/documents/{document_id}/versions?page_size=50&offset=50&search=v1. - Client cancellation propagates to database queries, object storage, and interactive AI requests. The API context deadline is 30 seconds for regular requests and 150 seconds for AI/MCP routes, bounded further by any earlier caller deadline. Errors retain HTTP 200 and use envelope statuses
CANCELLED(499) orDEADLINE_EXCEEDED(504). Database rollback/object cleanup has a separate bounded cleanup context. - Background summary jobs survive request cancellation and process restarts. One worker per instance claims jobs with a 180-second lease; each attempt is bounded to 150 seconds. Transient preparation/persistence errors retry up to three attempts with a five-second delay. Graceful shutdown releases durable work for retry; expired leases recover after crashes. Provider response failures are stored as
failedfor explicit retry. Targets, permissions, and generation tokens are rechecked before saving completion. No provider configuration storesskippedimmediately without enqueueing work. - Access logs include
route(the Gin route template),app_code, andapp_statusalongside the transport status, latency and trace ID. Business errors therefore remain distinguishable when transport HTTP status is 200. Request/response bodies and credential values are excluded.