Exporting Quality Evaluation Results to an External Data Warehouse
Executive Summary & Architectural Context
Genesys Cloud provides robust internal dashboards for Quality Management (QM). However, enterprise organizations rarely consume data in a silo. Quality metrics-such as an agent’s compliance score, empathy rating, or specific form question results-must often be merged with external HR systems, CRM sales data, or custom PowerBI dashboards in a centralized Data Warehouse (DWH) like Snowflake, AWS Redshift, or Google BigQuery.
Because Genesys Cloud is a multi-tenant SaaS platform, you cannot establish a direct ODBC/JDBC connection to its underlying database. Instead, you must architect an ETL (Extract, Transform, Load) pipeline using the Genesys Cloud Platform API.
This masterclass details the precise API orchestration required to automatically extract completed Quality Evaluations, flatten their deeply nested scoring structures, and push them to your DWH for enterprise-wide business intelligence.
Prerequisites, Roles & Licensing
- Licensing: Genesys Cloud CX 2 or 3 (WEM add-on).
- Roles & Permissions:
- OAuth Client with
quality:readonlyandanalytics:readonly.
- OAuth Client with
- Platform Dependencies:
- A middleware ETL server (e.g., Python script, AWS Lambda, Apache Airflow) to run the extraction cron job.
The Implementation Deep-Dive
1. The Architectural Strategy
You cannot “subscribe” to a webhook for completed evaluations. The required architectural pattern is Polling with High-Water Marks.
- A nightly Python script runs at 1:00 AM.
- It queries the API for all evaluations created between
Yesterday 00:00:00andYesterday 23:59:59. - It iterates through the results, formats them into a flat CSV or JSON block, and executes an
INSERTagainst the DWH.
2. Querying the Analytics API for Evaluations
To find evaluations, you must first find the conversations that contain evaluations.
- Endpoint:
POST /api/v2/analytics/evaluations/aggregates/query - The Trap: The aggregate query only tells you how many evaluations happened. It does not give you the actual scores.
- The Correct Endpoint: You must use the Conversation Detail query with an Evaluation filter.
- Endpoint:
POST /api/v2/analytics/conversations/details/query
- Endpoint:
Payload:
{
"interval": "2026-05-13T00:00:00Z/2026-05-14T00:00:00Z",
"evaluationFilters": [
{
"type": "and",
"predicates": [
{
"type": "dimension",
"dimension": "evaluationState",
"value": "Finished"
}
]
}
],
"paging": { "pageSize": 100, "pageNumber": 1 }
}
3. Extracting the Detailed Scorecard
The Conversation Details query returns the Conversation ID and the Evaluation ID. However, to get the actual answers to specific questions (e.g., “Did the agent authenticate the caller?”), you must make a secondary GET request for the specific scorecard.
- Iterate through the results of your Conversation query.
- For every Evaluation ID found, execute:
GET /api/v2/quality/conversations/{conversationId}/evaluations/{evaluationId}
- The Response Payload: This returns a massive JSON object detailing the
evaluationFormId, the totalevaluationScore, and ananswersarray containing the specific boolean or multiple-choice results for every single question.
4. Flattening the Payload for the DWH
A Data Warehouse requires flat, tabular data. You must write a Python transformation layer to map the nested JSON into a relational row.
Example Python Transformation:
def transform_eval_to_row(eval_json):
row = {
"evaluation_id": eval_json["id"],
"conversation_id": eval_json["conversation"]["id"],
"agent_id": eval_json["agent"]["id"],
"evaluator_id": eval_json["evaluator"]["id"],
"total_score": eval_json["evaluationScore"],
"status": eval_json["status"],
"release_date": eval_json["releaseDate"]
}
# Iterate through the specific question groups to extract sub-scores
for q_group in eval_json.get("answers", {}).get("questionGroupScores", []):
group_id = q_group["questionGroupId"]
score = q_group["score"]
# Pivot the data: dynamically create columns like 'score_group_xyz'
row[f"score_{group_id}"] = score
return row
Once flattened into a dictionary, use pandas or your DWH connector to bulk insert the rows.
Validation, Edge Cases & Troubleshooting
Edge Case 1: Rate Limiting on the Quality Endpoint
If your contact center does 500 evaluations a day, iterating through 500 GET /api/v2/quality/... requests sequentially will take a few seconds. If you try to execute them concurrently via asynchronous threads, you will instantly hit the Genesys Cloud API Rate Limit (typically 300 requests per minute).
- Troubleshooting: You must implement a strict concurrency limiter in your ETL script (e.g., using Python’s
asyncio.Semaphore(5)or standard sleep delays) to ensure you do not exceed 15-20 requests per second. Always check theX-RateLimit-RemainingHTTP header.
Edge Case 2: Calibration Evaluations
When Quality teams perform “Calibrations” (multiple evaluators scoring the exact same call to test their own accuracy), those evaluations are flagged differently.
- The Trap: If you blind-import all evaluations, Calibration scores will skew your agent performance averages, as they are tests for the evaluators, not the agents.
- Solution: In the raw JSON returned by the Quality endpoint, check the
isCalibrationboolean field. IfTrue, either drop the record in your ETL layer or load it into a completely separateqm_calibrationstable in your DWH.
Edge Case 3: Form Versioning
If a Quality Manager updates a question on the Evaluation Form, Genesys Cloud creates a new version of the form (e.g., v1 → v2). The IDs of the questions change.
- Solution: Your DWH schema must not hardcode column names to specific Question IDs unless you are prepared for them to break. Store the raw answers as a JSONB column (in Postgres/Snowflake) so your BI analysts can dynamically query the nested keys regardless of form version.
Official References
- Quality API Overview: Genesys Developer Center: Quality Management API
- Conversation Details Query: Genesys Developer Center: Query for Conversation Details
- Rate Limits: Genesys Developer Center: API Rate Limits