openapi: 3.1.0
info:
  title: Chart Splat API
  description: |
    Generate beautiful charts programmatically using Chart.js configuration.
    Send your chart configuration and receive a base64-encoded PNG image.

    ## Authentication
    All requests require an API key. Include it in your requests using one of these methods:
    - `Authorization: Bearer YOUR_API_KEY`
    - `X-Api-Key: YOUR_API_KEY`

    ## Rate Limits
    Rate limits are based on your subscription plan:
    - **Free**: 100 requests/month
    - **Pro**: 10,000 requests/month
    - **Enterprise**: Unlimited

    Rate limit headers are included in all responses:
    - `X-RateLimit-Limit`: Your monthly limit
    - `X-RateLimit-Remaining`: Requests remaining this month
    - `X-RateLimit-Reset`: When the limit resets (ISO 8601)
  version: 1.0.0
  contact:
    name: Chart Splat Support
    url: https://chartsplat.com/contact
    email: support@chartsplat.com
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT

servers:
  - url: https://api.chartsplat.com
    description: Production server
  - url: http://localhost:3001
    description: Local development server

tags:
  - name: Charts
    description: Chart generation endpoints
  - name: API Keys
    description: API key management (requires Cognito auth)
  - name: Usage
    description: Usage statistics (requires Cognito auth)
  - name: Account
    description: Account management (requires Cognito auth)

security:
  - ApiKeyAuth: []
  - BearerAuth: []

paths:
  /chart:
    post:
      operationId: generateChart
      summary: Generate a chart image
      description: |
        Generate a chart image from Chart.js configuration.
        Returns a base64-encoded PNG image.
      tags:
        - Charts
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChartRequest'
            examples:
              barChart:
                summary: Bar Chart
                value:
                  type: bar
                  data:
                    labels: ["Jan", "Feb", "Mar", "Apr"]
                    datasets:
                      - label: Revenue
                        data: [12, 19, 3, 5]
                        backgroundColor: "#8b5cf6"
              lineChart:
                summary: Line Chart
                value:
                  type: line
                  data:
                    labels: ["Mon", "Tue", "Wed", "Thu", "Fri"]
                    datasets:
                      - label: Visitors
                        data: [100, 200, 150, 300, 250]
                        borderColor: "#3b82f6"
                        fill: false
              pieChart:
                summary: Pie Chart
                value:
                  type: pie
                  data:
                    labels: ["Red", "Blue", "Yellow"]
                    datasets:
                      - data: [30, 50, 20]
                        backgroundColor: ["#ef4444", "#3b82f6", "#eab308"]
      responses:
        '200':
          description: Chart generated successfully
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
              description: Monthly request limit
            X-RateLimit-Remaining:
              schema:
                type: integer
              description: Requests remaining this month
            X-RateLimit-Reset:
              schema:
                type: string
                format: date-time
              description: When the rate limit resets
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChartResponse'
        '400':
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                missingBody:
                  value:
                    error: Request body is required
                invalidJson:
                  value:
                    error: Invalid JSON in request body
                invalidConfig:
                  value:
                    error: "Invalid chart configuration. Required: data.labels and data.datasets"
        '401':
          description: Authentication failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                missingKey:
                  value:
                    error: API key required
                    message: Include your API key in the Authorization header (Bearer YOUR_KEY) or X-Api-Key header
                invalidKey:
                  value:
                    error: Invalid API key
        '429':
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'
        '500':
          description: Server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /health:
    get:
      operationId: healthCheck
      summary: Health check
      description: Check if the API is running
      tags:
        - Charts
      security: []
      responses:
        '200':
          description: API is healthy
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok
                  message:
                    type: string
                    example: Chart Splat API is running

  /api-keys:
    get:
      operationId: listApiKeys
      summary: List API keys
      description: Get all API keys for the authenticated user
      tags:
        - API Keys
      security:
        - CognitoAuth: []
      responses:
        '200':
          description: List of API keys
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiKeyList'
        '401':
          description: Not authenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

    post:
      operationId: createApiKey
      summary: Create an API key
      description: Create a new API key for the authenticated user
      tags:
        - API Keys
      security:
        - CognitoAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: A friendly name for the API key
                  example: Production Key
      responses:
        '201':
          description: API key created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiKeyCreated'
        '401':
          description: Not authenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: API key limit reached
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /api-keys/{keyId}:
    delete:
      operationId: deleteApiKey
      summary: Delete an API key
      description: Delete an API key by ID
      tags:
        - API Keys
      security:
        - CognitoAuth: []
      parameters:
        - name: keyId
          in: path
          required: true
          schema:
            type: string
          description: The API key ID
      responses:
        '200':
          description: API key deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: API key deleted successfully
        '401':
          description: Not authenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: API key not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /usage:
    get:
      operationId: getUsage
      summary: Get usage statistics
      description: Get usage statistics for the authenticated user
      tags:
        - Usage
      security:
        - CognitoAuth: []
      responses:
        '200':
          description: Usage statistics
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UsageStats'
        '401':
          description: Not authenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /account:
    get:
      operationId: getAccount
      summary: Get account information
      description: Get account information for the authenticated user
      tags:
        - Account
      security:
        - CognitoAuth: []
      responses:
        '200':
          description: Account information
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountInfo'
        '401':
          description: Not authenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /checkout:
    post:
      operationId: createCheckoutSession
      summary: Create checkout session
      description: Create a Stripe checkout session for upgrading to Pro
      tags:
        - Account
      security:
        - CognitoAuth: []
      responses:
        '200':
          description: Checkout session created
          content:
            application/json:
              schema:
                type: object
                properties:
                  sessionId:
                    type: string
                    description: Stripe checkout session ID
                  url:
                    type: string
                    format: uri
                    description: URL to redirect user to for checkout
        '401':
          description: Not authenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-Api-Key
      description: Your Chart Splat API key (starts with `cs_`)

    BearerAuth:
      type: http
      scheme: bearer
      description: Your Chart Splat API key as a Bearer token

    CognitoAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: AWS Cognito JWT token for authenticated endpoints

  schemas:
    ChartRequest:
      type: object
      required:
        - data
      properties:
        type:
          type: string
          enum: [line, bar, pie, doughnut, radar, polarArea]
          default: line
          description: The type of chart to generate
        data:
          $ref: '#/components/schemas/ChartData'
        options:
          $ref: '#/components/schemas/ChartOptions'

    ChartData:
      type: object
      required:
        - labels
        - datasets
      properties:
        labels:
          type: array
          items:
            type: string
          description: Labels for the X-axis or segments
          example: ["Jan", "Feb", "Mar", "Apr"]
        datasets:
          type: array
          items:
            $ref: '#/components/schemas/Dataset'
          description: Array of datasets to display

    Dataset:
      type: object
      required:
        - data
      properties:
        label:
          type: string
          description: Label for the dataset (shown in legend)
          example: Revenue
        data:
          type: array
          items:
            type: number
          description: Data points for the dataset
          example: [12, 19, 3, 5]
        backgroundColor:
          oneOf:
            - type: string
            - type: array
              items:
                type: string
          description: Background color(s) for the dataset
          example: "#8b5cf6"
        borderColor:
          oneOf:
            - type: string
            - type: array
              items:
                type: string
          description: Border color(s) for the dataset
          example: "#6366f1"
        borderWidth:
          type: number
          description: Border width in pixels
          default: 1
        fill:
          type: boolean
          description: Whether to fill the area under line charts
          default: false

    ChartOptions:
      type: object
      properties:
        width:
          type: integer
          minimum: 100
          maximum: 4000
          default: 800
          description: Image width in pixels
        height:
          type: integer
          minimum: 100
          maximum: 4000
          default: 600
          description: Image height in pixels
        plugins:
          type: object
          description: Chart.js plugin options
        scales:
          type: object
          description: Chart.js scale options

    ChartResponse:
      type: object
      properties:
        image:
          type: string
          description: Base64-encoded PNG image with data URI prefix
          example: "data:image/png;base64,iVBORw0KGgo..."
        format:
          type: string
          enum: [png]
          description: Image format
          example: png
        width:
          type: integer
          description: Image width in pixels
          example: 800
        height:
          type: integer
          description: Image height in pixels
          example: 600

    Error:
      type: object
      properties:
        error:
          type: string
          description: Error type or message
        message:
          type: string
          description: Detailed error message

    RateLimitError:
      type: object
      properties:
        error:
          type: string
          example: Rate limit exceeded
        message:
          type: string
          example: You have used 100 of 100 requests this month. Upgrade your plan for more.
        limit:
          type: integer
          description: Monthly request limit
        used:
          type: integer
          description: Requests used this month
        plan:
          type: string
          enum: [free, pro, enterprise]
          description: Current subscription plan

    ApiKeyList:
      type: object
      properties:
        apiKeys:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                description: API key ID
              name:
                type: string
                description: Friendly name for the key
              prefix:
                type: string
                description: First characters of the key (for identification)
                example: "cs_abc1..."
              createdAt:
                type: string
                format: date-time
              lastUsedAt:
                type: string
                format: date-time

    ApiKeyCreated:
      type: object
      properties:
        message:
          type: string
          example: API key created successfully
        apiKey:
          type: object
          properties:
            key:
              type: string
              description: The full API key (only shown once!)
              example: "cs_abc123xyz789..."
            id:
              type: string
            name:
              type: string
            prefix:
              type: string
            createdAt:
              type: string
              format: date-time
        warning:
          type: string
          example: "Save this key securely. It won't be shown again."

    UsageStats:
      type: object
      properties:
        usage:
          type: object
          properties:
            current:
              type: integer
              description: Requests used this month
            limit:
              type: integer
              description: Monthly limit
            remaining:
              type: integer
              description: Requests remaining
            percentUsed:
              type: integer
              description: Percentage of limit used
            plan:
              type: string
              enum: [free, pro, enterprise]
            billingCycle:
              type: object
              properties:
                start:
                  type: string
                  format: date
                end:
                  type: string
                  format: date
        history:
          type: array
          items:
            type: object
            properties:
              month:
                type: string
                example: "2024-01"
              count:
                type: integer

    AccountInfo:
      type: object
      properties:
        account:
          type: object
          properties:
            userId:
              type: string
            email:
              type: string
              format: email
            plan:
              type: string
              enum: [free, pro, enterprise]
            createdAt:
              type: string
              format: date-time
            hasStripeSubscription:
              type: boolean
        stats:
          type: object
          properties:
            apiKeysCount:
              type: integer
            apiKeysLimit:
              type: integer
            currentMonthUsage:
              type: integer
            usageLimit:
              type: integer
        planDetails:
          type: object
          properties:
            name:
              type: string
              example: Free
            requestsPerMonth:
              oneOf:
                - type: integer
                - type: string
                  enum: [Unlimited]
            maxApiKeys:
              oneOf:
                - type: integer
                - type: string
                  enum: [Unlimited]
