openapi: "3.1.0"
info:
  title: WhenWorks Scheduling API
  description: |
    Create group scheduling polls with WhenWorks. Anyone can vote without a WhenWorks account.

    Perfect for AI agents and automation tools that need to schedule meetings with multiple people.

    ## Key Features
    - **No account required for voters** - Share a poll link, anyone can vote
    - **Multiple time options** - Propose several dates/times and find the best one
    - **Real-time results** - See who's available as votes come in
    - **Best times ranking** - Automatically calculate optimal meeting times

    ## Authentication
    All endpoints require a Bearer token (API key) in the Authorization header.
    Get your API key from https://www.whenworks.cc/settings/api
  version: "1.0.0"
  contact:
    name: WhenWorks Support
    url: https://www.whenworks.cc/developers
    email: support@whenworks.cc

servers:
  - url: https://www.whenworks.cc/api/v1
    description: Production server

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API Key
      description: |
        API key authentication. Get your key from https://www.whenworks.cc/settings/api

        Format: `Authorization: Bearer ww_live_...`

  schemas:
    Poll:
      type: object
      properties:
        poll_id:
          type: string
          description: Unique poll identifier
          example: "123e4567-e89b-12d3-a456-426614174000"
        share_id:
          type: string
          description: Short shareable ID used in URLs
          example: "abc123XY"
        poll_url:
          type: string
          description: Shareable voting URL (anyone can vote without account)
          example: "https://www.whenworks.cc/polls/abc123XY"
        title:
          type: string
          description: Poll title
          example: "Team Lunch Next Week"
        created_at:
          type: string
          format: date-time
          description: When the poll was created
        options_count:
          type: integer
          description: Number of time options in the poll
          example: 3

    PollOption:
      type: object
      properties:
        option_id:
          type: string
          description: Unique option identifier
        date:
          type: string
          format: date
          description: Date for this option
          example: "2026-03-30"
        start_time:
          type: string
          description: Start time (HH:MM format)
          example: "12:00"
        end_time:
          type: string
          description: End time (HH:MM format)
          example: "14:00"
        label:
          type: string
          nullable: true
          description: Optional custom label

    BestTime:
      type: object
      properties:
        rank:
          type: integer
          description: Rank (1 = best)
          example: 1
        option_id:
          type: string
        date:
          type: string
          format: date
          example: "2026-03-30"
        start_time:
          type: string
          example: "12:00"
        end_time:
          type: string
          example: "14:00"
        yes_count:
          type: integer
          description: Number of "yes" votes
          example: 5
        maybe_count:
          type: integer
          description: Number of "maybe" votes
          example: 1
        no_count:
          type: integer
          description: Number of "no" votes
          example: 0
        score:
          type: number
          description: Calculated score (yes + maybe*0.5)
          example: 5.5
        label:
          type: string
          description: Human-readable time label
          example: "Tuesday, March 30 at 12:00 PM - 2:00 PM"

    Error:
      type: object
      properties:
        error:
          type: string
          description: Error code
          example: "validation_error"
        message:
          type: string
          description: Human-readable error message
          example: "Request validation failed"
        status:
          type: integer
          description: HTTP status code
          example: 400

security:
  - bearerAuth: []

paths:
  /polls:
    post:
      operationId: createPoll
      summary: Create a scheduling poll
      description: |
        Creates a new WhenWorks poll and returns a shareable voting link.

        **Anyone can vote on this poll without creating a WhenWorks account.**

        Use this when you need to find a time that works for multiple people.
      tags:
        - Polls
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - title
                - options
              properties:
                title:
                  type: string
                  description: Name of the meeting or event
                  example: "Team Lunch"
                  maxLength: 200
                description:
                  type: string
                  description: Optional context or details
                  example: "Let's find a time that works for everyone"
                  maxLength: 2000
                poll_type:
                  type: string
                  enum:
                    - date_selection
                    - time_slots
                  default: date_selection
                  description: |
                    - `date_selection`: Voting on dates only
                    - `time_slots`: Voting on specific date + time combinations
                timezone:
                  type: string
                  description: Timezone for the poll (IANA format)
                  example: "America/Los_Angeles"
                  default: "UTC"
                deadline:
                  type: string
                  format: date-time
                  description: When voting closes (ISO 8601)
                  example: "2026-03-28T23:59:00Z"
                allow_maybe:
                  type: boolean
                  description: Allow "maybe" responses in addition to yes/no
                  default: true
                options:
                  type: array
                  description: Proposed dates/times for the meeting
                  minItems: 1
                  maxItems: 100
                  items:
                    type: object
                    required:
                      - date
                    properties:
                      date:
                        type: string
                        format: date
                        description: Date for this option
                        example: "2026-03-30"
                      start_time:
                        type: string
                        description: Start time in HH:MM format (optional)
                        example: "12:00"
                      end_time:
                        type: string
                        description: End time in HH:MM format (optional)
                        example: "14:00"
            examples:
              date_only:
                summary: Date selection poll
                value:
                  title: "Team Lunch"
                  options:
                    - date: "2026-03-30"
                    - date: "2026-03-31"
                    - date: "2026-04-01"
              time_slots:
                summary: Time slots poll
                value:
                  title: "Weekly Standup"
                  poll_type: "time_slots"
                  timezone: "America/Los_Angeles"
                  options:
                    - date: "2026-03-30"
                      start_time: "09:00"
                      end_time: "10:00"
                    - date: "2026-03-30"
                      start_time: "14:00"
                      end_time: "15:00"
                    - date: "2026-03-31"
                      start_time: "09:00"
                      end_time: "10:00"
      responses:
        "200":
          description: Poll created successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Poll"
        "400":
          description: Validation error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          description: Unauthorized - invalid API key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

    get:
      operationId: listPolls
      summary: List your polls
      description: Get a paginated list of your scheduling polls
      tags:
        - Polls
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 10
            minimum: 1
            maximum: 100
          description: Number of polls to return
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
            minimum: 0
          description: Number of polls to skip (for pagination)
      responses:
        "200":
          description: List of polls
          content:
            application/json:
              schema:
                type: object
                properties:
                  polls:
                    type: array
                    items:
                      type: object
                      properties:
                        poll_id:
                          type: string
                        share_id:
                          type: string
                        poll_url:
                          type: string
                        title:
                          type: string
                        description:
                          type: string
                          nullable: true
                        poll_type:
                          type: string
                        created_at:
                          type: string
                          format: date-time
                        deadline:
                          type: string
                          format: date-time
                          nullable: true
                  total:
                    type: integer
                    description: Total number of polls
                  limit:
                    type: integer
                  offset:
                    type: integer
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /polls/{id}:
    get:
      operationId: getPoll
      summary: Get poll details
      description: Get detailed information about a specific poll, including all options
      tags:
        - Polls
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: Poll ID
      responses:
        "200":
          description: Poll details
          content:
            application/json:
              schema:
                type: object
                properties:
                  poll_id:
                    type: string
                  share_id:
                    type: string
                  poll_url:
                    type: string
                  title:
                    type: string
                  description:
                    type: string
                    nullable: true
                  poll_type:
                    type: string
                  timezone:
                    type: string
                  deadline:
                    type: string
                    format: date-time
                    nullable: true
                  allow_maybe:
                    type: boolean
                  created_at:
                    type: string
                    format: date-time
                  options:
                    type: array
                    items:
                      $ref: "#/components/schemas/PollOption"
        "404":
          description: Poll not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /polls/{id}/results:
    get:
      operationId: getPollResults
      summary: Get poll results
      description: |
        Get vote counts for each option in a poll.

        Shows how many people voted yes/maybe/no for each time option.
      tags:
        - Results
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: Poll ID
      responses:
        "200":
          description: Poll results
          content:
            application/json:
              schema:
                type: object
                properties:
                  poll_id:
                    type: string
                  share_id:
                    type: string
                  title:
                    type: string
                  total_respondents:
                    type: integer
                    description: Number of people who voted
                    example: 8
                  options:
                    type: array
                    items:
                      type: object
                      properties:
                        option_id:
                          type: string
                        date:
                          type: string
                          format: date
                        start_time:
                          type: string
                          nullable: true
                        end_time:
                          type: string
                          nullable: true
                        label:
                          type: string
                          nullable: true
                        yes_count:
                          type: integer
                          example: 5
                        maybe_count:
                          type: integer
                          example: 2
                        no_count:
                          type: integer
                          example: 1
        "404":
          description: Poll not found

  /polls/{id}/best-times:
    get:
      operationId: getBestTimes
      summary: Get best meeting times
      description: |
        Get the top-ranked times from a poll, sorted by availability.

        **This is the key endpoint for AI agents** - it tells you which times work best for the group.

        Score calculation: `yes_count + (maybe_count * 0.5)`
      tags:
        - Results
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: Poll ID
        - name: top_n
          in: query
          schema:
            type: integer
            default: 3
            minimum: 1
            maximum: 50
          description: Number of top results to return
      responses:
        "200":
          description: Ranked best times
          content:
            application/json:
              schema:
                type: object
                properties:
                  poll_id:
                    type: string
                  share_id:
                    type: string
                  title:
                    type: string
                  timezone:
                    type: string
                  best_times:
                    type: array
                    items:
                      $ref: "#/components/schemas/BestTime"
              example:
                poll_id: "123e4567-e89b-12d3-a456-426614174000"
                share_id: "abc123XY"
                title: "Team Lunch"
                timezone: "America/Los_Angeles"
                best_times:
                  - rank: 1
                    option_id: "opt123"
                    date: "2026-03-30"
                    start_time: "12:00"
                    end_time: "14:00"
                    yes_count: 5
                    maybe_count: 1
                    no_count: 0
                    score: 5.5
                    label: "Tuesday, March 30 at 12:00 PM - 2:00 PM"
        "404":
          description: Poll not found

tags:
  - name: Polls
    description: Create and manage scheduling polls
  - name: Results
    description: Get voting results and find best times
