{"_id":"@giggy-ai/sdk","_rev":"5-a8cfc940a6addf1836cb4784158a6b9e","name":"@giggy-ai/sdk","dist-tags":{"latest":"0.2.1"},"versions":{"0.0.0-stage":{"name":"@giggy-ai/sdk","version":"0.0.0-stage","_id":"@giggy-ai/sdk@0.0.0-stage","stub":true,"maintainers":[{"name":"giggy","email":"grqdigitalcapital@gmail.com"}],"dist":{"shasum":"8aebeee4d3568eb289e2b5af0e086a57e4b8bf0b","tarball":"https://registry.npmjs.org/@giggy-ai/sdk/-/sdk-0.0.0-stage.tgz","fileCount":2,"integrity":"sha512-VozajGTD3bDJuxn3FY/uEAyVKEQf5nnaiPxY13qf9F4xNE8nF0IgOcPswDq+mIPRHS/nEIe9zEEVkRFXilyQFg==","signatures":[{"sig":"MEQCIAYhxfBJXRpRmFx4/riWOzbuaqxBjIt1Tu6IqGH5csPrAiBIomLvtOGRGZ2ToE0rRuNYSGjBcaOgpRO3OsE3G7SR8w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":335},"_npmUser":{"name":"giggy","email":"grqdigitalcapital@gmail.com"},"description":"Temporary package placeholder for staged publishing","directories":{}},"0.1.0":{"name":"@giggy-ai/sdk","version":"0.1.0","keywords":["giggy","text-to-speech","tts","speech","speech-synthesis","voice-ai","voice-agents","typescript","javascript","nodejs","sdk"],"license":"ISC","_id":"@giggy-ai/sdk@0.1.0","maintainers":[{"name":"giggy","email":"grqdigitalcapital@gmail.com"}],"homepage":"https://giggy.ai/docs/speech-api","bugs":{"url":"https://github.com/giggy-ai/giggy-js/issues"},"dist":{"shasum":"28a7f2bdf583685adb2625c7aea2637441bc0229","tarball":"https://registry.npmjs.org/@giggy-ai/sdk/-/sdk-0.1.0.tgz","fileCount":23,"integrity":"sha512-m10jVBUA0xJg0oX2C5BnCrWPfcaQVUTloAskggxoS7GJlEzxlDm/7jcOvI2D5Ibl68G6tecA5z9bnoguUJy/zg==","signatures":[{"sig":"MEYCIQDPSMtkdIEEHMlM18IFy13/qAA3GThcYPs4fBE0SPUi2QIhAON4GCpmcpFRHhic1jJTugLG7SQDBSpDHmLdwftjP/W7","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDkr6ZPn0h6MVZYBbzmAVu2QkdDDiXJClffhFKa0Yo/UwIhANLeCV0UOLryo6r3QBWpng1Znr3pg7KTamTj68XDcO+/","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21059},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"1c221f711ee41aa2ec133c8992b5e347f753261d","scripts":{"test":"npm run build && node --test test/*.test.mjs","build":"npm run clean && tsc -p tsconfig.json","check":"npm test","clean":"node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"","prepack":"npm run build"},"_npmUser":{"name":"giggy","email":"grqdigitalcapital@gmail.com"},"repository":{"url":"git+https://github.com/giggy-ai/giggy-js.git","type":"git"},"_npmVersion":"11.13.0","description":"Official JavaScript and TypeScript SDK for the Giggy text-to-speech API.","directories":{},"sideEffects":false,"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"7.0.2","@types/node":"22.20.5"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.1.0_1791407226537_0.2499015572602985","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@giggy-ai/sdk","version":"0.1.1","keywords":["giggy","text-to-speech","speech-to-text","tts","stt","speech","speech-synthesis","voice-ai","voice-agents","typescript","javascript","nodejs","sdk"],"license":"ISC","_id":"@giggy-ai/sdk@0.1.1","maintainers":[{"name":"giggy","email":"grqdigitalcapital@gmail.com"}],"homepage":"https://giggy.ai/docs/speech-api","bugs":{"url":"https://github.com/giggy-ai/giggy-js/issues"},"dist":{"shasum":"d31b4d7bc90aaed4599bc82e78620554736d6296","tarball":"https://registry.npmjs.org/@giggy-ai/sdk/-/sdk-0.1.1.tgz","fileCount":23,"integrity":"sha512-2qaQfmebLlEyTIMlAW/xzXxXUFxbut/mwp2KqKOSqFwBBs0LKazMyvl+s7NSEoVNG2K/fiFnyeMDa7MQtbSpsQ==","signatures":[{"sig":"MEUCIQDAoZmdjzA+Dc9AuTL9UYgQUWToZyaFlFQL2pxSNg5avQIgcH6joWWJ6jyYALG5theNt8jvR8tG0FahEmWlVa4tC7o=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIC2IAzO2fu7z9wpdskUy5SQJuRCHlF6XH/goaglt7wW2AiBb8NmDzlPF9GdRdHqGNmdvGWhBISO5PNg6SnAEDDrVeA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@giggy-ai%2fsdk@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":62121},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"9c989e56ed834fb668301a9d6ae72f58b266b776","scripts":{"test":"npm run build && node --test test/*.test.mjs","build":"npm run clean && tsc -p tsconfig.json","check":"npm test","clean":"node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"","prepack":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"ba6681df-71bb-4752-a267-e411e117b09e"}},"repository":{"url":"git+https://github.com/giggy-ai/giggy-js.git","type":"git"},"_npmVersion":"11.21.0","description":"Official JavaScript and TypeScript SDK for Giggy text-to-speech and speech-to-text.","directories":{},"sideEffects":false,"_nodeVersion":"24.21.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"7.0.2","@types/node":"22.20.5"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.1.1_1791914155279_0.7925866195112554","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@giggy-ai/sdk","version":"0.2.0","keywords":["giggy","text-to-speech","speech-to-text","tts","stt","speech","speech-synthesis","voice-ai","voice-agents","typescript","javascript","nodejs","sdk"],"license":"ISC","_id":"@giggy-ai/sdk@0.2.0","maintainers":[{"name":"giggy","email":"grqdigitalcapital@gmail.com"}],"homepage":"https://giggy.ai/docs/speech-api","bugs":{"url":"https://github.com/giggy-ai/giggy-js/issues"},"dist":{"shasum":"c0e4b08fd156947202de8d37b25151388c6c833e","tarball":"https://registry.npmjs.org/@giggy-ai/sdk/-/sdk-0.2.0.tgz","fileCount":23,"integrity":"sha512-cseM7sjS2lu22II9yhcuRLwOv0oIPxRDMMY/mtImcH9kUmKrD+MkwgHC0kEM9mdcmQQ0ryEAQfY1Z7WVQUsvgQ==","signatures":[{"sig":"MEQCIF+lYQf6Ov8XshmdQZ6+pRK8M6g0YO12FbYhk/IXqPF1AiBnaWZSC3C9El7BV1Nu/dWfAFmP8v66+UaiObY+yyt6tA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCDBoqAbc2QrBWIXK1Urjynxe6tzsqYj6v6q641larkbAIgTQc3SNYs9mkBQbfb7/9q5EiYCkESQ0ClpJq0bB9+mN0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@giggy-ai%2fsdk@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":79099},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"b254b4eea8c01df4f5c6ae77da6f198e82fc9882","scripts":{"test":"npm run build && node --test test/*.test.mjs","build":"npm run clean && tsc -p tsconfig.json","check":"npm test","clean":"node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"","prepack":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"ba6681df-71bb-4752-a267-e411e117b09e"}},"repository":{"url":"git+https://github.com/giggy-ai/giggy-js.git","type":"git"},"_npmVersion":"11.21.1","description":"Official JavaScript and TypeScript SDK for Giggy text-to-speech and speech-to-text.","directories":{},"sideEffects":false,"_nodeVersion":"24.21.0","dependencies":{"ws":"8.21.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/ws":"^8.18.2","typescript":"7.0.2","@types/node":"22.20.5"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.2.0_1792821881039_0.34101413602726804","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"_id":"@giggy-ai/sdk@0.2.1","bugs":{"url":"https://github.com/giggy-ai/giggy-js/issues"},"dist":{"shasum":"b0862877665729d2d3c0993eb3a1a5a8e62723e3","tarball":"https://registry.npmjs.org/@giggy-ai/sdk/-/sdk-0.2.1.tgz","fileCount":27,"integrity":"sha512-oHh4wwahjvdUEMW9r4qiLoGlmlY1+DOc736oH9jkvrGgPUJzvbYEe8+m+FRY3lpqweLkLOQbXNgjyWzYyosiJg==","signatures":[{"sig":"MEYCIQCiQxo9iwiA8TZzJnycjry3rvDj5WR8hJ7tn7DFdjAA3gIhALi42N4EWg3IpDTmD+68hOU/UJO6RnzYtVUDIMA9iIft","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIH5byjsxQouthGJISN1YEFKNAvSrn2J6mVbX8/0FKj3YAiAad1sXigMXIv/15HQjlrC6WEnLfLr9OBWDIeIZ3mVy9A=="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@giggy-ai%2fsdk@0.2.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":87877},"main":"./dist/index.js","name":"@giggy-ai/sdk","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"6e463c3e8af0f512608ee35bef4b38e1a16bfa3a","license":"ISC","scripts":{"test":"npm run build && node --test test/*.test.mjs","build":"npm run clean && tsc -p tsconfig.json","check":"npm test","clean":"node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"","prepack":"npm run build"},"version":"0.2.1","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"ba6681df-71bb-4752-a267-e411e117b09e"}},"homepage":"https://giggy.ai/docs/speech-api","keywords":["giggy","text-to-speech","speech-to-text","tts","stt","speech","speech-synthesis","voice-ai","voice-agents","typescript","javascript","nodejs","sdk"],"repository":{"url":"git+https://github.com/giggy-ai/giggy-js.git","type":"git"},"_npmVersion":"11.21.1","description":"Official JavaScript and TypeScript SDK for Giggy text-to-speech and speech-to-text.","directories":{},"maintainers":[{"name":"giggy","email":"grqdigitalcapital@gmail.com"}],"sideEffects":false,"_nodeVersion":"24.22.1","dependencies":{"ws":"8.21.1","undici":"^7.30.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/ws":"^8.18.2","typescript":"7.0.2","@types/node":"22.20.5"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sdk_0.2.1_1793573959973_0.8563055251842535"}}},"time":{"created":"2026-10-07T21:01:45.439Z","modified":"2026-11-01T22:59:20.406Z","0.0.0-stage":"2026-10-07T21:01:45.439Z","0.1.0":"2026-10-07T21:07:06.646Z","0.1.1":"2026-10-13T17:55:55.360Z","0.2.0":"2026-10-24T06:04:41.330Z","0.2.1":"2026-11-01T22:59:20.081Z"},"bugs":{"url":"https://github.com/giggy-ai/giggy-js/issues"},"license":"ISC","homepage":"https://giggy.ai/docs/speech-api","keywords":["giggy","text-to-speech","speech-to-text","tts","stt","speech","speech-synthesis","voice-ai","voice-agents","typescript","javascript","nodejs","sdk"],"repository":{"url":"git+https://github.com/giggy-ai/giggy-js.git","type":"git"},"description":"Official JavaScript and TypeScript SDK for Giggy text-to-speech and speech-to-text.","maintainers":[{"name":"giggy","email":"grqdigitalcapital@gmail.com"}],"readme":"# Giggy Speech SDK for Node.js and TypeScript\n\n[![SDK CI](https://github.com/giggy-ai/giggy-js/actions/workflows/ci.yml/badge.svg)](https://github.com/giggy-ai/giggy-js/actions/workflows/ci.yml)\n\nOfficial JavaScript and TypeScript SDK for Giggy text-to-speech, recorded-audio speech-to-text and short live PCM transcription sessions.\n\nStart with [one-call recording transcription](#transcribe-a-recording), [uploaded-WAV transcript revisions](#stream-transcript-revisions-from-an-uploaded-wav), or [live PCM replay](#live-microphone-pcm-session). The Node live example replays a file through the live input protocol; applications supply microphone capture. Live input is PCM16 mono 16 kHz, 0.5–30 seconds per session.\n\nGiggy provides text-to-speech and speech-to-text APIs for developers building voice agents and voice-enabled products.\n\n## Install\n\nRequires Node.js 22 or newer.\n\n```bash\nnpm install @giggy-ai/sdk\n```\n\nVersion **0.2.1** provides the current WebSocket live transport. Install `npm install @giggy-ai/sdk@0.2.1`. Version 0.1.1 retains its earlier live transport; version 0.1.0 provides TTS only. Existing applications can keep their installed versions and legacy endpoint while upgrading deliberately.\n\nChoose another integration in the [developer tool guide](https://giggy.ai/docs/speech-api#api-developer-tools): [Python](https://github.com/giggy-ai/giggy-python), [Pipecat TTS/live STT](https://github.com/giggy-ai/pipecat-giggy), [n8n TTS](https://github.com/giggy-ai/n8n-nodes-giggy), or [MCP speech/transcription tools](https://github.com/giggy-ai/giggy-mcp). For executable recording and TTS walkthroughs, use [giggy-examples](https://github.com/giggy-ai/giggy-examples).\n\n## Get a Giggy API key\n\nCreate an API key through your Giggy account. Keep it on the server; never embed it in browser JavaScript.\n\n```bash\nexport GIGGY_API_KEY=\"giggy_sk_...\"\n```\n\n## Find a Giggy voice\n\nAvailable voices for your Giggy account are returned by `GET https://api.giggy.ai/v1/voices`. This endpoint requires a Giggy API key as a bearer token. Each entry's `voice_id` is the UUID to pass as `voiceId` to the SDK.\n\n```bash\ncurl --fail --show-error \\\n  --header \"Authorization: Bearer ${GIGGY_API_KEY}\" \\\n  \"https://api.giggy.ai/v1/voices\"\n```\n\nThe response contains a `voices` array; use `voices[].voice_id`:\n\n```bash\nexport GIGGY_VOICE_ID=\"your-giggy-voice-uuid\"\n```\n\n## Keep a speech session connected\n\nCreate one SDK client for the speech session. Connect during startup, before the first utterance:\n\n```js\nconst giggy = new Giggy({ apiKey: process.env.GIGGY_API_KEY });\ntry {\n  await giggy.connect();\n  // Handle utterances with this same client.\n} finally {\n  await giggy.close();\n}\n```\n\nConstruction performs no network I/O. The client owns a private HTTP pool with 60-second idle\nretention; it does not change the process-wide fetch dispatcher. `connect()` establishes a\nconnection and starts a credential-free health GET every 20 seconds until `close()`.\nThese requests do not generate audio, spend credits or warm the model. A failed health check\nis attempted again at the next interval; speech and upload requests are never automatically\nreplayed. Network changes can still cause reconnection. Warm HTTP does not pre-open a live STT\nWebSocket or guarantee model latency. Close live STT iterators separately.\n\n## Generate your first MP3\n\nCreate `speech.mjs`:\n\n```js\nimport { writeFile } from 'node:fs/promises';\nimport { Giggy } from '@giggy-ai/sdk';\n\nconst apiKey = process.env.GIGGY_API_KEY;\nconst voiceId = process.env.GIGGY_VOICE_ID;\n\nif (!apiKey || !voiceId) {\n  throw new Error('Set GIGGY_API_KEY and GIGGY_VOICE_ID.');\n}\n\nconst giggy = new Giggy({ apiKey });\nconst audio = await giggy.speech.create({\n  text: 'Hello from Giggy.',\n  voiceId,\n});\n\nawait writeFile('speech.mp3', audio);\nconsole.log('Wrote speech.mp3');\n```\n\nRun it with:\n\n```bash\nnode speech.mjs\n```\n\n## Build from source\n\nThe SDK has zero runtime dependencies. Clone the public repository and build the JavaScript and TypeScript declarations in `dist/`:\n\n```bash\ngit clone https://github.com/giggy-ai/giggy-js.git\ncd giggy-js\nnpm ci\nnpm run build\n```\n\n## Basic text-to-speech\n\n```js\nimport { writeFile } from 'node:fs/promises';\nimport { Giggy } from '@giggy-ai/sdk';\n\nconst giggy = new Giggy({\n  apiKey: process.env.GIGGY_API_KEY,\n});\n\nconst audio = await giggy.speech.create({\n  text: 'Hello from Giggy.',\n  voiceId: process.env.GIGGY_VOICE_ID,\n});\n\nawait writeFile('speech.mp3', audio);\n```\n\nThe default request is `POST https://api.giggy.ai/v1/text-to-speech` with `model_id=giggyspeech`, `mode=batch`, and `output_format=mp3_24000_160`.\n\n## Fast speech\n\n```js\nconst audio = await giggy.speech.create({\n  text: 'Hello from Giggy.',\n  voiceId: process.env.GIGGY_VOICE_ID,\n  mode: 'fast',\n});\n```\n\n## Streaming text-to-speech\n\n```js\nimport { createWriteStream } from 'node:fs';\nimport { Readable } from 'node:stream';\nimport { pipeline } from 'node:stream/promises';\n\nconst stream = await giggy.speech.stream({\n  text: 'This speech is streaming.',\n  voiceId: process.env.GIGGY_VOICE_ID,\n});\n\nawait pipeline(\n  Readable.fromWeb(stream),\n  createWriteStream('speech.pcm'),\n);\n```\n\nStreaming forces `mode=streaming` and defaults to `output_format=pcm_24000`. The SDK returns the response stream directly and does not buffer the complete audio.\n\nThe progressive streaming endpoint rejects `Idempotency-Key` with HTTP 422. `speech.stream()` therefore omits that header and does not accept an `idempotencyKey` option. `speech.create()` generates a fresh key automatically, or accepts a caller-provided `idempotencyKey` for an intentional replay of the same request. The SDK does not automatically retry synthesis requests.\n\n## Transcribe a recording\n\nPrepare a WAV file with signed PCM16, mono, 16 kHz audio. Batch is free for 0.5–60 seconds; Fast accepts 0.5 seconds–12 hours and uses credits. The Node.js SDK streams the file body instead of buffering the whole recording. These STT methods are in version 0.1.1 of this checkout; npm currently serves an older version until this package is published.\n\n```js\nimport { Giggy } from '@giggy-ai/sdk';\n\nconst giggy = new Giggy({ apiKey: process.env.GIGGY_API_KEY });\nconsole.log((await giggy.transcriptions.transcribe({ audioPath: 'recording.wav', mode: 'batch' })).text);\n```\n\n`transcribe()` submits once, polls the durable generation, then fetches the signed transcript URL without your API key. It stops on failure or after a configurable timeout: pass `{ pollIntervalMs: 2500, timeoutMs: 1800000 }` as its second argument to change the defaults. Its error includes the generation UUID for inspection. Use `submit()`, `get()`, and `result()` separately for submit-now/fetch-later workflows. A completed generation may have no downloadable result after retention cleanup. Use `mode: 'fast'` for a paid recording, `language: 'en'` for a known language, or omit `language` for automatic detection. `clientRequestId` accepts a UUID; it does not authorize automatic retries of an ambiguous upload. The SDK never retries automatically.\n\n### Prepare a compatible WAV\n\nThe API accepts signed 16-bit PCM, mono, 16 kHz WAV for this path. Convert MP3, M4A, stereo, or another sample rate locally before calling the SDK:\n\n```bash\nffmpeg -i input.mp3 -ac 1 -ar 16000 -c:a pcm_s16le recording.wav\nffprobe -v error -show_entries stream=codec_name,sample_rate,channels -of default=noprint_wrappers=1 recording.wav\n```\n\n`ffprobe` should report `pcm_s16le`, `16000`, and `1`. Use 0.5–60 seconds for Batch. Renaming a file `.wav` does not convert it. Keep the recording and returned generation UUID until the final transcript is verified.\n\n## Stream transcript revisions from an uploaded WAV\n\nUploaded-recording Streaming is paid. Events are parsed across network chunk boundaries. A `transcript_chunk` contains cumulative provisional text: replace the displayed value instead of appending it.\n\n```js\nlet id;\nfor await (const { event, data } of giggy.transcriptions.stream({ audioPath: 'recording.wav' })) {\n  if (event === 'generation_created') id = data.generation.generation_uuid;\n  if (event === 'transcript_chunk') console.log('Replace preview:', data.text);\n}\nif (typeof id !== 'string') throw new Error('No admitted generation');\nconsole.log('Final:', (await giggy.transcriptions.result(id)).text);\n```\n\nEOF alone does not prove success: `result()` checks the durable generation. If the stream fails, reconcile with `get()`.\n\n## Live microphone PCM session\n\nThis example requires version 0.2.0 or newer. Earlier versions retain their legacy live transport. Recording `stream()` remains explicit HTTPS/SSE. New API requests default to `https://api.giggy.ai/v1`; existing `https://giggy.ai/v1` clients remain supported. Live sessions use one authenticated socket, binary PCM and one JSON `stop`, with no per-frame HTTP requests. The application supplies turn boundaries. The server assigns the generation ID; omit client request IDs. The SDK checks the final input ACK, transcript identity and saved text/duration before successful completion.\n\n`giggy.transcriptions.live()` opens the paid live WebSocket session at `wss://api.giggy.ai/v1/audio/transcriptions`. This runnable example replays a short recording in real time through the live input contract, so it needs no microphone device. Convert a 0.5–10 second recording to headerless PCM16 mono 16 kHz first:\n\n```bash\nffmpeg -i input.mp3 -ac 1 -ar 16000 -f s16le live.pcm\n```\n\nThen run the following as a Node.js module with `GIGGY_API_KEY` set. The sender and WebSocket event reader run concurrently. For a real microphone, replace the file chunks with captured PCM16 frames, keeping the same ordering, pacing, final frame, and error handling.\n\n```js\nimport { readFile } from 'node:fs/promises';\nimport { setTimeout as delay } from 'node:timers/promises';\nimport { Giggy } from '@giggy-ai/sdk';\n\nconst pcm = await readFile('live.pcm');\nif (pcm.length < 16000 || pcm.length > 320000 || pcm.length % 2) throw new Error('Use 0.5–10 seconds of PCM16 mono 16 kHz');\nconst giggy = new Giggy({ apiKey: process.env.GIGGY_API_KEY });\nconst stop = new AbortController();\nlet generationId;\nlet sender;\nlet senderError;\ntry {\n  for await (const { event, data } of giggy.transcriptions.live({ signal: stop.signal })) {\n    if (event === 'generation_created') generationId = data.generation.generation_uuid;\n    if (event === 'microphone_ready') {\n      const ready = data;\n      sender = (async () => {\n        let sequence = 0;\n        for (let offset = 0; offset < pcm.length; offset += 3200) {\n          const frame = pcm.subarray(offset, offset + 3200);\n          await giggy.transcriptions.sendLiveFrame({ generationUuid: ready.generation_uuid,\n            sequence: sequence++, pcm: frame, signal: stop.signal });\n          await delay(frame.length / 32, undefined, { signal: stop.signal });\n        }\n        await giggy.transcriptions.sendLiveFrame({ generationUuid: ready.generation_uuid,\n          sequence, pcm: new Uint8Array(), complete: true, signal: stop.signal });\n      })().catch(error => { senderError = error; stop.abort(); });\n    }\n    if (event === 'transcript_chunk') console.log('Replace preview:', data.text);\n  }\n} catch (error) {\n  if (!senderError) throw error;\n}\nif (sender) await sender;\nif (senderError) throw senderError;\nif (!generationId) throw new Error('No admitted generation');\nconsole.log('Final:', (await giggy.transcriptions.result(generationId)).text);\n```\n\nAwait each local socket send before incrementing `sequence`; a frame is at most 32,000 bytes. Closing an unfinished live stream cancels its work. Never automatically reconnect or resend an ambiguously accepted frame. Follow the [full live input contract](https://giggy.ai/docs/speech-api#api-stt-streaming) for readiness, framing, duration, cancellation, and billing. The SDK does not provide microphone capture or turn detection.\n\n## Custom speed\n\n```js\nconst audio = await giggy.speech.create({\n  text: 'Hello.',\n  voiceId: process.env.GIGGY_VOICE_ID,\n  speed: 1,\n});\n```\n\nThis is sent as `voice_settings.speed`; the API validates the supported range.\n\n## Errors\n\nUnsuccessful API responses throw `GiggyAPIError`, which exposes `status`, the raw response `body`, `method`, and `url`.\n\n## Public API\n\n- `Giggy`\n- `GiggyAPIError`\n- `SpeechCreateParams`\n- `SpeechStreamParams`\n- `SpeechMode` (`batch` or `fast`)\n- `TranscriptionSubmitParams`, `TranscriptionStreamParams`, `TranscriptionEvent`\n- `TranscriptionAdmission`, `TranscriptionGeneration`, `TranscriptionResult`\n- `LiveTranscriptionParams`, `LiveTranscriptionFrame`\n- `giggy.speech.create(params)` → `Promise<Uint8Array>`\n- `giggy.speech.stream(params)` → `Promise<ReadableStream<Uint8Array>>`\n- `giggy.transcriptions.submit(params)` → admission metadata\n- `giggy.transcriptions.transcribe(params, options?)` → completed transcript\n- `giggy.transcriptions.get(generationUuid)` → generation status\n- `giggy.transcriptions.result(generationUuid)` → completed transcript\n- `giggy.transcriptions.stream(params)` → parsed SSE events\n- `giggy.transcriptions.live(params)` → live WebSocket events\n- `giggy.transcriptions.sendLiveFrame(params)` → locally sent binary PCM frame\n\n## Developer resources\n\n- Documentation: https://giggy.ai/docs/speech-api\n- OpenAPI: https://api.giggy.ai/v1/openapi.json\n- Runnable integrations: https://github.com/giggy-ai/giggy-examples\n- MCP: https://github.com/giggy-ai/giggy-mcp\n- Python SDK: https://github.com/giggy-ai/giggy-python\n- Pricing: https://giggy.ai/pricing\n\n## Framework integration examples\n\n- [LiveKit TTS](https://github.com/giggy-ai/giggy-examples/tree/main/livekit/python)\n- [Pipecat TTS](https://github.com/giggy-ai/giggy-examples/tree/main/pipecat/python)\n- [Vapi custom TTS](https://github.com/giggy-ai/giggy-examples/tree/main/vapi)\n- [OpenAI-compatible TTS](https://github.com/giggy-ai/giggy-examples/tree/main/node/openai-compatible)\n- [Giggy MCP](https://github.com/giggy-ai/giggy-mcp)\n\nThese examples demonstrate Giggy compatibility. LiveKit, Pipecat and Vapi integrations do not currently use this SDK internally.\n\n## Transcription method reference\n\nAll methods belong to `giggy.transcriptions`. SDK defaults select free Batch; the REST endpoint defaults to paid Fast.\n\n| Method | Inputs and defaults | Returns |\n| --- | --- | --- |\n| `transcribe(params, { pollIntervalMs: 2500, timeoutMs: 1800000 })` | `audioPath`, optional Batch/Fast `mode`, `language`, `clientRequestId`, `signal` | Promise of the final transcript |\n| `submit(params)` | The same WAV admission parameters | Promise of admission metadata |\n| `get(uuid, signal?)` | Owning generation UUID | Promise of generation status |\n| `result(uuid, signal?)` | Completed generation UUID | Promise of signed transcript JSON; no API key sent to artifact host |\n| `stream(params)` | `audioPath`, optional `language/clientRequestId/signal`; paid Streaming | Async generator of typed transcript events |\n| `live({ language?, timeoutMs?, signal? })` | Paid live admission; automatic language detection | Async generator of typed transcript events |\n| `sendLiveFrame({ generationUuid, sequence, pcm, complete?, signal? })` | Ordered PCM16 Uint8Array; even length; maximum 32,000 bytes | Promise<void> after local socket send; final acceptance arrives as input_complete |\n\n`transcribe` applies a single deadline from before upload through status polling and artifact retrieval. Its timeout is combined with your AbortSignal; aborting either interrupts network I/O and polling waits. A timeout or abort stops this client call, but does not cancel an admitted uploaded recording. The error contains its UUID when admission was received. `timeoutMs` must be an integer from 1 to 4294967295; `pollIntervalMs` must be a positive integer. Other methods accept your signal so your application can set its own deadline.\n\n`TranscriptionEvent` is a discriminated union: checking `event` narrows `data` to the existing payload. For `generation_created`, read `data.generation.generation_uuid`; for `microphone_ready`, read `data.generation_uuid/attempt`; for `transcript_chunk`, use `data.text/sequence/replace/complete`; for `generation_updated`, read `data.status` and optional `data.generation`. Replace cumulative preview text, and reconcile durable completion after EOF. The SDK rejects an unknown named event rather than silently treating it as a supported payload.\n\n## Troubleshooting and migration\n\n### Migrating OpenAI speech and transcription\n\nOpenAI-compatible **TTS** uses `https://api.giggy.ai/v1/audio/speech`. Keep the OpenAI speech client, set `baseURL: 'https://api.giggy.ai/v1'`, use your Giggy API key, set `model: 'giggyspeech'`, and use a Giggy voice UUID. Choose a supported response format and set `maxRetries: 0` for synthesis. See the [existing OpenAI-client example](https://github.com/giggy-ai/giggy-examples/tree/main/node/openai-compatible).\n\n**STT is a separate contract.** Replace an OpenAI `audio.transcriptions.create(...)` call with `giggy.transcriptions.transcribe({ audioPath: 'recording.wav', mode: 'batch' })` and consume `result.text`. A `baseURL` change alone does not migrate STT: Giggy's REST input is raw WAV with `xi-api-key`, rather than an OpenAI multipart upload, and its Batch/Fast admission returns a generation UUID before the final transcript. The SDK handles that existing lifecycle. SDK transcription defaults to Batch; raw REST defaults to paid Fast. Convert input locally to PCM16 mono 16 kHz WAV and remove unsupported transcription options rather than inventing fields.\n\n| Symptom | Action |\n| --- | --- |\n| `transcriptions` is undefined | Check your installed package: STT starts at 0.1.1; 0.1.0 is TTS only. |\n| HTTP 401/403 | Check key validity and its owning space. Keep the key on your server. |\n| HTTP 429 | Stop new admissions and honor the server response; never replay an ambiguous upload automatically. |\n| Upload timeout before a UUID | Keep the original input/request identity and inspect History before submitting again. `clientRequestId` is not an idempotency guarantee. |\n| Timeout or SSE EOF after a UUID | Use `get(uuid)` to distinguish processing from failure, then `result(uuid)` on completion. |\n| Completed result missing/expired | Read status again with the owning key; use a refreshed signed URL when available. Retention or deletion can remove content permanently. |\n| Live input error | Abort/close the live generator and reconcile status. Unfinished live disconnects cancel work; uploaded-WAV disconnects do not. |\n| Empty text | No speech was detected; inspect the actual recording. |\n\nHTTP API failures raise `GiggyAPIError` with status and raw body. Parameter errors raise `TypeError`. Transcription timeouts and malformed/unavailable/terminal failed results raise `Error`; caller abort preserves the signal's reason. Log UUIDs and statuses, not signed URLs, keys or live input tokens.\n\nTo migrate an AssemblyAI recording workflow, map `client.transcripts.transcribe({ audio })` to `giggy.transcriptions.transcribe({ audioPath: wavPath })`. The result's `text` remains a string, but URLs and arbitrary media need local conversion to PCM16 mono 16 kHz WAV. Speaker labels, word times, confidence, subtitles and speech-analysis options have no corresponding Giggy fields. Live event handling must follow cumulative revisions and explicit session completion, with 30 seconds of audio and 35 seconds from readiness; AssemblyAI turn detection options do not translate to Giggy request fields.\n\nSee the [Node recording walkthrough](https://github.com/giggy-ai/giggy-examples/tree/main/node/basic-tts#transcribe-a-recording) and [framework STT guide](https://github.com/giggy-ai/giggy-examples#stt-in-voice-agent-frameworks).\n","readmeFilename":"README.md"}