Hi Justin
Hope the procedure below can help.
Genesys uses "media minutes" for billing Speech & Text Analytics (STA) / Transcription.
These are not simply the duration of calls.
Billing is based on audio duration actually processed by Speech Transcription
For voice, the calculation is roughly:
Transcription Minutes = Total processed audio duration (in minutes)
Voice – Divisions, Queues, Transcription Minutes (approx.)
Endpoint:
POST /api/v2/analytics/conversations/aggregates/query
Example body (for a billing month):
{
"interval": "2025-11-01T00:00:00.000Z/2025-11-30T23:59:59.999Z",
"granularity": "P1M",
"groupBy": [
"divisionId",
"queueId",
"mediaType"
],
"filter": {
"type": "and",
"predicates": [
{
"type": "dimension",
"dimension": "mediaType",
"operator": "matches",
"value": "voice"
},
{
"type": "dimension",
"dimension": "hasRecording",
"operator": "matches",
"value": "true"
}
]
},
"metrics": [
"tRecording" // total recorded audio ms
]
}
How to get "Transcription Minutes" from this:
For each row where mediaType = voice:
TranscriptionMinutes_Voice = tRecording / 60000
…and then aggregate by:
divisionId → map to division name
queueId → map to queue name
If you want to exclude internal/consult calls, you can tighten the filter with a segmentType predicate or direction = inbound/outbound.
2️⃣ Digital – Divisions, Queues, "Transcription Minutes" Equivalent
For chat/email, there's no real "minutes" of audio, so billing is typically based on text volume. You can approximate consumption using the Transcripts Aggregates API.
Endpoint:
POST /api/v2/analytics/transcripts/aggregates/query
Example body:
{
"interval": "2025-11-01T00:00:00.000Z/2025-11-30T23:59:59.999Z",
"granularity": "P1M",
"groupBy": [
"divisionId",
"queueId",
"mediaType"
],
"filter": {
"type": "and",
"predicates": [
{
"type": "dimension",
"dimension": "mediaType",
"operator": "matches",
"value": "chat"
}
]
},
"metrics": [
"oTranscriptsByteCount" // total bytes of transcript text
]
}
If you also want email, add an or for mediaType:
"filter": {
"type": "and",
"clauses": [
{
"type": "or",
"predicates": [
{
"type": "dimension",
"dimension": "mediaType",
"operator": "matches",
"value": "chat"
},
{
"type": "dimension",
"dimension": "mediaType",
"operator": "matches",
"value": "email"
}
]
}
]
}
Converting to a "minutes" approximation
You'll need to align this with your billing model. A common internal approximation is something like:
TranscriptionMinutes_Digital = (oTranscriptsByteCount / 1024 / X)
Where X is your assumed "KB per minute equivalent" (you'll get that from your commercial / Genesys account team or by reverse-engineering from invoice totals).
Combining Voice + Digital per Division and Queue
Once you call both APIs:
Normalize keys: divisionId, queueId, mediaType
Convert:
VoiceMinutes = tRecording / 60000
DigitalMinutes = oTranscriptsByteCount → minutes via your rule
Create a final dataset:
Division Queue Media Type Voice Minutes Digital Minutes Total "Transcription"
Div A Q1 voice 12,345.6 – 12,345.6
Div A Q1 chat – 2,100.0 2,100.0
… … … … … …
Practical step-by-step (summary)
Define the billing period
Example: 2025-11-01 to 2025-11-30 (in UTC).
Call Conversations Aggregates (voice)
POST /api/v2/analytics/conversations/aggregates/query
Group by: divisionId, queueId, mediaType
Metric: tRecording
Calculate: Minutes_Voice = tRecording / 60000.
Call Transcripts Aggregates (digital)
POST /api/v2/analytics/transcripts/aggregates/query
Group by: divisionId, queueId, mediaType
Metric: oTranscriptsByteCount
Convert to minutes according to your business rule (or keep it as bytes/KB).
Fetch reference tables
Divisions: GET /api/v2/authorization/divisions
Queues: GET /api/v2/routing/queues
Join everything in BI / Excel
Relate using the IDs (divisionId, queueId).
Create columns such as:
Division Name
Queue Name
Voice Minutes
Digital Bytes/KB or Digital Minutes
Total "Transcription Consumption" (if you want to sum voice + digital).
------------------------------
David Betoni
Principal PS Consultant
------------------------------