ATProto Lexicon Resolution Setup Guide
This guide explains how to set up and deploy ATProto lexicon resolution for BridgeBeats's custom media lookup and playlist lexicons, ensuring compliance with the AT Protocol Lexicon Specification.
Table of Contents
Overview
BridgeBeats uses custom ATProto lexicons to store music lookup results and user playlists as structured records on ATProto Personal Data Servers (PDS).
Lexicons:
link.bridgebeats.lookup— Music lookup results (stored on the BridgeBeats server PDS)link.bridgebeats.playlist— User playlists with cross-platform substitutions (stored on the user's PDS)
The link.bridgebeats.lookup NSID is also a code constant: ATProtoStorageService registers the collection as new Nsid("link.bridgebeats.lookup"). Changing the NSIDs would break ATProto compatibility for existing records. The authority domain for serving the lexicon schemas is bridgebeats.link.
According to the ATProto specification, lexicon schemas must be:
- Published at a predictable HTTPS endpoint on the authority domain
- Optionally registered via DNS TXT records for stronger authority verification
- Served with proper CORS headers for cross-origin access
- Accessible to ATProto clients and tools for schema validation
BridgeBeats serves the published schema files from wwwroot/.well-known/atproto-lexicon/ as static files with Content-Type: application/json; charset=utf-8, an Access-Control-Allow-Origin: * header (along with Access-Control-Allow-Methods: GET, HEAD, OPTIONS), and a one-day cache. This serving behavior is configured in StartupExtensions.
Lexicon Schemas
link.bridgebeats.lookup
The lookup lexicon schema is located at:
src/BridgeBeats.Web/wwwroot/.well-known/atproto-lexicon/link.bridgebeats.lookup
And is served at:
https://bridgebeats.link/.well-known/atproto-lexicon/link.bridgebeats.lookup
Schema structure
The lexicon defines two types:
main (record type), keyed by
any. Its record requiresresultsandlookedUpAt:results: array of provider results (1–10 items)lookedUpAt: ISO8601 datetime timestamp
providerResult (embedded object), requiring
provider,artist,title,url, andmarketRegion:provider: enum (appleMusic,spotify,tidal)artist: string (max 500 chars)title: string (max 500 chars)externalId: optional ISRC (tracks) or UPC (albums) string (max 50 chars)url: URI string (max 2000 chars)artUrl: optional URI string (max 2000 chars)marketRegion: ISO3166-1 alpha-2 country code (max 2 chars, defaultus)isAlbum: boolean (true for albums/EPs, false for tracks)
See the lexicon file for the complete JSON schema definition.
link.bridgebeats.playlist
The playlist lexicon schema is located at:
src/BridgeBeats.Web/wwwroot/.well-known/atproto-lexicon/link.bridgebeats.playlist
And is served at:
https://bridgebeats.link/.well-known/atproto-lexicon/link.bridgebeats.playlist
Schema structure
The playlist lexicon supports user-created playlists stored on the user's own PDS (not the BridgeBeats server PDS).
main (record type), keyed by
tid. Its record requirestitle,createdBy,updatedAt,lookupRepository, andtracks:title: string (required, max 300 chars / max 100 graphemes)description: optional string (max 3000 chars / max 1000 graphemes)createdBy: DID of the playlist creator (required)updatedAt: ISO 8601 UTC datetime timestamp (required)lookupRepository: DID of the repository containing the referencedlink.bridgebeats.lookuprecords (required; defaults to the BridgeBeats server DID)tracks: array of rkey strings referencinglink.bridgebeats.lookuprecords (1–16,384 items)substitutions: optional per-provider track substitutions
substitutionMap (embedded object): maps each provider name to its index substitutions.
appleMusic: anindexSubstitutionsmap for Apple Musicspotify: anindexSubstitutionsmap for Spotifytidal: anindexSubstitutionsmap for Tidal
indexSubstitutions (embedded object): maps zero-based track-index strings to substitute track rkeys.
Key design decisions
Tracks are rkeys, not full AT-URIs: to support up to 16,384 tracks within ATProto's record-size limit, tracks are stored as rkey strings rather than full AT-URIs. Each rkey is at most 18 characters in the format
track:{ISRC}and must carry a valid ISRC. ThelookupRepositoryfield provides the DID needed to reconstruct full AT-URIs. ThePlaylistRecordcontract notes that albums are expanded to individual tracks.Substitutions enable cross-platform flexibility: when a track isn't available on a specific provider, users can specify an alternative track for that provider at a given playlist position.
User PDS storage: unlike lookup records (stored on the BridgeBeats server PDS), playlist records are stored on the user's own PDS, giving users full ownership of their playlist data.
TID-based record keys: playlist record keys use Timestamp Identifiers (TIDs) for chronological sorting, rather than deterministic keys. This is reflected in the lexicon's
"key": "tid".
See the lexicon file for the complete JSON schema definition.
Creating the lexicon/schema record
Use goat to create the schema records.
The commands below are recovered from the prior version of this guide. Verify the PDS hostname (
stage-atproto.pds.bridgebeats.link), the secrets path, and the currentgoatCLI flags against your deployment before running them; they were not re-validated against a running PDS for this revision.
Lookup lexicon
cp BridgeBeats/src/BridgeBeats.Web/wwwroot/.well-known/atproto-lexicon/link.bridgebeats.lookup ./link.bridgebeats.lookup.json
goat account login -u "stage-atproto.pds.bridgebeats.link" --app-password $(cat BridgeBeats/secrets/atproto_password.txt)
goat record create --rkey link.bridgebeats.lookup ./link.bridgebeats.lookup.json
Playlist lexicon
cp BridgeBeats/src/BridgeBeats.Web/wwwroot/.well-known/atproto-lexicon/link.bridgebeats.playlist ./link.bridgebeats.playlist.json
goat account login -u "stage-atproto.pds.bridgebeats.link" --app-password $(cat BridgeBeats/secrets/atproto_password.txt)
goat record create --rkey link.bridgebeats.playlist ./link.bridgebeats.playlist.json
The output from the record-create command will look something like this:
at://did:plc:{did_value}/com.atproto.lexicon.schema/link.bridgebeats.lookup ...
at://did:plc:{did_value}/com.atproto.lexicon.schema/link.bridgebeats.playlist ...
Take the DID portion did:plc:{did_value} and create your DNS TXT record.
DNS Configuration
To establish domain authority for the lexicon NSID, configure DNS TXT records. This step is required for full ATProto compliance and stronger trust.
Required DNS TXT records
Add the following DNS TXT record to your domain (bridgebeats.link):
- Record Type: TXT
- Host/Name:
_lexicon - Value:
did=<your-did-here> - TTL: 3600 (1 hour) or your preferred value
Example DNS configuration
_lexicon.bridgebeats.link. 3600 IN TXT "did=did:plc:your-did-identifier"