Docs/IPNS Tutorial
Tutorial

InterPlanetary Name System (IPNS)

IPNS enables mutable references to IPFS content, solving the problem of sharing updated content without distributing new CIDs.

Understanding IPNS

The Challenge with IPFS Content

IPFS provides content-addressed storage where every file is referenced by its unique CID. When content changes, its CID changes too.

How IPNS Solves This

IPNS creates a persistent, updateable name that can point to different CIDs over time.

Key concepts

TermDescription
IPNS keyEd25519 keypair that signs records; created and held server-side
IPNS namePublic identifier derived from that key (k51q…)
IPNS recordSigned statement binding the name to a CID
VersionThis platform's addition: every publish is retained in history

1. Create a pointer

POST /api/ipns/create generates a key and publishes the first record.

bash
curl -X POST https://api.ekayana.com/api/ipns/create \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "cid": "QmXyz…", "file_name": "protocol.pdf" }'

The returned record carries the stable name plus the CID it currently points at:

json
{
  "id": 1,
  "ipns_name": "k51qzi5uqu5d…",
  "ipns_key_name": "…",
  "current_cid": "QmXyz…",
  "original_cid": "QmXyz…",
  "file_name": "protocol.pdf",
  "owner_user_id": 42,
  "version": 1
}

Share ipns_name. It never changes again.

2. Publish an update

Upload the new revision to get a new CID, then repoint the name:

bash
curl -X POST https://api.ekayana.com/api/ipns/update \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "ipns_name": "k51qzi5uqu5d…", "cid": "QmNewCid…" }'

version increments and current_cid moves; original_cid still records where the pointer started.

Updating requires write access: either you own the record, or you supply a UCAN granting write - as the optional ucan_token field in the body, or as an X-UCAN-Token header. That is how a collaborator publishes a revision without owning the pointer.

3. Read

OperationEndpoint
Record by nameGET /api/ipns/{ipns_name}
Record by original CIDGET /api/ipns/by-cid/{cid}
Resolve to current CIDGET /api/ipns/{ipns_name}/resolve
Version historyGET /api/ipns/{ipns_name}/versions
bash
curl https://api.ekayana.com/api/ipns/k51qzi5uqu5d…/resolve \
  -H "Authorization: Bearer $TOKEN"
json
{ "ipns_name": "k51qzi5uqu5d…", "cid": "QmNewCid…" }

History is the point for research data

GET /api/ipns/{ipns_name}/versions returns every CID the name has pointed to:

json
{ "ipns_name": "k51qzi5uqu5d…", "versions": [ … ], "total": 3 }

Superseding a dataset does not erase it. A paper citing version 1 keeps resolving to the exact bytes that were reviewed, because that CID is still pinned, while new readers following the name get the current revision. Mutable reference, immutable history.

Practical notes

  • Resolution is slower than a CID fetch. It costs a DHT lookup, so cache the result and refresh in the background rather than resolving per request.
  • Cite CIDs, publish IPNS names. Use the IPNS name where readers should track the latest revision; use the CID where a reference must never move.
  • Keys live server-side. There is no export endpoint - a pointer is bound to the account that created it.