openapi: 3.1.0
info:
  title: Mahita Catalog API
  version: 1.0.0
  description: Public, published recipe knowledge and scoped integration surfaces.
servers:
  - url: https://mahita.ai
paths:
  /api/v1/catalog/recipes:
    get:
      summary: Search published recipes
      parameters:
        - {name: search, in: query, schema: {type: string}}
        - {name: cuisine, in: query, schema: {type: string}}
        - {name: tags, in: query, schema: {type: string}, description: Comma-separated tags}
        - {name: jain, in: query, schema: {type: boolean}}
        - {name: limit, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}
        - {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}
      responses:
        '200':
          description: Published catalog entries
          content:
            application/json:
              schema: {$ref: '#/components/schemas/RecipeList'}
  /api/v1/catalog/recipes/{slug}:
    get:
      summary: Fetch a published recipe by slug
      parameters:
        - {name: slug, in: path, required: true, schema: {type: string}}
      responses:
        '200': {description: Published recipe}
        '404': {description: Not found}
  /api/v1/catalog/foods:
    get:
      summary: Search the provenance-labelled sample food catalog
      description: Public synthetic sample data only. Production must replace sample estimates with a licensed, versioned nutrition source before regulated data is enabled.
      parameters:
        - {name: search, in: query, schema: {type: string}}
        - {name: limit, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}
        - {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}
      responses:
        '200': {description: Sample foods with nutrient provenance and review boundary}
  /api/v1/embed/recipes:
    get:
      summary: CORS-safe published recipe feed for external applications
      responses:
        '200': {description: Embeddable recipe cards}
  /api/v1/corporate/analytics/aggregate:
    get:
      summary: Synthetic aggregate contract; production requires a scoped enterprise key or admin session
      security: [{MahitaApiKey: []}]
      responses:
        '200': {description: Aggregate-only report with no PHI}
        '403': {description: Missing organization authorization}
  /api/v1/metabase/exercises:
    get:
      summary: Search the tagged movement library
      parameters:
        - {name: muscle, in: query, schema: {type: string}}
        - {name: forceVector, in: query, schema: {type: string}}
        - {name: equipment, in: query, schema: {type: string}, description: Comma-separated equipment tags}
        - {name: contraindication, in: query, schema: {type: string}}
        - {name: limit, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 20}}
        - {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}
      responses:
        '200': {description: Tagged educational exercise entries}
  /api/v1/me/dashboard:
    get:
      summary: Read the signed-in member dashboard summary
      security: [{CookieSession: []}]
      responses:
        '200': {description: Account-linked nutrition, movement, program, and recent activity summary}
        '401': {description: Authentication required}
  /api/v1/me/insights:
    get:
      summary: Read transparent rule-based personal next actions
      description: Uses only confirmed Mahita meal and workout entries; not medical advice or a clinical readiness score.
      security: [{CookieSession: []}]
      responses:
        '200': {description: Evidence-backed early-signal brief}
        '401': {description: Authentication required}
  /api/v1/me/recommendations:
    get:
      summary: Read preference-ranked recipe recommendations
      description: Applies hard exclusion, allergen, and Jain filters before ranking by goals, pantry matches, and preparation time.
      security: [{CookieSession: []}]
      responses:
        '200': {description: Preference-ranked published recipes}
        '401': {description: Authentication required}
  /api/v1/me/context:
    get:
      summary: Read the explainable member context graph brief
      description: Connects confirmed preferences, pantry, meal plans, and member-entered activity to next actions. It does not produce a diagnosis, clinical readiness score, or employer report.
      security: [{CookieSession: []}]
      responses:
        '200': {description: Context connections and explainable next actions}
        '401': {description: Authentication required}
  /api/v1/me/privacy:
    get:
      summary: Read the member privacy and active-session summary
      description: Returns account data categories, sharing boundaries, retention text, and non-secret session metadata.
      security: [{CookieSession: []}]
      responses:
        '200': {description: Privacy center summary without tokens or password material}
        '401': {description: Authentication required}
  /api/v1/me/export:
    get:
      summary: Export the signed-in member's Mahita data
      description: Returns the member's own account, preference, planning, activity, and feedback records. Secrets and internal audit metadata are excluded.
      security: [{CookieSession: []}]
      responses:
        '200': {description: JSON data export}
        '401': {description: Authentication required}
  /api/v1/me/deletion-request:
    post:
      summary: Request account deletion review
      description: Requires the exact confirmation string DELETE_MY_ACCOUNT. The local adapter records a reviewable request and does not delete data.
      parameters:
        - {name: Idempotency-Key, in: header, required: false, schema: {type: string, minLength: 8, maxLength: 128}}
      security: [{CookieSession: []}]
      responses:
        '202': {description: Deletion review request recorded}
        '403': {description: CSRF validation failed}
  /api/v1/me/sessions/revoke-others:
    post:
      summary: Revoke all other active sessions for the signed-in member
      description: Keeps the current session active and invalidates every other stored session token.
      security: [{CookieSession: []}]
      responses:
        '200': {description: Other sessions revoked}
        '403': {description: CSRF validation failed}
  /api/v1/me/nutrition/log:
    post:
      summary: Confirm a nutrition log from the reviewed sample matcher
      parameters:
        - {name: Idempotency-Key, in: header, required: false, schema: {type: string, minLength: 8, maxLength: 128}, description: Reuse the same key when retrying a request so it is applied once.}
      security: [{CookieSession: []}]
      responses:
        '201': {description: Persisted nutrition log and estimate totals}
        '403': {description: CSRF validation failed}
  /api/v1/me/meal-plan/suggestions:
    get:
      summary: Find preference-aware replacements for one meal slot
      description: Applies the member's explicit hard filters and published recipe catalog only. It does not infer medical suitability.
      parameters:
        - {name: date, in: query, schema: {type: string, format: date}}
        - {name: mealSlot, in: query, required: true, schema: {type: string, enum: [BREAKFAST, LUNCH, DINNER, SNACK]}}
      security: [{CookieSession: []}]
      responses:
        '200': {description: Current slot and replacement suggestions}
        '401': {description: Authentication required}
  /api/v1/me/workouts/complete:
    post:
      summary: Persist a completed workout and its sets
      parameters:
        - {name: Idempotency-Key, in: header, required: false, schema: {type: string, minLength: 8, maxLength: 128}, description: Reuse the same key when retrying a request so it is applied once.}
      security: [{CookieSession: []}]
      responses:
        '201': {description: Persisted workout log}
        '403': {description: CSRF validation failed}
  /api/v1/me/programs:
    get:
      summary: List the member's workout programs
      security: [{CookieSession: []}]
      responses:
        '200': {description: Versionable program foundation}
    post:
      summary: Create a member workout program
      parameters:
        - {name: Idempotency-Key, in: header, required: false, schema: {type: string, minLength: 8, maxLength: 128}, description: Reuse the same key when retrying a request so it is applied once.}
      security: [{CookieSession: []}]
      responses:
        '201': {description: Created program}
  /api/v1/me/calendar:
    get:
      summary: Read member calendar events for a date range
      security: [{CookieSession: []}]
      responses:
        '200': {description: Planned personal, meal, and workout events}
    post:
      summary: Add a member calendar event
      parameters:
        - {name: Idempotency-Key, in: header, required: false, schema: {type: string, minLength: 8, maxLength: 128}, description: Reuse the same key when retrying a request so it is applied once.}
      security: [{CookieSession: []}]
      responses:
        '201': {description: Created event}
  /api/v1/me/feedback:
    get:
      summary: Read the signed-in member's own feedback
      security: [{CookieSession: []}]
      responses:
        '200': {description: Recent feedback submitted by this account}
    post:
      summary: Submit private product feedback
      description: Accepts a bounded feature, rating, reason, and optional 500-character note. Do not submit health or identifying information.
      parameters:
        - {name: Idempotency-Key, in: header, required: false, schema: {type: string, minLength: 8, maxLength: 128}, description: Reuse the same key when retrying a request so it is applied once.}
      security: [{CookieSession: []}]
      responses:
        '201': {description: Feedback recorded}
        '403': {description: CSRF validation failed}
  /api/v1/admin/api-clients:
    get:
      summary: List scoped API clients without raw secrets
      security: [{CookieSession: []}]
      responses:
        '200': {description: API client lifecycle metadata}
        '403': {description: Platform administrator role required}
    post:
      summary: Create a scoped API client
      security: [{CookieSession: []}]
      responses:
        '201': {description: Created client and one-time raw key}
        '403': {description: CSRF or administrator authorization failed}
  /api/v1/admin/api-clients/{id}:
    patch:
      summary: Activate or deactivate a scoped API client
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      security: [{CookieSession: []}]
      responses:
        '200': {description: Updated client metadata without raw secrets}
        '403': {description: CSRF or administrator authorization failed}
  /api/v1/admin/api-clients/{id}/rotate:
    post:
      summary: Rotate an integration key and reset its expiry
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      security: [{CookieSession: []}]
      responses:
        '200': {description: New one-time raw key and lifecycle metadata}
        '403': {description: CSRF or administrator authorization failed}
  /api/v1/admin/audit:
    get:
      summary: Read recent platform audit metadata
      security: [{CookieSession: []}]
      responses:
        '200': {description: Recent audit events without credential material}
        '403': {description: Platform administrator role required}
  /api/v1/auth/managed/status:
    get:
      summary: Read managed identity readiness without secret values
      responses:
        '200': {description: OIDC, PKCE, MFA, and recovery contract status}
  /api/v1/care/messages/threads:
    get:
      summary: List consent-scoped asynchronous care message threads
      description: Synthetic local-adapter contract. Only active relationships with the messages scope are visible.
      security: [{CookieSession: []}]
      responses: {'200': {description: Relationship-scoped message threads}}
    post:
      summary: Start a message thread within an active care relationship
      parameters:
        - {name: Idempotency-Key, in: header, required: true, schema: {type: string, minLength: 8, maxLength: 128}}
      security: [{CookieSession: []}]
      responses: {'201': {description: Created message thread}, '403': {description: Consent or CSRF policy failure}}
  /api/v1/care/messages/threads/{id}:
    get:
      summary: Read one relationship-scoped message thread
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      security: [{CookieSession: []}]
      responses: {'200': {description: Thread and bounded messages}, '404': {description: Thread not found}}
  /api/v1/care/messages/threads/{id}/messages:
    post:
      summary: Send an asynchronous message to the other relationship participant
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
        - {name: Idempotency-Key, in: header, required: true, schema: {type: string, minLength: 8, maxLength: 128}}
      security: [{CookieSession: []}]
      responses: {'201': {description: Message thread with the new message}, '403': {description: Consent or CSRF policy failure}}
  /api/v1/care/messages/{id}/read:
    post:
      summary: Mark a received care message as read
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
        - {name: Idempotency-Key, in: header, required: true, schema: {type: string, minLength: 8, maxLength: 128}}
      security: [{CookieSession: []}]
      responses: {'200': {description: Read marker recorded}}
  /api/v1/care/invitations:
    get:
      summary: List invitations visible to the signed-in member or practitioner
      security: [{CookieSession: []}]
      responses: {'200': {description: Relationship invitations}}
    post:
      summary: Create a relationship invitation
      description: Requires an existing target account in the local adapter; production adds the managed notification gateway.
      parameters:
        - {name: Idempotency-Key, in: header, required: true, schema: {type: string, minLength: 8, maxLength: 128}}
      security: [{CookieSession: []}]
      responses: {'201': {description: Pending invitation}, '403': {description: CSRF or policy failure}}
  /api/v1/care/invitations/{id}/accept:
    post:
      summary: Accept an invitation with explicit, narrowing-only consent
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
        - {name: Idempotency-Key, in: header, required: true, schema: {type: string, minLength: 8, maxLength: 128}}
      security: [{CookieSession: []}]
      responses: {'200': {description: Active relationship and consent grant}}
  /api/v1/care/roster:
    get:
      summary: Read a coach or clinician's active consented roster
      security: [{CookieSession: []}]
      responses: {'200': {description: Relationship-scoped roster}}
  /api/v1/care/programs:
    post:
      summary: Create a draft versioned care program
      parameters:
        - {name: Idempotency-Key, in: header, required: true, schema: {type: string, minLength: 8, maxLength: 128}}
      security: [{CookieSession: []}]
      responses: {'201': {description: Draft care program}}
  /api/v1/care/programs/{id}/versions:
    post:
      summary: Create the next immutable program version
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
        - {name: Idempotency-Key, in: header, required: true, schema: {type: string, minLength: 8, maxLength: 128}}
      security: [{CookieSession: []}]
      responses: {'201': {description: New draft version}}
  /api/v1/care/tasks/{id}/complete:
    post:
      summary: Complete, skip, snooze, or flag a member task
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
        - {name: Idempotency-Key, in: header, required: true, schema: {type: string, minLength: 8, maxLength: 128}}
      security: [{CookieSession: []}]
      responses: {'200': {description: Updated member task}}
  /api/v1/care/followups:
    get:
      summary: List relationship-scoped follow-ups
      security: [{CookieSession: []}]
      responses: {'200': {description: Follow-up queue}}
    post:
      summary: Schedule a practitioner follow-up
      security: [{CookieSession: []}]
      responses: {'201': {description: Follow-up record}}
  /api/v1/care/clinician/reviews:
    get:
      summary: Read the assigned clinician review queue
      security: [{CookieSession: []}]
      responses: {'200': {description: Clinical review queue}}
  /api/v1/care/medication/questions:
    get:
      summary: Read relationship-scoped medication questions
      security: [{CookieSession: []}]
      responses: {'200': {description: Questions and non-prescribing responses}}
    post:
      summary: Ask a clinician a medication question without requesting a prescription
      description: Emergency questions are routed to urgent local care. The endpoint rejects medication-change instructions in clinician responses.
      security: [{CookieSession: []}]
      responses: {'201': {description: Routed medication question}}
components:
  securitySchemes:
    MahitaApiKey:
      type: apiKey
      in: header
      name: X-Mahita-Api-Key
    CookieSession:
      type: apiKey
      in: cookie
      name: __Host-mahita_session
  schemas:
    RecipeList:
      type: object
      required: [success, meta, data]
      properties:
        success: {type: boolean}
        meta:
          type: object
          properties: {totalCount: {type: integer}}
        data:
          type: array
          items: {$ref: '#/components/schemas/Recipe'}
    Recipe:
      type: object
      required: [id, slug, title, servings, ingredients, instructions]
      properties:
        id: {type: string}
        slug: {type: string}
        title: {type: string}
        description: {type: string}
        cuisine: {type: string}
        region: {type: string}
        tags: {type: array, items: {type: string}}
        servings: {type: integer}
        ingredients: {type: array, items: {type: object}}
        instructions: {type: array, items: {type: string}}
        macrosPerServing: {type: object}
