name: Public API with Organization-Scoped Automation Keys
overview: Build the public API on top of the shipped organization automation foundation: the /org/[slug]/automation section already exists, MCP is live, /automation/api and /automation/zapier exist as placeholder pages, and org-scoped automation keys already exist in the backend. This PRD updates the remaining work to ship the actual public API experience and docs.
todos:
- id: confirm-existing-foundation
content: Confirm and preserve the shipped automation foundation (
Automationnav,/org/[slug]/automationredirect, MCP page, organization automation key backend) status: completed - id: org-automation-foundation
content: Keep using
organization_api_keyand/organization/automation/*as the shared automation-key foundation for MCP, API, and Zapier status: completed - id: mcp-page-reference content: Use the existing MCP implementation as the structural reference for the API page (route shell, server load, feature API class, feature page component, translations) status: completed
- id: agents-guidance
content: Ensure all implementation in this initiative follows
AGENTS.mdstatus: completed - id: api-tab-page
content: Replace the placeholder
/org/[slug]/automation/apipage with a real API page that follows the MCP page pattern status: completed - id: api-tab-server-load
content: Add
/org/[slug]/automation/api/+page.server.tsto load API key and usage data using the existing organization automation endpoints status: completed - id: api-tab-copy content: Add API-specific translations and content for docs links, usage messaging, and key management states status: completed
- id: v1-validation-schemas content: Add public API input/output validation schemas on top of the existing automation-key schemas status: completed
- id: v1-services content: Create versioned public API services for courses and audience/students status: completed
- id: v1-routes
content: Create and register
/v1public API routes authenticated by organization automation keys status: completed - id: public-api-scopes
content: Finalize the public API scope model and middleware requirements for
apiandzapierautomation keys status: completed - id: tests
content: Add API tests for automation auth,
/v1routes, and contract coverage status: completed - id: openapi-contracts content: Ensure all public API routes are represented in generated OpenAPI output status: completed
- id: openapi-publish
content: Regenerate and upload the latest OpenAPI spec via
upload-openapi-spec.tsstatus: completed - id: docs-openapi-integration
content: Add the public API docs experience in
apps/docsstatus: completed - id: build-verify content: Build and verify API and docs packages after implementation status: completed isProject: false
Public API with Organization-Scoped Automation Keys
Status
- Done (shipped)
Goal
Ship a versioned public API on top of the existing organization automation platform. The current codebase already supports shared org-scoped automation keys and a dedicated Automation section in /org; this PRD now focuses on the remaining API product work rather than re-specifying the already-shipped foundation.
Implementation Guardrails
- All implementation in this initiative must follow AGENTS.md.
- Do not design this as a brand-new standalone automation surface. Follow the existing patterns already used by the MCP implementation.
- For dashboard work, the API page must mirror the MCP structure:
- route shell under
apps/dashboard/src/routes/org/[slug]/automation/* - server-side data loading in
+page.server.ts - state and mutations in
apps/dashboard/src/lib/features/automation/api/automation.svelte.ts - request/response types in
apps/dashboard/src/lib/features/automation/utils/types.ts - page composition in
apps/dashboard/src/lib/features/automation/pages/api.svelte
- route shell under
- Do not define new dashboard types inside
.svelte.tsfiles. Keep feature types inutils/types.tsand infer them from the API client. - Keep user-facing copy in
apps/dashboard/src/lib/utils/translations/en.json.
Current State Confirmed in Code
Org navigation and routes
These pieces already exist and should be treated as the current baseline:
apps/dashboard/src/lib/features/ui/navigation/org-navigation.ts- contains an admin-only
Automationsection under/org/[slug]/automation - exposes nested entries for
MCP,Zapier, andAPI
- contains an admin-only
apps/dashboard/src/routes/org/[slug]/automation/+page.ts- redirects
/org/[slug]/automationto/org/[slug]/automation/mcp
- redirects
apps/dashboard/src/routes/org/[slug]/automation/mcp/+page.svelte- shipped MCP route shell using
Page.Root,Page.Header, andPage.Body
- shipped MCP route shell using
apps/dashboard/src/routes/org/[slug]/automation/mcp/+page.server.ts- already loads automation keys and usage for
type=mcp
- already loads automation keys and usage for
apps/dashboard/src/routes/org/[slug]/automation/api/+page.svelte- already exists, but is currently a placeholder
apps/dashboard/src/routes/org/[slug]/automation/zapier/+page.svelte- already exists, but is currently a placeholder
Frontend automation feature foundation
These pieces already exist and should be reused:
apps/dashboard/src/lib/features/automation/api/automation.svelte.ts- shared automation API class for list/create/revoke/rotate
apps/dashboard/src/lib/features/automation/utils/types.ts- shared request and response inference types
apps/dashboard/src/lib/features/automation/pages/mcp.svelte- the current reference implementation for page structure and composition
apps/dashboard/src/lib/features/automation/pages/api.svelte- currently renders only a coming-soon callout
apps/dashboard/src/lib/utils/translations/en.json- already contains automation navigation and MCP copy
Backend automation-key foundation
This work is already implemented and should not be re-invented as a separate /api-key system:
packages/db/src/schema.ts- already defines
organization_api_key - already defines
organization_automation_usage
- already defines
packages/utils/src/validation/organization/automation-key.ts- already defines key types:
mcp,api,zapier - already defines scopes, query params, creation payload, and param validation
- already defines key types:
packages/db/src/queries/organization/automation-key.ts- already handles persistence for organization automation keys
apps/api/src/services/organization/automation-key.ts- already handles secret generation, hashing, creation, revoke, rotate, and auth
apps/api/src/routes/organization/automation.ts- already exposes:
GET /organization/automation/usageGET /organization/automation/keysPOST /organization/automation/keysDELETE /organization/automation/keys/:keyIdPOST /organization/automation/keys/:keyId/rotate
- already exposes:
Important correction to the old PRD
The old PRD assumed:
- a brand-new Automation page still needed to be created
- Automation should be one page with internal tabs
- a standalone
/api-keybackend should be introduced Webhookswas one of the primary tabs
That is no longer accurate.
The current product structure is:
- org navigation owns the Automation section
- Automation is split into nested routes:
mcp,zapier, andapi - the shared backend lives under
/organization/automation/* - MCP is the shipped reference page
apiandzapierare present as placeholder pages
Existing Foundation to Build On
1. Shared Automation Keys
The public API must reuse the existing organization-scoped automation-key model.
Current model:
- table:
organization_api_key - key types:
mcp,api,zapier - key prefixes: generated from the actual secret prefix
- auth: bearer token via the existing automation-key service/middleware path
- rotation and revocation: already implemented
- usage tracking: already implemented in
organization_automation_usage
Design requirement:
- do not introduce a second key table or a second dashboard key-management surface
- do not reintroduce the older
/api-keyroute design from the original PRD - build the public API on the existing
organization/automationcontracts unless there is a deliberate migration plan
2. Dashboard Information Architecture
The Automation product is already organized as nested org routes, not a tabbed single-page shell.
Required route structure:
/org/[slug]/automation- redirect only
/org/[slug]/automation/mcp- existing reference implementation
/org/[slug]/automation/api- target page for public API setup and management
/org/[slug]/automation/zapier- separate placeholder or future implementation
Design requirement:
- keep the org sidebar/navigation pattern unchanged
- do not replace nested routes with a new internal tabs container for top-level Automation navigation
- if tabs are used inside a page, use them only for local subcontent, the way MCP uses setup tabs for client snippets
Remaining Product Scope
3. API Page in Dashboard
The next dashboard milestone is to replace the placeholder API page with a real implementation.
Target route files
apps/dashboard/src/routes/org/[slug]/automation/api/+page.svelteapps/dashboard/src/routes/org/[slug]/automation/api/+page.server.tsapps/dashboard/src/lib/features/automation/pages/api.svelteapps/dashboard/src/lib/features/automation/api/automation.svelte.tsapps/dashboard/src/lib/features/automation/utils/types.tsapps/dashboard/src/lib/utils/translations/en.json
Required structure
The API page must follow the same structural pattern already used by MCP:
-
Route shell:
- use
Page.Root,Page.Header,Page.HeaderContent,Page.Title, andPage.Body - set the page title from
automation.tabs.api - use an API-specific subtitle, not the generic coming-soon copy
- use
-
Server load:
- add
+page.server.ts - load key data with
classroomio.organization.automation.keys.$get({ query: { type: 'api' } }) - load usage data with
classroomio.organization.automation.usage.$get({ query: { type: 'api' } }) - hydrate the shared
automationApistore the same way MCP currently does
- add
-
Feature page:
- keep composition in
apps/dashboard/src/lib/features/automation/pages/api.svelte - mirror the MCP page layout style and sectioning
- do not leave this page as a single callout
- keep composition in
Required API page sections
The real API page should include the following, using the MCP page as the UX baseline:
- admin permission callout for non-admin users
- usage cards or equivalent summary block for API-specific limits
- API key table filtered to
type === 'api' - create key flow
- rotate key flow
- revoke key flow
- one-time secret reveal after creation or rotation
- docs/discovery section with a link to the public API documentation
- API-specific setup guidance
Reuse requirements
- reuse
automationApiinstead of introducing a separate API-only dashboard client - reuse shared automation types in
utils/types.ts - add new helper utilities only if the API page needs API-specific setup snippets or docs helpers
4. Public API Routes
The actual public API is still pending.
Router structure
Create:
apps/api/src/routes/v1/index.tsapps/api/src/routes/v1/courses.tsapps/api/src/routes/v1/audience.ts
Register in apps/api/src/app.ts as:
.route('/public-api/v1', v1Router)
Authentication model
All /public-api/v1 routes must authenticate with organization automation keys.
Requirements:
- use the existing automation-key authentication path
- require
type: 'api'or an equivalent scope model that intentionally permits public API access - document and enforce scopes clearly
- do not rely on session auth for
/public-api/v1
Planned endpoint groups
Initial public API surface:
| Method | Path | Description |
|---|---|---|
| GET | /public-api/v1/courses |
List organization courses |
| POST | /public-api/v1/courses |
Create a course |
| GET | /public-api/v1/courses/:courseId |
Get course details |
| PUT | /public-api/v1/courses/:courseId |
Update a course |
| DELETE | /public-api/v1/courses/:courseId |
Soft-delete a course |
| GET | /public-api/v1/courses/:courseId/export |
Export course content as JSON |
| GET | /public-api/v1/courses/:courseId/students |
List enrolled students |
| GET | /public-api/v1/audience |
List organization audience members |
| POST | /public-api/v1/audience |
Add a student to the organization |
| POST | /public-api/v1/audience/assign-courses |
Assign one or more audience members to one or more courses |
| GET | /public-api/v1/audience/:studentId |
Get student details |
| PUT | /public-api/v1/audience/:studentId |
Update student details |
| DELETE | /public-api/v1/audience/:studentId |
Remove a student from the organization |
Enrollment decision:
- keep only the audience assignment endpoint for enrollment
- do not add a separate course-centric enrollment route such as
POST /public-api/v1/courses/:courseId/students - a single audience member plus a single course in
POST /public-api/v1/audience/assign-coursescovers the single-enrollment case - multiple audience members and multiple courses in the same payload cover the bulk-assignment case
5. Validation and Services
Add public API schemas and services on top of the existing automation-key foundation.
Target files:
packages/utils/src/validation/...apps/api/src/services/v1/course.tsapps/api/src/services/v1/audience.ts
Requirements:
- follow the route/service/validation split defined in
AGENTS.md - each route must return a single response type shape
- keep business logic in services, not routes
- reuse existing DB queries where possible
6. OpenAPI and Docs
The backend already has OpenAPI infrastructure. The remaining work is to ensure the new public API is included and discoverable.
OpenAPI requirements
- all new
/public-api/v1/*routes must be documented with the existing Hono OpenAPI patterns - request params, query, body, success, and error responses must be declared
- avoid undocumented public API routes
Spec publishing
Use the existing script:
apps/api/scripts/upload-openapi-spec.ts
Required flow after API changes:
- Implement or update routes and schemas.
- Run
pnpm --filter @cio/api upload:openapi. - Verify the latest spec includes the new routes.
Docs integration
Add the public API docs experience in apps/docs.
Target tasks:
- Add the API docs page or route.
- Wire it to the published OpenAPI source.
- Add docs navigation for API.
- Verify the docs build still passes.
7. Testing
Add tests for:
- organization automation key auth behavior relevant to public API access
/v1/courses/v1/audience- OpenAPI contract inclusion for public API routes
Use Hono app-level testing where possible.
8. Build and Verification
Required verification commands after implementation:
pnpm --filter @cio/api buildpnpm --filter @cio/api upload:openapipnpm --filter @cio/docs build
Manual verification:
/org/[slug]/automationstill redirects to/org/[slug]/automation/mcp/org/[slug]/automation/apinow renders the real API page rather than the placeholder- API key creation, rotation, and revoke flows work for
type=api /public-api/v1/*routes respond under the new base path- docs navigation exposes the public API docs entry