REST API Reference
Complete reference for the ResolveDB REST API.
Base URL
All API requests should be made to:
https://api.resolvedb.com/api/v1Authentication
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_KEYGetting 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 /recordsList records visible to the authenticated customer or active organization. API keys are additionally limited to the namespaces in their key scope.
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
| namespace | string | Filter by namespace |
| resource | string | Filter by resource name |
| ttl_min | integer | Minimum configured TTL hint in seconds |
| ttl_max | integer | Maximum configured TTL hint in seconds |
| created_after | string | Earliest creation time (ISO 8601) |
| created_before | string | Latest 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/:idRetrieve a single record by ID.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
| id | UUID | Opaque 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 /recordsCreate 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:
| Field | Type | Required | Description |
|---|---|---|---|
| record.key | string | Yes | DNS key ([params....]resource.namespace.version) |
| record.data | string | Yes | Strict Base64; maximum 2,586 bytes after decoding |
| record.content_type | string | No | Stored content type |
| record.ttl_seconds | integer | No | Configured envelope TTL hint; does not override the effective DNS RR TTL |
| record.expires_in | integer | No | Storage lifetime in seconds; distinct from the TTL hint |
| record.expires_at | string | No | Explicit 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/:idUpdate an existing record. Only include fields you want to change.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
| id | UUID | Opaque record ID returned by the API |
Request Body:
| Field | Type | Description |
|---|---|---|
| record.data | string | New Base64 encoded data |
| record.ttl_seconds | integer | New configured envelope TTL hint; does not override the effective DNS RR TTL |
| record.expires_in | integer | New storage lifetime in seconds; 0 clears expiry |
| record.expires_at | string | New 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/:idDelete a record. This action is permanent.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
| id | UUID | Opaque 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_keysList 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_keysCreate a new API key. The full token is only returned once in this response - store it securely.
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
| api_key.name | string | Yes | Descriptive name for the key |
| api_key.scopes.operations | array | No | read and/or write; empty means both |
| api_key.scopes.namespaces | array | No | Explicit namespace names; empty means all accessible namespaces |
| api_key.expires_at | string | No | ISO 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
tokenfield 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/:idRevoke an API key. This action is immediate and permanent. Any requests using this key will be rejected.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
| id | UUID | Opaque 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:
| Parameter | Type | Required | Description |
|---|---|---|---|
| q | string | Yes | UQRP 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
| Namespace | Auth Required | Notes |
|---|---|---|
public | No | All public schemas freely accessible |
| Private namespaces | Not exposed | The 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 /webhooksCreate Webhook
POST /webhooksThe 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 & Path | Purpose |
|---|---|
GET /webhooks/:id | Fetch a single webhook (secret omitted). |
PATCH /webhooks/:id | Update name, url, events, scopes, or enabled state. |
DELETE /webhooks/:id | Delete a webhook and its delivery history. |
POST /webhooks/:id/test | Send a test delivery to the endpoint. |
POST /webhooks/:id/regenerate_secret | Rotate secret and signing_secret (returns both new values once). |
GET /webhooks/:id/deliveries | Paginated recent deliveries (status, response code, errors). |
GET /webhooks/events | The catalog of valid event types. |
Account
Endpoints for managing your account and retrieving profile information.
Get Current User
GET /meGet 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
| Code | Name | Description |
|---|---|---|
| 200 | OK | Request succeeded |
| 201 | Created | Resource created successfully |
| 204 | No Content | Request succeeded, no body returned |
| 400 | Bad Request | Invalid request body or parameters |
| 401 | Unauthorized | Missing or invalid API key |
| 403 | Forbidden | API key lacks required scope |
| 404 | Not Found | Resource does not exist |
| 422 | Unprocessable Entity | Validation error |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server error (contact support) |
Error Codes
| Code | Description |
|---|---|
| authentication_error | Invalid or missing API key |
| authorization_error | API key lacks required permissions |
| validation_error | Request body failed validation |
| not_found | Requested resource does not exist |
| rate_limit_exceeded | Too many requests |
| quota_exceeded | Account record limit reached |
| server_error | Internal 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 class | Limit |
|---|---|
| Unauthenticated requests by IP | 100 per minute |
| Authenticated requests by customer | 1,000 per minute |
| Writes by customer | 60 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:
| Tier | Record cap |
|---|---|
| Free | 1,000 |
| Pro | 50,000 |
| Team | 500,000 |
| Enterprise | 1,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
- Quickstart Guide - Get up and running in 5 minutes
- UQRP Protocol - Learn the DNS query format
- Webhooks - Signed event delivery for record/namespace changes
- Security - Authentication and encryption options