REST API Reference

Complete reference for the ResolveDB REST API.

Base URL

All API requests should be made to:

https://api.resolvedb.com/api/v1

Authentication

The ResolveDB API uses Bearer authentication. Customer JWTs can access account management endpoints; API keys are limited by their read/write operation scope and optional namespace allowlist.

Bearer Token

Authorization: Bearer YOUR_JWT_OR_API_KEY

Getting API Keys

Generate API keys from the API Keys section of your dashboard. Each key has configurable permissions and can be revoked at any time.

Important: API key tokens are only displayed once upon creation. Store them securely. If you lose a key, you must generate a new one.

Example Request

curl https://api.resolvedb.com/api/v1/me \
  -H "Authorization: Bearer YOUR_JWT"

Records

Records are the core data objects in ResolveDB. Each record is addressable via DNS and contains Base64-encoded data.

List Records

GET /records

List records visible to the authenticated customer or active organization. API keys are additionally limited to the namespaces in their key scope.

Query Parameters:

ParameterTypeDescription
namespacestringFilter by namespace
resourcestringFilter by resource name
ttl_minintegerMinimum configured TTL hint in seconds
ttl_maxintegerMaximum configured TTL hint in seconds
created_afterstringEarliest creation time (ISO 8601)
created_beforestringLatest creation time (ISO 8601)

Example Request:

curl "https://api.resolvedb.com/api/v1/records?namespace=acme-catalog" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response:

[
  {
    "id": "5d4d9af0-5e66-4b89-95fd-3c2a02f5c844",
    "key": "config.acme-catalog.v1",
    "resource": "config",
    "namespace": "acme-catalog",
    "version": "v1",
    "data": "eyJkYXRhYmFzZSI6InBvc3RncmVzIn0=",
    "content_type": "application/json",
    "ttl_seconds": 3600,
    "expires_at": null,
    "created_at": "2026-08-27T10:30:00Z",
    "updated_at": "2026-08-27T10:30:00Z"
  }
]

Get Record

GET /records/:id

Retrieve a single record by ID.

Path Parameters:

ParameterTypeDescription
idUUIDOpaque record ID returned by the API

Example Request:

curl https://api.resolvedb.com/api/v1/records/5d4d9af0-5e66-4b89-95fd-3c2a02f5c844 \
  -H "Authorization: Bearer YOUR_API_KEY"

Response:

{
  "id": "5d4d9af0-5e66-4b89-95fd-3c2a02f5c844",
  "key": "config.acme-catalog.v1",
  "resource": "config",
  "namespace": "acme-catalog",
  "version": "v1",
  "data": "eyJkYXRhYmFzZSI6InBvc3RncmVzIn0=",
  "content_type": "application/json",
  "ttl_seconds": 3600,
  "expires_at": null,
  "created_at": "2026-08-27T10:30:00Z",
  "updated_at": "2026-08-27T10:30:00Z"
}

Create Record

POST /records

Create a new record after creating its namespace. The data field must be strict Base64 and may decode to at most 2,586 bytes. Hosted-record keys use [<params>....]<resource>.<namespace>.<version>.

Request Body:

FieldTypeRequiredDescription
record.keystringYesDNS key ([params....]resource.namespace.version)
record.datastringYesStrict Base64; maximum 2,586 bytes after decoding
record.content_typestringNoStored content type
record.ttl_secondsintegerNoConfigured envelope TTL hint; does not override the effective DNS RR TTL
record.expires_inintegerNoStorage lifetime in seconds; distinct from the TTL hint
record.expires_atstringNoExplicit storage expiry (ISO 8601)

Example Request:

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": "eyJkYXRhYmFzZSI6InBvc3RncmVzIn0=",
      "content_type": "application/json",
      "ttl_seconds": 3600
    }
  }'

Response:

{
  "id": "5d4d9af0-5e66-4b89-95fd-3c2a02f5c844",
  "key": "config.acme-catalog.v1",
  "resource": "config",
  "namespace": "acme-catalog",
  "version": "v1",
  "data": "eyJkYXRhYmFzZSI6InBvc3RncmVzIn0=",
  "content_type": "application/json",
  "ttl_seconds": 3600,
  "expires_at": null,
  "created_at": "2026-08-27T10:30:00Z",
  "updated_at": "2026-08-27T10:30:00Z"
}

Update Record

PATCH /records/:id

Update an existing record. Only include fields you want to change.

Path Parameters:

ParameterTypeDescription
idUUIDOpaque record ID returned by the API

Request Body:

FieldTypeDescription
record.datastringNew Base64 encoded data
record.ttl_secondsintegerNew configured envelope TTL hint; does not override the effective DNS RR TTL
record.expires_inintegerNew storage lifetime in seconds; 0 clears expiry
record.expires_atstringNew explicit storage expiry

Example Request:

curl -X PATCH https://api.resolvedb.com/api/v1/records/5d4d9af0-5e66-4b89-95fd-3c2a02f5c844 \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "record": {
      "data": "eyJkYXRhYmFzZSI6Im15c3FsIn0=",
      "ttl_seconds": 7200
    }
  }'

Response:

{
  "id": "5d4d9af0-5e66-4b89-95fd-3c2a02f5c844",
  "key": "config.acme-catalog.v1",
  "resource": "config",
  "namespace": "acme-catalog",
  "version": "v1",
  "data": "eyJkYXRhYmFzZSI6Im15c3FsIn0=",
  "content_type": "application/json",
  "ttl_seconds": 7200,
  "expires_at": null,
  "created_at": "2026-08-27T10:30:00Z",
  "updated_at": "2026-08-27T12:45:00Z"
}

Delete Record

DELETE /records/:id

Delete a record. This action is permanent.

Path Parameters:

ParameterTypeDescription
idUUIDOpaque record ID returned by the API

Example Request:

curl -X DELETE https://api.resolvedb.com/api/v1/records/5d4d9af0-5e66-4b89-95fd-3c2a02f5c844 \
  -H "Authorization: Bearer YOUR_API_KEY"

Response:

Returns HTTP 204 No Content on success.


API Keys

Manage API keys for programmatic access to the ResolveDB API. These management endpoints require an authenticated customer JWT; an API key cannot list, mint, modify, or revoke API keys.

List API Keys

GET /api_keys

List all API keys for the authenticated user. Note: The actual token values are not returned for security reasons.

Example Request:

curl https://api.resolvedb.com/api/v1/api_keys \
  -H "Authorization: Bearer YOUR_JWT"

Response:

[
  {
    "id": "6e9b21f5-2f91-4b48-b6d4-f8c932337857",
    "name": "Production API Key",
    "scopes": {
      "operations": ["read", "write"],
      "namespaces": ["acme-catalog"]
    },
    "last_used_at": "2026-08-27T09:00:00Z",
    "expires_at": null,
    "created_at": "2026-08-27T08:00:00Z"
  }
]

Create API Key

POST /api_keys

Create a new API key. The full token is only returned once in this response - store it securely.

Request Body:

FieldTypeRequiredDescription
api_key.namestringYesDescriptive name for the key
api_key.scopes.operationsarrayNoread and/or write; empty means both
api_key.scopes.namespacesarrayNoExplicit namespace names; empty means all accessible namespaces
api_key.expires_atstringNoISO 8601 expiration date

Example Request:

curl -X POST https://api.resolvedb.com/api/v1/api_keys \
  -H "Authorization: Bearer YOUR_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": {
      "name": "Production API Key",
      "scopes": {
        "operations": ["read", "write"],
        "namespaces": ["acme-catalog"]
      },
      "expires_at": "2027-12-31T23:59:59Z"
    }
  }'

Response:

Important: The token field is only returned once. Store it immediately in a secure location.

{
  "id": "6e9b21f5-2f91-4b48-b6d4-f8c932337857",
  "name": "Production API Key",
  "scopes": {
    "operations": ["read", "write"],
    "namespaces": ["acme-catalog"]
  },
  "last_used_at": null,
  "expires_at": "2027-12-31T23:59:59Z",
  "created_at": "2026-08-27T10:30:00Z",
  "token": "<64-character-hex-token>"
}

Revoke API Key

DELETE /api_keys/:id

Revoke an API key. This action is immediate and permanent. Any requests using this key will be rejected.

Path Parameters:

ParameterTypeDescription
idUUIDOpaque API key ID returned by the API

Example Request:

curl -X DELETE https://api.resolvedb.com/api/v1/api_keys/6e9b21f5-2f91-4b48-b6d4-f8c932337857 \
  -H "Authorization: Bearer YOUR_JWT"

Response:

Returns HTTP 204 No Content on success.


Schema Discovery

Retrieve JSON Schema definitions for registered public UQRP resources to understand response formats, field types, and error codes.

Get Resource Schema

GET /schema?q=<query>

Get the JSON Schema for a specific resource. The query parameter accepts any UQRP query format - operation and parameters are ignored, only the resource/namespace/version are extracted.

Query Parameters:

ParameterTypeRequiredDescription
qstringYesUQRP query (e.g., weather.public.v1.resolvedb.net)

Example Requests:

# Get schema for weather resource
curl 'https://doh.resolvedb.io/schema?q=weather.public.v1.resolvedb.net'

# Works with full queries too - operation and params are ignored
curl 'https://doh.resolvedb.io/schema?q=get.seattle.weather.public.v1.resolvedb.net'

Response:

{
  "status": "ok",
  "version": "rdb1",
  "namespace": "public",
  "resource": "weather",
  "resource_version": "v1",
  "schema": {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$id": "https://resolvedb.net/schema/public/weather/v1",
    "title": "Weather Schema",
    "description": "Weather data for a location",
    "type": "object",
    "additionalProperties": false,
    "properties": {
      "tc": {
        "type": "number",
        "description": "Temperature in Celsius. Use for metric regions.",
        "example": 22.5
      },
      "tf": {
        "type": "number",
        "description": "Temperature in Fahrenheit. Use for US/Imperial regions.",
        "example": 72.5
      }
    },
    "required": ["tc", "tf"]
  },
  "meta": {
    "auth_required": false,
    "rate_limit_tier": "standard",
    "default_ttl": 300
  },
  "dns_format": {
    "query_template": "get.<city>.weather.public.v1.resolvedb.net",
    "placeholders": {
      "city": {"type": "string", "examples": ["seattle", "london"]}
    },
    "example_response": "v=rdb1;s=ok;t=data;tc=22.5;tf=72.5"
  },
  "http_format": {
    "endpoint": "GET /resolve?name=get.seattle.weather.public.v1.resolvedb.net&type=TXT",
    "curl_example": "curl 'https://doh.resolvedb.io/resolve?name=get.seattle.weather.public.v1.resolvedb.net&type=TXT'",
    "schema_endpoint": "GET /schema?q=weather.public.v1.resolvedb.net"
  },
  "error_responses": [
    {"status": "notfound", "code": "E004", "description": "City not found"},
    {"status": "ratelimit", "code": "E010", "description": "Rate limit exceeded", "retry_after": true}
  ]
}

Access Control

NamespaceAuth RequiredNotes
publicNoAll public schemas freely accessible
Private namespacesNot exposedThe schema endpoint rejects non-public namespaces

Use Cases

  • LLM Context: Rich field descriptions enable AI to understand API responses
  • Client Validation: JSON Schema validates responses before processing
  • API Discovery: Explore available resources and their capabilities
  • Documentation: Automatically generate API documentation from schemas

Webhooks

Register HTTPS endpoints to receive signed notifications when your records and namespaces change. Webhooks are a paid feature (the free tier may not register any). See the Webhooks guide for the event catalog, payload schema, and HMAC signature-verification examples.

List Webhooks

GET /webhooks

Create Webhook

POST /webhooks

The plaintext secret and dedicated HMAC key signing_secret are returned only in this response (and from regenerate_secret). Store them securely; use signing_secret directly to verify delivery signatures. Neither value can be retrieved again.

Example Request:

curl -X POST https://api.resolvedb.com/api/v1/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "webhook": {
          "name": "prod-listener",
          "url": "https://hooks.example.com/resolvedb",
          "events": ["record.upserted", "record.deleted"],
          "scopes": { "namespaces": ["acme-catalog"] }
        }
      }'

Response (201 Created):

{
  "id": "44c3d8fb-4639-40cb-8431-f95e2d5cc0ee",
  "name": "prod-listener",
  "url": "https://hooks.example.com/resolvedb",
  "events": ["record.upserted", "record.deleted"],
  "enabled": true,
  "failure_count": 0,
  "last_triggered_at": null,
  "scopes": { "namespaces": ["acme-catalog"] },
  "secret": "<64-char-hex-secret>",
  "signing_secret": "<64-char-hex-signing-secret>",
  "created_at": "2026-06-13T12:00:00Z"
}

Valid events are record.upserted, record.deleted, namespace.upserted, and namespace.deleted (also available from GET /webhooks/events). Registration is rejected (422) for non-HTTPS URLs, URLs that resolve to private/internal addresses, or when your tier's webhook quota is reached.

Other Webhook Endpoints

Method & PathPurpose
GET /webhooks/:idFetch a single webhook (secret omitted).
PATCH /webhooks/:idUpdate name, url, events, scopes, or enabled state.
DELETE /webhooks/:idDelete a webhook and its delivery history.
POST /webhooks/:id/testSend a test delivery to the endpoint.
POST /webhooks/:id/regenerate_secretRotate secret and signing_secret (returns both new values once).
GET /webhooks/:id/deliveriesPaginated recent deliveries (status, response code, errors).
GET /webhooks/eventsThe catalog of valid event types.

Account

Endpoints for managing your account and retrieving profile information.

Get Current User

GET /me

Get the current authenticated user's profile information.

Example Request:

curl https://api.resolvedb.com/api/v1/me \
  -H "Authorization: Bearer YOUR_CUSTOMER_JWT"

Account endpoints require a customer session JWT and reject API-key principals.

Response:

{
  "id": "1a5a30f2-0eb4-48dc-9577-770a4b75d990",
  "email": "developer@example.com",
  "role": "user",
  "records_count": 42,
  "api_keys_count": 2,
  "namespaces_count": 1,
  "created_at": "2026-08-27T08:00:00Z"
}

Error Handling

The API uses conventional HTTP response codes to indicate success or failure of requests. Errors include a JSON body with details.

Error Response Format

{"error":"Record not found"}

Validation failures use an errors array, for example {"errors":["Key can't be blank"]}.

HTTP Status Codes

CodeNameDescription
200OKRequest succeeded
201CreatedResource created successfully
204No ContentRequest succeeded, no body returned
400Bad RequestInvalid request body or parameters
401UnauthorizedMissing or invalid API key
403ForbiddenAPI key lacks required scope
404Not FoundResource does not exist
422Unprocessable EntityValidation error
429Too Many RequestsRate limit exceeded
500Internal Server ErrorServer error (contact support)

Error Codes

CodeDescription
authentication_errorInvalid or missing API key
authorization_errorAPI key lacks required permissions
validation_errorRequest body failed validation
not_foundRequested resource does not exist
rate_limit_exceededToo many requests
quota_exceededAccount record limit reached
server_errorInternal server error

DNS queries use DNS RCODEs for request-level failures. See the UQRP protocol for the shipped mapping.


Rate Limits

API requests are rate limited to ensure fair usage and system stability.

General Limits

Request classLimit
Unauthenticated requests by IP100 per minute
Authenticated requests by customer1,000 per minute
Writes by customer60 per minute and 600 per hour

Sensitive endpoints such as sign-in, verification, passkeys, and webhook secret operations have additional lower limits. A throttled response includes Retry-After; normal responses do not include X-RateLimit-* counters.

Record quotas are entitlement limits rather than request-rate limits:

TierRecord cap
Free1,000
Pro50,000
Team500,000
Enterprise1,000,000

Handling Rate Limits

When rate limited, the API returns HTTP 429. Respect Retry-After:

// Example: Exponential backoff in JavaScript
async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const response = await fetch(url, options);

    if (response.status === 429) {
      const retryAfter = Number(response.headers.get('Retry-After') || i + 1);
      await new Promise(r => setTimeout(r, retryAfter * 1000));
      continue;
    }

    return response;
  }
  throw new Error('Rate limit exceeded after retries');
}

Next Steps