Skip to main content

Quality Management API

Run a contact-center quality program end to end: author weighted evaluation forms, score agent calls (or let the AI auto-score them and override when needed), run blind calibration sessions to measure reviewer agreement, read an org-wide quality rollup across voice and inbox, and rank agents on a configurable leaderboard. Base path: /api/v1/quality Authentication: API key (X-API-Key) or session JWT. Roles: the reviewer endpoints (forms, scoring, calibration, gamification leaderboards, and the org summary) require the owner, admin, or supervisor role. An agent can read their own evaluations (GET /evaluations returns only their own rows), acknowledge or appeal an evaluation made about them, and read their own gamification card (GET /gamification/me). All data is scoped to the calling tenant. Validation failures return 422 with a VALIDATION_ERROR body; see Error codes.
This is the contact-center Quality Management resource — evaluation scorecards, calibration, and agent gamification. It is unrelated to the per-call Voice AI Quality (VAQI) metrics documented under /api/v1/voice/intelligence. One scores how a human agent handled a call; the other scores call audio and AI-agent behavior.

Using the SDKs

Prefer the typed client, but this page’s endpoint has no helper yet — the generic request() keeps auth/retries and the { data, meta } envelope identical:
Python (same call via the SDK’s escape hatch):
The Python SDK is core-scope — it wraps the 8 core resources (messaging, voice, contacts, campaigns, verify, numbers) and reaches everything else through the generic client.request() escape hatch above. See the Python SDK. Raw curl in the body of this page works identically. Full SDK index at SDK quickstart.

Evaluation forms

A form defines the rubric a reviewer scores against: a list of weighted sections, each holding weighted criteria. Weights are bare numbers and are normalized within their section and across the form, so you can author them as percentages or as plain relative weights. Each criterion has a max_score (default 100); reviewers submit a raw 0..max_score value per criterion and the server rolls everything up to a single 0..100 total. Mark a section auto_fail to force the whole evaluation to 0 when any criterion in it scores zero (the compliance-gate pattern). Set sample_rate_pct (0–100) on a form to have the continuous auto-sampler — a 15-minute tick over each agent’s completed calls, including AI voice agents — queue a weighted share as pending evaluations for a reviewer to score. 0 (the default) keeps the form manual-only.
Example form definition

Evaluations

An evaluation scores one call for one agent against one form. The reviewer submits a scores map of criterion_id → 0..max_score; the server re-derives total_score from the form weights, so a client can never set the total directly.

Recording library

The searchable post-call recording and transcript library — one unified surface joining every recording, its finalised diarised transcript segments, the latest linked evaluation, and the recording QC verdict, so the hit list is the QA worklist. Full filter matrix, example requests, and the sibling surfaces that distinguish this route from whole-call transcript search and per-recording caption export are on the Recording library guide. | POST | /api/v1/quality/evaluations/{id}/acknowledge | Agent acknowledges their evaluation | | POST | /api/v1/quality/evaluations/{id}/appeal | Agent appeals with a written note | | POST | /api/v1/quality/evaluations/{id}/resolve | Reviewer closes an appealed evaluation | | POST | /api/v1/quality/evaluations/{id}/claim-score | Reviewer scores a pending auto-sampled row | | POST | /api/v1/quality/evaluations/{id}/override | Reviewer corrects an AI auto-scored row |

Status lifecycle

An evaluation moves through pending → acknowledged or pending → appealed → resolved:
  • The evaluated agent (and only that agent) can acknowledge or appeal a pending or acknowledged evaluation. An appeal requires an appeal_note.
  • A reviewer closes an appealed evaluation with resolve. Resolving closes the appeal; it does not regrade the score.

Listing and pagination

GET /evaluations orders newest-first and uses an opaque keyset cursor. Read next_cursor from a response and pass it back as the cursor query parameter to fetch the next page; a null cursor means there are no more rows. Filter with agent_id, call_id, reviewer_id, status, auto_scored, and flagged_for_review. Agents may only list their own evaluations — the agent_id filter is forced to the caller for non-reviewer roles.

Auto-sampling and AI auto-scoring

Two kinds of system-created rows surface in the list with a distinct reviewer_id and may be claimed or corrected:
  • Auto-sampled rows are queued un-scored (total_score 0) by a form’s sample_rate_pct. A reviewer fills in the real per-criterion scores with claim-score; the server re-derives the total and stamps the reviewer. Only a pending, still-unclaimed auto-sampled row is eligible — claiming a human-authored row returns 409.
  • AI auto-scored rows carry auto_scored: true, and those below your tenant’s flag threshold carry flagged_for_review: true. A reviewer corrects one with override; the corrected total is re-derived, the row is stamped with the reviewer, and flagged_for_review is cleared. Only a pending, not-yet-corrected AI row is eligible.

Calibration

A calibration session pins one call and one form and invites a roster of reviewers who each score the call blind — they cannot see another reviewer’s score or the AI’s score until they submit their own. Once two or more reviewers have submitted, the report computes per-criterion variance, overall agreement, each reviewer’s delta from consensus, and the AI’s drift from that consensus. Calibration scores are practice rows; they never feed the agent-facing scorecard, ack/appeal flow, or leaderboard. The session detail and the report enforce the blind rule server-side: an invited reviewer who has not yet submitted gets 403 from the report until they score. Each reviewer may submit once per session (a second attempt returns 409). If the call already has an AI auto-scored evaluation against the same form, it is seeded read-only as a drift baseline.

Quality summary

A cross-channel rollup of LLM-judged conversation outcomes across both voice and inbox, for a supervisor dashboard. Pass days (1–90, default 30) and conv_type (inbox, voice, or all). The response returns overall totals (scored count, pass rate, average confidence), a per-channel breakdown, the top rubrics by evaluation volume with their pass rates, and a short list of recent low-confidence failures for triage. A time series of official reviewer-scored evaluations for a supervisor dashboard: per-day score averages over a window, plus per-agent and per-scorecard-form (rubric) breakdowns. This is the complementary surface to the point-in-time summary above — the summary answers “where does quality stand right now”; the trend answers “is it moving”. Pass days (1–90, default 30) and optionally drill the whole series with agent_id (one evaluated agent) or form_id (one rubric). The response echoes the resolved window, returns overall totals (evaluation count, average score, distinct agents and forms scored), the chronological per-day series, and the top 25 agents and top 25 forms by evaluation volume. avg_score is the weighted 0–100 rollup the server derives when an evaluation is scored (see worked example 1 below) — the trend averages those totals per day. Only official scores count: an agent’s self-assessment and evaluations still under appeal or already resolved stay out of the average, so the line you read is the current reviewer-verdict signal.

Gamification

Rank agents on points and badges computed on demand from existing QA, call, and CSAT aggregates — no extra setup. The board is derived for a window and an optional queue or agent allow-list against a configurable ruleset. Scope a leaderboard with period (day, week, month) or an explicit from/to window, and optionally a queue_id or agent_ids list. Owner and admin callers see all agents; a supervisor sees only the agents in the queues they supervise, and requesting a queue they do not supervise returns 403. Pass point_rules or badge_definitions in the body to preview a tuned ruleset before adopting it. GET /gamification/me returns only the calling agent’s slice — ranked against the same default board so the agent’s rank always matches the supervisor view.

Worked examples

Eight end-to-end operator flows with real request and response bodies, covering scoring, calibration, trends, sampling settings, workload management, autoscore settings, and the recordings playbook. All calls below assume ORBIT_API_KEY holds a tenant API key and BASE_URL points at the product domain (https://orbit.devotel.io). Resource ids such as evform_…, call_…, and user_… are tenant-scoped examples — substitute your own.

1. Score a call against a form

The reviewer sends only the per-criterion scores; the server re-derives the weighted total from the form definition and stamps the caller as reviewer_id.
Node SDK (no typed helper yet — the generic request() keeps the envelope identical):
201:
total_score is the weighted 0–100 rollup the server derived: the opening section (crit_greeting 100 at weight 1, crit_identity 80 at weight 2) normalises to 86.67, the compliance section (crit_pii 100) contributes 100, and the section weights (20 × 86.67 + 30 × 100) ÷ 50 land the total at 94.67. The derivation runs server-side from the form’s weight fields — any total_score you send in the body is ignored; you cannot set the total directly. Fetch the weights from GET /evaluation-forms/{id} if you need to preview a score before submitting. Response fields: status always lands pending for a reviewer-scored evaluation; the evaluated agent moves it to acknowledged (or appealed, which a reviewer then closes with resolve). For an agent scoring their own call, use POST /evaluations/self — it takes the same body minus agent_id, stamps both agent_id and reviewer_id to the caller, and lands directly in acknowledged.

2. Compute the gamification leaderboard

Rank the support queue over the trailing week and preview a tuned points ruleset in one call: pass period: "week", narrow with queue_id, and override point_rules to try a heavier QA weighting before adopting it (GET /gamification/config returns the default rules when you want a starting point).
200:
Response fields: rules_source reports custom when the request supplied its own point_rules, otherwise default. entries is ordered by totalPoints — an empty array means no agent in scope has data for the window yet. Pass from/to (ISO 8601, both required) instead of period for an arbitrary window, or agent_ids instead of queue_id to run a hand-picked cohort. A supervisor is silently limited to the queues they supervise, and requesting a queue outside that set returns 403.

3. Run a blind calibration session

Three calls trace the full session lifecycle: open the session, submit one reviewer’s blind score, then read the agreement report. The report is blind-gated — an invited reviewer who has not yet submitted gets 403 BLIND_SUBMISSION_REQUIRED until they score, so score first, then read. Create the session pinned to one call and one form:
201:
The creator is always added to the roster, so the response de-duplicates and can grow reviewer_ids beyond what you sent. ai_seeded: true means this call already had an AI auto-scored evaluation against the same form — that score is copied in read-only as the report’s drift baseline; it never counts toward the human consensus. Each reviewer then submits their score (one submission per reviewer — a second attempt returns 409 ALREADY_SUBMITTED):
201:
As with POST /evaluations, total_score is re-derived from the form weights — only the scores map is taken from the request. Once two or more reviewers have submitted, read the report:
200:
Response fields: ready is false until at least two human reviewers have submitted (variance needs two graders); below that the numeric fields are still returned zeroed so you can render a partial state. reviewer_deltas holds one entry per human reviewer with their signed distance from the consensus; ai_delta is the seeded AI score’s distance from that same consensus, or null when no AI baseline was seeded. Calibration scores are practice rows — they never feed the agent-facing evaluations or the leaderboard. Close the session with POST /calibrations/{id}/close when the cohort is done; a closed session rejects further submissions with 409 INVALID_STATE.

4. Read the QA score trend

Track the support queue’s official scores over the trailing month, then drill the same series into one agent as soon as a downward slope shows up.
200:
Response fields: window echoes the resolved filters so you can render the exact query you served. An out-of-range days falls back to 30, and an invalid agent_id / form_id degrades to the unfiltered org view — the endpoint never rejects a malformed drill with 4xx. avg_score on totals is null when nothing was scored in the window (per-day and per-row breakdown entries carry the day’s or row’s own average). Both breakdowns are capped at 25 rows ordered by evaluation volume, with an id tie-break so the page is stable across polls. Append &agent_id=user_… or &form_id=evform_… to drill the same payload shape into one agent or one rubric.

5. Configure QA sampling settings

The weekly auto-sampler reads its knobs from your organization settings — qa_sample_assignment.enabled, samples_per_agent_per_week, and lookback_days. Update them with a wholesale PUT on the general settings surface (owner or admin role). Write the block (send every field you mean to keep — the key replaces the previous one wholesale):
Node SDK (no typed helper for the settings surface — the generic request()):
200 — the full organization record is returned, including the updated qa_sample_assignment block. Read the current value back with GET /api/v1/settings/general; the same endpoint serves the autoscore settings (example 7) and this qa_sample_assignment block together. See the QA sampling guide for the sweep’s behaviour and range limits (1–20 samples per agent, 1–30 days lookback).

6. Manage the QA workload

Work on the reviewer queue: assign one call to one evaluator, move an open assignment across evaluators when load shifts, and read every evaluator’s open/overdue count against the per-evaluator quota. Assign a call to a specific evaluator:
201data.id is the new assignment. Two assignments on the same call return 409 ALREADY_ASSIGNED; one evaluator already at its quota returns 409 QUOTA_EXCEEDED. Tune the quota (default max_open_per_evaluator: 25) and due window (default due_days: 3) through the general settings surface (see example 5), persisted under qa_evaluation_assignment. Rebalance an open assignment to a different evaluator while it is still pending and unscored:
409 INVALID_STATE if the assignment is already scored — a submitted score carries an audit trail the evaluator owns. Node SDK (no typed helper — the generic request()):
Read the whole reviewer pool’s workload — each evaluator’s open count, quota, remaining capacity, and overdue count:
200:
Response fields: every reviewer eligible under the reviewer-scope guard (owner / admin / supervisor) gets one row, with open_count, quota, remaining, and overdue_count derived from the tenant’s due_days window. Narrow the list with ?evaluator_id=user_…. The full behaviour matrix (agent visibility, the 409 codes, per-evaluator due windows) is in the QA workload guide.

7. Configure AI autoscore settings

The AI autoscore sweep reads its master toggle and review threshold from organization settings — qa_autoscore.enabled and qa_autoscore.flag_threshold. Write them through the general settings surface (owner or admin role), then let the 60-second sweep pick up the change.
Node SDK (no typed helper — the generic request()):
200 — the updated organization record. enabled: true is the only state the sweep treats as truthy; any other shape is off. flag_threshold accepts 0–100 (default 70) — auto-scored evaluations below it are stamped flagged_for_review: true, which surfaces them in the “Needs human review” dashboard filter and the workload queue (example 6). A numeric string is also accepted; an absent value falls back to 70. For the sweep’s per-tick behaviour and the readiness gates it checks, see the AI Auto-QA guide.

8. Work the recordings playbook

Run the post-call recordings pipeline end to end: find the recording in the library, check its QC verdict, preserve it with a legal hold, export its transcript for a review bundle, and mint a share link for an external auditor. Start by filtering the QA worklist — transcript search plus QC and score bands (see the recording library guide for the full filter matrix):
Node SDK (no typed helper — the generic request()):
Get the recording’s QC verdict (pending / passed / failed / skipped; re-run it with POST /recordings/{id}/qc/run when you suspect the capture):
200:
Preserve it for litigation with a tenant-owned legal hold (the hold exempts both the media object and the database row from the retention sweeps):
Export the transcript as a caption file — WebVTT (default) or SubRip, with an optional PII-pseudonymized variant for an eDiscovery bundle:
Mint a time-limited public share link a guest with no Orbit account can play (video-room recordings only; video:write scope):
200data.share_url, data.token, and data.expires_at; lifetimes clamp between 5 minutes and 30 days (default 7 days when expires_in_seconds is omitted). Revoke every outstanding link for the same recording with:
The full pipeline — QC re-runs (which also fan out a recording.qc_failed webhook), per-conversation legal-hold batches, tamper-evident integrity seals, and clip/highlight extraction — is covered in the recordings pipeline guide.

See also