Developer Guide
Push your media data to the AT Protocol and waterruupto indexes it automatically.
How it works
- You create records on your PDS in waterruupto's lexicon format
- Jetstream broadcasts the event to the network
- Our indexer picks it up, resolves metadata, and indexes it
- Your data appears on the site — and stays on your PDS
Entity reference
Every rating and comment targets an entity via an entityRef:
{
"entityType": "musicAlbum", // or "musicTrack"
"source": "spotify",
"sourceId": "4aawyAB9vmqN0BTKmVLGCR" // Spotify ID
}Supported entity types
| entityType | source | sourceId |
|---|---|---|
| musicAlbum | spotify | Spotify album ID |
| musicTrack | spotify | Spotify track ID |
More entity types and sources coming.
Rating
Collection: xyz.waterruupto.rating
{
"entityRef": {
"entityType": "musicAlbum",
"source": "spotify",
"sourceId": "4aawyAB9vmqN0BTKmVLGCR"
},
"value": 8, // 1–10
"createdAt": "2025-01-15T12:00:00Z"
}Comment
Collection: xyz.waterruupto.comment
{
"entityRef": {
"entityType": "musicTrack",
"source": "spotify",
"sourceId": "3n3Ppam7vgaVa1iaRUc9Lp"
},
"text": "The bass line on this track is incredible.",
"createdAt": "2025-01-15T12:00:00Z"
}Comments also support an optional musicClip field with startSeconds and endSeconds for referencing a specific part of a track.
Example: create a rating
Using @atproto/api to write a rating record to your PDS:
import { AtpAgent } from "@atproto/api";
const agent = new AtpAgent({ service: "https://bsky.social" });
await agent.login({ identifier: "you.bsky.social", password: "..." });
await agent.com.atproto.repo.createRecord({
repo: agent.session.did,
collection: "xyz.waterruupto.rating",
record: {
entityRef: {
entityType: "musicAlbum",
source: "spotify",
sourceId: "4aawyAB9vmqN0BTKmVLGCR",
},
value: 8,
createdAt: new Date().toISOString(),
},
});Bulk migration
Have a RateYourMusic export or Letterboxd CSV? Write a script that maps each entry to the lexicon format above and calls createRecord for each one. The indexer picks up every record automatically — no registration or API keys needed.
Lexicon source
Full lexicon schemas are in the GitHub repository.