LASTWAVE ADDON DOCS

Build an addon.

An addon is a small web service that LastWave asks for lossless, Hi-Res and Dolby Atmos streams. Implement three endpoints, return the JSON shown here, and any LastWave app can use your addon.

01 / START · OVERVIEW

How an addon fits in

LastWave streams from YouTube Music by default. When a user has an addon, LastWave first asks the addon whether it has a better version of the track that’s about to play. If it does, that stream plays. If it doesn’t, playback continues from YouTube, so a missing track is never a problem.

  1. 1

    Validate

    GET manifest.json – is this a usable addon?

  2. 2

    Search

    GET search – find the closest matching track.

  3. 3

    Stream

    GET stream/{id} – return a playable source.

  4. 4

    Play

    LastWave plays it and shows the real quality.

At a glance

EndpointPurposeMinimum response
GET manifest.jsonIdentify your addonid, name, version, resources containing search and stream
GET search?q=Find the tracktracks[], each with id and title
GET stream/{id}Return the audioA playable source (url or manifestXml), plus sampleRate and bitDepth
Next: Quick start

02 / START · QUICK START

Up and running in three steps

  1. Build the three endpoints. Start from the minimal example, or follow the reference for the manifest, search and stream responses.
  2. Test them with curl. Each request should return the JSON shown in the reference.
    curl https://addon.example.com/manifest.json
    curl "https://addon.example.com/search?q=Example%20Song%20Example%20Artist&quality=hi_res&atmos=none"
    curl "https://addon.example.com/stream/48213?quality=hi_res&atmos=none"
  3. Add it to the app. On Desktop open Settings → Sources → Add addon. On Android open Provider Modules → Addon URL and use Test connection.

Stuck on step three? A row marked unreachable means nothing usable answered at that URL. Check HTTPS, the manifest, and that the root ends where manifest.json lives.

Next: Addon URL

03 / START · ADDON URL

One URL is all a user adds

Users paste a single URL: your addon’s root. LastWave appends manifest.json, search and stream/{id} to it, so all three must live under the same root.

FormExampleNotes
Standalone roothttps://addon.example.com/Simplest. A path prefix such as https://example.com/lw/ also works.
Per-user roothttps://addon.example.com/a/<token>/A hex token of 16+ characters after /a/ is treated as a private, per-user URL. Revoke a token by answering 404.

Rules

  • LastWave accepts the root with or without a trailing slash, a pasted manifest.json URL, or a deeper stream/… or search URL, and normalizes all of them to the root.
  • Use HTTPS in production. Only http and https URLs are accepted.
  • Send Access-Control-Allow-Origin: * so browsers and tools can read your responses.
  • LastWave may send extra request headers (such as a User-Agent of LastWave-Player). Ignore any header you don’t recognize.
Next: Manifest

04 / API REFERENCE · MANIFEST

Tell LastWave what you are

Request

GET{root}manifest.jsonLastWave caches the response for about 10 minutes.

Response

{
  "id": "com.example.addon",
  "name": "Example Addon",
  "version": "1.0.0",
  "resources": ["search", "stream"]
}
FieldRequiredMeaning
idYesA stable identifier for your addon, for example a reverse-DNS string.
nameYesThe name shown to users in Settings.
versionYesYour addon’s version string.
resourcesYesMust include both "search" and "stream". If either is missing, LastWave rejects the URL as “not an addon”.

Notes

  • Extra fields are ignored, so it’s safe to add your own.
Next: Search

06 / API REFERENCE · STREAM

Hand over the audio

Request

GET{root}stream/{id}?quality=…&atmos=…Returns JSON describing one playable stream.

Response

Return at least one playable source. You can use a direct file, or a DASH manifest:

Progressive file

A direct URL to a FLAC (or other audio) file.

{
  "url": "https://cdn.example.com/48213.flac",
  "format": "flac",
  "codec": "flac",
  "container": "flac",
  "sampleRate": 96000,
  "bitDepth": 24,
  "quality": "Hi-Res Lossless",
  "encrypted": false
}

DASH manifest

A URL to an .mpd, or the manifest inline as manifestXml.

{
  "url": "https://example.com/48213.mpd",
  "format": "dash",
  "manifest": "dash",
  "codec": "flac",
  "container": "mp4",
  "sampleRate": 96000,
  "bitDepth": 24,
  "quality": "Hi-Res Lossless",
  "encrypted": false
}
FieldNotes
urlThe playable source. LastWave also reads dataUrl, directUrl, streamUrl, downloadUrl and mediaUrl, and an inline manifestXml. At least one is required. If you offer both a direct file and a manifest, Desktop prefers the direct file.
format, codec, containerFor example flac / flac / flac, or dash / flac / mp4. Lossy streams use a codec such as mp4a.40.2.
sampleRateIn Hz: 44100, 48000, 96000, 192000.
bitDepthFor lossless: 16 or 24. Leave it out for lossy streams. Report the real value, because LastWave shows it to the listener and never guesses it from the bitrate.
bitrateOptional, in bits per second.
qualityA label such as Lossless, Hi-Res Lossless or Dolby Atmos.
encryptedSet to false for plain streams.

Notes

  • The audio player fetches media with no extra headers. If your media URLs need protection, put the proof in the URL itself, for example a signed link with an expiry, and have /stream mint it.
  • Respond quickly. LastWave retries a failed stream request once after about 150 ms, and gives a whole lossless lookup roughly 30 seconds in total.
Next: Quality tiers

07 / CONCEPTS · QUALITY TIERS

What the quality value means

Users pick a tier in the app. LastWave turns it into the quality value your addon receives, and if you answer 404, it steps down to the next one.

User picksLastWave sendsThen tries
Dolby Atmosatmos (with atmos=auto)hi_res, lossless, high
Hi-Res · 24/192 or 24/96hi_reslossless, high
Lossless · 16/44.1losslesshi_res, high
320khighlossless
Data saver, YouTubenothingLastWave doesn’t ask the addon for the lossless ladder.

What each value means

  • hi_res: the best you have, up to 24-bit / 192 kHz.
  • lossless: CD-quality 16-bit / 44.1 kHz FLAC.
  • high: a high-bitrate lossy stream (320 kbps class).

Notes

  • Read the value case-insensitively and be forgiving: treat hires, max or flac sensibly.
  • Serve what you actually have. A track that only exists at 16/44.1 should return that for a hi_res request instead of an error. LastWave labels it honestly from your bitDepth and sampleRate.
Next: Dolby Atmos

08 / CONCEPTS · DOLBY ATMOS

Spatial audio, only when asked

Atmos is opt-in. LastWave only wants it when the user chose Dolby Atmos, which it signals with atmos=auto and quality=atmos.

Response

{
  "url": "https://example.com/48213-atmos.mpd",
  "format": "dash",
  "manifest": "dash",
  "codec": "eac3-joc",
  "container": "mp4",
  "sampleRate": 48000,
  "quality": "Dolby Atmos",
  "audioMode": "DOLBY_ATMOS",
  "encrypted": false
}

Rules

  • Set audioMode to DOLBY_ATMOS, codec to eac3-joc (E-AC-3 with Joint Object Coding) and quality to Dolby Atmos. Atmos streams are 48 kHz.
  • Flag Atmos tracks in search results with "atmos": true or an audioModes list containing DOLBY_ATMOS.
  • Never return Atmos for a stereo request. If the user picked Hi-Res, Lossless or 320k, LastWave discards any Atmos stream it receives, so don’t send one.
  • No Atmos version? Return the stereo stream, or a 404. LastWave steps down to Hi-Res stereo. On Android it also checks that the device can render spatial audio before it plays Atmos.
Next: Errors and quota

09 / OPERATE · ERRORS AND QUOTA

Say “no” the right way

StatusMeansWhat LastWave does
200Here is a stream (or search results).Plays it.
404Unknown track, no rendition at this tier, or a revoked URL.A clean miss. Steps down a tier, then falls back to YouTube.
429The user is out of quota.Stops asking and shows the limit. Send Retry-After in seconds.
5xx or timeoutYour service is having trouble.Retries once quickly, then treats it as a miss. After several misses in a row it skips your addon for about 30 seconds.

Quota headers

If you meter usage, tell LastWave about it on your responses. Desktop shows these as quota meters in Settings:

X-Quota-Limit: 500
X-Quota-Used: 120
X-Quota-Remaining: 380

Notes

  • Only count successful stream resolutions against a quota, never searches or failed lookups.
  • Answer a revoked or unknown per-user URL with 404 on every route, so it stops working immediately and LastWave moves on.
Next: Security

10 / OPERATE · SECURITY

Treat the URL like a password

  • A per-user URL is the credential: anyone who has it plays on that user’s quota. Use long, random tokens (at least 128 bits) and offer a way to regenerate one.
  • Never put API keys or backend credentials in the URL. Keep them on your server.
  • Don’t write full tokens to your logs.
  • Serve everything over HTTPS, and validate the token format before touching your database.
  • Rate-limit your endpoints. Search and manifest requests are cheap for LastWave to repeat.
Next: Minimal example

11 / BUILD · MINIMAL EXAMPLE

A working addon in under 40 lines

This Node.js server implements the whole contract with a one-track catalog. Replace the catalog with your own source.

import express from 'express';

const app = express();
const catalog = [
  { id: '1', title: 'Example Song', artist: 'Example Artist', album: 'Example Album',
    duration: 215, file: 'https://cdn.example.com/audio/1.flac', sampleRate: 44100, bitDepth: 16 },
];

app.use((req, res, next) => { res.set('Access-Control-Allow-Origin', '*'); next(); });

app.get('/manifest.json', (req, res) => {
  res.json({ id: 'com.example.addon', name: 'Example Addon', version: '1.0.0',
             resources: ['search', 'stream'] });
});

app.get('/search', (req, res) => {
  const q = String(req.query.q || '').toLowerCase();
  const tracks = catalog
    .filter((t) => q.includes(t.title.toLowerCase()) || q.includes(t.artist.toLowerCase()))
    .map(({ file, sampleRate, bitDepth, ...track }) => ({ ...track, format: 'flac', audioQuality: 'LOSSLESS' }));
  res.json({ tracks });
});

app.get('/stream/:id', (req, res) => {
  const track = catalog.find((t) => t.id === req.params.id);
  if (!track) return res.status(404).json({ error: 'Unknown track.' });
  // No Atmos version here: serve stereo (or 404) and LastWave steps down on its own.
  res.json({
    url: track.file, format: 'flac', codec: 'flac', container: 'flac',
    sampleRate: track.sampleRate, bitDepth: track.bitDepth,
    quality: 'Lossless', encrypted: false,
  });
});

app.listen(8787, () => console.log('Addon on http://localhost:8787/'));
Next: Publish checklist

12 / BUILD · PUBLISH CHECKLIST

Before you share your addon

  • The manifest lists both search and stream.
  • Search returns id, title, artist and a duration in seconds.
  • Stream returns a playable source plus real sampleRate and bitDepth.
  • A miss is a clean 404, never a placeholder file.
  • Atmos is returned only for Atmos requests.
  • Everything is served over HTTPS and answers quickly.
  • A revoked URL answers 404 on every route.
  • You only serve audio you have the rights to provide.
Next: Get help

13 / HELP · GET HELP

Questions, or want your addon listed?

For Hi-Res addons and more info, contact support on Discord or Telegram . Tell us what your addon serves and which app you’re testing with.