Gradium S2S API

The S2S API from Gradium — 1 operation(s) for s2s.

OpenAPI Specification

gradium-s2s-api-openapi.yml Raw ↑
openapi: 3.1.0
info:
  title: Gradium metering S2S API
  description: "This documentation covers the Gradium API.\n\nThis API exposes our Text-To-Speech and Speech-To-Text models, which offers low-latency, high-quality & natural sounding output and best in class accuracy.  \n\nFor issues, questions, or feature requests, please contact us at support@gradium.ai"
  version: 0.1.0
servers:
- url: https://api.gradium.ai/api
  description: Gradium API
tags:
- name: S2S
paths:
  /speech/s2s:
    get:
      tags:
      - S2S
      summary: S2S WebSocket Stream
      description: "Connect to this endpoint via WebSocket for real-time speech-to-speech: incoming audio is transcribed, optionally translated, and re-synthesized into speech.\n\n**Connection URL:**\n\n```\nwss://api.gradium.ai/api/speech/s2s\n```\n\n**Authentication:**\nInclude your API key in the WebSocket connection header:\n- Header: `x-api-key: your_api_key`\n\n---\n\n## Quick Reference\n\n| Direction | Message Type | Example |\n|-----------|-------------|---------|\n| \U0001F535⬆️ Client→Server | Setup (first) | `{\"type\": \"setup\", \"model_name\": \"default\", \"input_format\": \"pcm\", \"output_format\": \"pcm\", \"voice_id\": \"YTpq7expH9539ERJ\"}` |\n| \U0001F7E2⬇️ Server→Client | Ready | `{\"type\": \"ready\", \"request_id\": \"uuid\", \"sample_rate\": 48000}` |\n| \U0001F535⬆️ Client→Server | Audio | `{\"type\": \"audio\", \"audio\": \"base64...\"}` |\n| \U0001F7E2⬇️ Server→Client | Text (stream) | `{\"type\": \"text\", \"text\": \"Hello world\", \"start_s\": 0.5, \"stop_s\": 1.2}` |\n| \U0001F7E2⬇️ Server→Client | Audio (stream) | `{\"type\": \"audio\", \"audio\": \"base64...\"}` |\n| \U0001F535⬆️ Client→Server | EndOfStream | `{\"type\": \"end_of_stream\"}` |\n| \U0001F7E2⬇️ Server→Client | EndOfStream | `{\"type\": \"end_of_stream\"}` |\n| \U0001F534⬇️ Server→Client | Error | `{\"type\": \"error\", \"message\": \"Error description\", \"code\": 1008}` |\n\n---\n\n## Message Types\n\n### 1. Setup Message (First Message)\n\n**Direction:** Client → Server\n**Format:** JSON Object\n\n```json\n{\n  \"type\": \"setup\",\n  \"model_name\": \"default\",\n  \"input_format\": \"pcm\",\n  \"output_format\": \"pcm\",\n  \"voice_id\": \"YTpq7expH9539ERJ\"\n}\n```\n\n**Fields:**\n- `type` (string, required): Must be \"setup\"\n- `model_name` (string, optional): The speech-to-speech model to use (default: \"default\")\n- `stt_model_name` (string, optional): The speech-to-text model used to transcribe the input\n- `tts_model_name` (string, optional): The text-to-speech model used to synthesize the output\n- `input_format` (string, optional): Input audio format (default: \"wav\"). One of \"pcm\", \"pcm_8000\", \"pcm_16000\", \"pcm_22050\", \"pcm_24000\", \"pcm_44100\", \"pcm_48000\", \"wav\", \"opus\", \"ulaw_8000\", \"mulaw_8000\", \"alaw_8000\".\n- `output_format` (string, optional): Output audio format (default: \"wav\"). One of \"wav\", \"pcm\", \"opus\", \"ulaw_8000\", \"mulaw_8000\", \"alaw_8000\", \"pcm_8000\", \"pcm_16000\", \"pcm_22050\", \"pcm_24000\", \"pcm_44100\", \"pcm_48000\".\n- `voice_id` (string, optional): Voice ID from the library used for the synthesized output\n- `json_config` (object or string, optional): Advanced options. Set `target_language` to translate the speech (e.g. `{\"target_language\": \"en\"}`); omit it to keep the original language.\n\n**Important:** This must be the very first message sent after connection. The server will close the connection if any other message is sent first.\n\n---\n\n### 2. Ready Message\n\n**Direction:** Server → Client\n**Format:** JSON Object\n\n```json\n{\n  \"type\": \"ready\",\n  \"request_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n  \"sample_rate\": 48000,\n  \"frame_size\": 3840\n}\n```\n\n**Fields:**\n- `type` (string): Will be \"ready\"\n- `request_id` (string): Unique identifier for the session\n- `sample_rate` (integer): Output sample rate in Hz\n- `frame_size` (integer): Output frame size in samples\n\nThis message is sent by the server after receiving the setup message, indicating that the connection is ready to receive audio.\n\n---\n\n### 3. Audio Message\n\n**Direction:** Client → Server\n**Format:** JSON Object\n\n```json\n{\n  \"type\": \"audio\",\n  \"audio\": \"base64_encoded_audio_data...\"\n}\n```\n\n**Fields:**\n- `type` (string, required): Must be \"audio\"\n- `audio` (string, required): Base64-encoded input audio chunk\n\n**Audio Format Requirements (for PCM input):**\n- **Sample Rate**: 24000 Hz (24kHz)\n- **Format**: PCM (Pulse Code Modulation)\n- **Bit Depth**: 16-bit signed integer (little-endian)\n- **Channels**: Single channel (mono)\n- **Chunk Size**: Recommended 1920 samples per frame (80ms at 24kHz)\n\nSend audio messages to be converted. The server will stream back text and synthesized audio as it processes the input.\n\n---\n\n### 4. Text Response\n\n**Direction:** Server → Client\n**Format:** JSON Object\n\n```json\n{\n  \"type\": \"text\",\n  \"text\": \"Hello world\",\n  \"start_s\": 0.5,\n  \"stop_s\": 1.2,\n  \"stream_id\": 0\n}\n```\n\n**Fields:**\n- `type` (string): Will be \"text\"\n- `text` (string): The transcribed (and translated, if `target_language` is set) text segment\n- `start_s` (float): Start time of the segment in seconds\n- `stop_s` (float): Stop time of the segment in seconds\n- `stream_id` (integer or null): Stream identifier\n\n---\n\n### 5. Audio Response\n\n**Direction:** Server → Client\n**Format:** JSON Object\n\n```json\n{\n  \"type\": \"audio\",\n  \"audio\": \"base64_encoded_audio_data...\",\n  \"start_s\": 0.0,\n  \"stop_s\": 0.08,\n  \"stream_id\": 0\n}\n```\n\n**Fields:**\n- `type` (string): Will be \"audio\"\n- `audio` (string): Base64-encoded output audio chunk in the requested format\n- `start_s` (float): Start time of the chunk in seconds\n- `stop_s` (float): Stop time of the chunk in seconds\n- `stream_id` (integer or null): Stream identifier\n\nWhen using `\"pcm\"` output format, the audio is 16-bit signed integer mono. The output sample rate is reported in the `ready` message.\n\n---\n\n### 6. End Of Stream\n\n**Direction:** Client → Server and Server → Client\n**Format:** JSON Object\n\n```json\n{\n  \"type\": \"end_of_stream\"\n}\n```\n\nThe client sends this when it has finished sending audio. The server then returns any remaining text and audio, an `end_of_stream` message, and closes the connection.\n\n---\n\n## Error Handling\n\nWhen errors occur, the server sends an error message as JSON before closing the connection:\n\n```json\n{\n  \"type\": \"error\",\n  \"message\": \"Error description explaining what went wrong\",\n  \"code\": 1008\n}\n```\n\n**Common Error Codes:**\n- `1008`: Policy Violation (e.g., invalid API key, missing setup message, invalid audio format)\n- `1011`: Internal Server Error (unexpected server-side error)\n"
      parameters:
      - name: x-api-key
        in: header
        required: true
        schema:
          type: string
        description: Your Gradium API key
      responses:
        '101':
          description: WebSocket connection established
      x-codeSamples:
      - lang: cURL
        source: "wscat -c \"wss://api.gradium.ai/api/speech/s2s\" \\\n  -H \"x-api-key: your_api_key\"\n# After connection, paste:\n# {\"type\":\"setup\",\"model_name\":\"default\",\"input_format\":\"pcm\",\"output_format\":\"pcm\",\"voice_id\":\"YTpq7expH9539ERJ\",\"json_config\":{\"target_language\":\"en\"}}\n"
      - lang: Python
        source: "import asyncio\nimport base64\nimport json\n\nimport websockets\n\nIN_CHUNK_BYTES = 1920 * 2  # 80 ms at 24 kHz, 16-bit mono.\n\n\nasync def speech_to_speech(api_key: str, pcm_audio: bytes, voice_id: str) -> bytes:\n    setup = {\n        \"type\": \"setup\",\n        \"model_name\": \"default\",\n        \"input_format\": \"pcm\",\n        \"output_format\": \"pcm\",\n        \"voice_id\": voice_id,\n        \"json_config\": {\"target_language\": \"en\"},\n    }\n    out_audio = []\n\n    async with websockets.connect(\n        \"wss://api.gradium.ai/api/speech/s2s\",\n        additional_headers={\"x-api-key\": api_key},\n    ) as ws:\n        await ws.send(json.dumps(setup))\n        ready = json.loads(await ws.recv())\n        assert ready[\"type\"] == \"ready\"\n\n        async def producer():\n            for off in range(0, len(pcm_audio), IN_CHUNK_BYTES):\n                chunk = pcm_audio[off : off + IN_CHUNK_BYTES]\n                await ws.send(json.dumps({\n                    \"type\": \"audio\",\n                    \"audio\": base64.b64encode(chunk).decode(),\n                }))\n            await ws.send(json.dumps({\"type\": \"end_of_stream\"}))\n\n        async def consumer():\n            while True:\n                msg = json.loads(await ws.recv())\n                if msg[\"type\"] == \"text\":\n                    print(msg[\"text\"])\n                elif msg[\"type\"] == \"audio\":\n                    out_audio.append(base64.b64decode(msg[\"audio\"]))\n                elif msg[\"type\"] == \"end_of_stream\":\n                    return\n                elif msg[\"type\"] == \"error\":\n                    raise RuntimeError(msg[\"message\"])\n\n        await asyncio.gather(producer(), consumer())\n\n    return b\"\".join(out_audio)\n\n\nasyncio.run(speech_to_speech(\"your_api_key\", open(\"input.pcm\", \"rb\").read(), \"YTpq7expH9539ERJ\"))\n"
x-tagGroups:
- name: Documentation
  tags:
  - Documentation
  - FAQ
  - Release notes
- name: API Reference
  tags:
  - TTS
  - STT
  - Voices
  - Pronunciations
  - Credits