npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@motosan-dev/sunoapi

v0.2.1

Published

TypeScript SDK for [sunoapi.org](https://sunoapi.org) — a third-party API for Suno AI music generation.

Readme

@motosan-dev/sunoapi

TypeScript SDK for sunoapi.org — a third-party API for Suno AI music generation.

Zero external dependencies, uses native fetch.

Installation

npm install @motosan-dev/sunoapi

Quick Start

import { SunoApiClient } from "@motosan-dev/sunoapi";

const client = new SunoApiClient({
  apiKey: "your-api-key",
});

// Generate music and wait for completion
const result = await client.generateAndWait({
  prompt: "A chill lo-fi hip hop beat for studying",
  customMode: false,
  instrumental: true,
});

console.log(result.response?.sunoData);

Initialization

const client = new SunoApiClient({
  apiKey: "your-api-key",          // Required. Get from sunoapi.org
  baseUrl: "https://api.sunoapi.org", // Optional. Default value
  callbackUrl: "https://your-webhook.com/callback", // Optional. Global default callback URL
  pollingInterval: 5000,           // Optional. Polling interval (ms). Default: 5000
  pollingTimeout: 120000,          // Optional. Polling timeout (ms). Default: 120000
});

callBackUrl Priority

  1. Method parameter — each request can specify its own
  2. Config global settingnew SunoApiClient({ callbackUrl: "..." })
  3. Built-in placeholderhttps://example.com/callback when none is provided

API

Music Generation

generate(params)GenerateTaskResult

Submit a music generation task. Returns a taskId. Each request produces 2 tracks. Non-blocking.

const { taskId } = await client.generate({
  prompt: "Japanese city pop with funky bass",
  customMode: false,
  instrumental: false,
  model: "V4",               // Optional. Default: "V4"
  style: "City Pop",         // Optional
  title: "Tokyo Nights",     // Optional
  negativeTags: "heavy metal", // Optional
  vocalGender: "f",          // Optional. "m" | "f"
  styleWeight: 0.8,          // Optional. 0.0-1.0
  callBackUrl: "https://...", // Optional
});

generateAndWait(params)MusicGenerationRecord

Generate music and automatically poll until completion. Blocking — may take several minutes.

const record = await client.generateAndWait({
  prompt: "Upbeat electronic dance music",
  customMode: false,
  instrumental: true,
});

for (const audio of record.response?.sunoData ?? []) {
  console.log(audio.audioUrl, audio.duration);
}

extend(params)GenerateTaskResult

Extend an existing music track. Non-blocking.

const { taskId } = await client.extend({
  audioId: "audio-id-from-generation",
  defaultParamFlag: true,
  model: "V4",
  prompt: "Continue with a guitar solo",
  continueAt: 30.0,          // Start extension at 30 seconds
});

extendAndWait(params)MusicGenerationRecord

Extend music and automatically poll until completion. Blocking.

const record = await client.extendAndWait({
  audioId: "audio-id",
  defaultParamFlag: false,    // Reuse original settings
  model: "V4",
});

getMusicStatus(taskId)MusicGenerationRecord

Query music generation task status. Non-blocking.

const record = await client.getMusicStatus("task-id");
console.log(record.status);
// "PENDING" | "TEXT_SUCCESS" | "FIRST_SUCCESS" | "SUCCESS"
// | "CREATE_TASK_FAILED" | "GENERATE_AUDIO_FAILED" | "SENSITIVE_WORD_ERROR"

Lyrics Generation

generateLyrics(params)GenerateTaskResult

Submit a lyrics generation task (text only, no audio). Non-blocking.

const { taskId } = await client.generateLyrics({
  prompt: "A love song about missing someone in the rain",
});

generateLyricsAndWait(params)LyricsGenerationRecord

Generate lyrics and automatically poll until completion. Blocking.

const record = await client.generateLyricsAndWait({
  prompt: "A love song about missing someone in the rain",
});

console.log(record.response?.title);
console.log(record.response?.lyrics);

getLyricsStatus(taskId)LyricsGenerationRecord

Query lyrics generation task status. Non-blocking.

const record = await client.getLyricsStatus("task-id");

WAV Conversion

convertToWav(params)GenerateTaskResult

Submit a WAV conversion task for an existing track. Non-blocking.

const { taskId } = await client.convertToWav({
  taskId: "original-task-id",
  audioId: "audio-id",
});

convertToWavAndWait(params)WavConversionRecord

Convert to WAV and automatically poll until completion. Blocking.

const record = await client.convertToWavAndWait({
  taskId: "original-task-id",
  audioId: "audio-id",
});

console.log(record.response?.audioWavUrl); // WAV download URL

getWavStatus(taskId)WavConversionRecord

Query WAV conversion task status. Non-blocking.

const record = await client.getWavStatus("wav-task-id");
// record.successFlag: "PENDING" | "SUCCESS" | "CREATE_TASK_FAILED" | "GENERATE_WAV_FAILED" | "CALLBACK_EXCEPTION"

Credits

getCredits()number

Get the remaining API credit balance. Non-blocking.

const credits = await client.getCredits();
console.log(`Remaining credits: ${credits}`);

Error Handling

import {
  SunoApiError,
  SunoApiTimeoutError,
  SunoApiGenerationError,
  SunoApiValidationError,
} from "@motosan-dev/sunoapi";

try {
  await client.generateAndWait({ ... });
} catch (error) {
  if (error instanceof SunoApiValidationError) {
    // Invalid parameters — check error.message for details
  } else if (error instanceof SunoApiTimeoutError) {
    // Polling timed out — use error.taskId to check status later
  } else if (error instanceof SunoApiGenerationError) {
    // Generation failed (e.g. GENERATE_AUDIO_FAILED)
    console.log(error.status);
  } else if (error instanceof SunoApiError) {
    // API error (HTTP error or response code !== 200)
    console.log(error.code);
  }
}

| Error Class | Trigger | |-------------|---------| | SunoApiValidationError | Invalid request parameters | | SunoApiError | API response code !== 200, or HTTP non-2xx | | SunoApiTimeoutError | Polling exceeded pollingTimeout. Includes taskId for retry | | SunoApiGenerationError | Terminal failure status (e.g. GENERATE_AUDIO_FAILED) |

Types

All types are exported directly from the package:

import type {
  SunoModel,                // "V4" | "V4_5" | "V4_5PLUS" | "V4_5ALL" | "V5"
  GenerateMusicParams,
  ExtendMusicParams,
  GenerateLyricsParams,
  ConvertToWavParams,
  GenerateTaskResult,
  MusicGenerationRecord,
  MusicGenerationStatus,
  LyricsGenerationRecord,
  WavConversionRecord,
  WavConversionStatus,
  CreditsInfo,
  SunoAudioData,
  SunoApiClientConfig,
} from "@motosan-dev/sunoapi";