{
  "openapi": "3.0.0",
  "info": {
    "title": "Speech is Cheap API",
    "description": "The Speech is Cheap API allows you to create and manage transcription jobs. You can submit audio files for transcription, check the status of jobs, and retrieve the results when they are ready. The API is designed to be simple and easy to use, with a focus on providing accurate and affordable speech-to-text services.",
    "version": "2.0.0",
    "contact": {
      "name": "Speech is Cheap Support",
      "email": "support@speechischeap.com",
      "url": "https://docs.speechischeap.com"
    }
  },
  "servers": [
    {
      "url": "https://api.speechischeap.com/v2"
    }
  ],
  "tags": [
    {
      "name": "Jobs",
      "description": "Endpoints for managing transcription jobs."
    }
  ],
  "paths": {
    "/jobs": {
      "post": {
        "summary": "Create a New Transcription Job",
        "description": "This endpoint allows you to create a new transcription job by providing an audio file URL, a webhook callback URL, and optional configuration parameters.",
        "tags": [ "Jobs" ],
        "security": [
          {
            "BearerAuth": [ ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [ "input_url" ],
                "properties": {
                  "input_url": {
                    "type": "string",
                    "description": "The URL of the audio file to transcribe. Must be between six seconds and 24 hours long.\n\n**Supported File Types:**\n\nThe API supports a wide range of common audio and video containers and codecs. The following table lists the tested and verified combinations:\n\n| File Extension | Container | Audio Codec     | Video Codec   | Notes                                                 |\n|----------------|-----------|-----------------|---------------|-------------------------------------------------------|\n| `.mp3`         | MP3       | `libmp3lame`    | N/A           | Standard MP3 audio.                                   |\n| `.m4a`         | MP4       | AAC (Built-in)  | N/A           | AAC audio, typically using FFmpeg's built-in encoder. |\n| `.opus`        | Ogg       | Opus            | N/A           | Opus audio, often using libopus.                      |\n| `.flac`        | FLAC      | FLAC            | N/A           | Lossless audio.                                       |\n| `.wav`         | WAV       | PCM (`s16le`)   | N/A           | Uncompressed PCM audio, 16-bit signed little-endian.  |\n| `.mp4`         | MP4       | AAC             | H.264         | Video with AAC audio.                                 |\n| `.mp4`         | MP4       | AAC             | H.265         | Video with AAC audio.                                 |\n| `.webm`        | WebM      | Opus            | VP9           | Video with Opus audio.                                |\n| `.webm`        | WebM      | Opus            | AV1 (SVT-AV1) | Video with Opus audio, using the SVT-AV1 encoder.     |\n| `.ogg`         | Ogg       | Vorbis          | Theora        | Video with Vorbis audio.                              |\n",
                    "example": "https://example.com/audio-file.mp3"
                  },
                  "can_label_audio": { "type": "boolean", "default": false, "description": "When enabled, includes an audio classification label in the transcription." },
                  "can_parse_speakers": { "type": "boolean", "default": false, "description": "When enabled, adds `speaker_id` to each segment based on the speaker's voice." },
                  "can_parse_words": { "type": "boolean", "default": false, "description": "When enabled, includes a timecode for every word in the transcription." },
                  "can_stream_output": { "type": "boolean", "default": false, "description": "When enabled, streams progress and chronological transcription segments using SSE." },
                  "is_private": { "type": "boolean", "default": false, "description": "When enabled, immediately redacts the original `input_url` and deletes the segments after 12 hours." },
                  "language": {
                    "type": "string",
                    "description": "Two-letter ISO 639-1 language code. If not provided, the language will be auto-detected.",
                    "enum": [ "af", "sq", "am", "ar", "hy", "as", "az", "ba", "eu", "be", "bn", "bs", "br", "bg", "yue", "ca", "zh", "hr", "cs", "da", "nl", "en", "et", "fo", "fi", "fr", "gl", "ka", "de", "el", "gu", "ht", "ha", "haw", "he", "hi", "hu", "is", "id", "it", "ja", "jw", "kn", "kk", "km", "ko", "lo", "la", "lv", "ln", "lt", "lb", "mk", "mg", "ms", "ml", "mt", "mi", "mr", "mn", "my", "ne", "no", "nn", "oc", "ps", "fa", "pl", "pt", "pa", "ro", "ru", "sa", "sr", "sn", "sd", "si", "sk", "sl", "so", "es", "su", "sw", "sv", "tl", "tg", "ta", "tt", "te", "th", "bo", "tr", "tk", "uk", "ur", "uz", "vi", "cy", "yi", "yo" ]
                  },
                  "minimum_confidence": { "type": "number", "format": "float", "default": 0.5, "description": "Filter out segments that fall below this confidence threshold." },
                  "segment_duration": { "type": "number", "default": 30, "description": "Duration of each transcription segment in seconds. Must be between six and 30 seconds." },
                  "user_agent": { "type": "string", "description": "Custom user agent header to fetch the audio file." },
                  "webhook_url": { "type": "string", "description": "The URL where the transcription results may be sent to via a POST request." }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The job was successfully created and is being processed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "400": { "description": "Missing or invalid parameters" },
          "401": { "description": "Invalid or missing authentication token" },
          "402": { "description": "Missing subscription" },
          "500": { "description": "Server-side error occurred" }
        }
      }
    },
    "/jobs/health": {
      "get": {
        "summary": "Get API Health",
        "description": "This endpoint allows you to check the health of the Speech is Cheap Jobs API.",
        "tags": [ "Jobs" ],
        "responses": {
          "200": {
            "description": "Healthy",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "example": "Healthy"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}": {
      "get": {
        "summary": "Get Job Status and Output",
        "description": "This endpoint allows you to check the status of an existing transcription job and retrieve its results if available.",
        "tags": [ "Jobs" ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The ID of the job to retrieve."
          }
        ],
        "responses": {
          "200": {
            "description": "Request successful",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "404": { "description": "Job not found" },
          "500": { "description": "Server-side error occurred" }
        }
      },
      "delete": {
        "summary": "Cancel a Pending Job",
        "description": "This endpoint allows you to cancel a pending transcription job.",
        "tags": [ "Jobs" ],
        "security": [
          {
            "BearerAuth": [ ]
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The ID of the job to cancel."
          }
        ],
        "responses": {
          "200": {
            "description": "Job was successfully canceled",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "example": "OK"
                }
              }
            }
          },
          "401": { "description": "Invalid or missing authentication token" },
          "402": { "description": "Missing subscription" },
          "404": { "description": "Job not found, already completed, or already canceled" },
          "500": { "description": "Server-side error occurred" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key is required to create and cancel jobs."
      }
    },
    "schemas": {
      "Job": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "00000000-1111-7222-b333-444444444444-sic"
          },
          "status": {
            "type": "string",
            "enum": [ "PENDING", "COMPLETED", "FAILED", "CANCELED" ],
            "example": "PENDING"
          },
          "output": {
            "$ref": "#/components/schemas/JobOutput"
          }
        }
      },
      "JobOutput": {
        "type": "object",
        "properties": {
          "segments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Segment"
            }
          },
          "error": {
            "type": "string",
            "example": "Some error message"
          }
        }
      },
      "Segment": {
        "type": "object",
        "properties": {
          "id": { "type": "integer", "example": 1 },
          "start": { "type": "number", "format": "float", "example": 1.234 },
          "end": { "type": "number", "format": "float", "example": 12.345 },
          "text": { "type": "string", "example": "This is an example of some transcribed text output." },
          "confidence": { "type": "number", "format": "float", "example": 0.987 },
          "language": { "type": "string", "example": "en (99.95%)" },
          "processing_duration_in_s": { "type": "number", "format": "float", "example": 0.321 },
          "speaker_id": { "type": "string", "example": "A" },
          "label": { "type": "string", "example": "music" },
          "words": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Word"
            },
            "nullable": true
          }
        }
      },
      "Word": {
        "type": "object",
        "properties": {
          "start": { "type": "number", "format": "float", "example": 2.345 },
          "end": { "type": "number", "format": "float", "example": 2.567 },
          "text": { "type": "string", "example": "hi" }
        }
      }
    }
  }
}
