Documentation

Bio-DID-Sequencer

Bio-DID-Seq is the API service that ties the platform together. It keeps accounts and the did:bio records those accounts own, seals files and stores them on IPFS, validates the UCAN passes that share them, plans the registry transactions a wallet signs, and proxies to BioAgents, Dataverse and an AI model. A dataset that already has a DOI keeps it. The DID record carries the DOI and the DID document points at it, so adopting a DID never means abandoning the citation infrastructure a dataset already lives in.

Clients & AuthorizationResearcherwallet, session tokenBrowser applicationsigns bytes the API preparesUCAN passeswallet signed, revocableEkayana API (bio-did-seq)axum, Postgres, private IPFS clusterAPI modulesAccounts & walletssessions, Sign In With SolanaDID recordsowned subjects, workflowsFilessealed, pinned on writeUCAN validationpq-ucan, service as executorPapersregistration, ingestionIPNS namesversions, delegated updatesStoresPostgresaccounts, records, passesPrivate IPFS clusterswarm key, replicated pinsbio-did-registryDID documents on SolanaSealed payloadsowner bound envelopesMetadata documentspublic JSON, one per DIDIPNS keysfronted peer keystoreUpstream servicesBioAgentsElizaOS agents and pluginsDataversewith the user's own tokenOpenAI / Anthropic/api/ai/*, agent text modelKnowledge basepgvector, registered papersKnowledge graphOxigraph, one graph per DOIProtein structureAlphaFold DB, UniProtsession token and wallet signaturesread and writeproxied by the API
The Bio-DID-Seq service in four layers. Clients are the researcher with a wallet and session token, the browser application that signs bytes the API prepares, and the UCAN passes a wallet signs, all reaching the Ekayana API. The API modules cover accounts and wallets, DID records and workflows, sealed files, UCAN validation, papers and IPNS names. The stores are Postgres, a private IPFS cluster and the bio-did-registry on Solana, holding sealed payloads, public metadata documents and IPNS keys. The upstream services are BioAgents on ElizaOS with its knowledge base, knowledge graph and protein structure plugins, Dataverse with the user's own token, and OpenAI or Anthropic models behind the AI routes and the agent.

How it is layered

The service splits into five layers. Each layer has a different trust model, and keeping them separate lets one be swapped or audited without touching the others.

Storage

A private IPFS cluster. Several Kubo peers share a swarm key, so they connect only to each other and never to the public network, and IPFS Cluster replicates every pin across them. Every payload is sealed under a fresh content key before it is added, and pinned on every peer as part of the write, so a CID addresses ciphertext bound to the account that uploaded it. Public metadata documents for DIDs are added in the clear and referenced from the DID document. Integrity checking is built into the address, because a tampered block does not match its CID.

Identity

The did:bio method, W3C DID 1.0 conformant, specified in bio-did-spec v1.3 and anchored on Solana through the bio-did-registry program. A researcher's DID is their wallet address and resolves generatively, with no transaction. A dataset or paper is an owned subject, a program derived address the wallet creates, updates and retires through transactions it signs and pays for. The service holds no signing key for anyone. ML-DSA-87 is a first class verification method type in the documents.

Authorization

UCAN 1.0 through pq-ucan. A share is a delegation the owner's wallet signs. A read is an invocation the recipient's browser session key signs. The service is the executor and validates the whole chain before it opens a byte. Capabilities live inside the signed payload, so a holder cannot widen a grant. Revocation is recorded here and checked on every use.

Application

Rust, axum and Postgres. Uploads can run asynchronously behind a task handle, paper ingestion runs in the background, and every request carries an id, a timeout, a body limit and a per session or per address rate budget.

Integration

The connectors outward are BioAgents for the knowledge base, the knowledge graph and protein structure lookups, the Dataverse API, called with the user's own token. The BioAgents agent itself runs on an OpenAI, Anthropic or OpenRouter model.

Application LayerResearcherwalletEkayana APIBrowser applicationNext.jsAuthorization LayerUCAN 1.0 (pq-ucan)wallet-signed delegationsSession keysbrowser key signs read invocationsIdentity Layerdid:bio documentsW3C DID 1.0Owned subjectswallet-created PDAsbio-did-registrySolana programStorage LayerPrivate IPFS clusterpinned on every peerSealed payloadsAES-GCM, ML-KEM-1024 wrapPostgresrecords, passes, sessionsIntegrationDataversedemo and HarvardBioAgentsElizaOSOpenAI / AnthropicAI routes, agent modelauthorizederive and anchorseal and storeproxy
The five layers of the service and what each one talks to. Clients and the API sit on top, then UCAN authorization, then did:bio identity backed by the registry program, then storage on the private IPFS cluster, then the Dataverse, BioAgents and model provider integrations.

The DID document and the metadata document

Two documents describe every asset. The DID document lives on the registry and holds keys, controllers and service endpoints, and nothing else. This one is for a dataset, as GET /api/did/resolve/{did} returns it, trimmed of the resolution metadata.

json
{
  "@context": ["https://www.w3.org/ns/did/v1", "https://www.w3.org/ns/cid/v1"],
  "id": "did:bio:devnet:7Qm3...",
  "verificationMethod": [{
    "id": "did:bio:devnet:7Qm3...#default",
    "type": "Multikey",
    "controller": "did:bio:devnet:7Qm3...",
    "publicKeyMultibase": "z6Mk..."
  }],
  "authentication": ["did:bio:devnet:7Qm3...#default"],
  "assertionMethod": ["did:bio:devnet:7Qm3...#default"],
  "capabilityInvocation": ["did:bio:devnet:7Qm3...#default"],
  "controller": ["did:bio:devnet:HP3Hj9en..."],
  "service": [
    { "id": "did:bio:devnet:7Qm3...#metadata", "type": "BioMetadata",
      "serviceEndpoint": "ipfs://bafkrei..." },
    { "id": "did:bio:devnet:7Qm3...#dataverse", "type": "DataverseRepository",
      "serviceEndpoint": "https://doi.org/10.7910/DVN/EXAMPLE" }
  ]
}

The #default key is the owning wallet's, so the wallet can keep changing the document. The metadata document is what the #metadata service points at. It is a public JSON file on IPFS that the API rewrites and repins whenever the record changes.

json
{
  "id": "did:bio:devnet:7Qm3...",
  "kind": "dataset",
  "doi": "10.7910/DVN/EXAMPLE",
  "title": "CRISPR-Cas9 Gene Editing Dataset",
  "description": null,
  "researchers": [
    { "name": "Jane Smith", "orcid": "0000-0001-2345-6789", "role": "Principal Investigator", "affiliation": null }
  ],
  "keywords": ["CRISPR", "gene editing", "genomics"],
  "data_type": null,
  "license": "CC-BY-4.0",
  "related_identifiers": [],
  "funding": [],
  "created": "2026-07-24T10:00:00Z",
  "updated": "2026-07-24T10:00:00Z"
}

Names and ORCIDs appear because the owner chose to publish them. An email never does.

The three workflows that matter

Most interactions with the service reduce to one of these.

Creating and anchoring a DID

The API derives the subject and publishes the metadata. The wallet writes to the chain. The API confirms by reading the chain back.

POST /api/did (kind, metadata)Derive owned subject from wallet + nonceadd metadata.json (pinned)CIDRecord, anchored: falsePOST /api/workflows (anchor)Read account, quote rentPlan: instructions, rent, feeSigned transaction, wallet paysPOST /workflows/{id}/confirm (signature)Read transaction and accountanchored: trueResearcher (wallet)Ekayana APIIPFS clusterRegistry (Solana)
Creating and anchoring a DID. The researcher posts kind and metadata. The API derives an owned subject from the wallet and a nonce, pins the metadata document on IPFS and returns the unanchored record. The researcher asks for an anchor workflow and receives the planned instructions with rent and fee, signs and sends the transaction with the wallet, and posts the signature. The API reads the transaction and the account from the registry and marks the record anchored.

Registering a paper

A paper is a file you uploaded plus a DID of kind paper. Registration feeds the file to the BioAgents knowledge base in the background and fills in metadata the knowledge graph already holds for its DOI.

POST /api/upload (file)Seal under a fresh content keyadd (pinned)CIDPOST /api/research-paper (cid, title, doi)Create paper DID, publish metadata202 pendingcat CIDOpen the envelopeUpload to the knowledge baseExtract text, chunk, embedDocument idPaper record for the DOIAbstract, venue, authors, termsFill empty fields, status completedResearcherEkayana APIIPFS clusterBioAgentsKnowledge graph
Registering a paper. The researcher uploads the file, which the API seals and pins, then posts the CID, title and DOI. The API creates a paper DID with a public metadata document and answers 202 pending. In the background it reads and opens the file, uploads it to the BioAgents knowledge base, which extracts, chunks and embeds the text, then asks the knowledge graph for the DOI's record and fills empty fields before marking the paper completed.

Sharing a file

The service prepares bytes, the wallet signs them, and the service records the pass. The recipient redeems it with an invocation their session key signed.

POST /share/file/preparesigning_bytes (DAG-CBOR)Wallet signsPOST /share/file (bytes, signature)Verify, record the passtoken, token_hashSend the tokenPOST /ucan/invoke/prepareInvocation bytes, valid 60 sSession key signsGET /download/{cid} + two headersCheck revocation, validate chaincat CIDOpen the envelopeFileOwner (wallet)CollaboratorEkayana APIIPFS cluster
Sharing a file. The owner asks the API to prepare a share, signs the returned bytes with the wallet and posts them back. The API verifies and records the pass, and the owner sends the token to the collaborator. The collaborator prepares an invocation, signs it with the browser session key and downloads with the pass and the invocation in two headers. The API validates the chain with itself as executor, checks revocation, fetches the envelope from IPFS, opens it and returns the file.

API surface

All routes live under /api and answer JSON. Unless listed as public, they take Authorization: Bearer <session token>. Errors share one envelope, described on Errors & Rate Limits.

AreaRoutes with a sessionPublic routes
HealthGET /health, GET /ready
AccountsPOST /signout, GET /users/me, GET /users/search?q=POST /signup, POST /signin
WalletsGET /wallet, POST /wallet/nonce, POST /wallet/verify, DELETE /wallet/{address}, GET /wallet/identityPOST /wallet/challenge, POST /wallet/signup, POST /wallet/signin
FilesPOST /upload[?async=true], GET /upload/status/{task_id}, GET /download/{cid}, GET /metadata/{cid}, POST /delete, GET /pins
IPNSPOST /ipns/create, POST /ipns/update?ipns_name=, GET /ipns/by-cid/{cid}, GET /ipns/{name}, GET /ipns/{name}/versions, GET /ipns/{name}/resolve
DIDsGET /did, POST /did, GET /did/{did}, PUT /did/{did}, POST /did/{did}/dataverse, POST /did/{did}/deactivate (unanchored records only)GET /did/resolve/{did}
WorkflowsGET /workflows[?did=], POST /workflows (kind is anchor, sync or deactivate), GET /workflows/{id}, POST /workflows/{id}/confirm
UCANPOST /ucan/issue/prepare, POST /ucan/issue, POST /ucan/session/prepare, POST /ucan/session, POST /ucan/invoke/prepare, POST /ucan/revoke, GET /ucan/issued, GET /ucan/received, GET /ucan/token/{cid}POST /ucan/validate
SharingPOST /share/file/prepare, POST /share/file, DELETE /share/revoke/{cid}, GET /shared
PapersPOST /research-paper, GET /research-paper/did/{did}, GET /research-paper/cid/{cid}, GET /research-paper/search?query=, PUT /research-paper/{did}, POST /research-paper/{did}/ingest, GET /research-paper/{did}/knowledge-graph
DataverseGET /dataverse/collections, POST /dataverse/dataset, POST /dataverse/dataset/file/{pid}, PUT /dataverse/dataset/metadata, POST /dataverse/dataset/publish, GET /dataverse/dataset/{pid} and its /files, /versions and /citation, GET /dataverse/search, GET /dataverse/file/{id}
BioAgentsPOST /bioagents/query, POST /bioagents/query-ws, POST /bioagents/search, POST /bioagents/knowledge, POST /bioagents/knowledge/upload?agent_id=, GET /bioagents/knowledge/searchGET /bioagents/health, GET /bioagents/agents
Knowledge graphGET /bioagents/kg/papers, GET /bioagents/kg/authors, GET /bioagents/kg/paper?doi=, GET /bioagents/kg/hypotheses, POST /bioagents/kg/askGET /bioagents/kg/health
Protein structureGET /bioagents/structure/resolve, /report, /variant, /modelsGET /bioagents/structure/health
AIPOST /ai/chat, POST /ai/process-paperGET /ai/models
CollaborationGET /ws?token=, a WebSocket carrying subscribe and sync messages between collaborators

Create a DID

bash
curl -X POST https://api.ekayana.io/api/did \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "dataset",
    "metadata": {
      "title": "Research Dataset",
      "researchers": [{ "name": "John Doe", "role": "Lead Researcher" }],
      "keywords": ["biology", "genomics"],
      "license": "CC-BY-4.0"
    }
  }'

The account needs a linked wallet, because the subject is derived from it. Without one the call answers 409. The response is the record with anchored: false. Anchoring is a separate, wallet signed workflow.

GDPR

The architecture provides the following.

  • Nothing personal is anchored on-chain. Only public keys, opaque fragments and URIs are. The metadata document carries what the owner chose to publish and never an email address.
  • Erasure is effective. Every payload is encrypted before it reaches IPFS, and its content key is wrapped to a key only the service holds. Deleting a file unpins the platform's copy, and a replica a third party fetched earlier is an envelope nobody can open.
  • Access is explicit. Every share is a signed, expiring, revocable pass naming one CID and the actions allowed. There is no ambient organisation wide read to audit around, and no API key that grants everything.
  • Deactivation is final. Retiring an anchored DID leaves a permanent tombstone on the registry rather than a gap someone could reoccupy.
  • A compromise of the service exposes ciphertext and public documents rather than authority. The service signs no passes and no transactions on a user's behalf, so there is no key on the server that could act as you.

The registry is a public program. Anyone with a keypair can write to it, and no single operator's disappearance takes your identifiers with it.