How We Document APIs
This document explains our code-first approach to API documentation. We maintain a single source of truth (the API manifest) and auto-generate Mintlify reference tables from it.Overview
Our API documentation workflow follows these principles:- Code-first: The manifest in
packages/api-spec/src/manifest.tsis the source of truth - Auto-generated: Reference tables are generated from the manifest
- Scope-safe: Guardrails ensure no SuperAdmin endpoints leak into tenant docs
- Lightweight: Regex-based scanning, no runtime code changes
Workflow
Step 1: Scan Routes
Discover all API routes in the codebase:apps/scm/app/api/**/route.ts files and generates:
packages/.generated/api-routes.json- Complete route inventorypackages/.generated/manifest-stubs.ts- Suggested manifest entries
- Finds all route handlers
- Detects HTTP methods (GET, POST, etc.)
- Identifies authentication patterns
- Extracts Zod schema names
- Classifies routes as tenant-facing vs internal-only
Step 2: Generate Stubs
Create manifest stub suggestions:packages/.generated/api-manifest.stubs.ts- Ready-to-copy manifest entries
- Converts paths to stable IDs
- Infers tags from path prefixes
- Detects auth types
- Sets default stability (beta for safety)
- Marks internal-only routes
Step 3: Refine Manifest
Copy relevant stubs topackages/api-spec/src/manifest.ts and:
- Fill in summaries: Replace “TODO: Add summary” with clear descriptions
- Add descriptions: Provide detailed endpoint documentation
- Add examples: Include request/response examples
- Set permissions: Document required permissions
- Adjust stability: Mark stable endpoints as
stable(default isbeta) - Add query params: Document query parameters
- Add path params: Document dynamic route segments
Step 4: Validate
Check the manifest against guardrails:- ✅ No SuperAdmin paths or references
- ✅ All tenant routes have proper auth
- ✅ All IDs are unique
- ✅ All paths start with
/api/ - ✅ All routes have summaries and tags
Step 5: Generate Docs
Update Mintlify reference tables:docs-site/api-reference/forecasting.mdxdocs-site/api-reference/inventory.mdxdocs-site/api-reference/alerts.mdxdocs-site/api-reference/transfers.mdxdocs-site/api-reference/catalog.mdx
- Groups routes by tag
- Sorts by path, then method
- Generates markdown tables
- Includes permissions when available
- Marks beta endpoints with ⚠️
- Only updates delimited blocks (preserves other content)
CI Guard
Before committing, run the CI guard:- ✅ Manifest doesn’t contain excluded paths (SuperAdmin)
- ✅ Generated docs blocks are present in all target files
- ✅ Docs blocks are properly formatted
Scope Rules
✅ Include
- Tenant-facing APIs in
apps/scm/app/api/** - APIs consumed by external integrators
- Tenant-admin configuration APIs (
/api/admin/*)
❌ Exclude
- SuperAdmin endpoints (
apps/admin/**) - Tenant provisioning APIs
- Entitlement assignment APIs
- Billing admin operations
- Internal cron endpoints (unless tenant-configurable)
⚠️ When in Doubt
Mark ambiguous endpoints asinternalOnly: true until confirmed tenant-facing.
File Structure
Delimited Blocks
Generated tables are wrapped in delimited blocks:- Do NOT edit content between these markers
- The generator will overwrite it
- All other content in the file is preserved
Best Practices
- Keep it lightweight: Use regex-based scanning, don’t refactor runtime code
- Prefer correctness: Mark ambiguous endpoints as
internalOnly: true - Scope safety first: Better to exclude than include SuperAdmin endpoints
- Update regularly: Run
api:scanwhen adding new routes - Validate before commit: Run
api:validateandapi:guard
Troubleshooting
”Route not in docs”
- Check if route is in manifest:
packages/api-spec/src/manifest.ts - Verify route has correct tags matching target file
- Run
pnpm api:docsto regenerate tables - Check if route is marked
internalOnly: true
”CI guard failing”
- Check for SuperAdmin paths:
pnpm api:validate - Verify docs blocks exist: Check target files for delimited blocks
- Regenerate docs:
pnpm api:docs
”Missing permissions column”
Permissions column is only shown when routes havepermissions defined in manifest. Add permissions to routes that need them.