Overview
The MaestroQA API allows users to access and interact with their quality assurance data programmatically. By using the API, users can automate repetitive tasks, integrate MaestroQA with other tools, and build custom applications that leverage their QA data. In this article, we'll explore the main features of the MaestroQA API, show examples of how it can be used, and provide guidance on how to get started.
Whether you're a seasoned developer or new to APIs, this article will help you understand how to unlock the full potential of MaestroQA by using its API.
Table of Contents
Exports
Raw Grading Export (grading data)
Audit Logs Export (activity log data)
Tickets
Agents
Update an Agent
Coaching Points
To-Dos
Coaching Sessions
Metrics
Authentication
In order to make requests to the Maestro QA API, you must attach a valid API token to your request.
Obtaining an API Token
API tokens can be generated in the MaestroQA dashboard on the Other Settings page. Within "Other Settings", scroll down to the API Tokens section and click "Create New Token".
By default, API Tokens expire every 90 days for security purposes. This expiration can be turned off, or tokens can be deactivated manually.
Authenticating Requests
An API token must be provided for all requests. The token should be passed in the request's headers, in the format:
'apitoken': 'YOUR_API_TOKEN'
Example (Python)
import requests
headers = {
'Content-Type': 'application/json',
'apitoken': 'YOUR_API_TOKEN'
}
response = requests.get(url, headers=headers)
Certain endpoints allow tokens to be passed in the request body (noted in the endpoint's documentation); this is supported for backward compatibility only and is subject to change.
__________________________________________________________________
Formats
1. All dates should be UTC offset datetime strings, formatted according to the extended ISO 8601 format (reference)
[YYYY]-[MM]-[DD]T[HH]:[MM]:[SS]Z
ex. 2017-12-13T05:00:00Z
2. Each endpoint’s request parameters and response content should be JSON-encoded
Endpoints
The * symbol is used to denote required parameters
If a parameter is optional, it may be omitted from the request parameters. If an optional parameter is included, it must contain a valid value.
Request A “Raw” Export
Raw exports are the equivalent to the Raw CSV export in the MaestroQA dashboard. The export will include grades that were last updated between the specified start date and end date.
Raw exports generate a zip
file containing a CSV for each level of rubric scores:
total rubric scores
section scores
individual answer scores
annotations
CSAT
Definition
POST https://app.maestroqa.com/api/v1/request-raw-export
Body Parameters
Name | Type | Description |
startDate* | string (see formats) | Include grades that were updated after this date |
endDate* | string (see formats) | Include grades that were updated before this date |
name | string | Name for the export. Defaults to a randomly generated name |
singleFileExport | enum (individual_answers, section_scores, total_scores, annotations, csat) | Specify a single (optional) |
includeCalibrations | enum (all, none, only) | Specify whether calibration scores should be included in the export.
(optional) |
includeGraderQA | boolean | Specify whether grader QA benchmark scores should be included in the export. Default is (optional) |
includeDeleted | boolean | Specify whether deleted answers should be included in the export. Default is false (optional) |
apiToken | string | See authentication |
Response
The ID of the export that was requested - used to track the export's status and retrieve its results.
Name | Type | Description |
exportId | string | ID of the export that was requested |
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/request-raw-export'
payload = {
'startDate': '2018-08-13T00:00:00Z',
'endDate': '2018-08-19T00:00:00Z',
'name': 'Weekly Maestro Grades Export'
}
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.post(url, json=payload, headers=headers)
Example Response
{ 'exportId': 'id_1234' }
Retrieve the results of an export
After an export has been requested, check its status and fetch the URL from which to download the export’s results.
Definition
GET https://app.maestroqa.com/api/v1/get-export-data
Body Parameters
Name | Type | Description |
exportId* | string | The ID of the export whose results should be returned |
apiToken | string | See authentication |
Response
Status and result data for the requested export
Name | Type | Description |
status | enum (requested, in_progress, complete, errored) | The status of the export |
dataUrl | string | If status is "complete" and there is data to download, contains the URL to download the export. Otherwise, contains an empty string. |
Note: if there was no matching data for the parameters requested (ex. if you request dates in the future), the dataUrl
field will be empty, even when the status is 'complete' as there is nothing to download.
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/get-export-data'
payload = {
'exportId': 'THE_EXPORT_ID'
}
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.get(url, json=payload, headers=headers)
Example Response
{
'status': 'complete',
'dataUrl': 'https://subdomain.s3.amazonaws.com/path/to/file'
}
Here is a Data Dictionary for the files contained within the resulting export.
Request an “agent groups” export
An “agent groups” export is the equivalent to the Agent Groups export in the MaestroQA App. This will export all the agent groups and group membership.
Definition
POST https://app.maestroqa.com/api/v1/request-groups-export
Body Parameters
Name | Type | Description |
name | string | Name for the export. Defaults to a randomly generated name |
includeUnavailable | boolean | Whether to include all agents, or just those currently marked “available”. Default is (optional) |
apiToken | string | See authentication |
Response
The ID of the export that was requested - used to track the export's status and retrieve its results.
Name | Type | Description |
exportId | string | ID of the export that was requested |
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/request-groups-export'
payload = {
'name': 'Maestro Agent Groups Export',
'includeUnavailable': False
}
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.post(url, json=payload, headers=headers)
Example Response
{ 'exportId': 'id_1234' }
Request an “audit logs” export
An “audit log” export is the equivalent to the Activity Logs export in the MaestroQA App. This will export all the user activity in your account during the specified date range. See "What Can I Track in the Activity Log" for details on what is tracked in the activity log.
Definition
POST https://app.maestroqa.com/api/v1/request-audit-log-export
Body Parameters
Name | Type | Description |
startDate* | string (see formats) | Include logs that were created after this date |
endDate* | string (see formats) | Include logs that were created before this date |
name | string | Name for the export. Defaults to a randomly generated name |
apiToken | string | See authentication |
Response
The ID of the export that was requested - used to track the export's status and retrieve its results.
Name | Type | Description |
exportId | string | ID of the export that was requested |
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/request-audit-log-export'
payload = {
'startDate': '2018-08-13T00:00:00Z',
'endDate': '2018-08-19T00:00:00Z',
'name': 'Maestro Activity Log Export',
}
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.post(url, json=payload, headers=headers)
Example Response
{ 'exportId': 'id_1234' }
Create a Ticket
Create a new Ticket in your MaestroQA account.
Definition
POST https://app.maestroqa.com/api/v1/tickets
Body Parameters
Name | Type | Description |
ticket_id* | string | A unique identifier for the ticket. (required)
Note: this id must be unique - if the id is in use by any other ticket in your account, the request will fail with a 409 Conflict error |
type* | string | The ticket type/source from your external support system (required) |
subject* | string | The ticket's subject (required) |
agents* | array[string] | A list of the IDs or emails of agents associated with the ticket (required)
See Guide to User Roles for information about Agent IDs |
link* | string | A link to the ticket in your external resource (required) |
body | string | Text content block of the ticket. (recommended* - see Create a Ticket Comment for sending threaded text based content and Create an Attachment for sending media and other file type attachments) |
tags | string | The ticket's tags, formatted as a comma-separated string |
status | string | The ticket's status (ex: "Closed") |
csat_score | number | The CSAT score for the ticket |
first_seen | date string (see formats) | The date the ticket was created
Defaults to the current date |
last_seen | date string (see formats) | The date of the last activity on the ticket
Defaults to the current date |
attributes | object | Custom attributes for the ticket
Note: these attributes must already exist in your MaestroQA account. The values passed for each key will be validated against the attribute's expected value type (ex: string, boolean, etc.). Unrecognized attributes will be ignored. |
Response
The ticket that was created
Name | Type | Description |
ticket_id | string | A unique identifier for the ticket. |
type | string | The ticket type/source from your external support system |
subject | string | The ticket's subject |
agents | array[string] | A list of the IDs of agents associated with the ticket |
link | string | A link to the ticket in your external resource |
body | string | The text content of the ticket |
tags | string | The ticket's tags, formatted as a comma-separated string |
status | string | The ticket's status |
csat_score | number | The CSAT score for the ticket |
first_seen | date string (see formats) | The date the ticket was created |
last_seen | date string (see formats) | The date of the last activity on the ticket |
attributes | object | The ticket's custom attributes |
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/tickets'
payload = {
'ticket_id': 'unique_ticket_id',
'type': 'custom helpdesk',
'subject': 'New ticket',
'link': 'http://www.mynewticket.com',
'body': 'The text content of this ticket',
'status': 'open',
'agents': ['this_agent_id'],
'tags': 'login,support,escalated',
'csat_score': 5,
'first_seen': '2022-02-02T00:00:00.000Z',
'last_seen': '2022-03-07T00:00:00.000Z',
'attributes': {
'public_comment_count': 5,
'group': 'Support',
'first_resolution_time_total_minutes': 1023
}
}
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.post(url, json=payload, headers=headers)
Example Response
{
'ticket_id': 'unique_ticket_id',
'type': 'custom helpdesk',
'subject': 'New ticket',
'link': 'http://www.mynewticket.com',
'body': 'The text content of this ticket',
'status': 'open',
'agents': ['this_agent_id'],
'tags': 'login,support,escalated',
'csat_score': 5,
'first_seen': '2022-02-02T00:00:00.000Z',
'last_seen': '2022-03-07T00:00:00.000Z',
'attributes': {
'public_comment_count': 5,
'group': 'Support',
'first_resolution_time_total_minutes': 1023
}
}
Update a Ticket
Update an existing Ticket in your MaestroQA account.
Note: tickets fields synced from helpdesk integrations cannot be manually updated, but you can update/set custom fields
Definition
PATCH https://app.maestroqa.com/api/v1/tickets/:ticket_id
Path Parameters
Name | Type | Description |
ticket_id* | string | The unique identifier for the ticket (required) |
Body Parameters
Name | Type | Description |
type | string | The ticket type/source from your external support system |
subject | string | The ticket's subject |
agents | array[string] | A list of the IDs or emails of agents associated with the ticket
See Guide to User Roles for information about Agent IDs |
link | string | A link to the ticket in your external resource |
body | string | The text content of the ticket |
tags | string | The ticket's tags, formatted as a comma-separated string |
status | string | The ticket's status (ex: "Closed") |
csat_score | number | The CSAT score for the ticket |
first_seen | date string (see formats) | The date the ticket was created |
last_seen | date string (see formats) | The date of the last activity on the ticket |
attributes | object | Custom attributes for the ticket
Note: these attributes must already exist in your MaestroQA account. The values passed for each key will be validated against the attribute's expected value type (ex: string, boolean, etc.). Unrecognized attributes will be ignored. |
Response
The updated ticket
Name | Type | Description |
ticket_id | string | A unique identifier for the ticket. |
type | string | The ticket type/source from your external support system |
subject | string | The ticket's subject |
agents | array[string] | A list of the IDs of agents associated with the ticket |
link | string | A link to the ticket in your external resource |
body | string | The text content of the ticket |
tags | string | The ticket's tags, formatted as a comma-separated string |
status | string | The ticket's status |
csat_score | number | The CSAT score for the ticket |
first_seen | date string (see formats) | The date the ticket was created |
last_seen | date string (see formats) | The date of the last activity on the ticket |
attributes | object | The ticket's custom attributes |
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/tickets/unique_ticket_id'
payload = {
'subject': 'Updated subject!',
'status': 'closed',
'last_seen': '2022-03-15T00:00:00.000Z'
}
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.patch(url, json=payload, headers=headers)
Example Response
{
'_id': 'unique_maestro_id_for_ticket',
'ticket_id': 'unique_ticket_id',
'type': 'custom helpdesk',
'subject': 'Updated subject!',
'link': 'http://www.mynewticket.com',
'body': 'The text content of this ticket',
'status': 'closed',
'agents': ['this_agent_id'],
'tags': 'login,support,escalated',
'csat_score': 5,
'first_seen': '2022-02-02T00:00:00.000Z',
'last_seen': '2022-03-15T00:00:00.000Z'
}
Delete a Ticket
Delete an existing Ticket in your MaestroQA account.
Note: tickets synced from helpdesk integrations cannot be manually deleted
Definition
DELETE https://app.maestroqa.com/api/v1/tickets/:ticket_id
Path Parameters
Name | Type | Description |
ticket_id* | string | The unique identifier for the ticket (required) |
Response
N/A - successful delete requests will receive a 200 OK
response
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/tickets/unique_ticket_id'
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.delete(url, headers=headers)
Get a Ticket
Get basic information about an existing ticket.
Note: only basic ticket data is available for security/privacy considerations. Ticket attributes will only return for manually created tickets and will otherwise be redacted.
Definition
GET https://app.maestroqa.com/api/v1/tickets/:ticket_id
Path Parameters
Name | Type | Description |
ticket_id* | string | The unique identifier for the ticket (required) |
Response
The updated ticket
Name | Type | Description |
ticket_id | string | A unique identifier for the ticket. |
type | string | The ticket type/source from your external support system |
subject | string | The ticket's subject |
agents | array[string] | A list of the IDs of agents associated with the ticket |
link | string | A link to the ticket in your external resource |
body | string | The text content of the ticket |
tags | string | The ticket's tags, formatted as a comma-separated string |
status | string | The ticket's status |
csat_score | number | The CSAT score for the ticket |
first_seen | date string (see formats) | The date the ticket was created |
last_seen | date string (see formats) | The date of the last activity on the ticket |
createdAt | date string (see formats) | The date the ticket was created |
updatedAt | date string (see formats) | The date the ticket was last updated |
source | string | The source designated for the ticket |
attributes | object | The ticket's custom attributes |
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/tickets/unique_ticket_id'
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.get(url, headers=headers)
Example Response
{
"id": "unique_maestro_id_for_ticket",
"ticket_id": "unique_ticket_id",
"type": "custom helpdesk",
"subject": "Ticket Subject!",
"agents": [
"1"
],
"link": "http://www.mynewticket.com",
"body": "The text content of this ticket",
"tags": "tag1",
"status": "closed",
"csat_score": "10",
"first_seen": "2024-11-06T20:46:57.934Z",
"last_seen": "2024-11-06T20:46:57.934Z",
"createdAt": "2024-11-06T20:46:58.831Z",
"updatedAt": "2024-11-06T20:49:04.954Z",
"source": "custom",
"attributes": {
"public_comment_count": 5,
"recontact": true,
"group": "Support",
"first_resolution_time_total_minutes": 10520,
"full_resolution_time_total_minutes": 100000
}
}
Create a Ticket Comment
Create a comment for a specific ticket. Comments can represent dialogue from customers or agents.
Definition
POST https://app.maestroqa.com/api/v1/comments
Body Parameters
Name | Type | Required | Description |
body | string | Yes | The content of the comment |
ticket_id | string | Yes | The unique identifier of the ticket to which the comment is being added |
author_id | string | No | The identifier of the author (agent or customer) of the comment |
role | enum (customer, agent) | No | The role of the comment author (agent or customer) |
channel | string | No | The communication channel through which the comment was made (e.g. chat) |
public | boolean | No | Whether or not the comment was public. Defaults to true. |
time | date string (see formats) | No | The timestamp of when the comment was made. Defaults to the current time |
Response
The comment that was created
Name | Type | Description |
id | string | The unique identifier for the comment |
body | string | The content of the comment |
ticket_id | string | The identifier of the ticket associated with the comment |
author_id | string | The identifier of the author |
role | enum (agent, customer) | The role of the comment author |
channel | string | The channel used for the comment |
public | boolean | Whether the comment is public |
time | date string | The timestamp of the comment |
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/comments'
payload = {
'ticket_id': '427406478143',
'channel': 'chat',
'time': '2023-11-03T16:38:53.508Z',
'body': 'Hi, can I get some help?',
'role': 'customer',
'author_id': 'customer_12345',
'public': True
}
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.post(url, json=payload, headers=headers)
Example Response
{
"body": "Hi, can I get some help?",
"author_id": "customer_12345",
"role": "customer",
"channel": "chat",
"public": true,
"time": "2023-11-03T16:38:53.508Z",
"ticket_id": "427406478143",
"id": "16906fb5ce9d57646fa38362_427406478143_W7OU22JH4Q"
}
Create Many Ticket Comments
Create a batch of comments for one or more tickets. Comments can represent dialogue from customers or agents.
Definition
POST https://app.maestroqa.com/api/v1/comments-batch
Body Parameters
Name | Type | Required | Description |
batch | array | Yes | Array of comment objects (see structure of a "comment" object from Create a Ticket Comment request arguments)
*Note: there is a maximum of 500 comments per batch |
Response
The comments that were created
Name | Type | Description |
results | array | Array of created comment objects (see structure of a "comment" response from Create a Ticket Comment response documentation) |
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/comments-batch'
payload = {
batch: [
{
'ticket_id': '427406478143',
'channel': 'chat',
'time': '2023-11-03T16:38:53.508Z',
'body': 'Hi, can I get some help?',
'role': 'customer',
'author_id': 'customer_12345',
'public': True
},
{
'ticket_id': '513309837',
'channel': 'email',
'time': '2024-11-03T16:38:53.508Z',
'body': 'I have questions that need answering',
'role': 'customer',
'author_id': 'customer_abcdef',
'public': True
}
]
}
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.post(url, json=payload, headers=headers)
Example Response
{
results: [
{
"body": "Hi, can I get some help?",
"author_id": "customer_12345",
"role": "customer",
"channel": "chat",
"public": True,
"time": "2023-11-03T16:38:53.508Z",
"ticket_id": "427406478143",
"id": "16906fb5ce9d57646fa38362_427406478143_W7OU22JH4Q"
},
{
"ticket_id": "513309837",
"channel": "email",
"time": "2024-11-03T16:38:53.508Z",
"body": "I have questions that need answering",
"role": "customer",
"author_id": "customer_abcdef",
"public": true,
"id": "16fb5ce9d57646fa38362_513309837_W7lk22JH4Q"
}
]
}
Create an Attachment
Create an attachment for a specific ticket. This enables attaching photos, audio, files, and video to tickets, complementing the existing ticket and comment creation APIs.
There are two attachment flows available:
Using a presigned URL: Request a presigned URL to securely upload your files directly. Attachments uploaded this way appear in MaestroQA almost immediately.
Request: Obtain a presigned URL from the "create attachment" response
Upload: Use the presigned URL to upload your file with the specified
content_type
via aPUT
request. Ensure to set theContent-Type
andx-amz-server-side-encryption
headers (see code examples below)
Note: presigned URLs are valid for 10 minutes
Using a URL accessible to MaestroQA: Provide a URL where your file is publicly accessible. MaestroQA will asynchronously download and attach the file to your ticket. This process may take several hours, and visibility of the attachment within the application is not immediate.
Note: Ensure the URL is accessible to MaestroQA's system. MaestroQA uses static IPS (available upon request) to enable IP whitelisting
Definition
POST https://app.maestroqa.com/api/v1/attachments
Body Parameters
Name | Type | Required | Description |
url | string | No | Direct URL of the file to attach (see "Using a URL accessible to MaestroQA" above)
If not specified, this indicates Presigned URL flow and you will receive a |
ticket_id | string | Yes | The unique identifier of the ticket to which the comment is being added |
content_type | string | Yes | The mime type of the file being sent - ex. audio/mp3 |
id | string | No | Unique id of the attachment - helpful for identifying the attachment, for reference, or potentially stitching. If none is provided, a random ID will be generated and returned in the response. |
author_id | string | No | ID of the author (to associate the attachment with a specific agent or customer) |
public | boolean | No | If this attachment should create a public or private attachment comment, defaults to true. |
timestamp | date string (see formats) | No | The timestamp the attachment's comment should show. Helpful to ensure comments and attachments show in the proper chronological order.
Defaults to the current time. |
Response
The comment that was created
Name | Type | Description |
id | string | The unique identifier for the attachment |
presigned_url | string | If using Presigned URL flow, the |
Example Request for Presigned URL Flow (Python)
import requests
# Create an attachment shell and get a presigned URL from MaestroQA:
url = 'https://app.maestroqa.com/api/v1/attachments'
payload = {
'ticket_id': 'your_ticket_id',
'timestamp': '2022-12-13T05:00:00Z',
'content_type': 'audio/mp3',
}
headers = {'apitoken': 'your_api_token'}
response = requests.post(url, json=payload, headers=headers)
presigned_url = response.json().get('presigned_url')
# Use the presigned URL to upload your file:
with open('path_to_your_file.mp3', 'rb') as file:
upload_headers = {
'Content-Type': 'audio/mp3',
'x-amz-server-side-encryption': 'AES256'
}
upload_response = requests.put(presigned_url, data=file, headers=upload_headers)
Example Request for Accessible URL Flow (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/attachments'
payload = {
'ticket_id': 'your_ticket_id',
'content_type': 'image/png',
'url': 'https://example.com/your_file.png',
}
headers = {'apitoken': 'your_api_token'}
response = requests.post(url, json=payload, headers=headers)
Create an Agent
Definition
POST https://app.maestroqa.com/api/v1/agents
Body Parameters
Name | Type | Required | Description |
name | string | Yes | The full name of the agent |
available | boolean | Yes | Agent's availability status |
string | Yes | The email address of the agent
*must be unique (see error responses) | |
agentGroupId | string | No | The identifier for the agent group the agent should be added to |
agentId | string | No | A unique alphanumeric identifier for the agent. If not provided, a random id is generated
*must be unique if provided (see error responses) |
Success Response
The agent that was created
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/agents'
payload = {
'name': 'Allison Agent',
'available': True,
'email': 'brand_new_agent@maestroqa.com',
'agentId': 'allisonagent',
'agentGroupId': 'ZBceBjFgQjNY2qLof'
}
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.post(url, json=payload, headers=headers)
Example Response
{
"_id": "js6LYgg4Ey3EqYhfi",
"name": "Allison Agent",
"agentId": "allisonagent",
"available": true,
"email": "brand_new_agent@maestroqa.com",
"agentGroupId": "ZBceBjFgQjNY2qLof"
}
Update an Agent (add agent id to agent)
Definition
POST https://app.maestroqa.com/api/v1/agents/add-id-to-agent
Body Parameters
Name | Type | Required | Description |
string | Yes | The email address of the agent
*must be unique (see error responses) | |
agentId | string | Yes | A unique alphanumeric identifier for the agent.
*must be unique if provided (see error responses) |
Success Response
The agent that was updated
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/agents/add-id-to-agent'
payload = {
'email': 'brand_new_agent@maestroqa.com',
'agentId': 'allisonagent'
}
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.post(url, json=payload, headers=headers)
Update an Agent (update agent availability)
Definition
POST https://app.maestroqa.com/api/v1/update-agent-availability
Body Parameters
Name | Type | Required | Description |
string | Yes | The email address of the agent
*must be unique (see error responses) | |
available | boolean | Yes | The value to update agent availability to |
Success Response
The agent that was updated
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/update-agent-availability'
payload = {
'email': 'brand_new_agent@maestroqa.com',
'available': True
}
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.post(url, json=payload, headers=headers)
Retrieve a Single To-do
Fetch a single todo item by ID
Definition
GET https://app.maestroqa.com/api/v1/todos/:id
Path Parameters
Name | Type | Description |
id | string | The unique identifier of the todo to retrieve |
Response
The todo item
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/todos/CGsTFnNi5P8riTHmC'
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.get(url, headers=headers)
Example Response
{
"id": "CGsTFnNi5P8riTHmC",
"title": "A Todo",
"createdAt": "2023-06-28T16:03:21.089Z",
"updatedAt": "2023-06-28T16:03:30.804Z",
"agentId": "72999",
"creatorId": "HkeYnymy3fhgf3j5F",
"status": "incomplete",
"type": "general",
"coachingSessionIds": [],
"description": "This todo's description text"
}
Retrieve Many To-dos
Fetch multiple todos based on filter criteria.
Definition
GET https://app.maestroqa.com/api/v1/todos
Query Parameters
Name | Type | Description |
agentId | string | Filter to only todos for the provided agent ID |
creatorId | string | Filter to only todos created by the provided user ID |
startDate | date string (see formats) | Filter to only todos created after the provided date |
endDate | date string (see formats) | Filter to only todos created before the provided date |
count | integer | The number of results to return |
startIndex | integer | Offset to start pagination search results |
Response
Name | Type | Description |
startIndex | integer | Offset of paginated search results |
totalResults | integer | Total number of todos that match the provided query filters |
itemsPerPage | integer | The number of results per page |
Resources | array[todos] | List of todos matching the filter criteria |
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/todos'
params = {
'count': 1,
'startIndex': 50,
'startDate': '2023-06-01T15:08:45.781Z',
'endDate': '2023-08-01T15:08:45.781Z',
}
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.get(url, params=params, headers=headers)
Example Response
{
"startIndex": 50,
"totalResults": 254,
"itemsPerPage": 1,
"Resources": [
{
"id": "P9MTc9MogtHZpDKqm",
"title": "2. My First App",
"createdAt": "2023-06-26T21:01:32.469Z",
"updatedAt": "2023-06-26T21:01:32.469Z",
"agentId": "5595649818",
"creatorId": "zme7PkariKd5Hb4fT",
"status": "incomplete",
"type": "guru",
"answerId": "16906fb5ce9d57646fa38362_5311138_QqJEN5t8LXZRQZd4a_5595649818_GRADER_grading",
"description": ""
}
]
}
Retrieve a Single Coaching Point
Fetch a single coaching point by ID
Definition
GET https://app.maestroqa.com/api/v1/coaching-points/:id
Path Parameters
Name | Type | Description |
id | string | The unique identifier of the coaching point to retrieve |
Response
The coaching point
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/coaching-points/HHk4xnKwwpYsJHTnq'
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.get(url, headers=headers)
Example Response
{
"id": "6Lt3yHNcBBEyMSK8n",
"createdAt": "2023-06-21T17:52:36.687Z",
"updatedAt": "2023-06-24T05:42:18.599Z",
"agentId": "72999",
"creatorId": "zme7PkariKd5Hb4fT",
"criteriaId": null,
"rubricId": "AatxWWtXWKcfiN34E",
"answerId": "16906fb5ce9d57646fa38362_5310985_AatxWWtXWKcfiN34E_542897_GRADER_grading",
"type": "opportunities",
"classification": "qa",
"coachNotes": "Let's talk about greeting ",
"coachingSessionIds": [],
"textContent": ""
}
Retrieve Many Coaching Points
Fetch multiple coaching points based on filter criteria.
Definition
GET https://app.maestroqa.com/api/v1/coaching-points
Query Parameters
Name | Type | Description |
agentId | string | Filter to only coaching points for the provided agent ID |
creatorId | string | Filter to only coaching points created by the provided user ID |
startDate | date string (see formats) | Filter to only coaching points created after the provided date |
endDate | date string (see formats) | Filter to only coaching points created before the provided date |
count | integer | The number of results to return |
startIndex | integer | Offset to start pagination search results |
Response
Name | Type | Description |
startIndex | integer | Offset of paginated search results |
totalResults | integer | Total number of coaching points that match the provided query filters |
itemsPerPage | integer | The number of results per page |
Resources | array[coaching points] | List of coaching points matching the filter criteria |
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/coaching-points'
params = {
'count': 3,
'agentId': '72999',
'startDate': '2023-06-01T15:08:45.781Z',
'endDate': '2023-08-01T15:08:45.781Z',
}
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.get(url, params=params, headers=headers)
Example Response
{
"startIndex": 0,
"totalResults": 16,
"itemsPerPage": 3,
"Resources": [
{
"id": "6Lt3yHNcBBEyMSK8n",
"createdAt": "2023-06-21T17:52:36.687Z",
"updatedAt": "2023-06-24T05:42:18.599Z",
"agentId": "72999",
"creatorId": "zme7PkariKd5Hb4fT",
"criteriaId": null,
"rubricId": "AatxWWtXWKcfiN34E",
"answerId": "16906fb5ce9d57646fa38362_5310985_AatxWWtXWKcfiN34E_542897_GRADER_grading",
"type": "opportunities",
"classification": "qa",
"coachNotes": "Let's talk about greeting",
"coachingSessionIds": [],
"textContent": ""
},
{
"id": "Ai37xkEiq2HPy8zXs",
"createdAt": "2023-07-10T18:10:09.340Z",
"updatedAt": "2023-07-10T18:10:09.340Z",
"agentId": "72999",
"creatorId": "zme7PkariKd5Hb4fT",
"type": "strengths",
"classification": "general",
"coachNotes": "Good job asking probing questions ",
"coachingSessionIds": [
"2TGWZ8YdWnK9HyPgm"
],
"textContent": ""
},
{
"id": "B8wj8BptAFzgjWdti",
"createdAt": "2023-06-23T19:00:00.861Z",
"updatedAt": "2023-06-24T05:42:18.599Z",
"agentId": "72999",
"creatorId": "nQHdkaE76F7upgJwr",
"type": "n/a",
"classification": "general",
"coachNotes": null,
"coachingSessionIds": [],
"textContent": ""
}
]
}
Retrieve a Single Coaching Session
Fetch a single coaching session by ID
Definition
GET https://app.maestroqa.com/api/v1/coaching-sessions/:id
Path Parameters
Name | Type | Description |
id | string | The unique identifier of the coaching session to retrieve |
Response
The coaching session
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/coaching-sessions/25oWGcmSd34yZRR84'
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.get(url, headers=headers)
Example Response
{
"id": "25oWGcmSd34yZRR84",
"name": "Sample Coaching Session",
"createdAt": "2023-07-13T16:02:42.255Z",
"updatedAt": "2023-07-13T16:02:53.622Z",
"agentId": "72999",
"agentName": "Harrison Charles",
"coachId": "zme7PkariKd5Hb4fT",
"coachName": "Charlie Smith",
"creatorId": "zme7PkariKd5Hb4fT",
"agentNotes": "Agent's notes",
"coachNotes": "Coach's notes",
"coachPrivateNotes": "Private (not shared with agent) notes",
"sessionContents": "Contents of the sessions's 'Overview' tab",
"coachingTemplateId": "16906fb5ce9d57646fa38362",
"meetingFormat": "inPerson",
"agentConfirmed": false,
"coachConfirmed": false
}
Retrieve Many Coaching Sessions
Fetch multiple coaching sessions based on filter criteria.
Definition
GET https://app.maestroqa.com/api/v1/coaching-sessions
Query Parameters
Name | Type | Description |
agentId | string | Filter to only coaching sessions for the provided agent ID |
creatorId | string | Filter to only coaching sessions created by the provided user ID |
coachId | string | Filter to only coaching sessions where the coach matches the provided user ID |
startDate | date string (see formats) | Filter to only coaching sessions created after the provided date |
endDate | date string (see formats) | Filter to only coaching sessions created before the provided date |
count | integer | The number of results to return |
startIndex | integer | Offset to start pagination search results |
Response
Name | Type | Description |
startIndex | integer | Offset of paginated search results |
totalResults | integer | Total number of coaching points that match the provided query filters |
itemsPerPage | integer | The number of results per page |
Resources | array[coaching sessions] | List of coaching sessions matching the filter criteria |
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/coaching-sessions'
params = {
'count': 3,
'coachId': 'zme7PkariKd5Hb4fT',
'startDate': '2023-06-01T15:08:45.781Z',
'endDate': '2023-08-01T15:08:45.781Z',
}
headers = { 'apitoken': 'YOUR_API_TOKEN' }
response = requests.get(url, params=params, headers=headers)
Example Response
{
"startIndex": 0,
"totalResults": 253,
"itemsPerPage": 3,
"Resources": [
{
"id": "25oWGcmSd34yZRR84",
"name": "Sample Coaching Session",
"createdAt": "2023-07-13T16:02:42.255Z",
"updatedAt": "2023-07-13T16:02:53.622Z",
"agentId": "72999",
"agentName": "Harrison Charles",
"coachId": "zme7PkariKd5Hb4fT",
"coachName": "Charlie Smith",
"creatorId": "zme7PkariKd5Hb4fT",
"agentNotes": "Agent's notes",
"coachNotes": "Coach's notes",
"coachPrivateNotes": "Private (not shared with agent) notes",
"sessionContents": "Contents of the sessions's 'Overview' tab",
"coachingTemplateId": "16906fb5ce9d57646fa38362",
"meetingFormat": "inPerson",
"agentConfirmed": false,
"coachConfirmed": false
},
{
"id": "2BNoiJDcthvabPyxC",
"name": "Created by Matthew",
"createdAt": "2023-06-22T21:09:25.511Z",
"updatedAt": "2023-07-26T21:05:24.878Z",
"agentId": "0055e000000ZIqdAAG",
"agentName": "Automated Process",
"coachId": "zme7PkariKd5Hb4fT",
"coachName": "Matthew Chuck",
"creatorId": "zme7PkariKd5Hb4fT",
"agentNotes": "",
"coachNotes": "",
"coachPrivateNotes": "",
"sessionContents": "Performance\nAgent perspective on their performance since last review\nHow do you feel about your recent performance?\nHave you been experiencing any blockers in your workflow? Is there any additional support you need?\n\nGrowth\nDiscuss areas that the Agent has grown or excelled in. How has this contributed to their overall performance and their team’s?\n \n \n\nDevelopment Goals\nWhat career goals do you want to achieve in the coming quarter or year? What skills or competencies do you want to hone in on?\n\nThis Coming Quarter\n \n \n\nThis Coming Year\n \n \n\n",
"coachingTemplateId": "16906fb5ce9d57646fa38362_3",
"meetingFormat": "inPerson",
"agentConfirmed": false,
"coachConfirmed": false
},
{
"id": "2BendGuN7JqrKfRGn",
"name": "test coaching session",
"createdAt": "2023-06-03T04:02:13.764Z",
"updatedAt": "2023-06-03T04:02:30.120Z",
"agentId": "72999",
"agentName": "Harrison Hunter Rill",
"coachId": "zme7PkariKd5Hb4fT",
"coachName": "Harrison Hunter2",
"creatorId": "zme7PkariKd5Hb4fT",
"agentNotes": "",
"coachNotes": "",
"coachPrivateNotes": "",
"sessionContents": "",
"coachingTemplateId": "16906fb5ce9d57646fa38362_2",
"meetingFormat": "inPerson",
"agentConfirmed": false,
"coachConfirmed": true
}
]
}
Create a Ticket Metric
Create a metric and associate to a specific ticket and agent. Note a metric is defined by combination of the metric id, ticket id, source id and agent id. Meaning every metric is specific to an agent and a ticket. To create a ticket attribute that is not agent specific, you can use the normal Tickets API MaestroQA API.
Definition
POST => https://app.maestroqa.com/api/v1/ticket-metrics
Body Parameters
Name | Type | Required | Description |
ticket_id | string | Yes | Ticket ID of the ticket the metric is attached to |
source_id | string | Yes | The identifier of the source of the ticket. Important when there are multiple help desks or ticket source systems to ensure proper ticket identification especially if there can be overlapping ids. Ex. salesforce |
agent_id | string | Yes | The agent ID or email of the ticket the metric is attached to. Note this agent_id must be associated with an agent in MaestroQA. See the SCIM API SCIM | Maestro QA Help Center if you need to dynamically fetch agent ids or emails. |
metric_id | string | Yes | The metric ID of the metric you are passing. Ex. response_time |
metric_value | number | Yes | The value for the metric you are passing. Ex. 17 |
timestamp | string | Yes | The timestamp the metric comment should count for - ie when this metric “occurred”. Often this is something like the time the update or comment that generated the metric occurred or the ticket creation time. Expects ISO Format date string of this format: 2017-12-13T05:00:00Z
|
ticket_event_id | string | No | Identifier for sub event w/i a case - for example get survey id for CSAT/CES metrics, can be null for metrics that do not have a sub event |
metric_deleted | boolean | No | Use this to remove a metric from a ticket. For example, you could post a metric for a ticket. Then later, if that metric is no longer relevant, rather than setting it to zero, post metric_deleted as true and the metric will be disassociated from the ticket. |
Response
The metric that was created
Name | Type | Description |
ticket_id | string | Ticket ID of the ticket the metric is attached to |
metric_id | string | The metric ID of the metric you are passing. Ex. response_time |
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/ticket-metrics'
headers = {
'Content-Type': 'application/json',
'apitoken': 'YOUR_API_TOKEN'
}
individual_data = {
'ticket_id': '1234',
'source_id': 'internal_crm',
'agent_id': '456',
'metric_id': 'response_time',
'metric_value': 32,
'timestamp': '2017-12-13T05:00:00Z'
'metric_deleted': False,
}
res1 = requests.post(url, json=individual_data, headers=headers)
res1.status_code
# => 201
Example Response
{
"ticket_id": "1234",
"metric_id": "response_time"
}
Create Many Ticket Metrics
Create a batch of metrics for one or more tickets.
Definition
https://app.maestroqa.com/api/v1/ticket-metrics-batch
Body Parameters
Name | Type | Required | Description |
batch | array | Yes | Array of metric objects (see structure of a "metric" object from Create a Metric request arguments)
*Note: there is a maximum of 500 metrics per batch |
Response
The metrics that were created
Name | Type | Description |
results | array | Array of created metric objects (see structure of a "metric" response from Create a Metric response documentation) |
Example Request (Python)
import requests
bulk_endpoint = 'https://app.maestroqa.com/api/v1/ticket-metrics-batch'
headers = {
'Content-Type': 'application/json',
'apitoken': 'YOUR_API_TOKEN'
}
payload = {
batch: [
{
'ticket_id': '1234',
'source': 'internal_crm',
'agent_id': '456',
'mtric_id': 'response_time',
'metric_value': 32,
'timestamp': '2017-12-13T05:00:00Z',
'metric_deleted': False
},
{
'aegnt_id': 'agent12345',
'ticket_id': '1234',
'source': 'internal_crm',
'agent_id': '456',
'mtric_id': 'response_time',
'metric_value': 32,
'timestamp': '2017-12-13T05:00:00Z',
'metric_deleted': False
},
]
}
res2 = requests.post(url, json=bulk_data, headers=headers)
res2.status_code
# => 201
Example Response
{
"results": [
{
"ticket_id": "1234",
"metric_id": "response_time"
},
{
"ticket_id": "12345",
"metric_id": "response_time"
}
]
}
Create Agent Metrics
Create a batch of metrics for one or more agents.
Definition
https://app.maestroqa.com/api/v1/agent-metrics-batch
Body Parameters
Name | Type | Required | Description |
batch | array | Yes | Array of metric objects (see below for metric object structure)
*Note: there is a maximum of 500 metrics per batch |
agent_id | string | Yes | The agent ID or email of the ticket the metric is attached to. Note this agent_id must be associated with an agent in MaestroQA. See the SCIM API SCIM | Maestro QA Help Center if you need to dynamically fetch agent ids or emails. |
metric_id | string | Yes | The metric ID of the metric you are passing. Ex. hours_worked_in_seconds |
metric_value | number | Yes | The value for the metric you are passing. Ex. 17 |
timestamp | string | Yes | The timestamp the metric comment should count for - ie when this metric "occurred”. Often this is something like the time the update or comment that generated the metric occurred or the ticket creation time. Expects ISO Format date string of this format: 2017-12-13T05:00:00Z
|
Response
The metrics that were created
Name | Type | Description |
results | array | Array of created metric objects (see structure of a "metric" response from Create a Metric response documentation) |
Example Request (Python)
import requests
url = 'https://app.maestroqa.com/api/v1/agent-metrics-batch'
headers = {
'Content-Type': 'application/json',
'apitoken': 'YOUR_API_TOKEN'
}
payload = {
batch: [
{
'aegnt_id': 'agent1234',
'metric_id': 'hours_worked_in_seconds',
'metric_value': 28800,
'timestamp': '2017-12-13T05:00:00Z',
},
{
'aegnt_id': 'agent12345',
'metric_id': 'hours_worked_in_seconds',
'metric_value': 28800,
'timestamp': '2017-12-13T05:00:00Z',
},
]
}
res2 = requests.post(url, json=bulk_data, headers=headers)
res2.status_code
# => 201
Example Response
{
"results": [
{
"ticket_id": "1234",
"metric_id": "hours_worked"
},
{
"ticket_id": "12345",
"metric_id": "hours_worked"
}
]
}
Rate Limits
A given token has limits on how many times it can be used to make a request. The general guidelines to refer to are:
10 requests per second
100 requests per minute
You can expect to export 10,000 to 50,000 scores at time. The exact number is variable based on the size of your scorecard, number of comments per scorecard, and other factors.
Error Responses
Common error response scenarios:
cause: invalid API token
likely cause: request made for non-existent content (for example, making a "Get User" request for a user that has been deleted)
likely cause: a non-unique value was provided for a parameter that must be unique (for example, making "Create Agent" request with an email that is already in use by an existing agent)
the error response message will indicate which values were in conflict
likely cause: invalid values provided for one or more request parameters
the error response message will indicate which parameters were invalid
cause: exceeded rate limit
Troubleshooting
"Body Parameters" is not be confused with "Query Parameters". For example when using Postman, see the below screenshots clarifying the difference,
Query Parameters:
Body Parameters: