Skip to content

Analytics aggregate.

GET
/v1/profiles/{id}/analytics/{shape}
curl --request GET \
--url 'https://api.opdns.io/v1/profiles/example/analytics/counts_by_status?limit=100' \
--cookie opdns_session=<opdns_session>

Token scope: analytics:read. Same routing by log destination as /v1/profiles/{id}/logs, with one exception: counts_by_status and timeline filtered by time only (no device, status, qname, qtype, list or client_ip) always come from ClickHouse (source = clickhouse), also for none and self-hosted profiles. The cloud keeps hourly totals of every profile’s queries, counted by the edge even when no per-query row is kept, so these answer counter-derived totals (whole hours: a sub-hour range or bucket reports the enclosing hours). With any other filter they, and top_* and destinations always, follow the destination: relayed to the node for self-hosted, empty for none. Without ClickHouse configured, those two shapes also fall back to the destination’s routing. bucket applies to timeline (default 3600). In top_devices, device_name is the display name when one is set; rows stay grouped by device id. top_reasons groups queries by what decided them: columns reason_code (list, rule, operator:<code>, rewrite, none), list_id (set for list only), reason (the list name for list, the rule or operator text for the others, "" for none) and count, most frequent first, ties by reason_code, list_id, reason. Without a status filter it counts blocked and rewritten queries. destinations groups allowed queries (without a status filter) by answer address: columns ip, count, country (ISO 3166-1 alpha-2 of the address from the server’s GeoIP database, "" when unknown or when no database is configured; see geoip_attribution in GET /v1/meta) and owner (the company whose address it is: google, apple, meta, amazon, microsoft, or the CDNs cloudflare, akamai, fastly; "" for any other). top_owners counts queries by the company they reached: columns owner and count, most first, ties by owner; a query’s owner is its name’s (a curated domain suffix list) or else its first classified answer address’s; unclassified queries are left out; no default status filter. Nodes older than top_owners answer 501 shape_unsupported. top_pops counts queries by the PoP that answered them: columns pop (the PoP id as in GET /v1/pops, e.g. ams; queries a self-hosted node answered itself are node) and count, most first, ties by pop; no default status filter. Nodes older than top_pops answer 501 shape_unsupported.

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.

id
required

Public 6-character id; never 000000.

string
/^[a-z0-9]{6}$/
shape
required
string
Allowed values: counts_by_status top_domains top_devices top_blocked destinations timeline top_reasons top_owners top_pops
from
string

Inclusive start, RFC 3339 or Unix milliseconds.

to
string

Exclusive end, RFC 3339 or Unix milliseconds; default now.

device
Array<string>

Device id; repeat for several.

status
Array<string>
Allowed values: allowed blocked rewritten error

Repeat for several.

qname
string
<= 253 characters

Substring match for search, exact name otherwise.

qtype
Array<integer>

Numeric DNS type; repeat for several.

list
Array<integer>

Blocking list id; repeat for several.

client_ip
string
limit
integer
default: 100 >= 1 <= 1000
cursor
string
<= 512 characters

Opaque, from a previous result’s next_cursor.

bucket
integer
>= 60 <= 86400

Timeline bucket width in seconds.

Result.

Media typeapplication/json
object
shape
required

The fixed query shapes both ClickHouse and self-hosted nodes implement.

string
Allowed values: tail search counts_by_status top_domains top_devices top_blocked destinations timeline top_reasons top_owners top_pops
source
required
string
Allowed values: clickhouse node none
node

The node that answered, for source = node.

string format: uuid
columns
required
Array<object>
object
name
required
string
type
required
string
Allowed values: string int uint float bool time bytes unknown
rows
required

One array per row, cells in column order; time as RFC 3339, bytes as base64, null for NULL.

Array<Array>
next_cursor
string
partial

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.

boolean
partial_reason

Set when partial is true.

string
Allowed values: timeout overload node_reconnecting
Example
{
"shape": "tail",
"source": "clickhouse",
"columns": [
{
"type": "string"
}
],
"partial_reason": "timeout"
}

Malformed request.

Media typeapplication/problem+json
object
type
required
string format: uri
title
required
string
status
required
integer
code
required

Stable machine code.

string
Allowed values: bad_request body_too_large bad_if_match unauthenticated invalid_credentials signup_closed invite_required waitlist_unavailable invalid_token token_expired token_used session_required insufficient_scope csrf_rejected not_found version_mismatch ip_conflict unknown_list too_many_rules validation_failed rate_limited internal node_revoked node_offline node_busy node_timeout node_error result_too_large shape_unsupported node_token_superseded relay_unavailable not_implemented query_timeout query_too_expensive range_too_large too_many_queries second_factor_required invalid_second_factor mfa_enrolment_required mfa_required reauth_required no_second_factor totp_already_enabled totp_not_enabled last_credential passkey_exists passkey_invalid passkeys_unavailable ceremony_invalid account_pending_deletion credential_required deletion_pending no_deletion_pending deletion_started organisation_has_members export_in_progress export_not_ready block_exists invalid_recovery_code profile_not_empty invalid_cursor bad_idempotency_key idempotency_key_reused idempotency_in_progress too_many_streams too_many_reports password_too_short password_too_long profile_suspended
detail
string
errors
Array<object>
object
field
required
string
message
required
string
request_id
string
retry_after

Seconds, repeating the Retry-After header (rate limits, offline nodes).

integer
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.

Media typeapplication/problem+json
object
type
required
string format: uri
title
required
string
status
required
integer
code
required

Stable machine code.

string
Allowed values: bad_request body_too_large bad_if_match unauthenticated invalid_credentials signup_closed invite_required waitlist_unavailable invalid_token token_expired token_used session_required insufficient_scope csrf_rejected not_found version_mismatch ip_conflict unknown_list too_many_rules validation_failed rate_limited internal node_revoked node_offline node_busy node_timeout node_error result_too_large shape_unsupported node_token_superseded relay_unavailable not_implemented query_timeout query_too_expensive range_too_large too_many_queries second_factor_required invalid_second_factor mfa_enrolment_required mfa_required reauth_required no_second_factor totp_already_enabled totp_not_enabled last_credential passkey_exists passkey_invalid passkeys_unavailable ceremony_invalid account_pending_deletion credential_required deletion_pending no_deletion_pending deletion_started organisation_has_members export_in_progress export_not_ready block_exists invalid_recovery_code profile_not_empty invalid_cursor bad_idempotency_key idempotency_key_reused idempotency_in_progress too_many_streams too_many_reports password_too_short password_too_long profile_suspended
detail
string
errors
Array<object>
object
field
required
string
message
required
string
request_id
string
retry_after

Seconds, repeating the Retry-After header (rate limits, offline nodes).

integer
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).

Media typeapplication/problem+json
object
type
required
string format: uri
title
required
string
status
required
integer
code
required

Stable machine code.

string
Allowed values: bad_request body_too_large bad_if_match unauthenticated invalid_credentials signup_closed invite_required waitlist_unavailable invalid_token token_expired token_used session_required insufficient_scope csrf_rejected not_found version_mismatch ip_conflict unknown_list too_many_rules validation_failed rate_limited internal node_revoked node_offline node_busy node_timeout node_error result_too_large shape_unsupported node_token_superseded relay_unavailable not_implemented query_timeout query_too_expensive range_too_large too_many_queries second_factor_required invalid_second_factor mfa_enrolment_required mfa_required reauth_required no_second_factor totp_already_enabled totp_not_enabled last_credential passkey_exists passkey_invalid passkeys_unavailable ceremony_invalid account_pending_deletion credential_required deletion_pending no_deletion_pending deletion_started organisation_has_members export_in_progress export_not_ready block_exists invalid_recovery_code profile_not_empty invalid_cursor bad_idempotency_key idempotency_key_reused idempotency_in_progress too_many_streams too_many_reports password_too_short password_too_long profile_suspended
detail
string
errors
Array<object>
object
field
required
string
message
required
string
request_id
string
retry_after

Seconds, repeating the Retry-After header (rate limits, offline nodes).

integer
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).

Media typeapplication/problem+json
object
type
required
string format: uri
title
required
string
status
required
integer
code
required

Stable machine code.

string
Allowed values: bad_request body_too_large bad_if_match unauthenticated invalid_credentials signup_closed invite_required waitlist_unavailable invalid_token token_expired token_used session_required insufficient_scope csrf_rejected not_found version_mismatch ip_conflict unknown_list too_many_rules validation_failed rate_limited internal node_revoked node_offline node_busy node_timeout node_error result_too_large shape_unsupported node_token_superseded relay_unavailable not_implemented query_timeout query_too_expensive range_too_large too_many_queries second_factor_required invalid_second_factor mfa_enrolment_required mfa_required reauth_required no_second_factor totp_already_enabled totp_not_enabled last_credential passkey_exists passkey_invalid passkeys_unavailable ceremony_invalid account_pending_deletion credential_required deletion_pending no_deletion_pending deletion_started organisation_has_members export_in_progress export_not_ready block_exists invalid_recovery_code profile_not_empty invalid_cursor bad_idempotency_key idempotency_key_reused idempotency_in_progress too_many_streams too_many_reports password_too_short password_too_long profile_suspended
detail
string
errors
Array<object>
object
field
required
string
message
required
string
request_id
string
retry_after

Seconds, repeating the Retry-After header (rate limits, offline nodes).

integer
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).

Media typeapplication/problem+json
object
type
required
string format: uri
title
required
string
status
required
integer
code
required

Stable machine code.

string
Allowed values: bad_request body_too_large bad_if_match unauthenticated invalid_credentials signup_closed invite_required waitlist_unavailable invalid_token token_expired token_used session_required insufficient_scope csrf_rejected not_found version_mismatch ip_conflict unknown_list too_many_rules validation_failed rate_limited internal node_revoked node_offline node_busy node_timeout node_error result_too_large shape_unsupported node_token_superseded relay_unavailable not_implemented query_timeout query_too_expensive range_too_large too_many_queries second_factor_required invalid_second_factor mfa_enrolment_required mfa_required reauth_required no_second_factor totp_already_enabled totp_not_enabled last_credential passkey_exists passkey_invalid passkeys_unavailable ceremony_invalid account_pending_deletion credential_required deletion_pending no_deletion_pending deletion_started organisation_has_members export_in_progress export_not_ready block_exists invalid_recovery_code profile_not_empty invalid_cursor bad_idempotency_key idempotency_key_reused idempotency_in_progress too_many_streams too_many_reports password_too_short password_too_long profile_suspended
detail
string
errors
Array<object>
object
field
required
string
message
required
string
request_id
string
retry_after

Seconds, repeating the Retry-After header (rate limits, offline nodes).

integer
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.

Media typeapplication/problem+json
object
type
required
string format: uri
title
required
string
status
required
integer
code
required

Stable machine code.

string
Allowed values: bad_request body_too_large bad_if_match unauthenticated invalid_credentials signup_closed invite_required waitlist_unavailable invalid_token token_expired token_used session_required insufficient_scope csrf_rejected not_found version_mismatch ip_conflict unknown_list too_many_rules validation_failed rate_limited internal node_revoked node_offline node_busy node_timeout node_error result_too_large shape_unsupported node_token_superseded relay_unavailable not_implemented query_timeout query_too_expensive range_too_large too_many_queries second_factor_required invalid_second_factor mfa_enrolment_required mfa_required reauth_required no_second_factor totp_already_enabled totp_not_enabled last_credential passkey_exists passkey_invalid passkeys_unavailable ceremony_invalid account_pending_deletion credential_required deletion_pending no_deletion_pending deletion_started organisation_has_members export_in_progress export_not_ready block_exists invalid_recovery_code profile_not_empty invalid_cursor bad_idempotency_key idempotency_key_reused idempotency_in_progress too_many_streams too_many_reports password_too_short password_too_long profile_suspended
detail
string
errors
Array<object>
object
field
required
string
message
required
string
request_id
string
retry_after

Seconds, repeating the Retry-After header (rate limits, offline nodes).

integer
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
}
Retry-After
integer

not_implemented (cloud log queries not configured on this server) or shape_unsupported (node too old).

Media typeapplication/problem+json
object
type
required
string format: uri
title
required
string
status
required
integer
code
required

Stable machine code.

string
Allowed values: bad_request body_too_large bad_if_match unauthenticated invalid_credentials signup_closed invite_required waitlist_unavailable invalid_token token_expired token_used session_required insufficient_scope csrf_rejected not_found version_mismatch ip_conflict unknown_list too_many_rules validation_failed rate_limited internal node_revoked node_offline node_busy node_timeout node_error result_too_large shape_unsupported node_token_superseded relay_unavailable not_implemented query_timeout query_too_expensive range_too_large too_many_queries second_factor_required invalid_second_factor mfa_enrolment_required mfa_required reauth_required no_second_factor totp_already_enabled totp_not_enabled last_credential passkey_exists passkey_invalid passkeys_unavailable ceremony_invalid account_pending_deletion credential_required deletion_pending no_deletion_pending deletion_started organisation_has_members export_in_progress export_not_ready block_exists invalid_recovery_code profile_not_empty invalid_cursor bad_idempotency_key idempotency_key_reused idempotency_in_progress too_many_streams too_many_reports password_too_short password_too_long profile_suspended
detail
string
errors
Array<object>
object
field
required
string
message
required
string
request_id
string
retry_after

Seconds, repeating the Retry-After header (rate limits, offline nodes).

integer
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.

Media typeapplication/problem+json
object
type
required
string format: uri
title
required
string
status
required
integer
code
required

Stable machine code.

string
Allowed values: bad_request body_too_large bad_if_match unauthenticated invalid_credentials signup_closed invite_required waitlist_unavailable invalid_token token_expired token_used session_required insufficient_scope csrf_rejected not_found version_mismatch ip_conflict unknown_list too_many_rules validation_failed rate_limited internal node_revoked node_offline node_busy node_timeout node_error result_too_large shape_unsupported node_token_superseded relay_unavailable not_implemented query_timeout query_too_expensive range_too_large too_many_queries second_factor_required invalid_second_factor mfa_enrolment_required mfa_required reauth_required no_second_factor totp_already_enabled totp_not_enabled last_credential passkey_exists passkey_invalid passkeys_unavailable ceremony_invalid account_pending_deletion credential_required deletion_pending no_deletion_pending deletion_started organisation_has_members export_in_progress export_not_ready block_exists invalid_recovery_code profile_not_empty invalid_cursor bad_idempotency_key idempotency_key_reused idempotency_in_progress too_many_streams too_many_reports password_too_short password_too_long profile_suspended
detail
string
errors
Array<object>
object
field
required
string
message
required
string
request_id
string
retry_after

Seconds, repeating the Retry-After header (rate limits, offline nodes).

integer
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).

Media typeapplication/problem+json
object
type
required
string format: uri
title
required
string
status
required
integer
code
required

Stable machine code.

string
Allowed values: bad_request body_too_large bad_if_match unauthenticated invalid_credentials signup_closed invite_required waitlist_unavailable invalid_token token_expired token_used session_required insufficient_scope csrf_rejected not_found version_mismatch ip_conflict unknown_list too_many_rules validation_failed rate_limited internal node_revoked node_offline node_busy node_timeout node_error result_too_large shape_unsupported node_token_superseded relay_unavailable not_implemented query_timeout query_too_expensive range_too_large too_many_queries second_factor_required invalid_second_factor mfa_enrolment_required mfa_required reauth_required no_second_factor totp_already_enabled totp_not_enabled last_credential passkey_exists passkey_invalid passkeys_unavailable ceremony_invalid account_pending_deletion credential_required deletion_pending no_deletion_pending deletion_started organisation_has_members export_in_progress export_not_ready block_exists invalid_recovery_code profile_not_empty invalid_cursor bad_idempotency_key idempotency_key_reused idempotency_in_progress too_many_streams too_many_reports password_too_short password_too_long profile_suspended
detail
string
errors
Array<object>
object
field
required
string
message
required
string
request_id
string
retry_after

Seconds, repeating the Retry-After header (rate limits, offline nodes).

integer
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
}
Retry-After
integer

node_timeout: the node did not answer within 10 seconds; query_timeout: a cloud (ClickHouse) log query ran too long.

Media typeapplication/problem+json
object
type
required
string format: uri
title
required
string
status
required
integer
code
required

Stable machine code.

string
Allowed values: bad_request body_too_large bad_if_match unauthenticated invalid_credentials signup_closed invite_required waitlist_unavailable invalid_token token_expired token_used session_required insufficient_scope csrf_rejected not_found version_mismatch ip_conflict unknown_list too_many_rules validation_failed rate_limited internal node_revoked node_offline node_busy node_timeout node_error result_too_large shape_unsupported node_token_superseded relay_unavailable not_implemented query_timeout query_too_expensive range_too_large too_many_queries second_factor_required invalid_second_factor mfa_enrolment_required mfa_required reauth_required no_second_factor totp_already_enabled totp_not_enabled last_credential passkey_exists passkey_invalid passkeys_unavailable ceremony_invalid account_pending_deletion credential_required deletion_pending no_deletion_pending deletion_started organisation_has_members export_in_progress export_not_ready block_exists invalid_recovery_code profile_not_empty invalid_cursor bad_idempotency_key idempotency_key_reused idempotency_in_progress too_many_streams too_many_reports password_too_short password_too_long profile_suspended
detail
string
errors
Array<object>
object
field
required
string
message
required
string
request_id
string
retry_after

Seconds, repeating the Retry-After header (rate limits, offline nodes).

integer
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"
}