Portal search & analytics API
This page documents three related API surface areas: portal global search, the complete analytics dashboard specification, and config changelog enhancements. The portal search endpoint provides full-text search across all entity types — users, groups, models, audit events, DLP rules, and more — with relevance scoring and grouped results. The analytics dashboard endpoint provides the complete specification for aggregated organization usage data, extending the partial coverage in the avatar and analytics reference. The config changelog section documents new resource types and response fields added in recent sprints.
Base URL: https://api.arbitex.ai
Portal Search API
Section titled “Portal Search API”The portal search endpoint indexes all major entity types in real time. Search is full-text across a defined set of fields per entity type. Results are grouped by entity type, sorted by relevance score within each group, and returned in a single response. The endpoint is suitable for powering a global search bar in the admin UI, as well as for programmatic entity discovery.
Endpoint summary
Section titled “Endpoint summary”| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/v1/portal/search |
Bearer token or Admin API key | Full-text search across all portal entity types |
GET /v1/portal/search
Section titled “GET /v1/portal/search”Full-text search across all portal entity types. Returns results grouped by entity type with relevance scoring. Entity types not matched by the query are omitted from the response.
Authentication: Bearer token (org-scoped JWT) or Admin API key. The search scope is implicitly restricted to the caller’s organization. Multi-tenant administrators who supply an explicit org_id can search across organizations, subject to their cross-org permission grants.
Query parameters
Section titled “Query parameters”| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
q |
string | Yes | — | Search query. Minimum 2 characters. |
types |
string | No | all | Comma-separated entity types to search. Valid values: users, groups, models, conversations, audit_events, dlp_rules, policy_rules, api_keys, webhooks, organizations. |
limit |
integer | No | 20 | Maximum results per entity type (1–50). |
offset |
integer | No | 0 | Pagination offset applied per entity type. |
org_id |
string (UUID) | No | from token | Organization scope. Multi-tenant admins can override to search within a specific organization. |
Request
Section titled “Request”curl -s "https://api.arbitex.ai/v1/portal/search?q=john&types=users,groups&limit=10" \ -H "Authorization: Bearer $TOKEN"Response 200 OK
Section titled “Response 200 OK”{ "query": "john", "total_results": 15, "results": { "users": { "count": 12, "items": [ { "id": "usr_01HZ_JOHN", "type": "user", "title": "John Smith", "matched_fields": ["display_name", "email"], "score": 0.95, "url": "/admin/users/usr_01HZ_JOHN", "metadata": { "status": "active", "role": "member", "last_active": "2026-03-14T12:00:00Z" } } ], "has_more": true }, "groups": { "count": 3, "items": [ { "id": "grp_01HZ_ENG", "type": "group", "title": "Engineering", "subtitle": "12 members", "matched_fields": ["member_names"], "score": 0.72, "url": "/admin/groups/grp_01HZ_ENG", "metadata": { "member_count": 12, "policy_count": 3 } } ], "has_more": false } }, "search_duration_ms": 42}Response fields
Section titled “Response fields”| Field | Type | Description |
|---|---|---|
query |
string | Echo of the search query as submitted |
total_results |
integer | Total match count across all entity types |
results |
object | Map of entity type name → result set. Only types with at least one match are included. |
results.{type}.count |
integer | Total matches found for this entity type (may exceed limit) |
results.{type}.items |
array | Matching items up to the requested limit |
results.{type}.items[].id |
string | Entity identifier |
results.{type}.items[].type |
string | Entity type name (e.g., "user", "group") |
results.{type}.items[].title |
string | Primary display text (e.g., display name, rule name) |
results.{type}.items[].subtitle |
string | Secondary display text (e.g., email address, member count) |
results.{type}.items[].matched_fields |
array | Fields that contributed to the match for this item |
results.{type}.items[].score |
number | Relevance score from 0.0 (weakest) to 1.0 (strongest) |
results.{type}.items[].url |
string | Portal path to the entity detail page, suitable for navigation |
results.{type}.items[].metadata |
object | Entity-type-specific supplemental fields (see per-type details below) |
results.{type}.has_more |
boolean | true if the total count for this entity type exceeds the requested limit |
search_duration_ms |
integer | Server-side search execution time in milliseconds |
Searchable fields per entity type
Section titled “Searchable fields per entity type”| Entity Type | Searchable Fields |
|---|---|
users |
display_name, email, username, external_id |
groups |
name, description, member_names |
models |
name, provider, model_id, description |
conversations |
title, participant_names |
audit_events |
actor_email, action, resource_type, ip_address |
dlp_rules |
name, description, pattern |
policy_rules |
name, description, condition_summary |
api_keys |
name, prefix (last 4 characters only — full key values are never indexed) |
webhooks |
name, url, event_types |
organizations |
name, domain, plan_tier |
Metadata fields by entity type
Section titled “Metadata fields by entity type”The metadata object varies by entity type. Common fields:
| Entity Type | Metadata Fields |
|---|---|
users |
status, role, last_active |
groups |
member_count, policy_count |
models |
provider, status, request_count_30d |
conversations |
participant_count, message_count, created_at |
audit_events |
severity, outcome, occurred_at |
dlp_rules |
enabled, trigger_count_30d, action |
policy_rules |
enabled, priority, condition_count |
api_keys |
status, last_used, scopes |
webhooks |
enabled, delivery_success_rate, last_triggered |
organizations |
plan_tier, user_count, created_at |
Error responses
Section titled “Error responses”| Status | Code | Description |
|---|---|---|
400 |
query_too_short |
Query string is fewer than 2 characters |
400 |
invalid_type |
One or more values in the types parameter are not recognized entity type names |
401 |
unauthorized |
Missing or invalid authentication credential |
403 |
forbidden |
Caller lacks permission to search the requested organization scope |
429 |
rate_limited |
Search rate limit exceeded — 60 requests per minute per user |
Rate limiting: 60 requests per minute per authenticated user. Search queries are logged in the audit trail with the query string redacted after 90 days. The q parameter is never logged in plaintext in long-term storage.
Analytics Dashboard API
Section titled “Analytics Dashboard API”The analytics dashboard endpoint provides the full aggregated usage payload for an organization. This section documents the complete specification — including all query parameters, response fields, auto-granularity rules, and CSV export format. An earlier partial reference appears in the avatar and analytics API page; this section supersedes that coverage and adds the start_date/end_date custom range, the include filter, and the format=csv export option.
Endpoint summary
Section titled “Endpoint summary”| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/v1/orgs/{org_id}/analytics/dashboard |
Bearer token with analytics:read, or Admin API key |
Retrieve aggregated analytics for an organization |
GET /v1/orgs/{org_id}/analytics/dashboard
Section titled “GET /v1/orgs/{org_id}/analytics/dashboard”Retrieve the analytics dashboard payload for an organization. Results cover the requested time period and are returned as a snapshot computed at request time. Responses are not cached server-side — callers should implement their own caching layer when polling this endpoint at high frequency.
Authentication: Bearer token (org-scoped JWT) with analytics:read permission, or Admin API key scoped to the target organization.
Path parameters
Section titled “Path parameters”| Parameter | Type | Description |
|---|---|---|
org_id |
string (UUID) | Organization identifier |
Query parameters
Section titled “Query parameters”| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
period |
string | No | 30d |
Predefined time window: 7d, 30d, 90d, or custom. When custom, both start_date and end_date are required. |
start_date |
string (ISO 8601) | Conditional | — | Start of the custom date range (inclusive). Required when period=custom. |
end_date |
string (ISO 8601) | Conditional | — | End of the custom date range (inclusive). Required when period=custom. Maximum range: 365 days. |
granularity |
string | No | auto | Data point interval for usage_over_time: hourly, daily, weekly, or monthly. When auto, the server selects an appropriate interval based on the period (see table below). |
include |
string | No | all | Comma-separated list of response sections to include: summary, usage_over_time, token_distribution, top_models, top_users, dlp_summary. Omitting a section reduces response payload size. |
format |
string | No | json |
Response format: json or csv. When csv, the response is a flattened tabular export rather than JSON. |
Auto-granularity rules
Section titled “Auto-granularity rules”When granularity=auto (the default), the server selects an interval according to the period:
| Period | Default Granularity | Approximate Data Points |
|---|---|---|
7d |
hourly |
~168 |
30d |
daily |
30 |
90d |
daily |
90 |
custom, range ≤ 7 days |
hourly |
varies |
custom, range 8–90 days |
daily |
varies |
custom, range 91–365 days |
weekly |
varies |
Request
Section titled “Request”curl -s "https://api.arbitex.ai/v1/orgs/org_01HZ_ACME/analytics/dashboard?period=30d&include=summary,top_models" \ -H "Authorization: Bearer $TOKEN"Response 200 OK
Section titled “Response 200 OK”{ "org_id": "org_01HZ_ACME", "period": "30d", "granularity": "daily", "generated_at": "2026-03-14T12:00:00Z", "summary": { "total_requests": 284102, "total_input_tokens": 31204819, "total_output_tokens": 21636204, "estimated_cost_usd": 1847.32, "active_users": 142, "period_start": "2026-02-12T00:00:00Z", "period_end": "2026-03-13T23:59:59Z" }, "usage_over_time": [ { "date": "2026-02-12", "requests": 9102, "input_tokens": 1050341, "output_tokens": 843506, "cost_usd": 62.14 }, { "date": "2026-02-13", "requests": 8794, "input_tokens": 1020183, "output_tokens": 801247, "cost_usd": 60.02 }, { "date": "2026-03-13", "requests": 9470, "input_tokens": 1098324, "output_tokens": 863043, "cost_usd": 65.77 } ], "token_distribution": [ { "model": "gpt-4o", "input_tokens": 10823401, "output_tokens": 7491023, "total_tokens": 18314424 }, { "model": "claude-opus-4-6", "input_tokens": 8934102, "output_tokens": 6892341, "total_tokens": 15826443 }, { "model": "claude-sonnet-4-6", "input_tokens": 6201047, "output_tokens": 4730219, "total_tokens": 10931266 } ], "top_models": [ { "model": "gpt-4o", "provider": "openai", "requests": 98432, "tokens": 18314424, "cost_usd": 641.50, "percentage": 34.6 }, { "model": "claude-opus-4-6", "provider": "anthropic", "requests": 61203, "tokens": 15826443, "cost_usd": 554.03, "percentage": 21.5 }, { "model": "claude-sonnet-4-6", "provider": "anthropic", "requests": 54901, "tokens": 10931266, "cost_usd": 382.59, "percentage": 19.3 } ], "top_users": [ { "user_id": "usr_01HZ_JANE", "display_name": "Jane Doe", "requests": 4521, "tokens": 892341, "cost_usd": 31.23 }, { "user_id": "usr_01HZ_BOB", "display_name": "Bob Smith", "requests": 3874, "tokens": 741209, "cost_usd": 25.94 }, { "user_id": "usr_01HZ_ALICE", "display_name": "Alice Chen", "requests": 3102, "tokens": 618432, "cost_usd": 21.65 } ], "dlp_summary": { "total_scanned": 284102, "allowed": 282232, "redacted": 412, "blocked": 1458, "by_rule": [ { "rule_id": "dlp_01HZ_CC", "rule_name": "Credit Card Numbers", "triggers": 687 }, { "rule_id": "dlp_01HZ_SSN", "rule_name": "Social Security Numbers", "triggers": 412 }, { "rule_id": "dlp_01HZ_APIKEY", "rule_name": "API Key Detection", "triggers": 359 } ] }}Response fields
Section titled “Response fields”Top-level fields
| Field | Type | Description |
|---|---|---|
org_id |
string | Organization UUID echoed from the path |
period |
string | Resolved period identifier (7d, 30d, 90d, or custom) |
granularity |
string | Resolved time-series interval used for usage_over_time |
generated_at |
string (ISO 8601) | Timestamp when the snapshot was computed, UTC |
summary |
object | Aggregate totals for the full period — present unless excluded via include |
usage_over_time |
array | Time-series data points at the resolved granularity |
token_distribution |
array | Token volume breakdown by model |
top_models |
array | Models ranked by request count, descending |
top_users |
array | Top 10 users by request count, descending |
dlp_summary |
object | DLP activity totals and per-rule trigger counts |
summary object
| Field | Type | Description |
|---|---|---|
total_requests |
integer | Total gateway requests in the period |
total_input_tokens |
integer | Total prompt tokens consumed across all models |
total_output_tokens |
integer | Total completion tokens generated across all models |
estimated_cost_usd |
number | Estimated spend in USD, computed using the per-model pricing table at generation time |
active_users |
integer | Count of distinct users who made at least one request in the period |
period_start |
string (ISO 8601) | Actual start timestamp of the report window, UTC |
period_end |
string (ISO 8601) | Actual end timestamp of the report window, UTC |
usage_over_time array items
| Field | Type | Description |
|---|---|---|
date |
string | ISO 8601 date or datetime representing the start of the bucket |
requests |
integer | Request count in this time bucket |
input_tokens |
integer | Prompt token count in this bucket |
output_tokens |
integer | Completion token count in this bucket |
cost_usd |
number | Estimated spend in USD for this bucket |
token_distribution array items
| Field | Type | Description |
|---|---|---|
model |
string | Model identifier |
input_tokens |
integer | Total prompt tokens for this model in the period |
output_tokens |
integer | Total completion tokens for this model in the period |
total_tokens |
integer | Sum of input and output tokens |
top_models array items
| Field | Type | Description |
|---|---|---|
model |
string | Model identifier as submitted in gateway requests |
provider |
string | Model provider (e.g., "openai", "anthropic", "google") |
requests |
integer | Request count for this model in the period |
tokens |
integer | Total tokens consumed by this model |
cost_usd |
number | Estimated spend attributable to this model |
percentage |
number | Share of total requests, expressed as a percentage |
top_users array items (top 10, ordered by request count descending)
| Field | Type | Description |
|---|---|---|
user_id |
string | User UUID |
display_name |
string | User display name at snapshot generation time |
email |
string | User email address |
requests |
integer | Request count for this user in the period |
tokens |
integer | Total tokens consumed by this user |
cost_usd |
number | Estimated spend attributable to this user |
dlp_summary object
| Field | Type | Description |
|---|---|---|
total_scanned |
integer | Total content segments evaluated by the DLP pipeline |
allowed |
integer | Segments that passed DLP inspection without modification |
redacted |
integer | Segments where one or more sensitive fields were redacted before forwarding |
blocked |
integer | Requests blocked entirely due to a DLP policy match |
by_rule |
array | Per-rule trigger counts, ordered by trigger count descending |
by_rule[].rule_id |
string | DLP rule identifier |
by_rule[].rule_name |
string | DLP rule display name |
by_rule[].triggers |
integer | Number of times this rule triggered in the period |
CSV export format
Section titled “CSV export format”When format=csv is specified, the response body is text/csv rather than JSON. The CSV export is a flattened representation of the requested include sections. Because the response contains multiple logical tables, the CSV uses a section-per-block structure with blank lines between sections and a #section header comment on each:
#section: summaryperiod_start,period_end,total_requests,total_input_tokens,total_output_tokens,estimated_cost_usd,active_users2026-02-12T00:00:00Z,2026-03-13T23:59:59Z,284102,31204819,21636204,1847.32,142
#section: usage_over_timedate,requests,input_tokens,output_tokens,cost_usd2026-02-12,9102,1050341,843506,62.142026-02-13,8794,1020183,801247,60.02
#section: top_modelsmodel,provider,requests,tokens,cost_usd,percentagegpt-4o,openai,98432,18314424,641.50,34.6claude-opus-4-6,anthropic,61203,15826443,554.03,21.5
#section: top_usersuser_id,display_name,email,requests,tokens,cost_usdusr_01HZ_JANE,Jane Doe,[email protected],4521,892341,31.23
#section: dlp_summaryrule_id,rule_name,triggers,total_scanned,allowed,redacted,blockeddlp_01HZ_CC,Credit Card Numbers,687,284102,282232,412,1458dlp_01HZ_SSN,Social Security Numbers,412,284102,282232,412,1458The summary section always emits a single data row. The usage_over_time, top_models, top_users, and dlp_summary sections emit one row per entity. DLP per-rule rows repeat the aggregate totals (total_scanned, allowed, redacted, blocked) for convenience when consuming the CSV in tools that do not support multi-table formats.
Error responses
Section titled “Error responses”| Status | Description |
|---|---|
400 |
Invalid query parameter value — unrecognized period, granularity, or format; missing start_date or end_date when period=custom; custom date range exceeds 365 days |
403 |
Caller does not have analytics:read permission for this organization |
404 |
Organization not found |
Config Changelog API — Enhanced Fields
Section titled “Config Changelog API — Enhanced Fields”The config changelog endpoint (GET /api/v1/admin/config/changelog) was first documented in the security and admin API reference. This section documents new resource types and response fields added in recent sprints. All query and pagination parameters from the base specification apply unchanged.
New resource types
Section titled “New resource types”The following resource types are now indexed in the changelog as of sprint docs-0058:
| Resource Type | Added In | Description |
|---|---|---|
analytics_dashboard |
docs-0058 | Dashboard configuration changes — period defaults, auto-refresh interval, visible sections |
search_config |
docs-0058 | Portal search configuration — enabled entity types, per-type index settings, minimum query length |
theme_config |
docs-0058 | Organization theme and branding changes — logo, color scheme, custom CSS |
compliance_pack |
docs-0058 | Compliance policy pack enable, disable, or modify operations |
New response fields
Section titled “New response fields”The following fields are present on all changelog entries returned by the updated endpoint. Older entries created before docs-0058 will return null for these fields.
| Field | Type | Description |
|---|---|---|
change.impact_level |
string | Estimated blast radius of the change: low, medium, high, or critical. Computed heuristically based on resource type and the scope of fields modified. |
change.requires_restart |
boolean | Whether the configuration change requires a service restart to take effect. Most changes are applied live; this flag is true only for a small set of infrastructure-level settings. |
change.rollback_available |
boolean | Whether one-click rollback is supported for this change. Rollback is available for all resource types listed in this section, as well as for policy_rule, dlp_rule, and webhook changes. |
change.related_changes |
array of strings | IDs of other changelog entries that were submitted as part of the same batch operation. Empty array if the change was made individually. |
Updated request example
Section titled “Updated request example”Filter by resource type and impact level:
curl -s "https://api.arbitex.ai/api/v1/admin/config/changelog?resource_type=compliance_pack&impact_level=high&limit=20" \ -H "X-API-Key: arb_your_admin_api_key"Updated response example
Section titled “Updated response example”{ "entries": [ { "id": "chg_01HZ_COMPPACK_001", "resource_type": "compliance_pack", "resource_id": "pack_01HZ_HIPAA", "resource_name": "HIPAA Compliance Pack", "action": "enabled", "actor": { "user_id": "usr_01HZ_ADMIN", "display_name": "Platform Admin", }, "occurred_at": "2026-03-14T09:22:11Z", "change": { "before": { "enabled": false }, "after": { "enabled": true }, "impact_level": "high", "requires_restart": false, "rollback_available": true, "related_changes": [ "chg_01HZ_COMPPACK_002", "chg_01HZ_COMPPACK_003" ] }, "ip_address": "203.0.113.42", "user_agent": "Mozilla/5.0 ArbitexPortal/2.4.1" }, { "id": "chg_01HZ_SRCHCFG_001", "resource_type": "search_config", "resource_id": "srch_01HZ_ACME", "resource_name": "Portal Search Configuration", "action": "updated", "actor": { "user_id": "usr_01HZ_ADMIN", "display_name": "Platform Admin", }, "occurred_at": "2026-03-14T09:20:05Z", "change": { "before": { "enabled_types": ["users", "groups", "models"], "min_query_length": 2 }, "after": { "enabled_types": ["users", "groups", "models", "audit_events", "dlp_rules"], "min_query_length": 2 }, "impact_level": "low", "requires_restart": false, "rollback_available": true, "related_changes": [] }, "ip_address": "203.0.113.42", "user_agent": "Mozilla/5.0 ArbitexPortal/2.4.1" } ], "total": 2, "has_more": false}New query parameter: impact_level
Section titled “New query parameter: impact_level”The changelog endpoint now accepts an additional filter parameter:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
impact_level |
string | No | — | Filter entries to a specific impact level: low, medium, high, or critical. |
This parameter can be combined with all existing filters documented in the security and admin API reference (resource_type, actor_id, start_date, end_date, limit, offset).
Cross-references
Section titled “Cross-references”- Portal admin guide — configuring portal search, entity type visibility, and index settings
- Usage dashboard guide — interpreting analytics dashboard data, setting up automated exports
- Avatar and analytics API — related analytics endpoints and the earlier partial analytics specification
- Security and admin API — base config changelog specification, full query parameter reference