Skip to content

Linked Data

CDS v0.2.0 treats every event, source, and content type as a first-class resource on the web. This page explains why, how, and what that buys you.

Tim Berners-Lee proposed four rules for publishing data on the web:

  1. Use URIs as names for things.
  2. Use HTTP URIs so that people can look those names up.
  3. When someone looks up a URI, provide useful information (using standards).
  4. Include links to other URIs so that they can discover more things.

The Tower of Babel problem. Different systems use different identifiers for the same things. One lottery API calls the game megasena, another calls it mega-sena, a third uses an opaque numeric ID. A weather API returns temp_c, another returns temperature_celsius. The concepts are identical but the names are not, so combining data from these systems requires hand-written mapping code for every pair.

URIs solve this. When two systems refer to https://signed-data.org/vocab/lottery-brazil/mega-sena-result they mean the same thing — no mapping required.

Without Linked Data, JSON payloads are isolated silos. Each consumer must already know what every field means and where to get more information. Linked Data connects those silos: every field that references an external concept carries a dereferenceable URI that leads to a definition, and that definition links onward to related resources.

CDS assigns a stable URI to every entity in the system.

EntityURI patternExample
Eventhttps://signed-data.org/events/{uuid}.../events/a3f1c9e0-7b2d-4e8a-9f01-abc123def456
Sourcehttps://signed-data.org/sources/{source-id}.../sources/caixa.gov.br.loterias.v1
Content typehttps://signed-data.org/vocab/{domain}/{type}.../vocab/lottery-brazil/mega-sena-result

These URIs are not just opaque identifiers — they are addresses you can fetch.

All CDS URIs use HTTPS and are served by signed-data.org. No custom URI schemes, no URNs, no proprietary namespaces. Any HTTP client on any platform can resolve them.

Rule 3 — Provide useful information when a URI is looked up

Section titled “Rule 3 — Provide useful information when a URI is looked up”

Every CDS URI returns a JSON-LD document when dereferenced with an HTTP GET:

GET /sources/caixa.gov.br.loterias.v1 HTTP/1.1
Host: signed-data.org
Accept: application/ld+json
{
"@context": "https://signed-data.org/contexts/cds/v1.jsonld",
"@id": "https://signed-data.org/sources/caixa.gov.br.loterias.v1",
"name": "Caixa Econômica Federal — Loterias API v1",
"url": "https://servicebus2.caixa.gov.br/portaldeloterias/api/megasena",
"country": "BR",
"domains": ["lottery-brazil"]
}

Every CDS document contains outbound links:

  • An event links to its source via source.@id
  • The source document links to its domains (e.g., lottery-brazil)
  • The domains link to the vocabulary, which defines every content type and property

This creates a navigable graph. Starting from any event, you can follow links to discover what it means, where it came from, and what other data the same source publishes.

Developer ergonomics.

JSON-LD is valid JSON. An existing consumer that reads JSON from an HTTP endpoint does not need a JSON-LD processor, does not need to learn Turtle syntax, and does not need to install an RDF library. The event payload looks like ordinary JSON:

{
"@context": "https://signed-data.org/contexts/cds/v1.jsonld",
"@id": "https://signed-data.org/events/a3f1c9e0-...",
"content_type": "https://signed-data.org/vocab/lottery-brazil/mega-sena-result",
"occurred_at": "2026-03-29T00:00:00Z",
"source": {
"@id": "https://signed-data.org/sources/caixa.gov.br.loterias.v1"
}
}

The @context is a single URL that maps snake_case keys to full RDF predicates behind the scenes. For example, content_type maps to https://signed-data.org/vocab/cds#contentType and occurred_at maps to https://signed-data.org/vocab/cds#occurredAt. Consumers that do not care about RDF ignore @context entirely and read the JSON as-is.

No Turtle. No SPARQL required for basic use. If you need RDF, any JSON-LD processor will expand the same document into N-Triples, Turtle, or RDF/XML.

Tim Berners-Lee defined a 5-star scheme for open data. CDS earns all five.

StarsCriterionHow CDS meets it
Available on the web with an open licenseAll CDS schemas, libraries, and tooling are MIT-licensed. Events are published at HTTPS URIs.
★★Available as machine-readable structured dataEvents are JSON — parseable by every language and platform.
★★★Available in a non-proprietary open formatJSON is an open ECMA/IETF standard (RFC 8259), not a proprietary format like Excel or PDF.
★★★★Published using open standards from W3CEvery event carries a JSON-LD @context. Fields map to W3C RDF predicates.
★★★★★All of the above, plus links to other dataEvents link to source URIs, source URIs link to domain vocabularies, vocabulary URIs link to RDF definitions. The graph is connected.

Take a Mega Sena event and follow the links step by step.

Step 1 — Resolve the content type.

The event contains:

"content_type": "https://signed-data.org/vocab/lottery-brazil/mega-sena-result"

Dereference it:

GET /vocab/lottery-brazil/mega-sena-result HTTP/1.1
Host: signed-data.org
{
"@id": "https://signed-data.org/vocab/lottery-brazil/mega-sena-result",
"label": "Mega Sena draw result",
"description": "Official result of a Mega Sena lottery draw conducted by Caixa Econômica Federal.",
"domain": "lottery-brazil"
}

Now you know what the event represents.

Step 2 — Resolve the source.

GET /sources/caixa.gov.br.loterias.v1 HTTP/1.1
Host: signed-data.org
{
"@id": "https://signed-data.org/sources/caixa.gov.br.loterias.v1",
"name": "Caixa Econômica Federal — Loterias API v1",
"url": "https://servicebus2.caixa.gov.br/portaldeloterias/api/megasena",
"country": "BR",
"license": "public-domain",
"domains": ["lottery-brazil"]
}

Now you know where the data came from and how to reach the upstream API.

Step 3 — Resolve the context.

GET /contexts/cds/v1.jsonld HTTP/1.1
Host: signed-data.org
{
"@context": {
"cds": "https://signed-data.org/vocab/cds#",
"xsd": "http://www.w3.org/2001/XMLSchema#",
"content_type": { "@id": "cds:contentType", "@type": "@id" },
"occurred_at": { "@id": "cds:occurredAt", "@type": "xsd:dateTime" },
"source": { "@id": "cds:source", "@type": "@id" },
"fingerprint": { "@id": "cds:fingerprint" },
"payload": { "@id": "cds:payload" }
}
}

Now you know the RDF mapping for every field.

A JSON-LD processor expands the compact event into a set of RDF triples by applying the @context.

Compact event:

{
"@context": "https://signed-data.org/contexts/cds/v1.jsonld",
"@id": "https://signed-data.org/events/a3f1c9e0-7b2d-4e8a-9f01-abc123def456",
"content_type": "https://signed-data.org/vocab/lottery-brazil/mega-sena-result",
"occurred_at": "2026-03-29T00:00:00Z",
"source": {
"@id": "https://signed-data.org/sources/caixa.gov.br.loterias.v1"
}
}

Expanded triples:

SubjectPredicateObject
<events/a3f1c9e0-...>cds:contentType<vocab/lottery-brazil/mega-sena-result>
<events/a3f1c9e0-...>cds:occurredAt"2026-03-29T00:00:00Z"^^xsd:dateTime
<events/a3f1c9e0-...>cds:source<sources/caixa.gov.br.loterias.v1>

The compact form uses developer-friendly snake_case keys; the expanded form uses full RDF predicates. Both representations carry the same semantics.

The source registry is the canonical list of data sources that CDS recognises. Each entry is a JSON-LD document served from https://signed-data.org/sources/{source-id}.

FieldTypeDescription
namestringHuman-readable name of the source
urlstringBase URL of the upstream API
authstringAuthentication method (none, api-key, oauth2)
licensestringLicense of the source data (public-domain, cc-by-4.0, etc.)
countrystringISO 3166-1 alpha-2 country code
domainsstring[]List of domain identifiers (e.g., ["lottery-brazil"])
fingerprint_algorithmstringHash algorithm for source fingerprints (e.g., sha256)
certified_atstringISO 8601 timestamp when the source was certified
certified_bystringIdentifier of the entity that certified the source

If you run your own CDS issuer, you are not required to use signed-data.org. You can publish your own vocabulary and source definitions at your own domain. See Self-hosting for the full guide.

Because CDS events are valid JSON-LD, they are valid RDF. Any collection of events can be loaded into a triple store (Apache Jena, Blazegraph, Amazon Neptune, Oxigraph) and queried with SPARQL.

PREFIX cds: <https://signed-data.org/vocab/cds#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?event ?contentType ?occurredAt
WHERE {
?event cds:contentType ?contentType ;
cds:occurredAt ?occurredAt .
FILTER (
STRSTARTS(STR(?contentType), "https://signed-data.org/vocab/lottery-brazil/")
&& ?occurredAt >= "2026-03-01T00:00:00Z"^^xsd:dateTime
&& ?occurredAt < "2026-04-01T00:00:00Z"^^xsd:dateTime
)
}
ORDER BY ?occurredAt

This is not a feature CDS needs to build — it falls out of the data model for free. The investment in Linked Data pays forward: every new event is immediately queryable alongside every other event, across sources, domains, and time ranges, without writing any new code.