openapi: 3.1.0
info:
  title: Collected Notes Public API
  description: |
    The public read-only API for accessing published content on Collected Notes.

    These endpoints are designed for integrations, embeds, static site generators,
    and any tool that needs to read public note content. No authentication required
    for public/unlisted content.

    ## Who this is for

    - Static site generators fetching content from CN
    - Embeds and widgets showing note content
    - Third-party readers and aggregators
    - Anyone building on top of published CN content

    ## For CLI, MCP, and agent integrations

    If you need to **create, update, delete, search, or sync** notes, see the
    **Integration API** spec at `/api-integration.yaml`. That API requires
    authentication and is used by the `cn` CLI, MCP clients, and AI agents.

    ## Note Visibility

    - **public** — visible to everyone, listed on site
    - **unlisted** — accessible via direct link, not listed
    - **private** — only accessible to the owner (requires Integration API)
    - **public_unlisted** — public but not listed on site
  version: 2.0.0
  contact:
    name: Collected Notes Support
    url: https://collectednotes.com/contact

servers:
  - url: https://collectednotes.com
    description: Production
  - url: http://localhost:3000
    description: Development

tags:
  - name: Sites
    description: Read public site data and note listings
  - name: Notes
    description: Read individual notes in various formats

paths:
  /{site_path}.json:
    get:
      operationId: getSiteJson
      summary: Get site with notes
      description: |
        Returns site metadata along with all public notes (listed notes only;
        unlisted and private notes are excluded). Notes are returned as
        summaries (no body content).
      tags: [Sites]
      parameters:
        - $ref: '#/components/parameters/SitePath'
      responses:
        '200':
          description: Site data with note summaries
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SiteWithNotes'
              example:
                id: 42
                user_id: 7
                site_path: "my-blog"
                name: "My Blog"
                headline: "Thoughts on technology"
                about: "Welcome to my blog"
                domain: null
                created_at: "2024-01-15T10:30:00.000Z"
                updated_at: "2024-06-20T14:45:00.000Z"
                notes:
                  - id: 101
                    site_id: 42
                    user_id: 7
                    title: "Getting Started"
                    path: "getting-started"
                    headline: "A beginner's guide"
                    visibility: "public"
                    ordering: 1
                    tags: ["guide", "intro"]
                    source: "web"
                    created_at: "2024-03-10T09:00:00.000Z"
                    updated_at: "2024-03-10T09:00:00.000Z"
        '404':
          $ref: '#/components/responses/NotFound'

  /{site_path}/{note_path}.json:
    get:
      operationId: getNoteJson
      summary: Get note as JSON
      description: Returns a single note with full body content and metadata.
      tags: [Notes]
      parameters:
        - $ref: '#/components/parameters/SitePath'
        - $ref: '#/components/parameters/NotePath'
      responses:
        '200':
          description: Note with body
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Note'
        '404':
          $ref: '#/components/responses/NotFound'

  /{site_path}/{note_path}.md:
    get:
      operationId: getNoteMarkdown
      summary: Get note as Markdown
      description: Returns note content as Markdown with YAML frontmatter.
      tags: [Notes]
      parameters:
        - $ref: '#/components/parameters/SitePath'
        - $ref: '#/components/parameters/NotePath'
      responses:
        '200':
          description: Markdown with frontmatter
          content:
            text/markdown:
              schema:
                type: string
              example: |
                ---
                title: "Getting Started"
                path: "getting-started"
                visibility: "public"
                created_at: "2024-03-10T09:00:00.000Z"
                updated_at: "2024-03-10T09:00:00.000Z"
                ---

                # Getting Started

                Content here...
        '404':
          $ref: '#/components/responses/NotFound'

  /{site_path}/{note_path}.txt:
    get:
      operationId: getNotePlainText
      summary: Get note as plain text
      description: Returns the note body without formatting.
      tags: [Notes]
      parameters:
        - $ref: '#/components/parameters/SitePath'
        - $ref: '#/components/parameters/NotePath'
      responses:
        '200':
          description: Plain text body
          content:
            text/plain:
              schema:
                type: string
        '404':
          $ref: '#/components/responses/NotFound'

  /{site_path}/{note_path}/body:
    get:
      operationId: getNoteBody
      summary: Get rendered note body
      description: Returns the note body rendered as HTML with note metadata.
      tags: [Notes]
      parameters:
        - $ref: '#/components/parameters/SitePath'
        - $ref: '#/components/parameters/NotePath'
      responses:
        '200':
          description: HTML body with metadata
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NoteBody'
        '404':
          $ref: '#/components/responses/NotFound'

components:
  parameters:
    SitePath:
      name: site_path
      in: path
      required: true
      description: The site's URL slug
      schema:
        type: string
        pattern: '^[a-z0-9-]+$'
      example: my-blog
    NotePath:
      name: note_path
      in: path
      required: true
      description: The note's URL slug
      schema:
        type: string
      example: getting-started

  schemas:
    Site:
      type: object
      properties:
        id:
          type: integer
        user_id:
          type: integer
        site_path:
          type: string
        name:
          type: string
          nullable: true
        headline:
          type: string
          nullable: true
        about:
          type: string
          nullable: true
        domain:
          type: string
          nullable: true
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required: [id, user_id, site_path, created_at, updated_at]

    NoteSummary:
      type: object
      description: Note metadata without body
      properties:
        id:
          type: integer
        site_id:
          type: integer
        user_id:
          type: integer
        title:
          type: string
        path:
          type: string
        headline:
          type: string
          nullable: true
        visibility:
          $ref: '#/components/schemas/Visibility'
        ordering:
          type: integer
        tags:
          type: array
          description: Tags applied to the note
          items:
            type: string
        source:
          type: string
          nullable: true
          description: Where the note was last created/modified (web, ios, cli, api, mcp)
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required: [id, site_id, user_id, title, path, visibility, created_at, updated_at]

    Note:
      allOf:
        - $ref: '#/components/schemas/NoteSummary'
        - type: object
          properties:
            body:
              type: string
              description: Markdown content
          required: [body]

    NoteBody:
      type: object
      properties:
        body:
          type: string
          description: HTML-rendered content
        note:
          $ref: '#/components/schemas/NoteSummary'
      required: [body, note]

    SiteWithNotes:
      allOf:
        - $ref: '#/components/schemas/Site'
        - type: object
          properties:
            notes:
              type: array
              items:
                $ref: '#/components/schemas/NoteSummary'
          required: [notes]

    Visibility:
      type: string
      enum: [public, private, unlisted, public_unlisted]

    Error:
      type: object
      properties:
        error:
          type: string
      required: [error]

  responses:
    NotFound:
      description: Not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: "Not found"

security: []
