A self-hostable server for the DeDi standard, with an append-only Merkle log underneath: signed checkpoints, inclusion and consistency proofs, and other nodes witnessing that the log was never rewritten. It is a Merkle log, not a blockchain. New here? Start with the overview, then the quickstart.
Served by this node, from the copy embedded in the binary it is running — so these are the documents for this build, not for whatever is on a branch somewhere.
What this is, how to run one, and why it is not a blockchain.
| Overview | DeDi Node is a self-hostable, open-source server for the Decentralized Directory protocol, with an append-only Merkle log underneath so anyone can check that what it serves was published… |
| Quickstart | From nothing to a signed, provable record in about five minutes. You need Docker, curl and jq. No Go toolchain and no source checkout: everything runs from the published image… |
| Why DeDi Node exists | I built this because I was running a real Beckn network in production, and the single most important component in it — the registry, the thing every party trusts to answer "who is this… |
| Architecture | What each part of the node proves, and what it does not. The short version: the log makes history checkable, witnesses make it checked, replication keeps it up, and none of those three is a… |
Getting one up, configuring it, and choosing what it does.
| Configuration | Every environment variable dedid serve reads, and every CLI subcommand. The node has no config file: one binary, configured by its environment, so the same image is every role. Unset means… |
| API | Every route the node serves, what it accepts, and what it answers. The eight /dedi/lookup|query|versions routes are the DeDi standard's read API (api/openapi.yaml); everything else is this… |
| One-click deploy | Deploying gives you a Postgres with a volume and a DeDi node pulling flywheelai/dedi-node, on a public domain, signing a checkpoint every 30 seconds. It asks you nothing — the database… |
| Deployment modes | dedid ships as one binary with three trust planes. Two of them are feature flags: set the env vars and the plane turns on, unset them and it does not exist. There are no separate builds,… |
| Replication and high availability | Raft is a crash-fault protocol. A cluster keeps the directory available when a replica dies. It does not make the directory trustworthy: three replicas run by one operator follow that… |
| Crawler and mirror | The DeDi standard has two roles: a publisher signs files and hosts them, and a server crawls publishers and answers the read API for what it found. This node is a publisher by default (file… |
The console, and every write it can make.
| The operator console | The write plane's user interface, at /admin. Five tabs. Most of what they do is a signed entry in the node's log; Domains only reads. |
| Onboarding a participant | Admitting an identity to a registry: the Participants section's Onboard a participant disclosure in the console, and the signed write behind it. This is the operation that decides who the… |
| Key rotation | Replacing the key a participant signs with, without removing the participant, and the reasoning about time that makes a rotation safe rather than an outage. |
| Revocation | Withdrawing a binding: the console's Revoke a participant panel, which opens against the participant selected in the Participants table, what "revoked" means to everyone downstream, and how… |
| Child nodes and namespace delegation | A node can now stand in three different relations to another node, and the whole design rests on not confusing them. |
| Push notification | Revocation used to travel only as fast as caches expired. Measured end to end against two live beckn-onix v1.8.0 adapters, with the participant record declaring ttl: 20: |
| Discovery: who serves a domain | Answering "who serves domain X" rather than only "what key does this known subscriber use". The console's Who serves section, and the ?domain= filter behind it. |
| Governance (v0) | How identities get into — and out of — a dedid registry. Status: v0, deliberate minimum. The signed write plane carries out these decisions; it does not make them. |
The parts that make a claim checkable by someone who does not trust you.
| Witnessing | One node checking, on a schedule, that another node's log has only ever been appended to — and recording what it found in its own log, where the target cannot reach it. This is the part… |
| File publication | This node implements the producer half of the DeDi standard's file publication model (publishing-dedi-files.md): it signs and serves a DeDi file per registry, plus a signed manifest, so a… |
Where this node and the specification agree, and where they do not.
| Conformance against the DeDi standard | Not to be confused with the dedi.global platform's own OpenAPI document (73 paths), which describes a hosted implementation, not the standard. It matters because ONIX was built against it,… |
| Open gaps against the DeDi standard | Measured against the LFDT standard at commit 52e120d. Every claim here was checked by running code or reading the spec text, never inferred from our own docs — the entries marked proven… |
| Built-in reference registry schemas | The DeDi standard ships five reference registry schemas, read-only in the spec submodule at docs/spec/lfdt/schemas/: |
Deployments that depend on it, and what they check.
| Use case: a Beckn network | Beckn is the first thing this node was built for. Every signed Beckn message is checked by the receiving ONIX adapter against the sender's key in a DeDi registry, so the registry is the… |
| Use case: CREST | CREST issues verifiable credentials for work: who did what, under which terms, on whose authority. A credential is only as good as the facts behind it, so CREST publishes those facts to a… |
The original plan, superseded where the other pages say so.
| DeDi Node — Design Document | History. This is the original plan, written in July 2026 before most of the node existed. It is kept because its reasoning still explains the code, but it describes intentions, not the node… |
sequenceDiagram
autonumber
participant BAP as ONIX · BAP
participant BPP as ONIX · BPP
participant D as dedid
BAP->>BPP: select (signed)
BPP->>D: GET /lookup/bap.example.com/subscribers.beckn.one/{keyId}
D-->>BPP: signing_public_key (+ inclusion proof)
BPP->>BPP: verify signature ✓
BPP-->>BAP: on_select (signed)
BAP->>D: lookup BPP key → verify ACK ✓
Note over D: bad/absent key → 401 reject
ONIX's registry URL is a locked constant pointing at fabric.nfh.global,
so an adapter needs a small patch to use this node; see the Beckn use case.
sequenceDiagram
autonumber
participant A as Node A · primary
participant B as Node B · witness
B->>A: GET /log/checkpoint (signed)
B->>A: GET /log/proof/consistency?old&new
B->>B: verify append-only (RFC 6962)
B->>B: record verdict in own log
Note over B: forged history → alarm
| # | Test | Result |
|---|---|---|
| 1 | Published dedi-conformance suite v0.0.1 against the public node | 22/22: core, versioning, publication, beckn |
| 2 | In-process conformance module against the pinned openapi.yaml | 5 tests, 21 subtests pass |
| 3 | ONIX dediregistry client (v1.8.0) over the wire | 6/6 pass |
| 4 | Live two-adapter Beckn network resolving keys against this node | running; see use case |
| 5 | Inclusion proof checked in the browser (WebCrypto) | /verify |
| 6 | Witness verifies a target is append-only | verdicts at /dedi/witness |
| 7 | Witness detects a forked history, and a rewrite at the same size | alarm (unit tests) |
Results measured 3 October 2026 on build sha-69bffe0; how to rerun them is in
conformance.
The read routes, relative to this node. Plain GET, no auth. Every route, its
parameters and its errors: API.
| Endpoint | Returns |
|---|---|
/dedi/lookup/{namespace}/{registry}/{record} | the current version of a record |
/dedi/lookup/{namespace}/{registry} | registry metadata and schema |
/dedi/lookup/{namespace} | namespace metadata |
/dedi/query/{namespace}[/{registry}] | a filtered, paginated listing; ?domain= for who serves a domain |
/dedi/versions/{namespace}[/{registry}[/{record}]] | full version history |
/dedi/log/checkpoint | signed tree head (C2SP checkpoint) |
/dedi/log/proof/consistency?old=&new= | append-only proof between two tree sizes |
/dedi/log/history | checkpoints and writes over time |
/dedi/witness[/{origin}] | what this node has verified about other logs |
/dedi/delegations/{namespace} | child namespaces delegated, and their witness verdicts |
/dedi/network | peers, reachability, witness health, cluster state |
/dedi/stats | requests served, by status class, plus uptime |
/.well-known/dedi.index.json | signed DeDi manifest; files under /dedi-files/ |
/healthz, /metrics | liveness for probes; Prometheus metrics |
Lookup modifiers: ?proof=inclusion attaches a Merkle inclusion proof and the
signed checkpoint it verifies against; ?version_id= pins an exact version;
?as_on= resolves the record as of a date (YYYY-MM-DD, the close of that day in UTC) or an RFC 3339 timestamp.
Unknown or repeated parameters are a 400, never silently ignored. Example against the public
node (on your own node, use your host and a record you published):
curl -s "https://dedi.beckn.try-dough.com/dedi/lookup/bpp.example.com/subscribers.beckn.one/76EU7ofwRCF1aobQkShARrf1PAUsNpHqWUJoynPu9w45YFKmzqaPmy?proof=inclusion"
/dedi/network reports whether configured peers answered. That is an
observation, deliberately weaker than witnessing: reachability says a node replied, while a
witness verdict is evidence that a log has not been rewritten. Raft replicas of one node share its
key and prove nothing about each other; see replication.
Witness verdicts are published at /dedi/witness; the
_witness namespace that stores them is hidden from the directory browser and the
standard's read routes.
Onboarding is operator-gated: there is no self-service registration, by design — who exists on a network is a governed decision, and every onboarding or revocation is an auditable entry in the transparency log. To register a participant on the networks served by the reference nodes, email contact@theflywheel.in with your subscriber id, type (BAP, BPP, BG or CDS), namespace, and Ed25519 signing public key. Details: governance.
One container and one Postgres. Needs Docker; no source checkout and no Go toolchain.
docker network create dedi-net
docker run -d --name dedi-pg --network dedi-net \
-e POSTGRES_USER=dedi -e POSTGRES_PASSWORD=dedi -e POSTGRES_DB=dedi postgres:16-alpine
until docker exec dedi-pg pg_isready -h 127.0.0.1 -U dedi -q; do sleep 1; done
docker run -d --name dedi-node --network dedi-net -p 8080:8080 \
-e DATABASE_URL='postgres://dedi:dedi@dedi-pg:5432/dedi?sslmode=disable' \
-e DEDI_ORIGIN=localhost/log flywheelai/dedi-node:latest
until curl -sf localhost:8080/healthz >/dev/null; do sleep 1; done
curl -s localhost:8080/dedi/log/checkpoint # your own signed tree head
The node mints its identity key on first start and prints the public verifier key in its log. Opening the write plane and making a first signed write: quickstart. Every setting: configuration. Witnessing, anchoring and replication: deployment modes.
dediregistry plugin (pkg/plugin/implementation/dediregistry) this node serves, proven over the wire