openapi: 3.1.0
info:
  title: Lotsofsounds API
  description: Search, preview, and download thousands of sound effects and music tracks.
  version: 1.0.0
  contact:
    name: Lotsofsounds
    url: https://lotsofsounds.com

servers:
  - url: https://api.lotsofsounds.com
    description: Production

security: []

tags:
  - name: Sounds
    description: Browse, search, and download sounds
  - name: Samples
    description: Public sample endpoints — no API key required

paths:
  /api/v1/sounds/sample:
    get:
      operationId: listSampleSounds
      summary: List sample sounds
      description: |
        Returns up to 12 sample sounds with optional search. This endpoint is **public** and requires no authentication — use it to explore the response format before subscribing.
      tags:
        - Samples
      parameters:
        - name: q
          in: query
          schema:
            type: string
          description: Full-text search query (searches name and description)
          example: thunder
        - name: tags
          in: query
          schema:
            type: string
          description: Comma-separated tags to filter by (OR logic)
          example: nature,weather
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 12
            default: 12
          description: Max results (capped at 12)
      responses:
        '200':
          description: A list of sample sounds
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - pagination
                  - meta
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/SoundSummary'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
                  meta:
                    type: object
                    properties:
                      message:
                        type: string
                        example: These are sample sounds. Sign up for full catalog access.
                      upgrade_url:
                        type: string
                        format: uri
                        example: https://lotsofsounds.com/pricing
        '500':
          $ref: '#/components/responses/InternalError'

  /api/v1/sounds/sample/{id}/stream:
    get:
      operationId: streamSampleSound
      summary: Stream a sample sound
      description: |
        Returns a signed URL to stream a specific sample sound. No authentication required.
      tags:
        - Samples
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: The sound ID
          example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
      responses:
        '200':
          description: A signed streaming URL
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                properties:
                  data:
                    type: object
                    required:
                      - id
                      - name
                      - stream_url
                    properties:
                      id:
                        type: string
                        example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
                      name:
                        type: string
                        example: Thunder Rumble
                      stream_url:
                        type: string
                        format: uri
                        description: Signed S3 URL, expires in 1 hour
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalError'

  /api/v1/sounds:
    get:
      operationId: searchSounds
      summary: Search sounds
      description: |
        Search and filter the full sound catalog. Supports full-text search, tag filtering, duration ranges, sorting, and pagination.

        Requires a **Pro** or **Enterprise** subscription.
      tags:
        - Sounds
      security:
        - apiKey: []
      parameters:
        - name: q
          in: query
          schema:
            type: string
          description: Full-text search query (searches name and description)
          example: thunder
        - name: tags
          in: query
          schema:
            type: string
          description: Comma-separated tags to filter by (AND logic)
          example: nature,weather
        - name: min_duration
          in: query
          schema:
            type: number
          description: Minimum duration in seconds
          example: 1.0
        - name: max_duration
          in: query
          schema:
            type: number
          description: Maximum duration in seconds
          example: 30.0
        - name: sort
          in: query
          schema:
            type: string
            enum:
              - duration
              - name
            default: name
          description: Field to sort by
        - name: order
          in: query
          schema:
            type: string
            enum:
              - asc
              - desc
            default: desc
          description: Sort direction
        - name: page
          in: query
          schema:
            type: integer
            minimum: 1
            default: 1
          description: Page number
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
          description: Results per page (max 100)
      responses:
        '200':
          description: Paginated list of sounds
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - pagination
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Sound'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /api/v1/sounds/{id}:
    get:
      operationId: getSound
      summary: Get sound details
      description: |
        Returns full metadata for a single sound by ID.
      tags:
        - Sounds
      security:
        - apiKey: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: The sound ID
          example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
      responses:
        '200':
          description: Sound details
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                properties:
                  data:
                    $ref: '#/components/schemas/Sound'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /api/v1/sounds/{id}/stream:
    get:
      operationId: streamSound
      summary: Stream a sound
      description: |
        Returns a signed URL for streaming/playback. No download is counted.
      tags:
        - Sounds
      security:
        - apiKey: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: The sound ID
          example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
      responses:
        '200':
          description: A signed streaming URL
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                properties:
                  data:
                    type: object
                    required:
                      - id
                      - name
                      - stream_url
                    properties:
                      id:
                        type: string
                        example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
                      name:
                        type: string
                        example: Thunder Rumble
                      stream_url:
                        type: string
                        format: uri
                        description: Signed URL for streaming, expires in 1 hour
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /api/v1/sounds/{id}/download:
    get:
      operationId: downloadSound
      summary: Download a sound
      description: |
        Returns a signed download URL for the sound file. The URL expires after `1 hour`.
      tags:
        - Sounds
      security:
        - apiKey: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: The sound ID
          example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
      responses:
        '200':
          description: A signed download URL
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                properties:
                  data:
                    type: object
                    required:
                      - id
                      - name
                      - download_url
                      - expires_in
                    properties:
                      id:
                        type: string
                        example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
                      name:
                        type: string
                        example: Thunder Rumble
                      download_url:
                        type: string
                        format: uri
                        description: Signed CloudFront URL
                      expires_in:
                        type: integer
                        description: Seconds until the URL expires
                        example: 3600
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

components:
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: |
        Your API key. Generate one from the [dashboard](/dashboard/api-keys).
        Keys are prefixed with `los_`.

  schemas:
    SoundSummary:
      type: object
      required:
        - id
        - name
        - tags
        - duration
        - stream_url
      properties:
        id:
          type: string
          example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
        name:
          type: string
          example: Thunder Rumble
        description:
          type: string
          nullable: true
          example: Deep rolling thunder with rain
        tags:
          type: array
          items:
            type: string
          example:
            - nature
            - weather
            - thunder
        duration:
          type: number
          description: Duration in seconds
          example: 12.5
        stream_url:
          type: string
          format: uri
          description: URL to stream this sound
        download_url:
          type: string
          format: uri
          description: URL to download this sound (only present on authenticated endpoints)

    Sound:
      allOf:
        - $ref: '#/components/schemas/SoundSummary'
        - type: object
          properties:
            license:
              type: string
              nullable: true
              example: CC0

    Pagination:
      type: object
      required:
        - page
        - limit
        - total
        - totalPages
      properties:
        page:
          type: integer
          example: 1
        limit:
          type: integer
          example: 20
        total:
          type: integer
          description: Total sounds matching the query
          example: 342
        totalPages:
          type: integer
          example: 18

    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: string

  headers:
    X-RateLimit-Limit:
      description: Daily request quota for your plan
      schema:
        type: integer
        example: 2500
    X-RateLimit-Remaining:
      description: Requests remaining today
      schema:
        type: integer
        example: 2347
    X-RateLimit-Reset:
      description: Unix timestamp when the limit resets (midnight UTC)
      schema:
        type: integer
        example: 1711411200

  responses:
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Missing x-api-key header
    Forbidden:
      description: Plan does not include API access
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: string
              upgrade_url:
                type: string
                format: uri
          example:
            error: API access requires a Pro or Enterprise subscription
            upgrade_url: https://lotsofsounds.com/pricing
    NotFound:
      description: Sound not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Sound not found
    RateLimited:
      description: Rate limit exceeded
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: string
              limit:
                type: integer
              reset:
                type: integer
          example:
            error: Rate limit exceeded
            limit: 2500
            reset: 1711411200
    InternalError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Internal server error
