openapi: 3.1.0
info:
  title: OpenDocs API
  version: 1.0.0
  description: "Canonical public documentation, clipping, ingestion, source attribution, auto-tagging, search, formatting, submission, metadata, and AI-readable knowledge layer for the PlatPhormNews web mesh."
  contact:
    name: OpenDocs
    url: "https://docs.platphormnews.com"
servers:
  -
    url: "https://docs.platphormnews.com/api/v1"
    description: Production
security:
  -
    bearerAuth: []
  -
    platphormApiKey: []
paths:
  /documents:
    get:
      summary: List documents
      description: List all published documents with pagination and filtering
      tags:
        - Documents
      security: []
      parameters:
        -
          name: page
          in: query
          schema:
            type: integer
            default: 1
        -
          name: per_page
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
        -
          name: status
          in: query
          schema:
            type: string
            default: published
        -
          name: category
          in: query
          schema:
            type: string
        -
          name: q
          in: query
          schema:
            type: string
          description: Search query
        -
          name: tag
          in: query
          schema:
            type: string
      responses:
        200:
          description: List of documents
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/DocumentList"
    post:
      summary: Create document
      description: Create a new document
      tags:
        - Documents
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/DocumentCreate"
      responses:
        201:
          description: Document created
        401:
          description: Unauthorized
  /documents/{slug}:
    get:
      summary: Get document
      description: Get a specific document by slug
      tags:
        - Documents
      security: []
      parameters:
        -
          name: slug
          in: path
          required: true
          schema:
            type: string
      responses:
        200:
          description: Document details
        404:
          description: Not found
    put:
      summary: Update document
      description: Update an existing document
      tags:
        - Documents
      parameters:
        -
          name: slug
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/DocumentUpdate"
      responses:
        200:
          description: Document updated
        401:
          description: Unauthorized
        404:
          description: Not found
    delete:
      summary: Delete document
      description: Soft delete a document
      tags:
        - Documents
      parameters:
        -
          name: slug
          in: path
          required: true
          schema:
            type: string
      responses:
        200:
          description: Document deleted
        401:
          description: Unauthorized
        403:
          description: "Forbidden - requires admin scope"
        404:
          description: Not found
  /submissions:
    get:
      summary: List submissions
      description: List all submissions
      tags:
        - Submissions
      parameters:
        -
          name: status
          in: query
          schema:
            type: string
            enum:
              - pending
              - approved
              - rejected
        -
          name: source_url
          in: query
          schema:
            type: string
      responses:
        200:
          description: List of submissions
        401:
          description: Unauthorized
    post:
      summary: Create submission
      description: Submit new content for review (open endpoint)
      tags:
        - Submissions
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/SubmissionCreate"
      responses:
        201:
          description: Submission created
        400:
          description: Validation error
  /submissions/{id}:
    get:
      summary: Get submission
      tags:
        - Submissions
      parameters:
        -
          name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        200:
          description: Submission details
        404:
          description: Not found
    post:
      summary: Review submission
      description: Approve or reject a submission
      tags:
        - Submissions
      parameters:
        -
          name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/SubmissionReview"
      responses:
        200:
          description: Submission reviewed
  /search:
    get:
      summary: Search documents
      description: "Full-text search across all documents"
      tags:
        - Search
      security: []
      parameters:
        -
          name: q
          in: query
          required: true
          schema:
            type: string
            minLength: 2
        -
          name: category
          in: query
          schema:
            type: string
        -
          name: tag
          in: query
          schema:
            type: string
        -
          name: page
          in: query
          schema:
            type: integer
        -
          name: per_page
          in: query
          schema:
            type: integer
      responses:
        200:
          description: Search results
  /categories:
    get:
      summary: List categories
      tags:
        - Categories
      security: []
      responses:
        200:
          description: List of categories
    post:
      summary: Create category
      tags:
        - Categories
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/CategoryCreate"
      responses:
        201:
          description: Category created
  /webhooks:
    get:
      summary: List webhooks
      tags:
        - Webhooks
      responses:
        200:
          description: List of webhooks
    post:
      summary: Create webhook
      tags:
        - Webhooks
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/WebhookCreate"
      responses:
        201:
          description: Webhook created
  /keys:
    get:
      summary: List API keys
      tags:
        - Authentication
      responses:
        200:
          description: List of API keys
    post:
      summary: Create API key
      tags:
        - Authentication
      responses:
        201:
          description: API key created
    put:
      summary: Bootstrap API key
      description: Protected operator key bootstrap. Platform auth examples use PLATPHORM_API_KEY only.
      tags:
        - Authentication
      responses:
        201:
          description: Bootstrap key created
        403:
          description: Keys already exist
  /ingest:
    post:
      summary: Ingest URL
      description: Fetch and ingest content from an external URL
      tags:
        - Content
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - url
              properties:
                url:
                  type: string
                  format: uri
                  description: URL to ingest
                category:
                  type: string
                  description: Category slug
                tags:
                  type: array
                  items:
                    type: string
                auto_publish:
                  type: boolean
                  default: false
                target_audience:
                  type: string
      responses:
        201:
          description: Content ingested successfully
        400:
          description: Invalid URL or fetch error
  /clip/preview:
    post:
      summary: Preview public clip
      description: "Public-safe preview for web pages, platform posts, Reddit URLs, public Google Drive/Docs links, Dropbox links, image URLs, feeds, JSON, Markdown, HTML, or pasted text. The route is SSRF-guarded, bounded, and does not persist documents."
      tags:
        - Clipping
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/ClipPreviewRequest"
      responses:
        200:
          description: Clip preview
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/ClipPreviewResponse"
        400:
          description: Invalid source or unsupported input
  /clip/commit:
    post:
      summary: Commit public clip
      description: Submit a cleaned clip preview for review without an API key. Persisting a clip directly as a protected document requires PLATPHORM_API_KEY and mode=document.
      tags:
        - Clipping
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/ClipCommitRequest"
      responses:
        201:
          description: Clip committed as a pending submission or protected draft document
        401:
          description: PLATPHORM_API_KEY required for mode=document
        503:
          description: Server persistence unavailable; use local draft/export fallback
  /clip/platform-post:
    post:
      summary: Preview platform post clip
      description: "Public-safe clipping preview optimized for PlatPhormNews public posts and pages."
      tags:
        - Clipping
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/ClipPreviewRequest"
      responses:
        200:
          description: Platform post clip preview
  /clip/reddit:
    post:
      summary: Preview Reddit clip
      description: Public Reddit post/comment preview without Reddit auth. Returns an honest degraded preview if Reddit blocks or hides the content.
      tags:
        - Clipping
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/ClipPreviewRequest"
      responses:
        200:
          description: Reddit clip preview or degraded status
  /clip/google-drive:
    post:
      summary: Preview public Google Drive or Docs clip
      description: "Public-link only Google Drive/Docs preview. Permission-denied or login-required links degrade honestly."
      tags:
        - Clipping
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/ClipPreviewRequest"
      responses:
        200:
          description: Google Drive/Docs clip preview or degraded status
  /clip/dropbox:
    post:
      summary: Preview public Dropbox clip
      description: "Public Dropbox shared-link preview with bounded download conversion and degraded permission handling."
      tags:
        - Clipping
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/ClipPreviewRequest"
      responses:
        200:
          description: Dropbox clip preview or degraded status
  /clip/image:
    post:
      summary: Preview public image clip
      description: "Public image URL preview with MIME and size checks, manual alt text support, attribution, and OCR/AI alt-text degraded status unless a backend provider is configured."
      tags:
        - Clipping
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/ClipPreviewRequest"
      responses:
        200:
          description: Image clip preview or degraded status
  /clip/paste:
    post:
      summary: Preview pasted content clip
      description: "Public-safe paste cleanup for text, Markdown, or HTML without network fetches."
      tags:
        - Clipping
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/ClipPreviewRequest"
      responses:
        200:
          description: Paste clip preview
  /sources:
    get:
      summary: List public sources
      description: Aggregate public source inventory from published documentation. Returns degraded empty state if persistence is unavailable.
      tags:
        - Sources
      security: []
      responses:
        200:
          description: Public source inventory
  /sources/{id}:
    get:
      summary: Get public source
      description: "Get public-safe source attribution details and linked published documents for a source identifier."
      tags:
        - Sources
      security: []
      parameters:
        -
          name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        200:
          description: Public source details
        404:
          description: Source not found
  /network:
    get:
      summary: Get network status
      description: Get MCP network status and node configuration
      tags:
        - Network
      security: []
      parameters:
        -
          name: action
          in: query
          schema:
            type: string
            enum:
              - graph
              - discover
        -
          name: type
          in: query
          schema:
            type: string
          description: Service type filter
      responses:
        200:
          description: Network status
    post:
      summary: Network actions
      description: "Register with network, send heartbeat, or score documents"
      tags:
        - Network
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - action
              properties:
                action:
                  type: string
                  enum:
                    - register
                    - heartbeat
                    - "score-documents"
                    - "score-sources"
                    - "call-mcp"
                slugs:
                  type: array
                  items:
                    type: string
                identifiers:
                  type: array
                  items:
                    type: string
                endpoint:
                  type: string
                tool:
                  type: string
                params:
                  type: object
      responses:
        200:
          description: Action completed
  /scores:
    get:
      summary: Get document/source scores
      description: Get quality scores for documents or sources
      tags:
        - Scoring
      security: []
      parameters:
        -
          name: type
          in: query
          schema:
            type: string
            enum:
              - document
              - source
              - documents
              - sources
              - top
        -
          name: slug
          in: query
          schema:
            type: string
        -
          name: source
          in: query
          schema:
            type: string
        -
          name: limit
          in: query
          schema:
            type: integer
            maximum: 100
      responses:
        200:
          description: Score data
    post:
      summary: Batch score items
      description: Score multiple documents or sources
      tags:
        - Scoring
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - type
              properties:
                type:
                  type: string
                  enum:
                    - documents
                    - sources
                    - "external-documents"
                    - "external-sources"
                slugs:
                  type: array
                  items:
                    type: string
                identifiers:
                  type: array
                  items:
                    type: string
      responses:
        200:
          description: Scores calculated
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: PLATPHORM_API_KEY
      description: "Use Authorization: Bearer $PLATPHORM_API_KEY for protected Docs operations."
    platphormApiKey:
      type: apiKey
      in: header
      name: "X-PlatPhorm-API-Key"
      description: Alternative protected request header containing $PLATPHORM_API_KEY.
  schemas:
    DocumentCreate:
      type: object
      required:
        - title
        - content
      properties:
        slug:
          type: string
        title:
          type: string
        description:
          type: string
        content:
          type: string
        content_format:
          type: string
          enum:
            - markdown
            - html
            - text
        source_url:
          type: string
          format: uri
        source_identifier:
          type: string
        author_name:
          type: string
        author_email:
          type: string
          format: email
        category:
          type: string
        tags:
          type: array
          items:
            type: string
        status:
          type: string
          enum:
            - draft
            - published
    DocumentUpdate:
      type: object
      properties:
        title:
          type: string
        description:
          type: string
        content:
          type: string
        status:
          type: string
          enum:
            - draft
            - published
            - archived
    DocumentList:
      type: object
      properties:
        success:
          type: boolean
        data:
          type: array
          items:
            type: object
        meta:
          type: object
    SubmissionCreate:
      type: object
      required:
        - source_url
        - title
        - content
      properties:
        source_url:
          type: string
          format: uri
        source_identifier:
          type: string
        title:
          type: string
        content:
          type: string
        author_name:
          type: string
        author_email:
          type: string
          format: email
    SubmissionReview:
      type: object
      required:
        - action
      properties:
        action:
          type: string
          enum:
            - approve
            - reject
        slug:
          type: string
        category:
          type: string
        tags:
          type: array
          items:
            type: string
        publish_immediately:
          type: boolean
        reason:
          type: string
    CategoryCreate:
      type: object
      required:
        - slug
        - name
      properties:
        slug:
          type: string
        name:
          type: string
        description:
          type: string
        parent_id:
          type: string
          format: uuid
        icon:
          type: string
        order_index:
          type: integer
    WebhookCreate:
      type: object
      required:
        - url
      properties:
        url:
          type: string
          format: uri
        events:
          type: array
          items:
            type: string
        active:
          type: boolean
    ClipPreviewRequest:
      type: object
      properties:
        url:
          type: string
          format: uri
          description: "Public URL to clip. SSRF-guarded and size-limited."
        content:
          type: string
          description: Pasted plain text content.
        markdown:
          type: string
          description: Pasted Markdown content.
        html:
          type: string
          description: Pasted HTML content to clean.
        title:
          type: string
        sourceType:
          type: string
          enum:
            - webpage
            - platform_post
            - reddit
            - google_drive
            - google_docs
            - dropbox
            - image
            - paste
            - markdown
            - html
            - feed
            - json
            - text
        altText:
          type: string
          description: Manual alt text for image clips.
        caption:
          type: string
          description: Manual caption for image clips.
    ClipPreviewResponse:
      type: object
      properties:
        ok:
          type: boolean
        data:
          type: object
          properties:
            id:
              type: string
            sourceType:
              type: string
            status:
              type: string
              enum:
                - ready
                - degraded
                - unsupported
            title:
              type: string
            summary:
              type: string
            cleanedMarkdown:
              type: string
            attribution:
              type: object
            tags:
              type: array
              items:
                type: object
            trace:
              type: object
    ClipCommitRequest:
      type: object
      required:
        - title
        - cleanedMarkdown
      properties:
        mode:
          type: string
          enum:
            - submission
            - document
          default: submission
        title:
          type: string
        cleanedMarkdown:
          type: string
        summary:
          type: string
        canonicalUrl:
          type: string
          format: uri
        sourceType:
          type: string
        category:
          type: string
        tags:
          type: array
          items:
            type: string
        attribution:
          type: object
tags:
  -
    name: Documents
    description: Document management
  -
    name: Submissions
    description: Content submissions from external sources
  -
    name: Clipping
    description: "Public-safe clipping previews, formatting cleanup, source attribution, and clip commit"
  -
    name: Search
    description: "Full-text search"
  -
    name: Categories
    description: Category management
  -
    name: Sources
    description: Public source attribution inventory
  -
    name: Webhooks
    description: Webhook management
  -
    name: Authentication
    description: API key management
  -
    name: Content
    description: Content ingestion and processing
  -
    name: Network
    description: MCP network and service discovery
  -
    name: Scoring
    description: Document and source scoring
x-platphorm:
  service: docs
  purpose: "Canonical public documentation, clipping, ingestion, source attribution, auto-tagging, search, formatting, submission, metadata, and AI-readable knowledge layer for the PlatPhormNews web mesh."
  auth:
    environmentVariable: PLATPHORM_API_KEY
    acceptedHeaders:
      - "Authorization: Bearer $PLATPHORM_API_KEY"
      - "X-PlatPhorm-API-Key: $PLATPHORM_API_KEY"
  routeStandard:
    - /api/health
    - /api/v1/health
    - /api/docs
    - /openapi.yaml
    - /openapi.json
    - /llms.txt
    - "/llms-full.txt"
    - "/llms-index.json"
    - /robots.txt
    - /sitemap.xml
    - "/sitemap-main.xml"
    - "/sitemap-index.xml"
    - /rss.xml
    - /feed.xml
    - /manifest.webmanifest
    - /faq
    - "/.well-known/mcp.json"
    - "/.well-known/agents.json"
    - "/.well-known/ai-plugin.json"
    - "/.well-known/security.txt"
    - "/.well-known/trust.json"
    - /api/mcp
  mcp:
    endpoint: "https://docs.platphormnews.com/api/mcp"
    tools:
      - list_documents
      - get_document
      - create_document
      - update_document
      - delete_document
      - search
      - list_categories
      - get_related_docs
      - submit_content
      - ingest_url
      - clip_preview
      - clip_commit
      - clip_platform_post
      - clip_reddit
      - clip_google_drive
      - clip_dropbox
      - clip_image
      - clip_paste
      - clean_ingested_content
      - generate_source_attribution
      - suggest_tags
      - get_emoji
      - add_emoji_to_doc
      - bulk_import
      - regenerate_seo
      - generate_optimization
      - export_docs
      - get_stats
      - trigger_webhook
      - list_integrations
      - call_integration
      - parse_markdown
      - generate_share_links
      - search_docs
      - list_tags
      - list_project_docs
      - get_project_doc
      - trigger_automation
      - get_automation_status
    resources:
      - "project-docs://{slug}"
      - "docs://index"
      - "docs://categories"
      - "docs://recent"
      - "docs://popular"
      - "docs://tags"
      - "docs://sources"
      - "docs://submissions"
      - "docs://clips"
      - "docs://stats"
      - "docs://sitemap"
      - "docs://llms"
      - "docs://openapi"
      - "docs://trust-policy"
    prompts:
      - explain_doc
      - summarize_category
      - compare_docs
      - generate_faq
      - translate_doc
      - improve_seo
      - clean_ingested_content
      - clip_public_source
      - create_source_attribution
      - suggest_document_tags
