Preview release. These docs are a work in progress. Pages are still being written, links may break, and structure may shift without notice. Treat everything here as a draft and report issues on GitHub.
This guide is for application teams calling Registry Relay. It describes client behavior for the V1 dataset-scoped REST API.
For concrete deployment-specific paths and schemas, fetch the runtime OpenAPI
document from the deployment at GET /openapi.json, or read the
Registry Relay API reference.
Runtime OpenAPI is auth-gated by default unless server.openapi_requires_auth
is disabled for demos or controlled tooling.
sequenceDiagram
participant Client as Application client
participant Relay as Registry Relay
participant Notary as Registry Notary
Client->>Relay: Authenticated discovery (OpenAPI, metadata, schemas)
Relay-->>Client: Scoped views (ETag, 304 if unchanged)
Client->>Relay: Read records (limit, cursor, Data-Purpose)
alt transient failure, 429, or 503
Relay-->>Client: Problem Details with Retry-After
Client->>Relay: Retry idempotent GET with jittered backoff
end
Relay-->>Client: Entity records (opaque next_cursor)
opt signed response credentials enabled and requested
Client->>Relay: Read with Accept application/vc+jwt
Relay-->>Client: Signed VC-JWT, verified against issuer DID and schema
end
opt claim or evidence verification needed
Client->>Relay: Discover evidence offering
Relay-->>Client: access.kind registry-notary endpoint
Client->>Notary: Follow Registry Notary client docs
end
The typical client lifecycle: authenticated discovery, scoped reads with conservative retries, optional response provenance, and handoff to Registry Notary for verification. Each step is detailed in the sections that follow.
Connect to an existing deployment
Section titled “Connect to an existing deployment”When another organization operates the Relay you are integrating with, request three things from that operator before writing code:
- A named service identity. Every caller is a named principal in the
deployment’s auth config. For API-key deployments the operator runs
registry-relay generate-api-key --id <your_identity>and hands you the raw key once; only the fingerprint is stored server-side, so a lost key means a new one. For OIDC deployments, ask for the client registration details and the scope grant instead. - Dataset scopes. Scopes are dataset-local
<dataset_id>:<level>labels. The levels aremetadata(catalog, schema, and OpenAPI visibility),rows(entity record and relationship reads),evidence_verification(evidence-oriented standards-adapter access, separate from row reads),aggregate(aggregate discovery and execution), andadmin(admin listener operations, never needed for data reads). Name the workflows you run and ask for the minimal scope list; see Authentication in the API reference for the full semantics. - Accepted purpose values. If your reads serve a human or program
decision, the deployment may require a
Data-Purposeheader. Ask which purpose URIs your data-sharing agreement authorizes; see Purpose header below.
To confirm the grant works before integrating deeper, call GET /v1/datasets:
it lists every dataset visible to your principal. An empty list or a 403
means the scope grant does not match what you asked for; resolve that with the
operator before debugging client code.
Integration checklist
Section titled “Integration checklist”Before a client is allowed to consume Relay data, confirm:
- The caller has a named service identity in the deployment’s auth system.
- The caller has only the dataset scopes required for its workflow.
- Row reads that serve a human or program decision send
Data-Purpose. - Collection reads include required filters where entities declare them.
- The client handles RFC 9457 Problem Details instead of parsing text messages.
- The client treats cursors,
ETags, and provenance credentials as opaque values. - Logs redact bearer tokens, API keys, query values for sensitive fields, raw
row bodies, VC-JWT bodies, and Problem Details
detail.
Authentication
Section titled “Authentication”Relay deployments use one auth mode at startup:
- API key: send the raw key as
Authorization: Bearer <key>. - OIDC: send the access token as
Authorization: Bearer <jwt>.
Do not try both headers in the same client profile. Choose the mode advertised by the deployment operator.
Scopes are dataset-local and written as <dataset_id>:<level> (for example
social_registry:rows). Request only the scopes your workflow needs: a
metadata scope never implies row access, a row scope never implies aggregate
access, and the evidence_verification scope grants standards-adapter access
only, not a Relay-local verification execution endpoint. For the full scope
semantics see the Registry Relay API reference.
Purpose header
Section titled “Purpose header”Some entities require Data-Purpose for row or feature reads. Send a stable
purpose URI or controlled string that the operator can audit:
Data-Purpose: https://data.example.gov/purposes/service-intake-checkThe value is written verbatim into audit records. Purpose values are not enforced or validated at the consultation layer; Registry Notary is the purpose-certification layer. Do not put subject identifiers, free-text case notes, bearer tokens, or other secrets in this header. For the full list of entities that enforce this header and the resulting error code, see the Registry Relay API reference.
The set of acceptable purpose values is defined by the operator and your data-sharing agreement, not by Relay: there is no API route that enumerates valid purposes. If your agreement does not name specific URIs, propose a small set of stable URIs under a namespace your organization controls (one per workflow, as in the example above) and have the operator confirm them. Keep the values stable across releases so the operator’s audit trail stays queryable.
Discovery
Section titled “Discovery”Use scoped discovery before hard-coding dataset assumptions:
- Fetch the runtime OpenAPI document for the authenticated caller. Send your
bearer credentials on this request too:
GET /openapi.jsonis auth-gated by default, and an unauthenticated fetch fails unless the operator has disabledserver.openapi_requires_auth. - Fetch metadata catalog views for visible datasets and entity schemas.
- Cache metadata only as a private, principal-specific artifact.
- Refresh discovery after a deployment, config reload, or permission change.
Metadata responses may include ETag. If a client sends If-None-Match, an
unchanged scoped view can return 304 Not Modified. Shared caches must not
reuse one caller’s metadata for another caller.
Reading records
Section titled “Reading records”Treat entity names and field names as deployment contract, not table names. Table ids and source column names are private operator configuration.
Recommended client behavior:
- Always set an explicit
limit. - Preserve opaque
next_cursorvalues exactly as returned. - Restart pagination from the first page when filters, projection, purpose, or auth context changes.
- Handle
pagination.cursor_invalidatedby restarting the read with the same query intent. - Avoid broad unfiltered reads unless the entity contract explicitly allows them.
Fields marked sensitive: true are audit-redacted. That flag is not an
authorization control and does not hide fields from authorized API responses.
Aggregates
Section titled “Aggregates”Aggregates are predeclared by the operator. Clients may discover available measures, dimensions, defaults, disclosure controls, and structure before executing an aggregate.
For JSON responses, handle suppression and masking as normal result states. Suppressed groups are not transport failures.
CSV output is intended for operational exports and interoperability. When a deployment supports CSV aggregate output, clients must preserve:
- response headers describing disclosure and freshness;
- the
Link: rel="describedby"aggregate structure relation; - CSV header names exactly as returned.
SDMX JSON output is intended for statistical tooling. Request it with
?f=sdmx-json, request body "format": "sdmx-json", or
Accept: application/vnd.sdmx.data+json;version=2.1. SDMX messages declare
https://json.sdmx.org/2.1/sdmx-json-data-schema.json; clients must also
check the meta.x-completeness object before treating a cube as complete.
Relay SDMX conventions
Section titled “Relay SDMX conventions”Relay maps aggregate results onto SDMX JSON with a few relay-specific conventions integrators must account for:
- Measure descriptors carry relay extension keys alongside the standard SDMX
fields:
x-unitMeasurereports the measure unit,x-unitMultiplierreports the unit multiplier (ornullwhen unset), andx-decimalsreports the configured decimal precision (ornullwhen unset). meta.senderis fixed to{ "id": "registry-relay", "name": "Registry Relay" }. It identifies the relay as the message sender and does not vary by deployment or dataset.- The measure
definition_uriavailable in the native JSON and discovery responses is not mapped into the SDMX output. Clients that need a measure’s definition URI must read it from the native structure or measure-discovery responses.
Errors
Section titled “Errors”Relay returns Problem Details for non-2xx responses. Log only safe fields:
- HTTP status
codetitle- request id, if present
- retry-related headers, if present
Avoid logging detail in production unless the operator has confirmed it is
redacted for that deployment.
Typical client handling:
| Code Family | Client Action |
|---|---|
auth.* | Refresh credentials or fail closed |
entity.filter_required | Add one of the required filters |
pagination.cursor_invalidated | Restart pagination |
metadata.* | Refresh discovery or report deployment mismatch |
aggregate.* | Check aggregate structure, measure discovery, and caller scope |
provenance.* | Fall back to plain JSON only if the workflow permits unsigned data |
Retries
Section titled “Retries”Use conservative retries:
- Retry idempotent GETs for transient transport failures,
429, or503. - Honor
Retry-Afterwhen present. - Use jittered exponential backoff.
- Do not retry requests that could create audit ambiguity unless the route contract explicitly says it is idempotent.
Relay is read-only for registry data, but retries still create extra audit events and may repeat costly source reads.
Signed response credentials
Section titled “Signed response credentials”When signed response credentials are enabled, clients can request VC-JWT credentials with an accepted VC media type. The credential shape aligns with the W3C Verifiable Credentials Data Model 2.0; full VCDM conformance is not asserted, and the RegistryStack standards register records the exact claim level. Treat the returned compact JWS as an opaque signed artifact and verify it with the issuer DID document and published schemas.
These are signed response credentials, not W3C PROV-O. The provenance config
key governs the issuer configuration for backward compatibility, but the correct
public description is “signed response credentials”.
Do not confuse Relay signed response credentials with Registry Notary evidence verification. Relay can sign selected data responses. Registry Notary owns claim evaluation, evidence verification, credential issuance workflows, and the verification semantics behind evidence offerings.
Registry Notary handoff
Section titled “Registry Notary handoff”Relay publishes evidence offering metadata for discovery and delegates all claim and evidence verification to Registry Notary. The only evidence offering routes in Relay are:
GET /metadata/evidence-offeringsGET /metadata/evidence-offerings/{offering_id}These routes require the caller’s metadata scope for the owning dataset. They
return discovery records; they do not execute a check, compute claim hashes,
issue verification receipts, or disclose row data. There is no
POST /evidence-offerings/{offering_id}/verifications route in Relay.
sequenceDiagram participant Client as Service client participant Relay as Registry Relay participant Notary as Registry Notary Client->>Relay: GET /metadata/evidence-offerings Relay-->>Client: Offering metadata with access.kind registry-notary Client->>Notary: Submit claim or evidence to the advertised endpoint Notary-->>Client: Verification result or credential
The discovery and verification boundary. Relay publishes evidence offering metadata that points to a Notary; the client submits the claim or evidence to that Notary, which performs verification. Relay makes no verification decision.
When a client needs to verify claims or evidence:
- Fetch
GET /metadata/evidence-offerings(or the single-offering route by id) to discover available offerings. - Read the
access.kind: registry-notaryfield and the advertised Notary endpoint or discovery URL. - Follow Registry Notary’s client documentation for request shape, claim semantics, presentation, result verification, and credential issuance.
A discovery response looks like this (one offering shown; host names are illustrative):
{ "evidence_offerings": [ { "id": "benefits_person_evidence", "title": "Benefits person status evidence", "iri": "https://demo.example.gov/evidence-offerings/benefits-person", "description": "Registry Notary verification for submitted benefits person eligibility status and role facts.", "dataset_id": "benefits_casework", "entity": "person", "evidence_type": { "id": "benefits_person_record_evidence", "iri": "https://demo.example.gov/evidence-types/benefits-person-record", "name": "Benefits person record evidence" }, "evidence_type_iri": "https://demo.example.gov/evidence-types/benefits-person-record", "issuing_authority": { "id": "ministry_of_social_affairs", "iri": "did:web:social-affairs.demo.example.gov", "name": "Ministry of Social Affairs", "country": "ZZ" }, "jurisdiction": { "country": "ZZ", "region": null }, "level_of_assurance": "substantial", "lookup_keys": ["id"], "policy": { "purpose": ["https://demo.example.gov/purpose/social-protection-eligibility"] }, "procedure_contexts": [], "requirement_iris": ["https://demo.example.gov/requirements/benefits-person"], "information_concepts": [], "verification_request_schema_url": "https://relay.demo.example.gov/metadata/schema/benefits_casework/person/schema.json", "access": { "kind": "registry-notary", "ruleset": "benefits-person-v1", "endpoint_url": "https://notary.demo.example.gov/evidence-offerings/benefits-person/verifications", "discovery_url": "https://notary.demo.example.gov/.well-known/registry-notary", "conforms_to": "https://demo.example.gov/standards/registry-notary/evidence-v1" } } ]}The access object is what drives the handoff: kind is always
registry-notary in V1 (Relay is never the verifier), ruleset names the
Notary ruleset that governs verification for this offering, endpoint_url is
where claims or evidence are submitted, discovery_url is the Notary
well-known document for resolving endpoint details (either URL may be null
when the other is present), and conforms_to identifies the evidence contract
the offering follows.
The evidence_verification scope is available as a distinct label for
standards adapters and integrations that need evidence-oriented access separate
from row reads. It does not grant metadata, rows, aggregates, admin reload, or a
Relay-local verification endpoint.
Use Registry Notary’s documentation as the source of truth for verification semantics, claim request bodies, result interpretation, credential issuance, client retries, and verifier behavior: