TypeScript SDK setup
Keep your API key on your server. See SDK timeouts and recovery.
TypeScript
Section titled “TypeScript”Requires Node.js 20+ or Bun. The archive includes compiled JavaScript, types, client source, README, and license.
npm install https://docs.omnapi.com/sdk/omnapi-typescript-0.5.0.tgzimport { existsSync, readFileSync, writeFileSync } from "node:fs";import { OmnapiClient, OmnapiError } from "@omnapi/sdk";
const client = new OmnapiClient({ apiKey: process.env.OMNAPI_KEY!, fetch: (url, init) => fetch(url, { ...init, signal: init?.signal ?? AbortSignal.timeout(30_000), }),});
// Load this key and body from your durable job record on retries.const idempotencyKey = process.env.OMNAPI_REQUEST_KEY!;if (!idempotencyKey) throw new Error("Set and persist OMNAPI_REQUEST_KEY first");try { const receipt = existsSync("song-receipt.json") ? JSON.parse(readFileSync("song-receipt.json", "utf8")) : await client.generateSunoSong( { mode: "simple", prompt: "warm indie pop, brushed drums", model: "chirp-hawk" }, { idempotencyKey }, ); writeFileSync("song-receipt.json", JSON.stringify(receipt), { mode: 0o600 }); // On restart, read the receipt above and resume the existing Task. const task = await client.waitForTask(String(receipt.taskId), { timeoutMs: 30 * 60_000 }); if (task.status !== "COMPLETED") throw new Error(`Task ended: ${task.status}`); const song = task.resources?.find(resource => resource.type === "MUSIC"); console.log(song?.url);} catch (error) { if (error instanceof OmnapiError) { console.error(error.status, error.code, error.requestId); // Inspect details for taskId, and rateLimit.retryAfter for backoff. } throw error;}This excerpt assumes a durable job store. The downloadable HTTP programs show the persistence step in full. Do not regenerate a key after an uncertain POST. See MV contracts and the character-lock quote limitation before using MV helpers; the package README carries the same restrictions.