openapi: 3.1.0
info:
  title: Klutt3rbox Agent API
  version: 1.1.0
  description: Scoped API for trusted agents to manage a user's inventory.
servers:
  - url: https://klutt3rbox.ck42x.com
security:
  - bearerAuth: []
paths:
  /api/v1/inventory:
    get:
      operationId: listInventory
      summary: List or search items and containers
      x-required-scope: inventory:read
      parameters:
        - {
            name: id,
            in: query,
            description: Deterministic item read-back by UUID,
            schema: { type: string, format: uuid },
          }
        - {
            name: search,
            in: query,
            description: Case-insensitive search across item identity and detail fields; tags and AI keywords use exact element matching,
            schema: { type: string },
          }
        - { name: container, in: query, schema: { type: string } }
        - {
            name: format,
            in: query,
            schema: { type: string, enum: [full, compact] },
          }
        - {
            name: limit,
            in: query,
            schema:
              { oneOf: [{ type: integer }, { type: string, const: all }] },
          }
        - { name: offset, in: query, schema: { type: integer, minimum: 0 } }
      responses:
        '200': { description: User-scoped inventory }
    post:
      operationId: upsertInventoryItem
      summary: Create or idempotently update an item
      x-required-scope: items:write
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ItemInput' }
      responses:
        '200': { description: Existing item updated }
        '201': { description: Item created }
    patch:
      operationId: updateInventoryItems
      summary: Batch update items by ID
      x-required-scope: items:write
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [ids, updates]
              properties:
                ids:
                  type: array
                  minItems: 1
                  items: { type: string, format: uuid }
                updates: { $ref: '#/components/schemas/ItemUpdates' }
      responses:
        '200': { description: Items updated }
    delete:
      operationId: deleteInventoryItems
      summary: Delete items by IDs, search, category, or confirmed all
      x-required-scope: items:delete
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                ids:
                  type: array
                  items: { type: string, format: uuid }
                search: { type: string }
                category: { type: string }
                all: { type: boolean }
                confirmation:
                  {
                    type: string,
                    description: Required as DELETE ALL ITEMS when all is true,
                  }
      responses:
        '200': { description: Items deleted }
  /api/v1/containers:
    get:
      operationId: listContainers
      summary: List or search containers
      x-required-scope: inventory:read
      parameters:
        - { name: search, in: query, schema: { type: string } }
      responses:
        '200': { description: User-scoped containers }
    post:
      operationId: upsertContainer
      summary: Create or idempotently update a container
      x-required-scope: containers:write
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ContainerInput' }
      responses:
        '200': { description: Existing container updated }
        '201': { description: Container created }
    patch:
      operationId: updateContainer
      summary: Update a container
      x-required-scope: containers:write
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ContainerInput' }
      responses:
        '200': { description: Container updated }
    delete:
      operationId: deleteContainer
      summary: Delete a confirmed container and its items
      x-required-scope: containers:delete
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [containerKey, confirmation]
              properties:
                containerKey: { type: string }
                confirmation:
                  {
                    type: string,
                    description: Must equal DELETE followed by the container key,
                  }
      responses:
        '200': { description: Container and child items deleted }
  /api/v1/media:
    post:
      operationId: uploadItemMedia
      summary: Upload and attach or replace item media (4 MB maximum file)
      x-required-scope: media:write
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [itemId, kind, file]
              properties:
                itemId: { type: string, format: uuid }
                kind: { type: string, enum: [image, voice, receipt] }
                file: { type: string, format: binary }
      responses:
        '200': { description: Existing media replaced }
        '201': { description: Media attached }
    delete:
      operationId: deleteItemMedia
      summary: Delete one item media attachment
      x-required-scope: media:write
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [itemId, kind]
              properties:
                itemId: { type: string, format: uuid }
                kind: { type: string, enum: [image, voice, receipt] }
      responses:
        '200': { description: Media deleted }
  /api/items/analyze-image:
    post:
      operationId: analyzeInventoryImage
      summary: Analyze an image; save mode also requires item, container, and media write scopes
      x-required-scope: vision:analyze
      x-save-mode-scopes: [items:write, containers:write, media:write]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [imageData]
              properties:
                imageData: { type: string, description: Image data URI }
                containerKey: { type: string }
                quantityOverride: { type: integer, minimum: 1 }
                mode: { type: string, enum: [review, save], default: save }
      responses:
        '200': { description: Vision analysis result }
  /api/v1/agent-context:
    get:
      operationId: getAgentContext
      summary: Return a privacy-reduced inventory context packet
      x-required-scope: inventory:read
      parameters:
        - { name: project, in: query, schema: { type: string } }
        - {
            name: limit,
            in: query,
            schema: { type: integer, minimum: 1, maximum: 500 },
          }
      responses:
        '200': { description: Agent-safe context packet }
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: Klutt3rbox API key
  schemas:
    ContainerInput:
      type: object
      required: [containerKey]
      additionalProperties: false
      properties:
        containerKey: { type: string, maxLength: 64 }
        label: { type: string, maxLength: 200 }
        description: { type: [string, 'null'], maxLength: 1000 }
        location: { type: [string, 'null'], maxLength: 1000 }
        tags:
          type: array
          maxItems: 100
          items: { type: string }
    ItemFields:
      type: object
      properties:
        name: { type: string }
        description: { type: string }
        containerKey: { type: string }
        quantity: { type: integer, minimum: 1 }
        tags: { type: array, items: { type: string } }
        itemType: { type: string }
        category: { type: string }
        color: { type: string }
        material: { type: string }
        size: { type: string }
        brand: { type: string }
        model: { type: string }
        serialNumber: { type: string }
        metadata: { type: object, additionalProperties: true }
    ItemUpdates:
      allOf:
        - $ref: '#/components/schemas/ItemFields'
      unevaluatedProperties: false
    ItemInput:
      allOf:
        - $ref: '#/components/schemas/ItemFields'
        - type: object
          required: [containerKey, name]
          properties:
            containerKey: { type: string }
            name: { type: string }
            media:
              type: array
              maxItems: 10
              items:
                type: object
                required: [uri]
                properties:
                  uri: { type: string }
                  thumbnailUri: { type: [string, 'null'] }
                  kind:
                    {
                      type: string,
                      enum: [image, voice, receipt],
                      default: image,
                    }
      unevaluatedProperties: false
