FISLFinding Internet Structures & Links
A CID proves what the bytes are. It does not say where to get them. FISL is an HTTP lookup that answers that question, and atfisl publishes the answers on the AT Protocol.
A CID says what, not where
Content addressing decouples two questions that usually travel together: what the data is, and where you get it. Given a CID, a client can verify the bytes it receives no matter who served them. That leaves one question open, and it is the awkward one — who has them?
RASL answers it with hints baked into a URL at the time of writing. Hints go stale: domains lapse, mirrors move, certificates expire. FISL makes the answer dynamic. A client asks at the moment of retrieval, and gets back what publishers announce right now.
Two specifications
They fit together, and either works without the other.
dev.fisl.at records to their own AT Protocol repository. Every record is signed, and moves hosts with its publisher.
→
How it works
Publish
A publisher writes a record to their repository saying “this CID is retrievable at these URLs, until this time”. The record key is the CID itself, so a put replaces the announcement and a delete retracts it. There is no separate revocation mechanism.
Index
An indexer follows the firehose or backfills repositories, verifies each record was in a signed commit, and stores one row per publisher and CID. Indexers store what publishers said, not what is true — they never fetch the URLs.
Look up, then verify
A client sends the CID, gets back locations, fetches whichever transport it supports, and hashes the bytes. A wrong answer costs one failed request, not a corrupted file. That is what makes it safe to take location claims from strangers.
The lookup API
GET /routing/locations/{cid}/{format}
The format is named by the path, not negotiated with Accept, which keeps every
answer cacheable under exactly one URL. Indexers must support both json and
jsonl.
{
"locations": [
{
"publisher": "did:plc:ewvi7nxzyoun6zhxrhs64oiz",
"addrs": [
{
"url": "https://berjon.com/.well-known/rasl/bafkreifn5yxi7nkftsn46b6x26grda57ict7md2xuvfbsgkiahe2e7vnq4"
},
{ "url": "https://mirror.example.com/kitten.jpg", "expires": "2026-09-01T00:00:00Z" }
],
"size": 94201,
"expires": "2026-09-18T00:00:00Z"
}
]
}
200, not a 404.
The empty answer is {"locations": []}. A 404 means the indexer does
not support that format, and a 400 means the CID did not parse.
Try it
Because an atfisl record key is the CID, a publisher's PDS answers “do you serve this CID?” in one request — no indexer in the middle. The playground does exactly that, live, against the real network.
dev.fisl.at record to your own repository
→
Read the Lexicon
The full schema for the record, as published to a repository
→