openapi: 3.0.3
info:
  title: cvoice.ai API
  description: |
    Free AI voice generation API with 20,000+ celebrity voices. No usage limits, no cost.

    ## Quick Start
    1. Create an API key from your dashboard
    2. Test with `GET /api/me` (optional)
    3. Find voice IDs from our public datasets
    4. Generate audio with `POST /api/tts`

    ## Voice Datasets
    - **Characters**: [dataset_search.json](https://cvoice.ai/dataset_search.json) - 20,000+ characters with metadata
    - **Voices**: [dataset_voices.json](https://cvoice.ai/dataset_voices.json) - All voice IDs grouped by character

  version: 1.0.0
  contact:
    name: cvoice.ai Support
    email: support@cvoice.ai
    url: https://cvoice.ai/support
  license:
    name: API Terms of Service
    url: https://cvoice.ai/terms

servers:
  - url: https://cvoice.ai
    description: Production server

security:
  - ApiKeyAuth: []

tags:
  - name: Authentication
    description: API key information and validation
  - name: Text-to-Speech
    description: Generate AI voice audio from text

paths:
  /api/me:
    get:
      tags:
        - Authentication
      summary: Get API key information
      description: |
        Returns information about your API key including usage statistics,
        rate limits, and user details. Useful for verifying your API key
        is working correctly.
      operationId: getApiKeyInfo
      responses:
        '200':
          description: API key information retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiKeyInfo'
              example:
                api_key:
                  id: "550e8400-e29b-41d4-a716-446655440000"
                  name: "My API Key"
                  tier: "free"
                  created_at: "2024-01-15T10:30:00.000Z"
                  last_used_at: "2024-01-20T15:45:00.000Z"
                user:
                  id: "user_123"
                  email: "user@example.com"
                  name: "John Doe"
                rate_limits:
                  per_day: 1000
                  per_minute: 10
                usage:
                  requests_today: 45
                  total_requests: 1234
                  remaining_today: 955
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /api/tts:
    post:
      tags:
        - Text-to-Speech
      summary: Generate AI voice audio
      description: |
        Converts text to speech using an AI-generated voice. You can specify
        a voice_id from our dataset or omit it to use a default curated voice.

        The API returns a URL to the generated audio file (MP3 format), which
        is cached and served from our CDN. Same voice_id + text combination
        will always return the same audio URL.
      operationId: generateSpeech
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TTSRequest'
            examples:
              with_voice_id:
                summary: Generate with specific voice
                value:
                  voice_id: "00a77add-48d0-4088-b16b-695e5bd0fb73"
                  text: "Hello! This is a sample text for AI voice generation using cvoice.ai API."
              default_voice:
                summary: Generate with default voice
                value:
                  text: "Hello! This uses the default voice since voice_id is not provided."
              with_metadata:
                summary: Generate with character metadata
                value:
                  voice_id: "00a77add-48d0-4088-b16b-695e5bd0fb73"
                  text: "This is Jungkook speaking!"
                  person_slug: "jungkook"
                  person_name: "Jungkook"
      responses:
        '200':
          description: Audio generated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TTSResponse'
              example:
                url: "https://static.cvoice.ai/tts/00a77add-48d0-4088-b16b-695e5bd0fb73/a3f2b8c9d1e5.mp3"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /dataset_search.json:
    get:
      tags:
        - Datasets
      summary: Get characters dataset
      description: |
        Returns a public dataset of 20,000+ characters with their metadata.
        This endpoint requires no authentication.

        **Cache this locally** - it only updates when we deploy new characters.
      operationId: getCharactersDataset
      security: []
      responses:
        '200':
          description: Characters dataset retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Character'
              example:
                - id: 234322812
                  name: "Jungkook"
                  username: "jungkook"
                  image_url: "https://static.cvoice.ai/profiles/jungkook.jpg"
                  avatar: true
                  occupations: ["Pop Singer"]
                  country: "South Korea"
                  birth_year: 1997
                  voice_count: 89
                  fame_score: 5

  /dataset_voices.json:
    get:
      tags:
        - Datasets
      summary: Get voices dataset
      description: |
        Returns all voice IDs grouped by character username. Use this to get
        the voice_id parameter for the TTS endpoint.

        **Cache this locally** - it only updates when we deploy new voices.
      operationId: getVoicesDataset
      security: []
      responses:
        '200':
          description: Voices dataset retrieved successfully
          content:
            application/json:
              schema:
                type: object
                additionalProperties:
                  type: array
                  items:
                    $ref: '#/components/schemas/Voice'
              example:
                jungkook:
                  - voice_id: "00a77add-48d0-4088-b16b-695e5bd0fb73"
                    name: "Jungkook Official"
                    curated: true
                    preview_url: "https://static.cvoice.ai/voices/00a77add.mp3"
                  - voice_id: "uuid-456"
                    name: "Jungkook Voice 2"
                    curated: false
                    preview_url: "https://static.cvoice.ai/voices/uuid-456.mp3"

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: |
        API key for authentication. Format: `cvai_your_api_key_here`

        Get your API key from the [dashboard](https://cvoice.ai/dashboard/api).

  schemas:
    ApiKeyInfo:
      type: object
      properties:
        api_key:
          type: object
          properties:
            id:
              type: string
              format: uuid
              description: Unique API key identifier
            name:
              type: string
              description: Human-readable API key name
            tier:
              type: string
              enum: [free]
              description: API key tier (currently only "free")
            created_at:
              type: string
              format: date-time
              description: When the API key was created
            last_used_at:
              type: string
              format: date-time
              nullable: true
              description: When the API key was last used
        user:
          type: object
          properties:
            id:
              type: string
              description: User identifier
            email:
              type: string
              format: email
              description: User email address
            name:
              type: string
              description: User display name
        rate_limits:
          type: object
          properties:
            per_day:
              type: integer
              description: Maximum requests per day
              example: 1000
            per_minute:
              type: integer
              description: Maximum requests per minute
              example: 10
        usage:
          type: object
          properties:
            requests_today:
              type: integer
              description: Number of requests made today
            total_requests:
              type: integer
              description: Total number of requests ever made
            remaining_today:
              type: integer
              description: Requests remaining for today

    TTSRequest:
      type: object
      required:
        - text
      properties:
        voice_id:
          type: string
          format: uuid
          description: |
            Voice ID from the dataset_voices.json dataset.
            If omitted, a default curated voice will be used.
          example: "00a77add-48d0-4088-b16b-695e5bd0fb73"
        text:
          type: string
          minLength: 50
          maxLength: 500
          description: Text to convert to speech (50-500 characters)
          example: "Hello! This is a sample text for AI voice generation using cvoice.ai API."
        person_slug:
          type: string
          description: Character username slug (optional, for history display)
          example: "jungkook"
        person_name:
          type: string
          description: Character display name (optional, for history display)
          example: "Jungkook"

    TTSResponse:
      type: object
      properties:
        url:
          type: string
          format: uri
          description: URL to the generated audio file (MP3 format, hosted on CDN)
          example: "https://static.cvoice.ai/tts/00a77add-48d0-4088-b16b-695e5bd0fb73/a3f2b8c9d1e5.mp3"

    Character:
      type: object
      properties:
        id:
          type: integer
          description: Unique character identifier
        name:
          type: string
          description: Character display name
        username:
          type: string
          description: Character username slug (use this to lookup voices)
        image_url:
          type: string
          format: uri
          description: URL to character profile image
        avatar:
          type: boolean
          description: Whether the character has an avatar
        occupations:
          type: array
          items:
            type: string
          description: Character occupations/roles
        country:
          type: string
          description: Character's country
        birth_year:
          type: integer
          nullable: true
          description: Character's birth year
        voice_count:
          type: integer
          description: Number of available voices for this character
        fame_score:
          type: integer
          minimum: 1
          maximum: 5
          description: Character fame/popularity score (1-5)

    Voice:
      type: object
      properties:
        voice_id:
          type: string
          format: uuid
          description: Voice identifier (use this for TTS requests)
        name:
          type: string
          description: Voice display name
        curated:
          type: boolean
          description: Whether this is a curated/verified voice
        preview_url:
          type: string
          format: uri
          description: URL to voice preview audio sample

    Error:
      type: object
      properties:
        error:
          type: string
          description: Error type or code
        message:
          type: string
          description: Human-readable error message
        details:
          type: object
          description: Additional error details (optional)
          additionalProperties: true

  responses:
    BadRequest:
      description: Bad request - Invalid parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            invalid_text_length:
              summary: Text too short or too long
              value:
                error: "bad_request"
                message: "Text must be between 50 and 500 characters"
            invalid_voice_id:
              summary: Invalid voice ID format
              value:
                error: "bad_request"
                message: "Invalid voice_id format"

    Unauthorized:
      description: Unauthorized - Invalid or missing API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: "unauthorized"
            message: "Invalid or missing API key"

    RateLimitExceeded:
      description: Rate limit exceeded
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            per_minute_limit:
              summary: Per-minute limit exceeded
              value:
                error: "rate_limit_exceeded"
                message: "Rate limit exceeded: 10 requests per minute"
                details:
                  retry_after: 45
            daily_limit:
              summary: Daily limit exceeded
              value:
                error: "rate_limit_exceeded"
                message: "Rate limit exceeded: 1000 requests per day"
                details:
                  retry_after: 3600

    InternalServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: "internal_error"
            message: "An internal server error occurred"

x-tagGroups:
  - name: Core API
    tags:
      - Authentication
      - Text-to-Speech
  - name: Public Datasets
    tags:
      - Datasets
