
An Overview of X-Road
We recently finished our third X-Road training workshop in Mozambique, this time geared more towards developers. Other than minor logistical hiccups, I would say it went well. I figured it was time to write a post about what X-Road actually is.
From the official website: “X-Road® is open-source software that enables unified, secure data exchange between organisations within a collaborative ecosystem.” Typically that ecosystem is a national implementation with a focus on government data exchange, although other implementation models exist. Unlike more common tools, which focus either on internal API integrations (e.g. service mesh software like Istio or Linkerd) or on exposing external APIs (e.g. Kong, Tyk), X-Road focuses on standardizing secure API integrations among organizations within an ecosystem. Hopefully this will make more sense a little later once we get to some diagrams.
X-Road was first developed at the turn of the century in Estonia and first launched in 2001. There’s a great summary of the history of X-Road on the official website. These days it is developed by the Nordic Institute for Interoperability Solutions (NIIS), a non-profit jointly founded by Estonia and Finland to take over development, and the software is used in many countries. It’s MIT-licensed, but there haven’t been too many external contributions.
The problem
This is my understanding of how X-Road came to be, though I was a kid at the time. In 1991, Estonia regained independence and was a young and rather poor country. The Information Superhighway™ had clearly become a big deal, something the government could leverage to optimize service delivery. Given the nature of government data, security was critical. Let’s look at a couple of options for how the government could have approached this, from an architectural perspective.
Bespoke integrations
They could have just mandated interoperability without any technical tooling. This would mean that every organization would have to build or buy its own integration layer, possibly resulting in a zoo of different interfaces. This could end up being pretty brittle and expensive.
A central hub
They could have procured or built a centralized system, e.g. an enterprise service bus. This would mean a single point of failure for what would become the government’s data plane, both in terms of resilience and privacy. I imagine it might have also been a pretty expensive option.
A unified standard with proxies
This is essentially what they ended up going with: a decentralized system where organizations integrate through standardized secure proxies they run next to their own infra. Whatever an organization’s internal stack is, it integrates through a single standard protocol.
High-level architecture
Using X-Road requires running what’s called an Instance. Here’s what the core of one looks like. Most ecosystems run multiple Instances to separate testing and production environments. The green boxes here are X-Road system components.
X-Road Operator
One organization assumes the responsibility of running the ecosystem. This organization is called an X-Road Operator. It sets the policies and processes for managing the ecosystem. It also onboards new organizations, provides support to member organizations and is generally responsible for the success of the ecosystem. I used to be the PM for the X-Road Operator team in Estonia at RIA.
The key system component the Operator runs is the X-Road Central Server. It’s quite poorly named, as it is not really in the center of anything. The Central Server is used to manage member organizations (referred to as Members) and other bits of configuration (addresses of Security Servers, which Trust Service Providers are approved, etc.). The Central Server periodically signs that configuration and provides an API for Security Servers to fetch it. X-Road Security Servers then pull that configuration from the Central Server at an interval (once a minute by default), independently of any data exchange between the Members. For non-technical audiences I usually use the metaphor of a signed phonebook. For more technical folks, DNS would be a pretty close comparison (previous versions of X-Road actually used DNS for this).
The Management Security Server is a regular Security Server in terms of the software, but is configured to proxy the management APIs the Central Server provides. These are used by Security Server admins to manage their Subsystems (more on that later), change the address of their Security Server, etc.
The Monitoring Security Server is technically optional, but most Operators run monitoring through a separate Security Server. The Security Server software exposes Services that an Operator can use to query information about Security Server health and metadata about exchanged API requests. The message payloads never reach the Operator. This is basically telemetry for the ecosystem.
Trust Service Provider
X-Road requires PKI services for the security model. Every Security Server requires two types of certificates to be operational:
- An authentication certificate for the Security Server
- A signing certificate for every organization hosted on the Security Server (it has multitenancy support)
Additionally, the Security Server needs access to the Online Certificate Status Protocol (OCSP) server for certificate validity checks, as well as a timestamping service for message logs.
An Operator might choose to provide these services, or it might outsource them to a third-party Trust Service Provider (TSP). There’s an extensive electronic identity regulation in the EU called eIDAS (“electronic IDentification, Authentication and trust Services”) and X-Road leverages that, although technically any standards-conformant tools will work. At the time of writing, the Estonian ecosystem provides free, non-qualified services to its X-Road Members, but requires government institutions to use a qualified third-party TSP.
X-Road Members
X-Road Members are organizations that have joined an X-Road Instance. The access point to the X-Road ecosystem is an X-Road Security Server. Every API or client system that wants to integrate with other systems through X-Road has to be proxied through the Security Server (there is a feature planned that would allow the client system to not have a Security Server, more on this under Trade-offs). The aspiration here is resilience and security through decentralization — if something happens to one organization or Security Server, it doesn’t take down the whole country’s data exchange.
The Security Server handles things like message routing, access rights management, transport-level encryption, signing the messages, logging, error handling and so on. And crucially, every request-response exchange happens through two Security Servers, peer-to-peer.
Request flow
Overview
One request and its response, from a client application to a service and back. Use Next to follow it step by step.
All steps
- The client application sends the request to its own Security Server.
- The consumer Security Server checks the client, signs the request with the member’s signing key and writes it to its message log.
- It opens a mutually authenticated TLS channel to the provider’s Security Server. Both check the other’s certificate (OCSP).
- The provider Security Server checks the access rights, verifies the signature and logs the request.
- The service processes the request.
- The provider Security Server signs the response – including a hash of the request – and logs it.
- The response returns over the same channel.
- The consumer Security Server verifies the signature, checks that the response matches the request, logs it and passes it to the client.
From a developer’s perspective
These days, X-Road is relatively transparent to developers as long as you have a run-of-the-mill HTTP API. The main limitation is that it has to be synchronous. X-Road has support for two “protocols”: Message Protocol for REST and a legacy Message Protocol for SOAP. And yes, I know the issues with the term “REST”, but we had to name it something…
This is where I should briefly introduce some X-Road semantics. Every organization that joins an X-Road Instance is called a Member, as explained above. Members are categorized by a memberClass identifier (typically something like gov, ngo, com). Every Member can have one or more Subsystems, which are basically identifiers for their information systems or APIs. Every Subsystem has a unique subsystemCode identifier. Additionally, every Subsystem can have one or more Services, which are identifiers for APIs or endpoints they expose. Every Service has a unique serviceCode identifier. And every X-Road Instance has an Instance identifier. The Instance and memberClass identifiers are configured by the Operator. The convention for the memberCode is to use the organization’s business registry code (if one exists), and the subsystemCode and serviceCode are configured by the Member.
So a full X-Road identifier for a Service could look something like this (based on an actual example from Estonia):
EE/GOV/70006317/consent/reporting
Breaking it down:
- EE — the Instance identifier for Estonia’s production X-Road Instance
- GOV — the memberClass for government institutions
- 70006317 — the memberCode for the Estonian Information System Authority (RIA), taken from the Estonian business registry
- consent — the subsystemCode for RIA’s Consent Management System
- reporting — the serviceCode for the API that provides reporting on consent data
Demo time
We can pretty easily try out a demo integration locally without setting up a full X-Road Instance using a couple of Docker images.
- niis/xroad-security-server-standalone — a special Security Server image that runs a single Security Server with two pre-configured Subsystems without needing a Central Server or Trust Services. Made for this kind of demo.
- swaggerapi/petstore3 — a simple demo API that we can use to try out the integration.
First, I’ll create a Docker network so that the Security Server can reach the demo API.
docker network create xroad-demo
Next, I’ll run the Standalone Security Server (latest production version at the time of writing). This can take some time to start up.
docker run -d --name standalone --hostname ss --network xroad-demo \
-p 127.0.0.1:4000:4000 -p 127.0.0.1:8080:8080 \
niis/xroad-security-server-standalone:noble-7.8.3
Then I’ll run the demo API.
docker run -d --name petstore3 --network xroad-demo \
-p 8090:8080 \
swaggerapi/petstore3:latest
The petstore Swagger UI should be accessible at http://localhost:8090. The Security Server’s management web UI should be accessible at https://localhost:4000 (the certificate is self-signed). The pre-configured credentials are xrd / secret.

A screenshot of the Security Server management web UI.
On the Clients page we can see that this image comes with one pre-registered organization and two Subsystems. This image is special in that it works without the Central Server, Trust Services, etc., and we cannot change the configuration. However, the API integration works just like it would on a production server. We can now add our demo API as a Service to the TestService Subsystem. We could do this via the web UI, but I’ll do it via the management API just because that’s easier to blog.
I’ll create an API key with the role required to configure Services.
API_KEY=$(docker exec standalone curl -sk -u xrd:secret \
https://localhost:4000/api/v1/api-keys \
--json '["XROAD_SERVICE_ADMINISTRATOR"]' | jq -r .key)
Then I’ll use that API key to add a Service to the TestService Subsystem using the OpenAPI spec the petstore container provides. The Security Server will then parse the methods and endpoints from that spec. I’ll set the serviceCode to “petstore”. Note that the management API writes identifiers with colons (CS:ORG:1111:TestService), while the request URLs and headers we’ll use later separate them with slashes.
SD_ID=$(curl -sk https://localhost:4000/api/v1/clients/CS:ORG:1111:TestService/service-descriptions \
-H "Authorization: X-Road-ApiKey token=$API_KEY" \
--json '{"url": "http://petstore3:8080/api/v3/openapi.json", "rest_service_code": "petstore", "type": "OPENAPI3"}' \
| jq -r .id)
Freshly added Services are disabled by default, so I’ll enable ours.
curl -sk -X PUT https://localhost:4000/api/v1/service-descriptions/$SD_ID/enable \
-H "Authorization: X-Road-ApiKey token=$API_KEY"
Next I’ll grant the CS/ORG/1111/TestClient Subsystem access rights to all endpoints for our Service. We could also restrict access to specific HTTP methods and endpoints.
curl -sk https://localhost:4000/api/v1/services/CS:ORG:1111:TestService:petstore/service-clients \
-H "Authorization: X-Road-ApiKey token=$API_KEY" \
--json '{"items": [{"id": "CS:ORG:1111:TestClient", "service_client_type": "SUBSYSTEM"}]}'
Now I’ll try making a request from the client’s perspective, using the TestClient Subsystem. This is where we see the only modifications we need to make to request an API through a Security Server.
Firstly, we’ll send the request to the Security Server, instead of directly to the API server. We then need to pass the serviceId via the URL and we need to add an X-Road-Client header where we specify the Subsystem making the call.
http://localhost:8080— this is our Security Server running locally. By default it listens for requests on port 8080/r1— this is where the Security Server listens for “REST” requests, as opposed to the SOAP protocolCS/ORG/1111/TestService/petstore/— this is the full serviceId (instanceId/memberClass/memberCode/subsystemCode/serviceCode)pet/1— this is the actual API endpoint"X-Road-Client: CS/ORG/1111/TestClient"— this is how we specify which client Subsystem we are using
curl http://localhost:8080/r1/CS/ORG/1111/TestService/petstore/pet/1 \
-H "X-Road-Client: CS/ORG/1111/TestClient"
We should see something like this in the output:
{"id":1,"category":{"id":2,"name":"Cats"},"name":"Cat 1","photoUrls":["url1","url2"],"tags":[{"id":1,"name":"tag1"},{"id":2,"name":"tag2"}],"status":"available"}
That’s basically it from an integration perspective (minus setting up mTLS, which you would do in production). In our demo, we are using a single Security Server, but it is still doing all the X-Road stuff and routing the message via its transport protocol like it does in production. It is just routing the request to itself.
Signed message logs
Another distinctive property of X-Road is the level of non-repudiation it is designed to provide. As I mentioned earlier, the EU regulates electronic identity and transactions through eIDAS. X-Road Security Servers require every Member to have a signing certificate to operate. This certificate is used to sign every transaction. These signed message logs are then timestamped and archived as XAdES ASiC containers, the same standard we use in Estonia for regular digital signatures. If the certificate used was a qualified e-seal certificate (in eIDAS terms) from a qualified TSP, then that message archive has legal evidentiary value1.
As far as I know, Estonia is the only country using X-Road that actually requires the use of qualified certificates in the eIDAS sense. One financially and technically important consequence of this for Estonia is that organizations hosting Security Servers must store their private keys on an HSM (required by the Certificate Authority). Other ecosystems often have the Operator act as the TSP and provide the services itself.
Just for reference, another notable system that requires qualified certificates is PSD2 open banking.
Trade-offs
As with anything in tech, there are trade-offs. I’ll highlight some based on my personal experience and opinions.
- Currently, X-Road supports only synchronous request-response calls. Fine for your average HTTP/JSON APIs, but limited for everything else. Webhooks or polling can be used for more event-driven stuff. That said, support for other data-plane protocols may be added in the future.
- X-Road also requires both the client and the provider to have access to a Security Server, which is a pretty hefty piece of infrastructure compared to just having an API token. The good news is that NIIS is planning support for what they are calling “light context” — a way for API providers to configure a Service so that the client does not need a Security Server. Which providers will adopt it, and on what basis, remains to be seen. In practice, most organizations don’t run their own Security Server anyway (see the statistics below).
- The whole non-repudiation thing adds complexity, performance bottlenecks, a dependency on Trust Services and GDPR concerns. Most API gateways stick to API tokens and HTTPS. The value of that non-repudiation can be hard to quantify. It is possible to turn off message logging to address data-protection concerns, but the reliance on TSPs remains.
- A centralized system might offer some UX and DX benefits that are difficult or impossible to achieve with a decentralized system, but this is one trade-off I am perfectly happy with.
Other pillars of interoperability
This could be its own series of blog posts (and maybe it will be someday). The focus of X-Road is on technical interoperability. It helps a little with legal and organizational interoperability in terms of standardizing some policies and processes, but not much. In Estonia, we rarely have to interact with the government, and when we do, we can do almost everything online (see also the “once-only principle”). Achieving that level of digital services takes a lot more.
First off is the need for strong digital identity. To truly move services online, people need to be able to securely authenticate and digitally sign applications, documents, etc., with the same legal force as a handwritten signature. Here’s a personal confession — I basically do not have a handwritten signature. The last time I had to renew my ID-card, the lady taking care of my application asked me to re-sign the application three times and to write “I write signatures differently” next to the last one. I grew up being able to sign everything digitally.
Second is data management. In Estonia, everyone in the population register (citizens, residents) has a personal identification code, a unique identifier, which is used to map data across government registries. Unlike a US Social Security number, it isn’t treated as a secret, because knowing it doesn’t really give access to anything. If you use your favorite search engine to look me up, you’ll probably find mine. You can even find it on this site if you look hard enough.
But identifiers are not enough. You also need some kind of regulation and processes to ensure that data is not duplicated. You could think of this as similar to product teams in an enterprise. There are specific services you use for specific purposes. The population register is responsible for storing my name, date of birth, address and so on. The tax authority is responsible for storing my tax data. If any other organization needs that data, it queries it through an API instead of asking me.
Once you solve those problems at scale, the efficiency gains are significant.
Some statistics from Estonia
Here are some statistics from Estonia’s production X-Road Instance, X-tee, which I recently pulled for some exploratory data analysis.
Queries per year
Queries per year in Estonia’s production X-Road Instance. The lighter segment is one temporary bulk flow. Source: RIA, X-tee factsheets.
Ecosystem monitoring was introduced in 2003, so we don’t have data on the first two years. But the chart clearly shows steady growth over the years.
Who takes part
Organizations actively exchanging data on X-tee, by sector. About 1,030 in October 2026. Two thirds are businesses, but 81% of requests are between state institutions (August 2026). Sources: RIA, X-tee service catalogue and X-Road Metrics open data.
The Estonian X-Road Instance stats page shows a bigger participant number. My chart includes only the organizations that have active Subsystems and most of them exchanged data during August 2026.
A day of traffic
Requests per hour on a typical weekday and weekend day (median over August 2026, Estonian time). About 12 million requests per working day. Source: RIA, X-Road Metrics open data.
Who runs the Security Servers
Who runs the Security Server for organizations on X-tee. Most connect through one operated by another organization. Source: X-tee global configuration, 4 October 2026.
Operating a Security Server requires some technical expertise and infrastructure. Even though the system design is decentralized, in practice most organizations use Security Server hosting services provided by other organizations. There are a number of private-sector companies that provide this service in Estonia. In the public sector, several agencies run Security Servers for other agencies in their sector. The multitenancy feature (hosting multiple organizations in one Security Server) makes this a bit easier. Critical systems are still pretty decentralized.
SOAP and REST
Services in the X-tee public catalogue by protocol. One Service is one serviceCode in one Subsystem, with SOAP versions counted once. Source: X-tee service catalogue, 30 October 2026.
Support for “REST APIs” was only added in 2019, so there are a lot of legacy SOAP Services still in use. I chuckle every time I hear folks talk about SOAP in the past tense on podcasts. The data does show that the percentage of REST Services is increasing, as most new Services use the newer protocol.
Footnotes
-
Current X-Road versions use batch signing as a performance improvement, using Merkle trees to link the signed messages. This, however, is not exactly eIDAS compliant. X-Road version 8 is planned to remove batch signing and produce eIDAS-compliant message logs. ↩
Loading comments…