{"_id":"@eldritchlogic/heygen-sdk","name":"@eldritchlogic/heygen-sdk","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@eldritchlogic/heygen-sdk","version":"0.1.0","description":"Fully-typed Node.js/TypeScript SDK for the HeyGen API — videos, video agent, avatars, voices, translations, lipsync, streaming, webhooks, and every other documented endpoint.","keywords":["heygen","avatar","ai-video","video-generation","text-to-speech","video-translation","lipsync","sdk","api-client"],"license":"MIT","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"sideEffects":false,"publishConfig":{"access":"public"},"engines":{"node":">=18.17.0"},"scripts":{"build":"tsup","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","gen:types":"openapi-typescript specs/external-api.json -o src/generated/external-api.ts --default-non-nullable=false && node scripts/gen-aliases.mjs","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"devDependencies":{"@types/node":"^26.1.1","openapi-typescript":"^7.13.0","tsup":"^8.5.1","typescript":"^5.9.3","vitest":"^4.1.10"},"_id":"@eldritchlogic/heygen-sdk@0.1.0","_nodeVersion":"22.12.0","_npmVersion":"10.9.0","dist":{"integrity":"sha512-X6XZ47eCpFtfmgOUh6jmMh59uGgu/DN7gGI4fMdbkt+k1rH1cK50rFgHVYFYPuuExangsVQjsPUPUe7huHXMUA==","shasum":"384582ff33fb4eb03517fe2e5f67c4ecc74d6ed0","tarball":"https://registry.npmjs.org/@eldritchlogic/heygen-sdk/-/heygen-sdk-0.1.0.tgz","fileCount":9,"unpackedSize":1151672,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDlDE5oAdPrNCQO4phijUKMPS+DMXua/Kc4Kmrqr9wOhAIgQCAZmEubp6BWo0jiinvFSqeVSwL2K3oa/zisc6g4hhI="}]},"_npmUser":{"name":"eldritchlogic","email":"eldritchlogicllc@gmail.com"},"directories":{},"maintainers":[{"name":"eldritchlogic","email":"eldritchlogicllc@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/heygen-sdk_0.1.0_1784406283414_0.7088977569651904"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-18T20:24:43.231Z","0.1.0":"2026-07-18T20:24:43.580Z","modified":"2026-07-18T20:24:43.776Z"},"maintainers":[{"name":"eldritchlogic","email":"eldritchlogicllc@gmail.com"}],"description":"Fully-typed Node.js/TypeScript SDK for the HeyGen API — videos, video agent, avatars, voices, translations, lipsync, streaming, webhooks, and every other documented endpoint.","keywords":["heygen","avatar","ai-video","video-generation","text-to-speech","video-translation","lipsync","sdk","api-client"],"license":"MIT","readme":"# @eldritchlogic/heygen-sdk\n\nFully-typed Node.js/TypeScript SDK for the [HeyGen API](https://developers.heygen.com/reference) — **every documented endpoint is covered**: videos, Video Agent, avatars, realtime avatars, voices & TTS, video translation, lipsync, AI clipping, HyperFrames, assets, webhooks, brand, workflows, background removal, plus the complete legacy (pre-v3) API surface.\n\n- **100% endpoint coverage, mechanically verified.** A test suite walks HeyGen's published OpenAPI specs (vendored in [`specs/`](specs/)) and fails if any operation lacks an SDK method or hits the wrong method/path.\n- **Fully typed.** Request and response types are generated from HeyGen's official OpenAPI spec — every schema is exported by name.\n- **Zero runtime dependencies.** Built on the global `fetch` (Node.js ≥ 18.17, Bun, Deno, edge runtimes, modern browsers).\n- **Batteries included.** Cursor auto-pagination, job polling helpers, automatic retries with `Retry-After` support, idempotency keys, SSE streaming, and webhook signature verification.\n\n## Install\n\n```bash\nnpm install @eldritchlogic/heygen-sdk\n```\n\n## Quick start\n\n```ts\nimport { HeyGen } from \"@eldritchlogic/heygen-sdk\";\n\nconst heygen = new HeyGen({ apiKey: process.env.HEYGEN_API_KEY });\n\n// Create a video and wait for it to render.\nconst { video_id } = await heygen.videos.create({\n  type: \"avatar\",\n  avatar_id: \"your_avatar_look_id\",\n  script: \"Welcome to our product tour!\",\n  aspect_ratio: \"auto\",\n  resolution: \"1080p\",\n});\nconst video = await heygen.videos.waitForCompletion(video_id);\nconsole.log(video.video_url);\n```\n\nOr let the Video Agent do everything from a prompt:\n\n```ts\nconst session = await heygen.videoAgents.create({\n  prompt: \"A 30-second product intro for an AI note-taking app, upbeat tone\",\n});\nconst done = await heygen.videoAgents.waitForCompletion(session.session_id);\n```\n\n## Authentication & configuration\n\n```ts\nconst heygen = new HeyGen({\n  apiKey: \"...\",            // default: process.env.HEYGEN_API_KEY (sent as x-api-key)\n  accessToken: \"...\",       // alternative: OAuth2 bearer token\n  baseUrl: \"https://api.heygen.com\",  // override for testing/proxies\n  timeoutMs: 60_000,        // per-request timeout\n  maxRetries: 2,            // automatic retries on 429/5xx/network errors\n  defaultHeaders: {},       // merged into every request\n  fetch: customFetch,       // bring your own fetch\n});\n```\n\nEvery method also accepts per-request options as its last argument:\n\n```ts\nawait heygen.videos.create(body, {\n  idempotencyKey: crypto.randomUUID(), // safe retries for mutations\n  timeoutMs: 120_000,\n  signal: abortController.signal,\n  headers: { \"x-trace-id\": \"...\" },\n});\n```\n\n**Retries:** GET/PUT/DELETE requests are retried automatically on 429, 5xx, and network errors (respecting `Retry-After`). POST/PATCH requests are only retried when you pass an `idempotencyKey`, which HeyGen deduplicates server-side for 24 h.\n\n## Pagination\n\nList endpoints return a `Page<T>` with `data`, `hasMore`, and `nextToken`. Iterate the page to walk **all** pages lazily, or use `nextPage()` / `toArray(limit)`:\n\n```ts\nfor await (const voice of await heygen.voices.list({ language: \"English\" })) {\n  console.log(voice.name);\n}\n\nconst firstHundred = await (await heygen.videos.list()).toArray(100);\n```\n\n## Polling helpers\n\nAsync jobs expose `waitForCompletion` (and friends) that poll until a terminal status:\n\n```ts\nawait heygen.videos.waitForCompletion(videoId, { intervalMs: 5000, timeoutMs: 15 * 60_000 });\nawait heygen.videoTranslations.waitForCompletion(translationId);\nawait heygen.lipsyncs.waitForCompletion(lipsyncId);\nawait heygen.aiClipping.waitForCompletion(jobId);\nawait heygen.hyperframes.renders.waitForCompletion(renderId);\nawait heygen.backgroundRemovals.waitForCompletion(jobId);\nawait heygen.voices.waitForClone(voiceId);\nawait heygen.avatars.waitForTraining(groupId);\nawait heygen.videoTranslations.proofreads.waitForCompletion(proofreadId);\n```\n\nPrefer webhooks over polling in production — see below.\n\n## Webhooks\n\n```ts\nimport { verifyWebhookSignature, WebhookVerificationError } from \"@eldritchlogic/heygen-sdk\";\n\n// Register an endpoint (store the returned secret — it's only shown once):\nconst endpoint = await heygen.webhooks.endpoints.create({\n  url: \"https://yourapp.com/webhooks/heygen\",\n  events: [\"avatar_video.success\", \"avatar_video.fail\"],\n});\n\n// In your webhook handler (keep the raw body — parsed JSON won't verify):\napp.post(\"/webhooks/heygen\", express.raw({ type: \"application/json\" }), async (req, res) => {\n  try {\n    const event = await verifyWebhookSignature({\n      payload: req.body,                          // raw Buffer/string\n      signature: req.header(\"Heygen-Signature\")!, // hex HMAC-SHA256\n      timestamp: req.header(\"Heygen-Timestamp\"),  // replay protection (±300 s)\n      secret: process.env.HEYGEN_WEBHOOK_SECRET!,\n    });\n    // handle event ...\n    res.sendStatus(200);\n  } catch (err) {\n    if (err instanceof WebhookVerificationError) return res.sendStatus(401);\n    throw err;\n  }\n});\n```\n\n## Error handling\n\nAll API failures throw typed subclasses of `APIError` with `status`, `code`, `param`, `docUrl`, `requestId`, `headers`, and the raw `body`:\n\n| Status | Error class |\n| --- | --- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 409 | `ConflictError` (e.g. idempotent retry still in flight) |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` (with `.retryAfter` seconds) |\n| 5xx | `InternalServerError` |\n| network | `APIConnectionError` / `APITimeoutError` |\n\n```ts\nimport { RateLimitError } from \"@eldritchlogic/heygen-sdk\";\n\ntry {\n  await heygen.videos.create(body);\n} catch (err) {\n  if (err instanceof RateLimitError) console.log(`retry in ${err.retryAfter}s`);\n  throw err;\n}\n```\n\n## Endpoint reference\n\nEvery operation in HeyGen's OpenAPI specs, and the SDK method that calls it.\n\n### Videos — `heygen.videos`\n\n| Method | Endpoint |\n| --- | --- |\n| `create(body)` | `POST /v3/videos` |\n| `get(videoId)` | `GET /v3/videos/{video_id}` |\n| `list(params?)` | `GET /v3/videos` |\n| `delete(videoId)` | `DELETE /v3/videos/{video_id}` |\n| `statuses(params?)` | `GET /v3/videos/statuses` |\n| `batches.create(body)` | `POST /v3/videos/batches` |\n| `batches.get(batchId, params?)` | `GET /v3/videos/batches/{batch_id}` |\n| `createV2(body)` *(deprecated)* | `POST /v2/videos` |\n| `getV2(videoId)` *(deprecated)* | `GET /v2/videos/{video_id}` |\n| `listV2(params?)` *(deprecated)* | `GET /v2/videos` |\n| `deleteV2(videoId)` *(deprecated)* | `DELETE /v2/videos/{video_id}` |\n\n### Video Agent — `heygen.videoAgents`\n\n| Method | Endpoint |\n| --- | --- |\n| `create(body)` | `POST /v3/video-agents` |\n| `get(sessionId)` | `GET /v3/video-agents/{session_id}` |\n| `list(params?)` | `GET /v3/video-agents` |\n| `sendMessage(sessionId, body)` | `POST /v3/video-agents/{session_id}` |\n| `stop(sessionId, body?)` | `POST /v3/video-agents/{session_id}/stop` |\n| `listVideos(sessionId)` | `GET /v3/video-agents/{session_id}/videos` |\n| `getResource(sessionId, resourceId)` | `GET /v3/video-agents/{session_id}/resources/{resource_id}` |\n| `listStyles(params?)` | `GET /v3/video-agents/styles` |\n| `generateV1(body)` *(deprecated)* | `POST /v1/video_agent/generate` |\n\n### Avatars — `heygen.avatars`\n\n| Method | Endpoint |\n| --- | --- |\n| `create(body)` | `POST /v3/avatars` |\n| `listGroups(params?)` | `GET /v3/avatars` |\n| `getGroup(groupId)` | `GET /v3/avatars/{group_id}` |\n| `deleteGroup(groupId)` | `DELETE /v3/avatars/{group_id}` |\n| `createConsent(groupId, body)` | `POST /v3/avatars/{group_id}/consent` |\n| `looks.list(params?)` | `GET /v3/avatars/looks` |\n| `looks.get(lookId)` | `GET /v3/avatars/looks/{look_id}` |\n| `looks.update(lookId, body)` | `PATCH /v3/avatars/looks/{look_id}` |\n| `looks.delete(lookId)` | `DELETE /v3/avatars/looks/{look_id}` |\n\n### Avatar Realtime — `heygen.avatarRealtime`\n\n| Method | Endpoint |\n| --- | --- |\n| `createSession(body)` | `POST /v3/avatar-realtime` |\n| `getSession(streamId)` | `GET /v3/avatar-realtime/{stream_id}` |\n| `appendText(streamId, body)` | `POST /v3/avatar-realtime/{stream_id}/text` |\n| `cancel(streamId)` | `POST /v3/avatar-realtime/{stream_id}/cancel` |\n| `streamWords(streamId)` — async iterator over SSE | `GET /v3/avatar-realtime/{stream_id}/words` |\n\n### Voices & audio — `heygen.voices`, `heygen.audio`\n\n| Method | Endpoint |\n| --- | --- |\n| `voices.list(params?)` | `GET /v3/voices` |\n| `voices.get(voiceId)` | `GET /v3/voices/{voice_id}` |\n| `voices.delete(voiceId)` | `DELETE /v3/voices/{voice_id}` |\n| `voices.clone(body)` | `POST /v3/voices/clone` |\n| `voices.design(body)` | `POST /v3/voices` |\n| `voices.speech(body)` — TTS | `POST /v3/voices/speech` |\n| `voices.textToSpeechV1(body)` *(deprecated)* | `POST /v1/audio/text_to_speech` |\n| `voices.listV1(params?)` *(deprecated)* | `GET /v1/audio/voices` |\n| `audio.searchSounds(params)` | `GET /v3/audio/sounds` |\n\n### Templates — `heygen.templates`\n\n| Method | Endpoint |\n| --- | --- |\n| `list(params?)` | `GET /v3/templates` |\n| `get(templateId)` | `GET /v3/templates/{template_id}` |\n| `generate(templateId, body)` | `POST /v3/templates/{template_id}` |\n\n### Video translation — `heygen.videoTranslations`\n\n| Method | Endpoint |\n| --- | --- |\n| `create(body)` | `POST /v3/video-translations` |\n| `get(id)` | `GET /v3/video-translations/{video_translation_id}` |\n| `list(params?)` | `GET /v3/video-translations` |\n| `update(id, body)` | `PATCH /v3/video-translations/{video_translation_id}` |\n| `delete(id)` | `DELETE /v3/video-translations/{video_translation_id}` |\n| `listLanguages()` | `GET /v3/video-translations/languages` |\n| `statuses(params?)` | `GET /v3/video-translations/statuses` |\n| `proofreads.create(body)` | `POST /v3/video-translations/proofreads` |\n| `proofreads.get(id)` | `GET /v3/video-translations/proofreads/{proofread_id}` |\n| `proofreads.downloadSrt(id)` | `GET /v3/video-translations/proofreads/{proofread_id}/srt` |\n| `proofreads.uploadSrt(id, body)` | `PUT /v3/video-translations/proofreads/{proofread_id}/srt` |\n| `proofreads.generateVideo(id, body?)` | `POST /v3/video-translations/proofreads/{proofread_id}/generate` |\n| `batches.create(body)` | `POST /v3/video-translations/batches` |\n| `batches.get(batchId, params?)` | `GET /v3/video-translations/batches/{batch_id}` |\n| `createV2(body)` *(deprecated)* | `POST /v2/video_translate` |\n| `listTargetLanguagesV2()` *(deprecated)* | `GET /v2/video_translate/target_languages` |\n| `getCaptionV2(params)` *(deprecated)* | `GET /v2/video_translate/caption` |\n\n### Lipsync — `heygen.lipsyncs`\n\n| Method | Endpoint |\n| --- | --- |\n| `create(body)` | `POST /v3/lipsyncs` |\n| `get(lipsyncId)` | `GET /v3/lipsyncs/{lipsync_id}` |\n| `list(params?)` | `GET /v3/lipsyncs` |\n| `update(lipsyncId, body)` | `PATCH /v3/lipsyncs/{lipsync_id}` |\n| `delete(lipsyncId)` | `DELETE /v3/lipsyncs/{lipsync_id}` |\n| `statuses(params?)` | `GET /v3/lipsyncs/statuses` |\n| `batches.create(body)` | `POST /v3/lipsyncs/batches` |\n| `batches.get(batchId, params?)` | `GET /v3/lipsyncs/batches/{batch_id}` |\n\n### HyperFrames — `heygen.hyperframes`\n\n| Method | Endpoint |\n| --- | --- |\n| `renders.create(body)` | `POST /v3/hyperframes/renders` |\n| `renders.get(renderId)` | `GET /v3/hyperframes/renders/{render_id}` |\n| `renders.list(params?)` | `GET /v3/hyperframes/renders` |\n| `renders.delete(renderId)` | `DELETE /v3/hyperframes/renders/{render_id}` |\n\n### AI Clipping — `heygen.aiClipping`\n\n| Method | Endpoint |\n| --- | --- |\n| `create(body)` | `POST /v3/ai-clipping` |\n| `get(jobId)` | `GET /v3/ai-clipping/{job_id}` |\n| `list(params?)` | `GET /v3/ai-clipping` |\n| `delete(jobId)` | `DELETE /v3/ai-clipping/{job_id}` |\n\n### Assets — `heygen.assets`\n\n| Method | Endpoint |\n| --- | --- |\n| `upload(file, params?)` — multipart | `POST /v3/assets` |\n| `get(assetId)` | `GET /v3/assets/{asset_id}` |\n| `list(params)` | `GET /v3/assets` |\n| `delete(assetId)` | `DELETE /v3/assets/{asset_id}` |\n| `search(params)` | `GET /v3/assets/search` |\n| `createDirectUpload(body)` | `POST /v3/assets/direct-uploads` |\n| `completeUpload(assetId, body?)` | `POST /v3/assets/{asset_id}/complete` |\n| `statuses(params?)` | `GET /v3/assets/statuses` |\n| `batches.createDirectUploads(body)` | `POST /v3/assets/direct-uploads/batches` |\n| `batches.complete(body)` | `POST /v3/assets/complete/batches` |\n| `batches.get(batchId, params?)` | `GET /v3/assets/batches/{batch_id}` |\n\n### Webhooks — `heygen.webhooks`\n\n| Method | Endpoint |\n| --- | --- |\n| `endpoints.create(body)` | `POST /v3/webhooks/endpoints` |\n| `endpoints.list(params?)` | `GET /v3/webhooks/endpoints` |\n| `endpoints.update(endpointId, body)` | `PATCH /v3/webhooks/endpoints/{endpoint_id}` |\n| `endpoints.delete(endpointId)` | `DELETE /v3/webhooks/endpoints/{endpoint_id}` |\n| `endpoints.rotateSecret(endpointId)` | `POST /v3/webhooks/endpoints/{endpoint_id}/rotate-secret` |\n| `listEventTypes()` | `GET /v3/webhooks/event-types` |\n| `listEvents(params?)` | `GET /v3/webhooks/events` |\n| `verify(params)` | — HMAC verification helper |\n\n### Brand, users, workflows, background removal\n\n| Method | Endpoint |\n| --- | --- |\n| `brand.listKits(params?)` | `GET /v3/brand-kits` |\n| `brand.listGlossaries(params?)` | `GET /v3/brand-glossaries` |\n| `users.me()` | `GET /v3/users/me` |\n| `users.meV1()` *(deprecated)* | `GET /v1/user/me` |\n| `workflows.list()` | `GET /v1/workflows` |\n| `workflows.createExecution(body)` | `POST /v1/workflows/executions` |\n| `workflows.createGraphExecution(body)` | `POST /v1/workflows/graph-executions` |\n| `workflows.getExecution(executionId)` | `GET /v1/workflows/executions/{execution_id}` |\n| `backgroundRemovals.create(body)` | `POST /v3/background-removals` |\n| `backgroundRemovals.get(jobId)` | `GET /v3/background-removals/{job_id}` |\n| `backgroundRemovals.list(params?)` | `GET /v3/background-removals` |\n| `backgroundRemovals.delete(jobId)` | `DELETE /v3/background-removals/{job_id}` |\n\n### Legacy API — `heygen.legacy`\n\nThe complete pre-v3 surface (supported by HeyGen until **October 31, 2026**). Prefer the v3 resources above for new work; these methods return loosely-typed objects where HeyGen does not document response schemas.\n\n| Namespace | Endpoints |\n| --- | --- |\n| `legacy.streaming` | `newSession`, `startSession`, `listSessions`, `sendTask`, `interruptTask`, `stopSession`, `createSessionToken`, `listAvatars` — `/v1/streaming.*` |\n| `legacy.photoAvatars` | `generatePhotos`, `generateLooks`, `getGeneration`, `createGroup`, `addLooksToGroup`, `train`, `getTrainingStatus`, `addMotion`, `addSoundEffect`, `upscale`, `get`, `listGroups`, `listGroupAvatars` — `/v2/photo_avatar/*`, `/v2/avatar_group*` |\n| `legacy.videoAvatars` | `create`, `getStatus`, `delete` — `/v2/video_avatar` |\n| `legacy.videos` | `generate`, `getStatus`, `list`, `delete`, `createWebm` — `/v2/video/generate`, `/v1/video_status.get`, `/v1/video.list`, `/v1/video.delete`, `/v1/video.webm` |\n| `legacy.templates` | `list`, `get`, `generate`, `getVariableSchema` — `/v2/templates`, `/v2/template/{id}`, `/v2/template/{id}/generate`, `/v3/template/{id}` |\n| `legacy.webhooks` | `listEndpoints`, `addEndpoint`, `updateEndpoint`, `deleteEndpoint`, `listAvailableEvents` — `/v1/webhook/*` |\n| `legacy.folders` | `create`, `list`, `update`, `trash`, `restore` — `/v1/folders*` |\n| `legacy.brandVoices` | `list`, `update` — `/v1/brand_voice/*` |\n| `legacy.avatars` | `list` — `GET /v2/avatars` |\n| `legacy.voices` | `list` — `GET /v2/voices` |\n| `legacy.user` | `getRemainingQuota` — `GET /v2/user/remaining_quota` |\n| `legacy.videoTranslate` | `getStatus` — `GET /v2/video_translate/{id}` |\n| `legacy.assets` | `upload(file, contentType)` — `POST upload.heygen.com/v1/asset` |\n\n## Types\n\nEvery schema in HeyGen's OpenAPI spec is exported by name:\n\n```ts\nimport type { CreateVideoV3RequestBody, VideoDetail, AvatarLookItem } from \"@eldritchlogic/heygen-sdk\";\n```\n\n## Regenerating types\n\nThe specs are vendored in `specs/`. To refresh from HeyGen's published spec:\n\n```bash\ncurl -s https://developers.heygen.com/openapi/external-api.json -o specs/external-api.json\nnpm run gen:types   # regenerates src/generated/*, then `npm test` verifies coverage\n```\n\nIf HeyGen adds an endpoint, the coverage test fails until the SDK implements it.\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-cc30ae6937aa541316024df8cc3fd73d"}