Avatar, accuracy & analytics API
This page documents three related API surface areas: user avatar management, DLP accuracy metrics, and organization analytics dashboards. The avatar endpoints allow users and administrators to upload, serve, and remove profile images. The DLP accuracy endpoint exposes per-entity-type precision, recall, and false-positive rate metrics computed by the accuracy validation framework. The analytics dashboard endpoint provides aggregated usage data — requests, tokens, model breakdowns, and DLP summaries — for an organization over a configurable time window.
Base URL: https://api.arbitex.ai
Avatar API
Section titled “Avatar API”These endpoints handle upload, retrieval, and deletion of user avatar images. Avatars are processed server-side: validated for format and size, resized to 256×256, converted to WebP at quality 80, and stored using a content-addressed filename derived from the image hash. This ensures that identical images are deduplicated and that filenames are stable and cache-safe.
Avatar sources. Each user record tracks an avatar_source field that indicates how the current avatar was set:
| Source value | Meaning |
|---|---|
"upload" |
A custom image was uploaded via POST /api/users/{id}/avatar |
"oidc" |
The avatar was fetched from the OIDC picture claim provided by the user’s identity provider at last login |
"default" |
No custom upload and no IdP photo — the platform renders a generated default avatar (initials-based) |
When a user logs in via SSO and the identity provider supplies a picture URL, the platform fetches, resizes, and stores that image automatically — setting avatar_source to "oidc". A subsequent upload overrides this with avatar_source: "upload". Deleting the custom avatar reverts to "oidc" if a fetched IdP image is still on record, otherwise to "default".
Endpoint summary
Section titled “Endpoint summary”| Method | Path | Auth | Description |
|---|---|---|---|
POST |
/api/users/{id}/avatar |
Admin API key or own session | Upload a user avatar |
GET |
/api/avatars/{filename} |
None (public) | Serve a stored avatar image |
DELETE |
/api/v1/admin/users/{id}/avatar |
Admin API key | Remove a user’s custom avatar |
POST /api/users/{id}/avatar
Section titled “POST /api/users/{id}/avatar”Upload a new avatar image for a user. The server validates the file, resizes it to 256×256 pixels, converts it to WebP format at quality 80, and stores it under a content-addressed filename. The resulting URL is stable and immutably cacheable.
Authentication: API key with admin role, or the user’s own active session token. Non-admin users may only upload avatars for their own account — attempting to upload for a different user ID returns 403 Forbidden.
Content-Type: multipart/form-data
Path parameters
Section titled “Path parameters”| Parameter | Type | Description |
|---|---|---|
id |
string (UUID) | User UUID of the target account |
Request body fields
Section titled “Request body fields”| Field | Type | Required | Description |
|---|---|---|---|
file |
binary | Yes | Avatar image file. Accepted formats: JPEG, PNG, GIF, WebP. Maximum file size: 5 MB. |
Processing pipeline
Section titled “Processing pipeline”- Format validation — rejects files that are not JPEG, PNG, GIF, or WebP.
- Size validation — rejects payloads exceeding 5 MB before reading the full body.
- Resize — scales to exactly 256×256 pixels, preserving aspect ratio with center-crop.
- Conversion — re-encodes to WebP at quality 80.
- Content-addressed storage — the SHA-256 hash of the final WebP bytes becomes the filename.
Request
Section titled “Request”curl -X POST "https://api.arbitex.ai/api/users/usr_01HZ_JANE/avatar" \ -H "X-API-Key: arb_your_admin_api_key" \ -F "file=@/path/to/photo.jpg"Response 200 OK
Section titled “Response 200 OK”| Field | Type | Description |
|---|---|---|
avatar_url |
string | Relative path to the stored WebP image |
avatar_hash |
string | SHA-256 hex digest of the stored WebP bytes; used as the filename stem |
size_bytes |
integer | Size of the stored WebP file in bytes |
dimensions.width |
integer | Always 256 |
dimensions.height |
integer | Always 256 |
format |
string | Always "webp" |
avatar_source |
string | Always "upload" after a successful upload |
{ "avatar_url": "/api/avatars/a1b2c3d4e5f6789abc.webp", "avatar_hash": "a1b2c3d4e5f6789abc", "size_bytes": 8432, "dimensions": { "width": 256, "height": 256 }, "format": "webp", "avatar_source": "upload"}Error responses
Section titled “Error responses”| Status | Description |
|---|---|
400 |
Invalid file format — file is not JPEG, PNG, GIF, or WebP, or the file is corrupt |
403 |
Caller is not an admin and the id does not match their own user ID |
404 |
User not found |
413 |
Payload exceeds the 5 MB limit |
GET /api/avatars/{filename}
Section titled “GET /api/avatars/{filename}”Serve a stored avatar image by its content-addressed filename. This endpoint is public — no authentication is required. Because filenames are derived from image content hashes, they are effectively unguessable, and the response carries long-lived immutable cache headers.
Authentication: None.
Path parameters
Section titled “Path parameters”| Parameter | Type | Description |
|---|---|---|
filename |
string | Content-addressed filename including the .webp extension (e.g., a1b2c3d4e5f6789abc.webp) |
Response headers
Section titled “Response headers”| Header | Value |
|---|---|
Content-Type |
image/webp |
Cache-Control |
public, max-age=31536000, immutable |
Request
Section titled “Request”curl "https://api.arbitex.ai/api/avatars/a1b2c3d4e5f6789abc.webp" \ --output avatar.webpResponse 200 OK
Section titled “Response 200 OK”Raw WebP image bytes. No JSON body.
Error responses
Section titled “Error responses”| Status | Description |
|---|---|
404 |
No avatar exists with the given filename |
DELETE /api/v1/admin/users/{id}/avatar
Section titled “DELETE /api/v1/admin/users/{id}/avatar”Remove a user’s custom uploaded avatar. After deletion, the user’s avatar source reverts to their IdP-provided photo (fetched from the OIDC picture claim at last login) if one is available, or to the platform default if no IdP photo exists. If an IdP photo is available, it is re-processed through the same resize-and-convert pipeline and stored as a new WebP; the response reflects the updated URL.
Authentication: API key with admin role.
Path parameters
Section titled “Path parameters”| Parameter | Type | Description |
|---|---|---|
id |
string (UUID) | User UUID of the target account |
Request
Section titled “Request”curl -X DELETE "https://api.arbitex.ai/api/v1/admin/users/usr_01HZ_JANE/avatar" \ -H "X-API-Key: arb_your_admin_api_key"Response 200 OK
Section titled “Response 200 OK”| Field | Type | Description |
|---|---|---|
user_id |
string | UUID of the affected user |
avatar_source |
string | New avatar source: "oidc" if an IdP photo was applied, "default" if none was available |
avatar_url |
string or null | URL of the avatar now in use; null if avatar_source is "default" |
message |
string | Human-readable description of the outcome |
When an IdP photo is available:
{ "user_id": "usr_01HZ_JANE", "avatar_source": "oidc", "avatar_url": "/api/avatars/b9d3e2f1c0a87654.webp", "message": "Custom avatar removed. Reverted to IdP photo."}When no IdP photo is available:
{ "user_id": "usr_01HZ_JANE", "avatar_source": "default", "avatar_url": null, "message": "Custom avatar removed. No IdP photo available; reverted to platform default."}Error responses
Section titled “Error responses”| Status | Description |
|---|---|
404 |
User not found |
DLP accuracy API
Section titled “DLP accuracy API”The DLP accuracy endpoint exposes precision, recall, F1, and false-positive rate metrics for the active DLP pipeline. Metrics are computed by the accuracy validation framework and cover four detection tiers: regex, ner, llm, and credint. Results can be filtered by entity type, tier, or time period.
Detection tier overview:
| Tier | Description | Typical latency |
|---|---|---|
regex |
Deterministic pattern matching (e.g., credit card Luhn, SSN format) | < 1 ms |
ner |
Named entity recognition model — catches names, addresses, freeform PII | 10–20 ms |
llm |
LLM-based contextual classification for ambiguous or complex content | 150–300 ms |
credint |
Credential intelligence — validates API keys, tokens, and secrets against known formats and entropy thresholds | 30–60 ms |
Endpoint summary
Section titled “Endpoint summary”| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/api/v1/admin/dlp/accuracy |
Admin API key | Retrieve per-entity-type accuracy metrics |
GET /api/v1/admin/dlp/accuracy
Section titled “GET /api/v1/admin/dlp/accuracy”Retrieve DLP accuracy metrics aggregated over a configurable time period. The response includes overall pipeline-level statistics and two breakdowns: per entity type and per detection tier.
Authentication: API key with admin role.
Query parameters
Section titled “Query parameters”| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
entity_type |
string | No | — | Filter results to a specific entity type (e.g., CREDIT_CARD, US_SSN). Returns the by_entity_type array with a single entry if found. |
tier |
string | No | — | Filter by detection tier. One of: regex, ner, llm, credint. When specified, by_entity_type entries are limited to those primarily served by that tier. |
period |
string | No | 7d |
Aggregation window. One of: 24h, 7d, 30d. |
Request
Section titled “Request”curl "https://api.arbitex.ai/api/v1/admin/dlp/accuracy?period=7d&tier=regex" \ -H "X-API-Key: arb_your_admin_api_key"Response 200 OK
Section titled “Response 200 OK”Top-level fields
| Field | Type | Description |
|---|---|---|
period |
string | The requested aggregation window (e.g., "7d") |
generated_at |
string (ISO 8601) | Timestamp when the metrics snapshot was computed |
overall |
object | Pipeline-level aggregate metrics |
by_entity_type |
array | Per-entity-type breakdown (see below) |
by_tier |
array | Per-detection-tier breakdown (see below) |
overall object
| Field | Type | Description |
|---|---|---|
total_scanned |
integer | Total number of content segments evaluated by the DLP pipeline |
total_detections |
integer | Total number of positive detections (TP + FP) |
true_positives |
integer | Detections confirmed as genuine sensitive content |
false_positives |
integer | Detections confirmed as incorrect |
false_negatives |
integer | Known sensitive items not detected by the pipeline |
precision |
float | true_positives / total_detections |
recall |
float | true_positives / (true_positives + false_negatives) |
f1_score |
float | Harmonic mean of precision and recall |
fp_rate |
float | false_positives / total_scanned |
by_entity_type array items
| Field | Type | Description |
|---|---|---|
entity_type |
string | Entity type identifier (e.g., CREDIT_CARD) |
detections |
integer | Total detections for this entity type |
true_positives |
integer | Confirmed true positives |
false_positives |
integer | Confirmed false positives |
precision |
float | Precision for this entity type |
recall |
float | Recall for this entity type |
f1_score |
float | F1 score for this entity type |
fp_rate |
float | False positive rate against total scanned segments |
primary_tier |
string | The detection tier primarily responsible for this entity type |
by_tier array items
| Field | Type | Description |
|---|---|---|
tier |
string | Detection tier identifier: regex, ner, llm, or credint |
detections |
integer | Total detections attributed to this tier |
precision |
float | Precision for this tier |
recall |
float | Recall for this tier |
avg_latency_ms |
float | Average per-segment evaluation latency in milliseconds |
{ "period": "7d", "generated_at": "2026-03-14T12:00:00Z", "overall": { "total_scanned": 125430, "total_detections": 1847, "true_positives": 1793, "false_positives": 54, "false_negatives": 12, "precision": 0.9708, "recall": 0.9934, "f1_score": 0.9819, "fp_rate": 0.0004 }, "by_entity_type": [ { "entity_type": "CREDIT_CARD", "detections": 342, "true_positives": 338, "false_positives": 4, "precision": 0.9883, "recall": 0.9941, "f1_score": 0.9912, "fp_rate": 0.0001, "primary_tier": "regex" } ], "by_tier": [ { "tier": "regex", "detections": 1203, "precision": 0.9850, "recall": 0.9700, "avg_latency_ms": 0.8 }, { "tier": "ner", "detections": 489, "precision": 0.9612, "recall": 0.9801, "avg_latency_ms": 12.4 }, { "tier": "llm", "detections": 118, "precision": 0.9322, "recall": 0.9550, "avg_latency_ms": 210.7 }, { "tier": "credint", "detections": 37, "precision": 0.9730, "recall": 0.9200, "avg_latency_ms": 45.2 } ]}Error responses
Section titled “Error responses”| Status | Description |
|---|---|
400 |
Invalid query parameter value (e.g., unrecognized period or tier) |
403 |
Caller does not have the admin role |
Analytics API
Section titled “Analytics API”The analytics dashboard endpoint provides aggregated organization-level usage data over a configurable time window. It is intended for populating admin dashboards and automated reporting pipelines. The response includes summary totals, time-series usage data, per-model breakdowns, per-user breakdowns, and a DLP activity summary.
Endpoint summary
Section titled “Endpoint summary”| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/v1/orgs/{org_id}/analytics/dashboard |
Admin or analyst 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. The response is a snapshot computed at request time and is not cached server-side — callers should implement their own caching if polling frequently.
Authentication: API key with admin or analyst role scoped to the target organization.
Path parameters
Section titled “Path parameters”| Parameter | Type | Description |
|---|---|---|
org_id |
string (UUID) | Organization UUID |
Query parameters
Section titled “Query parameters”| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
period |
string | No | 30d |
Time window for the report. One of: 24h, 7d, 30d, 90d. |
granularity |
string | No | day |
Interval for usage_over_time data points. One of: hour, day, week. Must be consistent with period — e.g., hour granularity with a 90d period returns up to 2,160 data points. |
Request
Section titled “Request”curl "https://api.arbitex.ai/v1/orgs/org_01HZ_ACME/analytics/dashboard?period=30d&granularity=day" \ -H "X-API-Key: arb_your_admin_api_key"Response 200 OK
Section titled “Response 200 OK”Top-level fields
| Field | Type | Description |
|---|---|---|
org_id |
string | Organization UUID |
period |
string | Requested time period |
granularity |
string | Requested data point interval |
generated_at |
string (ISO 8601) | Timestamp when the dashboard snapshot was computed |
summary |
object | High-level aggregate totals for the period |
usage_over_time |
array | Time-series data points at the requested granularity |
top_models |
array | Models ranked by request count, descending |
top_users |
array | Users ranked by request count, descending |
dlp_summary |
object | DLP activity totals and top entity types |
summary object
| Field | Type | Description |
|---|---|---|
total_requests |
integer | Total gateway requests in the period |
total_tokens |
integer | Total tokens consumed (input + output) |
unique_users |
integer | Count of distinct users who made at least one request |
active_models |
integer | Count of distinct model IDs used |
dlp_detections |
integer | Total DLP positive detections |
policy_blocks |
integer | Total requests blocked by a policy rule |
avg_latency_ms |
integer | Mean gateway-to-provider round-trip latency in milliseconds |
usage_over_time array items
| Field | Type | Description |
|---|---|---|
timestamp |
string (ISO 8601) | Start of the time bucket, UTC |
requests |
integer | Request count in this bucket |
tokens |
integer | Token count in this bucket |
users |
integer | Distinct users active in this bucket |
top_models array items
| Field | Type | Description |
|---|---|---|
model_id |
string | Model identifier as submitted in gateway requests |
requests |
integer | Request count for this model |
tokens |
integer | Token count for this model |
percentage |
float | Share of total requests, as a percentage |
top_users array items
| Field | Type | Description |
|---|---|---|
user_id |
string | User UUID |
display_name |
string | User display name at time of report generation |
requests |
integer | Request count for this user |
tokens |
integer | Token count for this user |
dlp_summary object
| Field | Type | Description |
|---|---|---|
total_scans |
integer | Total content segments evaluated by the DLP pipeline |
detections |
integer | Total positive detections |
blocks |
integer | Requests blocked due to a DLP policy match |
redactions |
integer | Segments where content was redacted rather than blocked |
top_entity_types |
array of strings | Entity types with the highest detection counts, ordered descending |
{ "org_id": "org_01HZ_ACME", "period": "30d", "granularity": "day", "generated_at": "2026-03-14T12:00:00Z", "summary": { "total_requests": 284102, "total_tokens": 52841023, "unique_users": 142, "active_models": 8, "dlp_detections": 1847, "policy_blocks": 23, "avg_latency_ms": 245 }, "usage_over_time": [ { "timestamp": "2026-02-13T00:00:00Z", "requests": 9102, "tokens": 1693847, "users": 76 }, { "timestamp": "2026-03-14T00:00:00Z", "requests": 9470, "tokens": 1761367, "users": 89 } ], "top_models": [ { "model_id": "gpt-4o", "requests": 98432, "tokens": 18234567, "percentage": 34.6 }, { "model_id": "claude-opus-4-6", "requests": 61203, "tokens": 11482901, "percentage": 21.5 } ], "top_users": [ { "user_id": "usr_01HZ_JANE", "display_name": "Jane Doe", "requests": 4521, "tokens": 892341 }, { "user_id": "usr_01HZ_BOB", "display_name": "Bob Smith", "requests": 3874, "tokens": 741209 } ], "dlp_summary": { "total_scans": 284102, "detections": 1847, "blocks": 23, "redactions": 412, "top_entity_types": ["CREDIT_CARD", "SSN", "API_KEY"] }}Error responses
Section titled “Error responses”| Status | Description |
|---|---|
400 |
Invalid query parameter value (e.g., unrecognized period or granularity) |
403 |
Caller does not have the admin or analyst role for this organization |
404 |
Organization not found |