Type-safe TypeScript SDK for the OpenPlay Music API.
Built for Vers1ons — a creative rights platform empowering independent artists to collaborate and monetize their work.
npm install openplay-sdk
# or
pnpm add openplay-sdk
# or
yarn add openplay-sdkimport { createClient } from 'openplay-sdk'
const client = createClient({
apiKeyId: process.env.OPENPLAY_API_KEY_ID!,
apiSecretKey: process.env.OPENPLAY_API_SECRET_KEY!,
})
// Search releases
const releases = await client.releases.search({ q: 'album name' })
// Get a specific artist
const artist = await client.artists.get('artist-id')
// Auto-paginate through all artists
for await (const artist of client.artists.searchAll()) {
console.log(artist.name)
}- Full TypeScript support with complete type definitions
- Zod schemas for runtime validation
- Auto-pagination helpers for large result sets
- Webhook signature verification
- Bulk job utilities with polling
- Presigned URL upload support
- Comprehensive error handling
The SDK covers the following OpenPlay API resources:
- Artists - Create, read, update, delete, and search artists
- Labels - Manage record labels
- Publishers - Manage publishing entities
- Projects - Handle project/album metadata
- Releases - Manage release metadata and distribution
- Tracks - Track-level operations
- Works - Musical work/composition management
- Cover Art - Upload and manage artwork
- Art Resources - Additional artwork management
You can use createClientFromEnv() which reads from these environment variables:
OPENPLAY_API_KEY_ID- Your API key IDOPENPLAY_API_SECRET_KEY- Your API secret keyOPENPLAY_BASE_URL(optional) - Custom API base URL
import { createClientFromEnv } from 'openplay-sdk'
const client = createClientFromEnv()// Search a single page of releases
const page = await client.releases.search({
q: 'album',
label: ['My Label'],
})
// Auto-paginate through all matching releases
for await (const release of client.releases.searchAll({
title: 'Greatest Hits',
})) {
console.log(release.title)
}
// Validate and submit a release for distribution
const validation = await client.releases.validate(releaseId)
if (validation.valid) {
await client.releases.distribute(releaseId)
}import { uploadWithPresignedUrl } from 'openplay-sdk'
// Create a work
const work = await client.works.create({
title: 'Song Title',
iswc: 'T-000.000.001-0',
})
// Create a track that references the work
const track = await client.tracks.create({
title: 'Song Title',
works: [{ id: work.id }],
})
// Upload audio bytes for the track via presigned URL
await uploadWithPresignedUrl(
client.http,
`/connect/v2/tracks/${track.id}/upload/song.wav`,
audioData,
'song.wav'
)// Create a new artist
const artist = await client.artists.create({ name: 'New Artist' })
// Update artist metadata
const updated = await client.artists.update(artist.id, {
biography: 'Short bio...',
country: 'US',
})
// Search artists by name or free-text query
const artistsPage = await client.artists.search({ q: 'artist name' })import { ReleaseSchema } from 'openplay-sdk/schemas'
// Validate API responses or external data
const release = ReleaseSchema.parse(apiResponse)const page1 = await client.artists.search({ limit: 50 })
const page2 = await client.artists.search({ limit: 50, offset: 50 })// Iterate through all results
for await (const artist of client.artists.searchAll()) {
console.log(artist.name)
}
// Collect all results into an array
import { collectAll } from 'openplay-sdk'
const allArtists = await collectAll(client.artists.searchAll())The SDK provides typed errors for different failure scenarios:
import {
AuthenticationError,
NotFoundError,
RateLimitError,
ValidationError,
OpenPlayError,
} from 'openplay-sdk'
try {
await client.artists.get('invalid-id')
} catch (error) {
if (error instanceof NotFoundError) {
console.log('Artist not found')
} else if (error instanceof RateLimitError) {
console.log(`Rate limited, retry after ${error.retryAfter}s`)
} else if (error instanceof AuthenticationError) {
console.log('Invalid credentials')
}
}Verify incoming webhook signatures:
import { verifyWebhookSignature } from 'openplay-sdk/webhooks'
const { valid, error } = verifyWebhookSignature({
payload: rawBody, // raw string or Buffer
signature: req.headers['x-openplay-signature'] as string,
secret: process.env.OPENPLAY_WEBHOOK_SECRET!,
})
if (!valid) {
return res.status(401).json({ error })
}
// Handle the webhook safely hereSubmit bulk jobs and poll for completion:
import { submitAndWait } from 'openplay-sdk'
// Submit a bulk job and wait for completion
const bulkResult = await submitAndWait(
() => client.releases.submitBulkJob(),
() => client.releases.getBulkJobStatus(),
{ maxWaitMs: 5 * 60_000 }
)
console.log(bulkResult.status, bulkResult.results?.length)MIT