openapi: 3.0.3
info:
  title: Makrly API
  version: 1.0.0
  description: |
    The Makrly API lets you programmatically manage repositories, generate social media posts,
    and create changelog entries. Authenticate with a Bearer token from your dashboard.
  contact:
    email: hello@makrly.com
    url: https://makrly.com/developers
servers:
  - url: https://makrly.com/api/v1
    description: Production

security:
  - BearerAuth: []

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: "API key starting with mk_live_"

  schemas:
    Error:
      type: object
      properties:
        error:
          type: string
          description: Human-readable error message
          example: Repository not found
        code:
          type: string
          description: Machine-readable error code
          example: not_found

    PaginationMeta:
      type: object
      properties:
        page:
          type: integer
          example: 1
        limit:
          type: integer
          example: 20
        total:
          type: integer
          example: 42
        totalPages:
          type: integer
          example: 3

    Repo:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        fullName:
          type: string
        description:
          type: string
          nullable: true
        isPrivate:
          type: boolean
        isActive:
          type: boolean
        notableCommitCount:
          type: integer
        changelogEntryCount:
          type: integer
        lastSyncedAt:
          type: string
          format: date-time
          nullable: true
        createdAt:
          type: string
          format: date-time

    Post:
      type: object
      properties:
        id:
          type: integer
        platform:
          type: string
          enum: [short, thread, linkedin, facebook_profile, facebook_page]
        content:
          type: string
        createdAt:
          type: string
          format: date-time
        commit:
          type: object
          properties:
            id:
              type: integer
            sha:
              type: string
            message:
              type: string
            committedAt:
              type: string
              format: date-time
              nullable: true

    ChangelogEntry:
      type: object
      properties:
        id:
          type: string
        title:
          type: string
        slug:
          type: string
          nullable: true
        summary:
          type: string
          nullable: true
        content:
          type: string
        categories:
          type: array
          items:
            type: string
        imageUrl:
          type: string
          nullable: true
        viewCount:
          type: integer
        sourceType:
          type: string
          nullable: true
        publishedAt:
          type: string
          format: date-time
          nullable: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    Commit:
      type: object
      properties:
        id:
          type: integer
        sha:
          type: string
        message:
          type: string
        authorName:
          type: string
          nullable: true
        committedAt:
          type: string
          format: date-time
          nullable: true
        isNotable:
          type: boolean
        filesChanged:
          type: integer
          nullable: true
        additions:
          type: integer
          nullable: true
        deletions:
          type: integer
          nullable: true
        createdAt:
          type: string
          format: date-time

    GeneratedPosts:
      type: object
      properties:
        short:
          type: string
          description: Short post (280 chars, for X/Bluesky/Threads)
        thread:
          type: array
          items:
            type: string
          description: Thread posts (3-5 posts of 280 chars)
        linkedin:
          type: string
        facebookProfile:
          type: string
        facebookPage:
          type: string

paths:
  /repos:
    get:
      summary: List repositories
      operationId: listRepos
      tags: [Repositories]
      responses:
        "200":
          description: List of tracked repositories
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Repo"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /repos/{repoId}:
    get:
      summary: Get a repository
      operationId: getRepo
      tags: [Repositories]
      parameters:
        - name: repoId
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Repository details
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/Repo"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /repos/{repoId}/posts:
    get:
      summary: List posts for a repository
      operationId: listPosts
      tags: [Posts]
      parameters:
        - name: repoId
          in: path
          required: true
          schema:
            type: integer
        - name: platform
          in: query
          schema:
            type: string
            enum: [short, thread, linkedin, facebook_profile, facebook_page]
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
      responses:
        "200":
          description: Paginated list of posts
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Post"
                  meta:
                    $ref: "#/components/schemas/PaginationMeta"

  /posts/generate:
    post:
      summary: Generate posts from custom text
      operationId: generatePosts
      tags: [Posts]
      description: |
        Generates platform-specific social media posts from custom text using
        the user's configured AI provider, model, and personality settings.
        Requires an AI provider key configured in the dashboard.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [content]
              properties:
                content:
                  type: string
                  maxLength: 5000
                  description: The text to generate posts from
                repoId:
                  type: integer
                  description: Optional repo ID for context
                provider:
                  type: string
                  enum: [openai, openrouter, straico]
                  description: Override the default AI provider
                model:
                  type: string
                  description: Override the default AI model
      responses:
        "200":
          description: Generated posts for all platforms
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/GeneratedPosts"

  /posts/{id}:
    get:
      summary: Get a single post
      operationId: getPost
      tags: [Posts]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Post details
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/Post"
    patch:
      summary: Update a post
      operationId: updatePost
      tags: [Posts]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [content]
              properties:
                content:
                  type: string
      responses:
        "200":
          description: Updated post
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/Post"

  /repos/{repoId}/changelog/entries:
    get:
      summary: List changelog entries
      operationId: listChangelogEntries
      tags: [Changelog]
      parameters:
        - name: repoId
          in: path
          required: true
          schema:
            type: integer
        - name: status
          in: query
          schema:
            type: string
            enum: [published, draft]
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
      responses:
        "200":
          description: Paginated list of entries
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/ChangelogEntry"
                  meta:
                    $ref: "#/components/schemas/PaginationMeta"
    post:
      summary: Create a changelog entry
      operationId: createChangelogEntry
      tags: [Changelog]
      parameters:
        - name: repoId
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [title, categories]
              properties:
                title:
                  type: string
                content:
                  type: string
                summary:
                  type: string
                categories:
                  type: array
                  items:
                    type: string
                  example: ["new"]
                publishedAt:
                  type: string
                  format: date-time
                  description: Set to publish immediately, omit for draft
      responses:
        "201":
          description: Created entry
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/ChangelogEntry"

  /changelog/entries:
    get:
      summary: List changelog entries (scope-aware)
      operationId: listChangelogEntriesScoped
      tags: [Changelog]
      description: |
        List changelog entries. Requires `changelog:read` scope.
        Pass repoId as query param, or use a repo-scoped API key.
      parameters:
        - name: repoId
          in: query
          required: false
          schema:
            type: integer
          description: Required unless using a repo-scoped API key
        - name: status
          in: query
          schema:
            type: string
            enum: [published, draft]
        - name: cursor
          in: query
          schema:
            type: string
          description: Cursor-based pagination (entry ID)
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
      responses:
        "200":
          description: Cursor-paginated list of entries
          content:
            application/json:
              schema:
                type: object
                properties:
                  entries:
                    type: array
                    items:
                      $ref: "#/components/schemas/ChangelogEntry"
                  nextCursor:
                    type: string
                    nullable: true
                  hasMore:
                    type: boolean
    post:
      summary: Create a changelog entry (scope-aware)
      operationId: createChangelogEntryScoped
      tags: [Changelog]
      description: Requires `changelog:write` scope.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [title, categories]
              properties:
                repoId:
                  type: integer
                  description: Required unless using a repo-scoped API key
                title:
                  type: string
                content:
                  type: string
                summary:
                  type: string
                categories:
                  type: array
                  items:
                    type: string
                  example: ["new"]
                publish:
                  type: boolean
                  description: Whether to publish immediately
                publishedAt:
                  type: string
                  format: date-time
                  description: Custom publish date (used when publish=true)
      responses:
        "201":
          description: Created entry
          content:
            application/json:
              schema:
                type: object
                properties:
                  entry:
                    $ref: "#/components/schemas/ChangelogEntry"

  /changelog/entries/{id}:
    get:
      summary: Get a changelog entry
      operationId: getChangelogEntry
      tags: [Changelog]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Entry details
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/ChangelogEntry"
    patch:
      summary: Update a changelog entry
      operationId: updateChangelogEntry
      tags: [Changelog]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                content:
                  type: string
                summary:
                  type: string
                categories:
                  type: array
                  items:
                    type: string
                publishedAt:
                  type: string
                  format: date-time
                  nullable: true
                  description: Set to publish, null to unpublish
      responses:
        "200":
          description: Updated entry
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/ChangelogEntry"
    delete:
      summary: Delete a changelog entry
      operationId: deleteChangelogEntry
      tags: [Changelog]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      deleted:
                        type: boolean

  /changelog/settings:
    get:
      summary: Get changelog settings
      operationId: getChangelogSettings
      tags: [Changelog]
      description: Requires `settings:read` scope.
      parameters:
        - name: repoId
          in: query
          required: false
          schema:
            type: integer
          description: Required unless using a repo-scoped API key
      responses:
        "200":
          description: Changelog widget settings
          content:
            application/json:
              schema:
                type: object
                properties:
                  settings:
                    type: object
                    description: Full changelog settings object
    post:
      summary: Update changelog settings
      operationId: updateChangelogSettings
      tags: [Changelog]
      description: |
        Requires `settings:write` scope. Only appearance/content settings
        are API-accessible. Webhook/auto-mode settings require the dashboard.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                repoId:
                  type: integer
                  description: Required unless using a repo-scoped API key
                theme:
                  type: string
                  enum: [light, dark, auto]
                position:
                  type: string
                  enum: [bottom-right, bottom-left, top-right, top-left]
                primaryColor:
                  type: string
                  description: Hex color (e.g., #6366f1)
                triggerIcon:
                  type: string
                  enum: [bell, sparkles, megaphone, rocket, gift, newspaper, zap, party]
                title:
                  type: string
                isPublic:
                  type: boolean
      responses:
        "200":
          description: Updated settings
          content:
            application/json:
              schema:
                type: object
                properties:
                  settings:
                    type: object

  /repos/{repoId}/commits:
    get:
      summary: List commits for a repository
      operationId: listCommits
      tags: [Commits]
      parameters:
        - name: repoId
          in: path
          required: true
          schema:
            type: integer
        - name: notable
          in: query
          schema:
            type: boolean
          description: Filter to notable commits only
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
      responses:
        "200":
          description: Paginated list of commits
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Commit"
                  meta:
                    $ref: "#/components/schemas/PaginationMeta"
