Speaker Services – Analytics
The analytics endpoint returns pre-aggregated verification statistics for the requested time window.
Results are sliced by time bucket (day / week / month / total) and optionally filtered by speaker, embedding model, resolved model, voice print, or sentence-verification model.
Endpoint
Required scope: speaker:analytics:read
User view vs Admin view
- User view – callers who hold only
speaker:analytics:readreceive statistics scoped to their own verifications. Theuser_uuidof the authenticated user is applied automatically as a filter; no extra parameter is required or accepted. - Admin view – callers who additionally hold
speaker:analytics:admin(Admin, Operator, Manager, Supervisor) receive statistics for all users in the tenant. The per-user restriction is lifted entirely.
The endpoint URL and query parameters are identical for both views - the difference is purely driven by the caller's scopes.
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
from |
ISO 8601 UTC | Yes | – | Inclusive start of the analysis period. |
to |
ISO 8601 UTC | No | now | Exclusive end of the analysis period. |
granularity |
enum | No | DAY |
Time-bucket size. One of DAY, WEEK, MONTH, TOTAL. |
speakerId |
UUID | No | – | Limit statistics to a single speaker. |
voicePrintId |
UUID | No | – | Filter by a specific voice print. |
embeddingsModel |
string | No | – | Filter by speaker-embeddings model alias (e.g. en-general-v2). |
embeddingsResolvedModel |
string | No | – | Filter by resolved (concrete) speaker-embeddings model name. |
sentverModel |
string | No | – | Filter by sentence-verification model alias (e.g. en-sentver-v1). |
sentverResolvedModel |
string | No | – | Filter by resolved (concrete) sentence-verification model name. |
Response
Each bucket and the totals object now expose three independent decision breakdowns:
| Field | Measures |
|---|---|
decisionStats |
Final combined decision - speaker-embedding + sentence-verification policy applied together. |
speakerDecisionStats |
Speaker-embedding sub-decision only. |
sentenceDecisionStats |
Sentence-verification sub-decision only. |
Attribution note
decisionStats reflects the final outcome after all policy factors are applied. When you filter by
embeddingsModel or voicePrintId, look at speakerDecisionStats to measure the direct quality of
that embedding dimension. When you filter by sentverModel, look at sentenceDecisionStats.
Using decisionStats alone as a model-quality metric is misleading because the other sub-system
can pull the combined decision in a different direction.
{
"from": "2025-01-01T00:00:00Z",
"to": "2025-04-01T00:00:00Z",
"granularity": "MONTH",
"filters": {
"speakerId": null,
"embeddingsModel": null,
"embeddingsResolvedModel": null,
"voicePrintId": null,
"sentverModel": null,
"sentverResolvedModel": null
},
"buckets": [
{
"periodStart": "2025-01-01T00:00:00Z",
"periodEnd": "2025-02-01T00:00:00Z",
"processingStats": {
"total": 1240,
"completed": 1190,
"failed": 50,
"successRate": 0.9597,
"errorRate": 0.0403
},
"decisionStats": {
"totalDecided": 1190,
"accept": 870,
"review": 180,
"reject": 140,
"acceptRate": 0.7311,
"reviewRate": 0.1513,
"rejectRate": 0.1176
},
"speakerDecisionStats": {
"totalDecided": 1190,
"accept": 920,
"review": 150,
"reject": 120,
"acceptRate": 0.7731,
"reviewRate": 0.1261,
"rejectRate": 0.1008
},
"sentenceDecisionStats": {
"totalDecided": 1190,
"accept": 940,
"review": 130,
"reject": 120,
"acceptRate": 0.7899,
"reviewRate": 0.1092,
"rejectRate": 0.1008
}
}
],
"totals": {
"periodStart": "2025-01-01T00:00:00Z",
"periodEnd": "2025-04-01T00:00:00Z",
"processingStats": { "total": 3620, "completed": 3480, "failed": 140, "successRate": 0.9614, "errorRate": 0.0386 },
"decisionStats": { "totalDecided": 3480, "accept": 2534, "review": 526, "reject": 420, "acceptRate": 0.7282, "reviewRate": 0.1511, "rejectRate": 0.1207 },
"speakerDecisionStats": { "totalDecided": 3480, "accept": 2680, "review": 450, "reject": 350, "acceptRate": 0.7701, "reviewRate": 0.1293, "rejectRate": 0.1006 },
"sentenceDecisionStats": { "totalDecided": 3480, "accept": 2730, "review": 410, "reject": 340, "acceptRate": 0.7845, "reviewRate": 0.1178, "rejectRate": 0.0977 }
},
"cachedAt": "2025-05-11T22:40:00Z",
"cacheExpiresAt":"2025-05-11T23:40:00Z"
}
processingStats fields
| Field | Description |
|---|---|
total |
Total verification attempts in the bucket. |
completed |
Verifications with status COMPLETED. |
failed |
Verifications with status FAILED. |
successRate |
completed / total. null when total = 0. |
errorRate |
failed / total. null when total = 0. |
decisionStats / speakerDecisionStats / sentenceDecisionStats fields
All three decision stat objects share the same shape:
| Field | Description |
|---|---|
totalDecided |
Verifications that produced a decision (accept + review + reject). |
accept |
Number of ACCEPT decisions. |
review |
Number of REVIEW decisions. |
reject |
Number of REJECT decisions. |
acceptRate |
accept / totalDecided. null when totalDecided = 0. |
reviewRate |
review / totalDecided. null when totalDecided = 0. |
rejectRate |
reject / totalDecided. null when totalDecided = 0. |
Freshness fields
| Field | Description |
|---|---|
cachedAt |
UTC timestamp when the current cached result was computed. |
cacheExpiresAt |
UTC timestamp when the cached result will be considered stale. |
Caching Behaviour
Responses include cachedAt and cacheExpiresAt fields. Historical queries (where to is entirely in the past) are cached longer than live queries. Use Cache-Control headers for client-side caching.
| Window type | Condition | HTTP Cache-Control |
|---|---|---|
| Historical | to is entirely in the past |
max-age=3600, stale-while-revalidate=300 |
| Live / open | to overlaps now (or is omitted) |
max-age=60, stale-while-revalidate=30 |
Granularity Reference
| Value | Bucket size | periodEnd derivation |
|---|---|---|
DAY |
1 calendar day (UTC midnight boundaries) | periodStart + 1 day |
WEEK |
1 week starting Monday UTC | periodStart + 7 days |
MONTH |
1 calendar month UTC | periodStart + 1 month |
TOTAL |
Single bucket spanning the full requested period | to (request boundary) |
Example Requests
Monthly breakdown for the first quarter, all speakers
GET /api/v1/speaker-services/speaker-verification/analytics/verifications
?from=2025-01-01T00:00:00Z
&to=2025-04-01T00:00:00Z
&granularity=MONTH
Last 7 days, per-day, for one speaker
GET /api/v1/speaker-services/speaker-verification/analytics/verifications
?from=2025-05-05T00:00:00Z
&granularity=DAY
&speakerId=<uuid>
Last 30 days totals, filtered by speaker-embedding model alias
GET /api/v1/speaker-services/speaker-verification/analytics/verifications
?from=2025-04-11T00:00:00Z
&granularity=TOTAL
&embeddingsModel=en-general-v2
Filter by sentence-verification model alias
GET /api/v1/speaker-services/speaker-verification/analytics/verifications
?from=2025-04-11T00:00:00Z
&granularity=TOTAL
&sentverModel=en-sentver-v1
Filter by both speaker-embedding and sentence-verification model
GET /api/v1/speaker-services/speaker-verification/analytics/verifications
?from=2025-01-01T00:00:00Z
&embeddingsModel=en-general-v2
&sentverModel=en-sentver-v1
&granularity=MONTH