Query log tail or search.
const url = 'https://api.opdns.io/v1/profiles/example/logs?mode=tail&limit=100';const options = {method: 'GET', headers: {cookie: 'opdns_session=<opdns_session>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url 'https://api.opdns.io/v1/profiles/example/logs?mode=tail&limit=100' \ --cookie opdns_session=<opdns_session>Token scope: logs:read. Answered from the profile’s log destination:
cloud and both from ClickHouse (501 not_implemented when the server
has no ClickHouse configured; 504 query_timeout when a query runs too long),
self-hosted relayed to the profile’s node over the link (503 node_offline
with Retry-After when no node is connected), none an empty result.
The result has the same shape whichever answers. (Analytics
counts_by_status and timeline are the exception: see
/v1/profiles/{id}/analytics/{shape}.)
device_name is the device’s display name when one is set
(PATCH /v1/profiles/{id}/devices/{deviceId}), else the name the client sent.
Record columns, in order: ts, source, pop, node, profile_id,
device_id, device_name, client_ip, transport, qname, qtype,
status, reason_list_id, reason_rule, rcode, dnssec_validated,
cache_hit, latency_us, answer_ips, then four derived columns (the same
for ClickHouse and node results, whatever the node’s version):
reason(string): the list name when a list decided, else the rule or operator text as stored (denylist: *.example.com,rewrite: =nas.home,legal_order LO-17); empty when domain logging blanked a rule.reason_code(string):list,rule,operator:<code>(legal_order,abuse,csam),rewriteornone(allowed and failed queries).ede_code(uint): the Extended DNS Error the client received: 15 for operator blocks, 17 for every other block, 0 otherwise (the EDE of a failed upstream is not recorded).ede_text(string): the EDE extra text: the reason of a block.
A result is partial when the node answered with fewer rows than asked
because its query deadline was near, or when the profile’s node is
reconnecting (see QueryResult.partial).
Guardrails, per organisation and api replica: each shape
covers at most a fixed range, by plan (free: search, top_devices,
destinations and top_pops 31 days; the hourly shapes 400 days; tail
uncapped): a wider from..to is 422 range_too_large, and without
from the range starts that long before to. Queries draw on a cost
budget (two units per day of raw rows, one per week of hourly totals;
1,200 a minute) and at most four run at
once; a query waits up to five seconds for a slot, then is 429
too_many_queries with Retry-After, as is one over budget. A cloud
query reading more rows or memory than one query may is 422
query_too_expensive.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Public 6-character id; never 000000.
Query Parameters
Section titled “Query Parameters”Inclusive start, RFC 3339 or Unix milliseconds.
Exclusive end, RFC 3339 or Unix milliseconds; default now.
Device id; repeat for several.
Repeat for several.
Substring match for search, exact name otherwise.
Numeric DNS type; repeat for several.
Blocking list id; repeat for several.
Opaque, from a previous result’s next_cursor.
Responses
Section titled “Responses”Result.
object
The fixed query shapes both ClickHouse and self-hosted nodes implement.
The node that answered, for source = node.
object
One array per row, cells in column order; time as RFC 3339, bytes as base64, null for NULL.
Always sent (false when complete). True when the rows are fewer than the
query would give: the node cut its
answer short (partial_reason timeout near its query deadline, or
overload), or a self-hosted profile’s node is reconnecting
(node_reconnecting, no rows; a tail keeps its cursor). The rows present
are valid and next_cursor continues after them.
Set when partial is true.
Example
{ "shape": "tail", "source": "clickhouse", "columns": [ { "type": "string" } ], "partial_reason": "timeout"}Malformed request.
object
Stable machine code.
object
Seconds, repeating the Retry-After header (rate limits, offline nodes).
Example
{ "type": "https://opdns.io/problems/bad_request", "title": "Bad Request", "status": 400, "code": "bad_request", "detail": "invalid JSON body", "request_id": "5f2c9a0e7b1d4c38"}Not authenticated.
object
Stable machine code.
object
Seconds, repeating the Retry-After header (rate limits, offline nodes).
Example
{ "type": "https://opdns.io/problems/unauthenticated", "title": "Unauthorized", "status": 401, "code": "unauthenticated", "detail": "authentication required", "request_id": "5f2c9a0e7b1d4c38"}Authenticated but not allowed: insufficient_scope, session_required, csrf_rejected, mfa_enrolment_required (restricted session), mfa_required (an operator action, or an admin-scoped token, from a session signed in with the password alone; not in dev), reauth_required (sign in again within five minutes), account_pending_deletion (the account is in its deletion cooling-off).
object
Stable machine code.
object
Seconds, repeating the Retry-After header (rate limits, offline nodes).
Example
{ "type": "https://opdns.io/problems/insufficient_scope", "title": "Forbidden", "status": 403, "code": "insufficient_scope", "detail": "the token lacks the profiles:write scope", "request_id": "5f2c9a0e7b1d4c38"}Not found (also for resources of another organisation).
object
Stable machine code.
object
Seconds, repeating the Retry-After header (rate limits, offline nodes).
Example
{ "type": "https://opdns.io/problems/not_found", "title": "Not Found", "status": 404, "code": "not_found", "detail": "resource not found", "request_id": "5f2c9a0e7b1d4c38"}The query was refused: validation_failed (a bad parameter), range_too_large (from..to is wider than the shape allows; errors names from), or query_too_expensive (the query would read more rows or memory than one query may; narrow the range or add filters).
object
Stable machine code.
object
Seconds, repeating the Retry-After header (rate limits, offline nodes).
Example
{ "type": "https://opdns.io/problems/range_too_large", "title": "Unprocessable Content", "status": 422, "code": "range_too_large", "detail": "search queries cover at most 31 days; narrow from and to", "errors": [ { "field": "from", "message": "at most 31 days before to" } ], "request_id": "5f2c9a0e7b1d4c38"}Too many log queries of this organisation are running, or its query budget is spent (too_many_queries); retry after Retry-After seconds.
object
Stable machine code.
object
Seconds, repeating the Retry-After header (rate limits, offline nodes).
Example
{ "type": "https://opdns.io/problems/too_many_queries", "title": "Too Many Requests", "status": 429, "code": "too_many_queries", "detail": "too many log queries are running for this organisation; retry shortly", "request_id": "5f2c9a0e7b1d4c38", "retry_after": 1}Headers
Section titled “Headers”not_implemented (cloud log queries not configured on this server) or shape_unsupported (node too old).
object
Stable machine code.
object
Seconds, repeating the Retry-After header (rate limits, offline nodes).
Example
{ "type": "https://opdns.io/problems/not_implemented", "title": "Not Implemented", "status": 501, "code": "not_implemented", "detail": "cloud log queries are not configured on this server", "request_id": "5f2c9a0e7b1d4c38"}node_error: the node failed to answer.
object
Stable machine code.
object
Seconds, repeating the Retry-After header (rate limits, offline nodes).
Example
{ "type": "https://opdns.io/problems/node_error", "title": "Bad Gateway", "status": 502, "code": "node_error", "detail": "the node failed to answer", "request_id": "5f2c9a0e7b1d4c38"}node_offline: the profile’s logs live on a self-hosted node and no node is
connected; node_busy: the node has too many queries in flight;
relay_unavailable. Retry after Retry-After (also retry_after in the body).
object
Stable machine code.
object
Seconds, repeating the Retry-After header (rate limits, offline nodes).
Example
{ "type": "https://opdns.io/problems/node_offline", "title": "Service Unavailable", "status": 503, "code": "node_offline", "detail": "no node of this profile is connected", "request_id": "5f2c9a0e7b1d4c38", "retry_after": 30}Headers
Section titled “Headers”node_timeout: the node did not answer within 10 seconds; query_timeout: a cloud (ClickHouse) log query ran too long.
object
Stable machine code.
object
Seconds, repeating the Retry-After header (rate limits, offline nodes).
Example
{ "type": "https://opdns.io/problems/node_timeout", "title": "Gateway Timeout", "status": 504, "code": "node_timeout", "detail": "the node did not answer within 10 seconds", "request_id": "5f2c9a0e7b1d4c38"}