UQRP Protocol
Universal Query Response Protocol for DNS-Based Data Storage
Quick Reference: This is a condensed overview. For the complete technical specification including formal grammar (ABNF), encryption wire formats, and implementation requirements, see the Full Protocol Specification.
Shared Answering Contract (Implemented)
The shared UQRP contract is implemented across native DNS, DoT, wire DoH and both JSON entry forms, with real Rails, Go/JavaScript and MCP conformance:
- Resource versions use
v1,v2, and so on, separately from envelope formats and dataset release versions. Zero and leading-zero versions are rejected. - Encoded query parameters use case-stable
b32-orhex-; Base64 query-label encodings are retired. TXT payloade=b64means standard padded Base64. - All ordinary successes use
v=rdb1;s=ok;t=data, including units, sun, and moon; dataset formats remain distinct. When present,d=consumes the remainder. - Final DNS responses preserve the agreed error outcomes, validity-bounded TTLs, and zero cache lifetime for authenticated positive and negative answers.
- Requested DNSSEC material and query analytics extend to DoH.
Repository implementation is distinct from operator deployment and SDK publication.
The hosted-payload slice is implemented in the repository: Rails write/sync,
native DNS and DoH, preview Go/JavaScript decoders, and MCP preserve d= content
and standard padded Base64 binary. The final d= consumes all remaining text;
hello;s=error stays payload, not status metadata.
The hosted-lifecycle slice is implemented too: authorization precedes semantic parameter validation; private positive and negative DNS lifetimes are zero, including SOA/proofs; public positive TTLs are bounded by record expiry. Requested DNSSEC uses one signing generation, and usage counts successful authenticated evaluation even if later signing or delivery fails. Missing/expired values are NOERROR absence, malformed input is FORMERR, denial is REFUSED, and corrupt-state or lookup failure is SERVFAIL. Hosted and schema statistics now include DoH.
The computed-public slice is also implemented: units, moon, and gated mock-only BTC use shared native/DoH answering, flat ordinary success fields, resource TTLs, and requested DNSSEC.
Financial lookups (stock, forex, crypto) also use shared native/DoH answering
in the repository. They retain their flat fields, provider fallback, market-aware
TTLs, and optional stock reference-provenance triple. Invalid input/MIC returns
FORMERR, absent symbols empty NOERROR, provider failures SERVFAIL, and public
credential/policy denials REFUSED. Requested signing fails closed; financial
statistics cover both transports without private usage. Only get in public.v1
selects a financial provider. Payload ttl= remains a hint; wire HTTP caching
uses effective RR TTLs, while JSON remains no-store. Generic and typed Go/JS/MCP
conformance is covered by just client-conformance.
Dataset manifests and attestation keys now use shared answering too. Manifests
retain rdb-attest.v1, license/provenance, the signed display name, and opaque
Ed25519 attestation bytes. manifest.keys.datasets.public.v1.resolvedb.net
returns a distinct rdb-attest-keys.v1 public-key envelope, not DNSSEC DNSKEY.
Use manifest.bin-acme-v-1d2d0.datasets.public.v1.resolvedb.net for release 1.2.0;
omit -v-... for the latest attested release. Public TXT TTL is 3600 seconds;
JSON remains no-store. Go/JS/MCP decoding is covered by actual transport fixtures
and does not automatically verify either signature layer.
Dataset identity/as-of answering is also shared, with coherent observations and
transition-bounded TTLs. Case-stable query encoding and canonical resource
versions and all-family native/DoH evaluation analytics are implemented too.
Statistics use the selected family (records for hosted units, explicit
datasets) with verified private attribution through miss/expiry. Public and
dataset reads remain unattributed; canonical versions are preserved through 63
bytes, with absent/malformed versions represented as null on revised errors/denials.
During the consumer-first rollout, older analytics rows carry
event_contract=query_stats.v1 and a Legacy class label: their resource was
label-classified rather than the evaluated family, and unknown/noncanonical
legacy versions display null even on hits. Revised events/rows are
query_stats.v2; verified legacy namespace attribution is retained.
Complete repository conformance does not imply deployment or package publication.
Try it now
Overview
ResolveDB encodes public service data and hosted-record reads in DNS queries and responses. Public answers can use shared DNS caching; successful authenticated private answers use TTL 0.
Client DNS Resolver ResolveDB
| | |
|-- get.quebec.weather.public.v1.resolvedb.net ------>|
| | |
|<-- TXT "v=rdb1;s=ok;t=data;e=b64;f=json;d=..." ------|
| | |
|-- (cached locally) ------>| |Query Format
UQRP queries are structured DNS hostnames with each component serving a specific purpose:
<operation>.<params>.<resource>.<namespace>.<version>.resolvedb.<tld>| Component | Required | Description |
|---|---|---|
| operation | Yes | Shipped DNS operation such as get, geoip, or info |
| params | No | Encoded parameters |
| resource | Yes | Data resource name |
| namespace | Yes | public or one hosted namespace label |
| version | Yes | Resource version scoped to resource and namespace, such as v1 |
| resolvedb | Yes | Protocol marker |
| tld | Yes | .net (the only delegated authoritative UQRP TLD today) |
Examples
# Weather by city (public service)
dig TXT get.seattle.weather.public.v1.resolvedb.net +short
# Weather by coordinates (d = decimal point, _ separates lat/lon)
dig TXT get.47d6062_-122d3321.weather.public.v1.resolvedb.net +short
# Weather by IP location
dig TXT get.ip-8-8-8-8.weather.public.v1.resolvedb.net +short
# Weather by what3words (hyphens replace dots)
dig TXT get.w3w-filled-count-soap.weather.public.v1.resolvedb.net +short
# 3-day forecast
dig TXT get.seattle.forecast.public.v1.resolvedb.net +short
# GeoIP lookup
dig TXT geoip.ip-8-8-8-8.public.v1.resolvedb.net +short
# Stock quote
dig TXT get.AAPL.stock.public.v1.resolvedb.net +short
# Forex rate
dig TXT get.USD-EUR.forex.public.v1.resolvedb.net +short
# Crypto price
dig TXT get.BTC-USD.crypto.public.v1.resolvedb.net +short
# Authenticated hosted-record request
get.auth-rdbq<52>.config.acme-catalog.v1.resolvedb.netOperations
| Operation | Description | Auth Required | Transport |
|---|---|---|---|
get | Retrieve public data or a hosted record | No (public) / Yes (hosted) | DNS |
info | Resource metadata & JSON Schema | No | DNS + HTTP |
geoip | Geolocation for an explicit IP parameter | No | DNS |
manifest | Attested dataset manifest | No | DNS |
identity | Attested dataset identity fact | No | DNS |
Note: Write operations (
put,delete) are handled via the REST API atapi.resolvedb.com, not via DNS queries. DNS is optimized for reads; writes flow through the API.
Schema Discovery (info Operation)
Get JSON Schema for a registered public resource to understand its response format:
# Via DNS
dig TXT info.weather.public.v1.resolvedb.net +short
# Via HTTP (copy-paste any query - operation and params are ignored)
curl 'https://doh.resolvedb.io/schema?q=weather.public.v1.resolvedb.net'
curl 'https://doh.resolvedb.io/schema?q=get.seattle.weather.public.v1.resolvedb.net'The HTTP /schema response includes:
- schema: JSON Schema with field types, descriptions, and examples
- meta: Auth requirements, rate limits, default TTL
- dns_format: Query template and example response
- error_responses: Expected error codes and descriptions
The UQRP info query returns only the JSON Schema inside its TXT payload, rather
than the complete HTTP metadata document.
See Schema Access in the full spec.
Parameter Encoding
Query parameters use case-stable encodings for parameters requiring special
characters. Prefixes use hyphens (-); colons are not valid in DNS labels.
Core, Rails hosted-key validation, and preview Go/JS SDK support are implemented.
| Prefix | Encoding | Use Case |
|---|---|---|
| (none) | ASCII letters, digits, -, _ | Hosted key labels; public operation-specific grammar |
ip- | IP address | Dots replaced with hyphens (8-8-8-8) |
w3w- | what3words | Dots replaced with hyphens (filled-count-soap) |
b32- | Unpadded Base32, canonical lowercase | Case-stable encoded parameters |
hex- | Hexadecimal | Binary hashes |
auth- | Opaque rdbq namespace query token | Private hosted-record authorization |
Base64 query labels are unsuitable because DNS treats case variants as the same
name while Base64 can decode them to different bytes. This does not affect
Base64 inside TXT data or the Base64url dns= HTTP parameter.
b32- uses unpadded RFC4648 a-z2-7, with canonical lowercase output and
case-insensitive decoding. The token alphabet is separately 0-9a-v. Padding,
nonzero trailing bits, malformed hex, and retired b64-/base64-/rdb- forms
are rejected. Decoded bytes keep their case; only DNS spelling is normalized.
Private-query authorization runs before semantic decoding.
Public operations interpret decoded text with their normal parameter grammar.
For coordinate JSON {"lat":51.4769,"lon":0}, query:
dig TXT get.b32-pmrgyyluei5dkmjogq3tmojmejwg63rchiyh2.weather.public.v1.resolvedb.net +shortThe JSON fields are exactly lat and lon; decoded Lat is not silently
lowercased. Use Go B32Param or JavaScript b32Param to encode UTF-8 bytes.
Hosted keys retain encoded-label order and spelling: Base32, hex, and plain
labels remain different keys, even if their decoded values match.
Coordinate Encoding
For lat/lon coordinates, use d as decimal point and _ as separator:
# 47.6062, -122.3321 becomes:
dig TXT get.47d6062_-122d3321.weather.public.v1.resolvedb.net +shortNamespace Query Tokens
Private hosted records use an opaque token minted under the namespace API. The token is placed in the first label after the operation and is returned only once. Parameterized records place their key-parameter labels after it:
get.auth-rdbq<52>.config.acme-catalog.v1.resolvedb.netResponse Format
Successful data answers are DNS TXT records with a semicolon-delimited UQRP
envelope. Units, sun, moon, enabled BTC, weather, forecast, and GeoIP begin
v=rdb1;s=ok;t=data followed by their flat resource fields.
Hosted records use this core shape:
v=rdb1;s=ok;t=data;e=<plain|b64>;f=<json|text>;ttl=<seconds>;d=<payload>TXT RDATA can contain multiple 255-byte character strings. Concatenate them in
order before parsing. Split the envelope at ;d= so payload characters are not
mistaken for metadata. Decode d according to e before parsing f=json.
The envelope ttl= field is a configured hint. Inspect the DNS answer RR TTL for
the effective resolver cache lifetime; successful private RR TTL is always 0.
The query-level failure taxonomy is represented by DNS RCODE. Shared schema, zone-control, hosted, computed-public, location, financial, and dataset answering preserve it on native DNS and DoH, and the preview SDKs and MCP retain these distinctions. Evaluation analytics records the product outcome before response assembly; signing/encoding/delivery failures remain separate transport observations. Only successful authenticated evaluations emit usage.
| RCODE | Meaning |
|---|---|
NOERROR | Answer or NODATA |
FORMERR | Malformed operation or parameters |
SERVFAIL | Provider, storage, or rendering failure |
REFUSED | Authorization, namespace, or reserved-resource denial |
The larger status/error-envelope vocabulary in the full draft is not a promise that every listed status is emitted by the production v1 request paths. E014 is reserved and is not emitted.
Namespaces
ResolveDB places one namespace label in every UQRP name. public selects the
public service surface; another non-reserved label identifies a hosted
namespace.
Public Namespace
Globally accessible data through standardized interfaces:
get.london.weather.public.v1.resolvedb.net
get.AAPL.stock.public.v1.resolvedb.netHosted Namespace
Hosted namespaces are private by default. Use the opaque query token returned by the API over DoH or DoT so passive observers between the client and TLS endpoint cannot read the bearer credential:
get.auth-rdbq<52>.config.acme-catalog.v1.resolvedb.netNamespace Rules
| Rule | Constraint |
|---|---|
| Length | 3-32 characters |
| Characters | Lowercase a-z, 0-9, - (hyphen) |
| Start | Must be a letter |
| End | Must be a letter or number |
| Uniqueness | Globally unique, enforced case-insensitively |
The dashboard and API enforce a server-maintained reserved-name denylist. Namespace UUIDs identify API resources only and are not DNS aliases.
TTL & Caching
Public service, dataset, and operator-managed public-read answers can be cached
according to their DNS TTL. Successful authenticated private-record answers
always use TTL 0, regardless of the record's configured ttl_seconds.
Write Operations
Write operations (put, delete) use the HTTP API, not DNS. See API Reference for details.
# Create a record after creating the `acme-catalog` namespace
curl -X POST https://api.resolvedb.com/api/v1/records \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"record": {"key": "config.acme-catalog.v1", "data": "eyJoZWxsbyI6IndvcmxkIn0="}}'
# Delete a record
curl -X DELETE https://api.resolvedb.com/api/v1/records/<record-uuid> \
-H "Authorization: Bearer YOUR_API_KEY"After the sync fleet applies the write, the record is available through the private-record gate using a namespace query token.
Record listing is provided by GET /api/v1/records; DNS list, search, and
chunk retrieval are not implemented in UQRP v1. Hosted record payloads are
limited to 2,586 decoded bytes by the API so the complete rendered UQRP value
fits the core's 3,500-byte DNS envelope limit.
Security
ResolveDB implements multiple security layers:
Layer 1: DNSSEC
Native DNS uses ECDSA P-256 and Ed25519 signing with automatically refreshed
RRSIGs and NSEC black lies. The shared serving lifecycle pins a coherent
zone, DNSKEY set, signer, and validity window for each native response through
refresh. The same lifecycle initializes in HTTP-only mode. All shared query
families provide requested DoH signatures, denial proofs, and supporting DNSKEY
access. Required signing failures return SERVFAIL; signing does not set AD.
Layer 2: Content Integrity
Dataset facts include a separate Ed25519 operator attestation in addition to DNSSEC answer authenticity and integrity.
Layer 3: Encryption
Applications can encrypt hosted values before storing them. ResolveDB does not manage customer plaintext encryption keys.
Layer 4: Query Privacy
DNS-over-HTTPS (DoH) and DNS-over-TLS (DoT) encrypt queries in transit:
| Method | Endpoint | Use Case |
|---|---|---|
| DoH JSON | doh.resolvedb.io/resolve | Browsers, debugging |
| DoH Wire | doh.resolvedb.io/dns-query | RFC 8484 clients |
| DoT | dot.resolvedb.io:853 | Native TLS clients |
See DNS Access Methods for details and code examples.
Authentication
Hosted-product query tokens are passed via the auth- prefix:
get.auth-rdbq<52>.resource.namespace.v1.resolvedb.netComplete Specification
This quick reference covers the essentials. For comprehensive details, see:
- Full Protocol Specification - Draft specification with implemented and planned sections clearly marked
- DNS Access Methods - DoH JSON API, DoH wire format, and DoT configuration
Ready to build?
Create an account and start using the UQRP protocol.