{"openapi":"3.0.3","info":{"title":"APLG Learning Public API","description":"Public read-only JSON API for the APLG Learning platform: course catalog, statement review sessions, topics, landing content, and FAQs. Authenticated actions require a user JWT from POST /login. Error responses share one typed schema with a machine-readable detail and a human-readable message. Versioning: endpoints are versioned in the URL path (/v1). Breaking changes ship as a new version while the previous version keeps working for at least 6 months. A deprecated endpoint is announced in /api-docs and answers with Sunset and Deprecation response headers carrying its removal date.","version":"1.0.0"},"servers":[{"url":"/","description":"Same-origin API (this host)"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Role-bound user JWT from POST /login (Authorization: Bearer <token>). Tokens carry identity; permissions come from server-side roles, see /.well-known/oauth-protected-resource for the scope vocabulary."}},"schemas":{"Error":{"type":"object","required":["status","message"],"properties":{"status":{"type":"string","example":"error"},"message":{"type":"string","description":"Human-readable resolution hint."},"error":{"type":"string","description":"Machine-readable detail."}}}},"responses":{"BadRequest":{"description":"Invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing or invalid credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Authenticated but not allowed (e.g. account pending approval).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"TooManyRequests":{"description":"Rate limit exceeded. Back off per Retry-After.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Quota per window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Always 0 on rejection.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window slides.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"ServerError":{"description":"Unexpected failure.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/course-list":{"get":{"operationId":"listCourses","summary":"List public courses","description":"Paginated public course catalog with topic, type, and recency filters.","parameters":[{"name":"content_page_id","in":"query","description":"Comma-separated content page IDs to filter the catalog.","schema":{"type":"string"}},{"name":"topic_id","in":"query","description":"Topic ID from /v1/topic-list.","schema":{"type":"string"}},{"name":"type","in":"query","description":"Publication or learning type filter.","schema":{"type":"string"}},{"name":"sort","in":"query","description":"Sort order: recent, oldest, or az.","schema":{"type":"string","enum":["recent","oldest","az"]}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":10}}],"responses":{"200":{"description":"Course list with pagination metadata.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"Datas":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"topic_id":{"type":"string"},"cover_image_path":{"type":"string"}}}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/v1/statement-sessions":{"get":{"operationId":"listStatementSessions","summary":"List joint-statement review sessions","description":"Review sessions with draft files, deadlines, and open/closed status.","responses":{"200":{"description":"Session list.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"sessions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"category":{"type":"string"},"draft_file":{"type":"string"},"draft_name":{"type":"string"},"deadline":{"type":"string","format":"date-time","nullable":true},"status":{"type":"string","enum":["open","closed"]}}}}}}}}},"500":{"$ref":"#/components/responses/ServerError"}}}},"/v1/statement-sessions/{id}":{"get":{"operationId":"getStatementSession","summary":"Get one review session with submissions","description":"Session detail including draft file metadata and submitted feedback.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Session detail.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"session":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"category":{"type":"string"},"draft_file":{"type":"string"},"draft_name":{"type":"string"},"deadline":{"type":"string","format":"date-time","nullable":true},"status":{"type":"string","enum":["open","closed"]}}},"submissions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"uploader_name":{"type":"string"},"organization":{"type":"string"},"file_name":{"type":"string"},"file_url":{"type":"string"},"mime_type":{"type":"string"},"file_size":{"type":"integer"},"submitted_at":{"type":"string","format":"date-time"},"note":{"type":"string"}}}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/topic-list":{"get":{"operationId":"listTopics","summary":"List filter topics","description":"Topic taxonomy backing the list-page topic filters.","parameters":[{"name":"content_page_id","in":"query","description":"Scope topics to a content page.","schema":{"type":"string"}},{"name":"used_only","in":"query","description":"Only topics attached to content.","schema":{"type":"boolean"}},{"name":"include_global","in":"query","description":"Include page-agnostic topics.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Topic list.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"success"},"message":{"type":"string"},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}}}}}}}},"500":{"$ref":"#/components/responses/ServerError"}}}},"/login":{"post":{"operationId":"login","summary":"Obtain a user JWT","description":"Email and password login returning a JWT for authenticated actions such as enrollment and draft submission. Rate limited per IP.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string","format":"email"},"password":{"type":"string","format":"password"},"remember_me":{"type":"boolean","default":false}}}}}},"responses":{"200":{"description":"JWT issued.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"user":{"type":"object"},"token":{"type":"string"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/ServerError"}}}}}}