The provider protocol
A provider is where music comes from. Let’s DJ ships with none.
A provider is an HTTP service, never code we load. We do not execute your implementation, sandbox it, or manage its lifecycle. That means it can be written in any language, and it means your content never passes through our infrastructure.
This specification is written to stand on its own. The code of Let’s DJ is private, so there is no implementation to read beside it, and anything it left to inference would be something you could only find out by being refused. Where it gives a figure, a default, or an error code, that is how the service behaves today. Where it says nothing, such as which language you write in or how you store your files, the choice is yours and nothing here depends on it.
Words used here
The service is the Let’s DJ backend, at https://api.lets.dj. Every path in this specification that begins /providers/ is relative to it. All of them are HTTPS.
A library is what a connected provider is called in the app. A person who has connected one is its owner, and an owner may have several. Each library has its own sync token, so two providers on one machine are two libraries and need a token each.
A party is one session. It has a Stage, the screen everybody watches: a web page at app.lets.dj, open in a browser on a television or a laptop. Guests use phones to search and queue. Only the Stage plays anything.
A track is one song or video. The catalogue is the list of tracks a provider has. Media is the audio or video itself.
The sync token is the secret that identifies one library to the service. The media token is a different secret, one you generate, which protects your media.
The bridge is the program Let’s DJ publishes for sharing a folder of files from a computer. It is an ordinary provider, and it is used as the example wherever an example helps. Nothing in this protocol gives it a privilege another provider lacks.
The two halves
Catalogue and media travel different paths, and the split matters.
Catalogue metadata goes to the service. Guests search from their phones, and a phone should not need to reach your server: it may be on cellular, or on a different network entirely. So the catalogue is mirrored into the service, and search is one query across every provider in a party.
Media goes straight to the Stage. The screen fetches bytes from you directly. They are never proxied through us. This is deliberate: it keeps latency at LAN speed for local providers, keeps our bandwidth costs at zero, and keeps us out of the content path.
Which direction the catalogue moves depends on whether we can reach you:
- You are reachable from the internet (a licensed catalogue, a hosted service): we pull, on a schedule, with whatever credentials the owner gave us.
- You are not (anything on a home network): you push, whenever your library changes.
The push direction is what the bridge uses, and it is what the rest of this specification describes. The pull direction is implemented for one provider kind so far, an S3-compatible bucket, described in Cloud storage, and stays open to any other reachable source later.
What a provider does, in order
- Connect. Get a sync token by showing the owner a code and waiting for them to approve it. See Connecting a provider.
- Be reachable by a browser. The Stage is an HTTPS page, so your media needs an HTTPS address with a certificate a browser already trusts. A provider on a home network can ask us for a name and the certificate that goes with it, or bring its own. See A name and a certificate.
- Serve media. One route, with range requests. See Serving media.
- Send the catalogue, and artwork if you have it, and say what you are: Sending a catalogue and Capabilities.
- Keep it true. Send again when your library changes. Fetch a new certificate before the old one expires. If you opted in, collect and answer jobs: Answering on demand.
Conventions
Bodies are JSON in UTF-8, except media, which is bytes, and artwork, which is an image. Fields this specification does not mention are ignored. A string that is empty is treated as absent. Numbers must be finite.
Authentication is Authorization: Bearer <sync token> on every request to /providers/…, with two exceptions that belong to connecting: starting a pairing takes no credential, and polling one takes the poll secret instead. See Connecting a provider.
Errors are a non-2xx status and a JSON body, { "error": "<words>" }. The routes added more recently, for pairing, the address and the certificate, also carry "code": "<machine-readable>". Act on the status, and on code where there is one. Never act on the words, which are written for a person and may change.
- 400 means the request was malformed, and the
errorsays which part. - 401 means there was no bearer token.
- 403 means the token is not known. For a sync token that is permanent: the library was deleted. Stop retrying, discard the token, and connect again, and only when somebody is there to approve it. Opening a pairing prompt in front of a person who has walked away is worse than staying stopped.
- 404 means the thing you named is not there: an unknown track for artwork, an unknown job.
- 429, 502 and 503 are ours and are worth retrying. Wait for as long as
Retry-Aftersays when it is present, and back off when it is not.
Compatibility. Every field added to this protocol so far has been optional, and absent means what it meant before the field existed. A provider written before any of them is unaffected by them.
Frequency. The service does not rate limit these routes today, and that is not an invitation. Send when your library changes; the bridge also rescans every five minutes as a backstop, because watching a folder quietly misses changes on network shares. Poll for jobs about once a second, and only if you opted in.