openapi: 3.0.3
info:
  title: PathHub Public API
  version: "1.0.0"
  description: |
    PathHub gives external tools (Zapier, Make, n8n, Power Automate, custom code)
    structured access to your ActionPaths, tasks, documents, compliance data,
    and AI capabilities.

    **Authentication.** All calls require a key in the `Authorization: Bearer phk_live_…`
    header. Keys are workspace-bound — a key can only see and act on the
    workspace it was created in.

    **Scopes.** Each key has one or more scopes:
      * `read`  — list / fetch / export
      * `write` — mutate (e.g. PATCH tasks, create webhooks)
      * `ai`    — trigger AI features (chat, tools, agents, plan generation)

    Scopes are hierarchical — `ai` implies `write` which implies `read`.

    **Rate limits.**
      * 120 requests / minute / key (sliding window)
      * monthly request quota by tier (Pro 2 000, Max 20 000)
      * AI calls additionally count against the shared workspace AI quota

    **Errors.**
    All errors return `{"error": {"code": "<machine_code>", "message": "<human_text>"}}`.

servers:
  - url: https://app.pathhub.ai/api/v1
    description: Production

security:
  - bearerAuth: []

tags:
  - name: Projects
  - name: Tasks
  - name: Documents
  - name: Compliance & Templates
  - name: Webhooks
  - name: AI
  - name: Meta

paths:
  /projects:
    get:
      tags: [Projects]
      summary: List projects in the workspace
      security: [{bearerAuth: [read]}]
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items: {$ref: '#/components/schemas/ProjectSummary'}
                  count: {type: integer}

  /projects/{id}:
    get:
      tags: [Projects]
      summary: Get a single project (full detail)
      security: [{bearerAuth: [read]}]
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data: {$ref: '#/components/schemas/Project'}
        "404": {$ref: '#/components/responses/NotFound'}

  /projects/{id}/{resource}:
    get:
      tags: [Projects]
      summary: Get a single sub-resource of a project
      security: [{bearerAuth: [read]}]
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
        - name: resource
          in: path
          required: true
          schema:
            type: string
            enum: [phases, tasks, budget, risks, stakeholders, compliance, milestones, next-steps]
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items: {type: object, additionalProperties: true}
        "404": {$ref: '#/components/responses/NotFound'}

  /projects/{id}/export:
    get:
      tags: [Projects]
      summary: Export a project (markdown or json)
      description: |
        Markdown is recommended for handing the plan to LLMs (ChatGPT, Claude)
        or pasting into Notion/Confluence. JSON is the raw project structure.
      security: [{bearerAuth: [read]}]
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
        - name: format
          in: query
          required: false
          schema: {type: string, enum: [markdown, json], default: markdown}
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema: {type: object, properties: {data: {$ref: '#/components/schemas/Project'}}}
            text/markdown:
              schema: {type: string}
        "400": {description: "Unsupported format (e.g. pdf, excel — not yet available)"}
        "404": {$ref: '#/components/responses/NotFound'}

  /tasks/{id}:
    patch:
      tags: [Tasks]
      summary: Update a task (partial)
      description: |
        Updating the `checked` field emits a `task.status_changed` webhook event
        to all webhooks subscribed to that event in this workspace.
      security: [{bearerAuth: [write]}]
      parameters:
        - {name: id, in: path, required: true, schema: {type: string, description: "Task UUID"}}
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                text:          {type: string}
                checked:       {type: boolean}
                critical:      {type: boolean}
                responsible:   {type: string}
                description:   {type: string}
                time_estimate: {type: string}
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema: {type: object, properties: {data: {$ref: '#/components/schemas/Task'}}}
        "404": {$ref: '#/components/responses/NotFound'}

  /documents:
    get:
      tags: [Documents]
      summary: List uploaded / indexed documents
      security: [{bearerAuth: [read]}]
      parameters:
        - {name: project_id, in: query, required: false, schema: {type: string}}
      responses:
        "200":
          description: OK

  /documents/search:
    post:
      tags: [Documents]
      summary: Semantic RAG search across indexed documents
      security: [{bearerAuth: [read]}]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [query]
              properties:
                query:      {type: string, minLength: 2, maxLength: 2000}
                project_id: {type: string}
                top_k:      {type: integer, minimum: 1, maximum: 20, default: 8}
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      query: {type: string}
                      results:
                        type: array
                        items:
                          type: object
                          properties:
                            document_id: {type: string}
                            project_id:  {type: string}
                            chunk_index: {type: integer}
                            text:        {type: string}
                            filename:    {type: string}
                            score:       {type: number}

  /compliance-rules:
    get:
      tags: [Compliance & Templates]
      summary: Compliance library (DE/AT/CH + EU)
      description: |
        Without `country`, returns the meta-lists (countries, industries, size ranges).
        With `country`, returns matching rules.
      security: [{bearerAuth: [read]}]
      parameters:
        - {name: country,     in: query, required: false, schema: {type: string, enum: [DE, AT, CH]}}
        - {name: industry,    in: query, required: false, schema: {type: string}}
        - {name: size_range,  in: query, required: false, schema: {type: string, example: "10-49"}}
        - {name: locale,      in: query, required: false, schema: {type: string, enum: [de, en]}}
        - {name: q,           in: query, required: false, schema: {type: string, description: "free-text filter"}}
      responses:
        "200": {description: OK}

  /project-templates:
    get:
      tags: [Compliance & Templates]
      summary: Pre-built project templates
      security: [{bearerAuth: [read]}]
      parameters:
        - {name: locale,   in: query, required: false, schema: {type: string, enum: [de, en]}}
        - {name: category, in: query, required: false, schema: {type: string, example: IT}}
      responses:
        "200": {description: OK}

  /webhooks:
    get:
      tags: [Webhooks]
      summary: List webhooks
      security: [{bearerAuth: [read]}]
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items: {$ref: '#/components/schemas/Webhook'}
                  available_events:
                    type: array
                    items: {type: string}
    post:
      tags: [Webhooks]
      summary: Create a webhook
      description: |
        Returns `{id, secret, url, events}` exactly **once**. The `secret` is
        required to verify the HMAC-SHA256 signature PathHub sends on every
        delivery (`X-PathHub-Signature: t=<unix_ts>,v1=<hex_mac>`).
      security: [{bearerAuth: [write]}]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url:    {type: string, format: uri, description: "HTTPS endpoint"}
                events:
                  type: array
                  items: {type: string}
                  description: "Subset of available_events; empty array = all"
      responses:
        "201":
          description: Created (secret returned once)
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:     {type: string}
                  secret: {type: string, description: "Shown ONCE — store it now"}
                  url:    {type: string}
                  events: {type: array, items: {type: string}}

  /webhooks/{id}:
    delete:
      tags: [Webhooks]
      summary: Delete a webhook
      security: [{bearerAuth: [write]}]
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        "200": {description: OK}
        "404": {$ref: '#/components/responses/NotFound'}

  /ai/agents:
    get:
      tags: [AI]
      summary: List available AI agents (e.g. status_report, week_plan, risk_scan)
      security: [{bearerAuth: [read]}]
      responses:
        "200": {description: OK}

  /ai/projects/{id}/recommendations:
    post:
      tags: [AI]
      summary: Generate AI-recommended next actions for a project
      security: [{bearerAuth: [ai]}]
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        "200": {description: OK}
        "429": {description: "AI quota exceeded"}

  /ai/projects/{id}/tools/{tool}:
    post:
      tags: [AI]
      summary: Run a planning tool (RACI, risk matrix, WBS, SWOT, etc.)
      security: [{bearerAuth: [ai]}]
      parameters:
        - {name: id,   in: path, required: true, schema: {type: string}}
        - name: tool
          in: path
          required: true
          schema:
            type: string
            enum: [raci, risk-matrix, stakeholder-map, wbs, comm-plan, cost-compare, milestone-roadmap, eisenhower, swot, gantt-detail, resource-plan, resource-plan-weekly]
      responses:
        "200": {description: OK}
        "429": {description: "AI quota exceeded"}

  /ai/projects/{id}/agents/{task}:
    post:
      tags: [AI]
      summary: Run an autonomous AI agent against a project
      security: [{bearerAuth: [ai]}]
      parameters:
        - {name: id,   in: path, required: true, schema: {type: string}}
        - name: task
          in: path
          required: true
          schema:
            type: string
            enum: [status_report, week_plan, stakeholder_update, risk_scan, project_report, kickoff, lastenheft]
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                params:
                  type: object
                  additionalProperties: {type: string}
                  description: Free-form key-value pairs forwarded to the agent.
      responses:
        "200": {description: OK}
        "429": {description: "AI quota exceeded"}

  /ai/projects/{id}/chat:
    post:
      tags: [AI]
      summary: Chat with the project assistant (with optional RAG)
      security: [{bearerAuth: [ai]}]
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                message:
                  type: string
                  description: "Single user message (shortcut for messages=[{role:'user', content:…}])"
                messages:
                  type: array
                  items:
                    type: object
                    required: [role, content]
                    properties:
                      role:    {type: string, enum: [user, assistant]}
                      content: {type: string}
                locale:  {type: string, enum: [de, en]}
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      message:
                        type: object
                        properties:
                          role:    {type: string}
                          content: {type: string}
                      tokens_used: {type: integer}
                      sources:
                        type: array
                        items: {type: object, additionalProperties: true}

  /ai/generate-plan:
    post:
      tags: [AI]
      summary: Generate a full ActionPath (project plan) from a description
      description: |
        This is the headline endpoint. Provide a short description and PathHub
        will produce a full structured plan (phases, tasks, budget, risks,
        stakeholders, milestones, compliance) and save it as an ActionPath in
        the calling key's workspace.

        Counts against the AI quota AND the project-count quota. Subject to the
        monthly cap on new AI plans (cost guard).
      security: [{bearerAuth: [ai]}]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [description]
              properties:
                description:        {type: string, minLength: 20, maxLength: 5000}
                title:              {type: string}
                project_type:       {type: string}
                budget_eur:         {type: number}
                desired_timeline_weeks: {type: integer}
                start_date:         {type: string, format: date}
                deadline:           {type: string, format: date}
                team_size:          {type: integer}
                priority:           {type: string}
                scope:              {type: string}
                change_management:  {type: string}
                maturity_level:     {type: string}
                risk_profile:       {type: string}
                compliance_country: {type: string, enum: [DE, AT, CH]}
                compliance_industry:    {type: string}
                compliance_company_size: {type: string, example: "10-49"}
                complexity:               {type: string}
                phase_count:              {type: integer}
                project_management_style: {type: string}
                custom_prompt:            {type: string}
                locale:                   {type: string, enum: [de, en]}
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  project: {$ref: '#/components/schemas/Project'}
        "400": {description: "Invalid input (description too short / too long)"}
        "429": {description: "AI quota, project quota, or monthly plan cap exceeded"}

  /usage:
    get:
      tags: [Meta]
      summary: Current workspace API + AI usage / quotas
      security: [{bearerAuth: [read]}]
      responses:
        "200": {description: OK}

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: phk_live_*

  responses:
    NotFound:
      description: Not found (or not visible to this key's workspace)
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: object
                properties:
                  code:    {type: string, example: not_found}
                  message: {type: string}

  schemas:
    ProjectSummary:
      type: object
      properties:
        project_id:   {type: string}
        project_name: {type: string}
        category:     {type: string}
        created_at:   {type: string, format: date-time}
        updated_at:   {type: string, format: date-time}

    Project:
      type: object
      description: Full ActionPath (project plan).
      additionalProperties: true
      properties:
        project_id:   {type: string}
        project_name: {type: string}
        project_description: {type: string}
        category:     {type: string}
        total_duration_weeks: {type: integer}
        phase_count: {type: integer}
        target_due_date: {type: string, format: date}
        phases:    {type: array, items: {type: object, additionalProperties: true}}
        budget_items: {type: array, items: {type: object, additionalProperties: true}}
        milestones:   {type: array, items: {type: object, additionalProperties: true}}
        risks:        {type: array, items: {type: object, additionalProperties: true}}
        stakeholders: {type: array, items: {type: object, additionalProperties: true}}
        next_steps:   {type: array, items: {type: object, additionalProperties: true}}
        compliance_items: {type: array, items: {type: object, additionalProperties: true}}

    Task:
      type: object
      properties:
        id:            {type: string}
        text:          {type: string}
        checked:       {type: boolean}
        critical:      {type: boolean}
        responsible:   {type: string}
        description:   {type: string}
        time_estimate: {type: string}

    Webhook:
      type: object
      properties:
        id:          {type: string}
        url:         {type: string, format: uri}
        events:      {type: array, items: {type: string}}
        active:      {type: integer, description: "0 or 1"}
        created_at:  {type: string, format: date-time}
        last_delivery_at: {type: string, format: date-time, nullable: true}
