openapi: 3.1.0
info:
  title: Survey Forms Public API
  version: 1.0.0
  description: Public REST API for published surveys, responses, and analytics.
servers:
  - url: http://localhost:3000/api/v1
security:
  - bearerAuth: []
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API Key
  schemas:
    Problem:
      type: object
      required: [title, status]
      properties:
        type:
          type: string
        title:
          type: string
        status:
          type: integer
        detail:
          type: string
        errors:
          type: object
    Survey:
      type: object
      properties:
        id:
          type: string
        slug:
          type: string
        title:
          type: string
        description:
          type: string
          nullable: true
        status:
          type: string
        redirectUrl:
          type: string
          nullable: true
        theme:
          type: object
        questions:
          type: array
          items:
            type: object
    ResponseCreate:
      type: object
      required: [answers]
      properties:
        answers:
          type: object
          additionalProperties: true
        respondent:
          type: object
          additionalProperties:
            type: string
        externalUserId:
          type: string
          nullable: true
        startedAt:
          type: string
          format: date-time
paths:
  /surveys:
    get:
      summary: List published surveys
      responses:
        "200":
          description: Published surveys
  /surveys/{slug}:
    get:
      summary: Fetch a published survey schema
      parameters:
        - in: path
          name: slug
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Survey schema
        "404":
          description: Survey not found
  /surveys/{slug}/responses:
    get:
      summary: List survey responses with cursor pagination
      parameters:
        - in: path
          name: slug
          required: true
          schema:
            type: string
        - in: query
          name: from
          schema:
            type: string
            format: date-time
        - in: query
          name: to
          schema:
            type: string
            format: date-time
        - in: query
          name: limit
          schema:
            type: integer
        - in: query
          name: cursor
          schema:
            type: string
        - in: query
          name: respondent.{key}
          description: >-
            Only responses whose stored respondent field `key` equals the value,
            for example `respondent.company-name=IKEA Vestby` to read one canteen.
            Repeat with different keys to combine filters.
          schema:
            type: string
      responses:
        "200":
          description: Paginated responses
    post:
      summary: Submit a survey response
      parameters:
        - in: path
          name: slug
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ResponseCreate"
      responses:
        "201":
          description: Response created
  /surveys/{slug}/analytics:
    get:
      summary: Fetch survey analytics
      parameters:
        - in: path
          name: slug
          required: true
          schema:
            type: string
        - in: query
          name: from
          schema:
            type: string
            format: date-time
        - in: query
          name: to
          schema:
            type: string
            format: date-time
        - in: query
          name: source
          schema:
            type: string
            enum: [web, iframe, api]
        - in: query
          name: granularity
          schema:
            type: string
            enum: [day, week, month]
      responses:
        "200":
          description: Analytics payload