Customer Satisfaction (CSAT) surveys offer insights into your end users’ support experiences by encouraging them to quickly rate their resolved tickets, helping you gather feedback to improve your service.

This article describes how to retrieve CSAT survey responses using the List Survey Responses endpoint.

If you are using the legacy CSAT option, you must deactivate the legacy CSAT and manually deactivate any custom CSAT automations and triggers before you can activate the updated CSAT option. You can have only one CSAT option activated at a time.

Note: CSAT survey responses are available on the Support Professional plan and above, and the Zendesk Suite Growth plan and above.

Using the List Survey Responses endpoint

The List Survey Responses endpoint retrieves information about all customer survey responses. It is not limited to any specific ticket as described in Getting the CSAT ratings of tickets. Example:

{    "survey_responses": [        {            "id": "01JH6AK11ZG44KKFNZ3B07T6A5",            "expires_at": "2025-02-06T20:02:45.439Z",            "responder_id": "28431426615831",            "subject_zrns": [                "zen:ticket:362",                "zen:request:362"            ],            "subjects": [                {                    "id": "362",                    "type": "ticket",                    "zrn": "zen:ticket:362"                },                {                    "id": "362",                    "type": "request",                    "zrn": "zen:request:362"                }            ],            "survey": {                "id": "01J9SGDYMNQ6JP4PS1VJDQAKM6",                "version": 4,                "state": "enabled"            },            "answers": [                {                    "type": "rating_scale",                    "rating": 1,                    "rating_category": "bad",                    "question": {                        "type": "rating_scale_numeric",                        "sub_type": "customer_satisfaction",                        "id": "01J9SGDW8FWZD5Z2CRZBZJRP2E"                    },                    "created_at": "2025-01-09T20:30:08.609Z",                    "updated_at": "2025-01-09T20:30:08.609Z"                }            ]        },        ...    ],    "meta": {        "has_more": false,        "after_cursor": "01JH6AK0V64VDDAF8S65G4AEV7",        "before_cursor": "01JH6AK11ZG44KKFNZ3B07T6A5"    }}

Example list survey responses script

The following Python script retrieves CSAT survey responses by performing the following steps:

  • Fetch all survey responses submitted since a specified date.
  • Extract and group survey answers based on their rating categories, such as "bad", "neutral", or "good".
  • Display the total number of survey responses and detailed ratings for each category.

Requirements

  • Python
  • requests library
  • arrow library
  • Admin role in your Zendesk account with API access

Disclamer

Zendesk provides this example script for instructional purposes only. Zendesk doesn't provide support for the example code. Zendesk doesn't support third-party technologies such as Python or command-line tools.

Sample script

Run python get_survey_responses.py on the command line.

File name: get_survey_responses.py

import osimport requestsimport arrow
# Load Zendesk API credentials and subdomain from environment variablesZENDESK_API_TOKEN = os.getenv('ZENDESK_API_TOKEN')ZENDESK_USER_EMAIL = os.getenv('ZENDESK_USER_EMAIL')ZENDESK_SUBDOMAIN = os.getenv('ZENDESK_SUBDOMAIN')
# Exit if required environment variables are missingif not all([ZENDESK_API_TOKEN, ZENDESK_USER_EMAIL, ZENDESK_SUBDOMAIN]):    print('Error: Missing required environment variables.')    exit(1)
# Base URL for fetching survey responsesAPI_URL = f'https://{ZENDESK_SUBDOMAIN}.zendesk.com/api/v2/guide/survey_responses'
# Set up HTTP Basic AuthenticationAUTH = f'{ZENDESK_USER_EMAIL}/token', ZENDESK_API_TOKEN

def fetch_survey_responses(start_date=None):    """    Fetch survey responses filtered from start_date onward, translating start_date into epoch time.    """    params = {}    if start_date:        epoch_start = arrow.get(start_date, 'MM-DD-YYYY').timestamp()        if epoch_start is None:            return None        params['filter[created_at_start]'] = int(epoch_start)
    try:        response = requests.get(API_URL, auth=AUTH, params=params)        response.raise_for_status()  # Raise error for bad responses        return response.json()    except requests.RequestException as e:        print(f"Error fetching data: {e}")        return None

def find_all_ratings_grouped_by_category(survey_responses):    """    Parse survey response and group ratings by their category.     """    grouped = {}        for response in survey_responses:        survey_id = response['survey']['id']                ticket_id = None        for subj in response['subjects']:            # Look for the ticket id associated with the response            if subj['type'] == 'ticket':                ticket_id = subj['id']                break
        for answer in response['answers']:            rating_category = answer['rating_category'].lower() or "undefined"            rating = answer['rating']            question_type = answer['question']['type']            entry = {                "rating": rating,                "rating_category": rating_category,                "question_type": question_type,                "survey_id": survey_id,                "ticket_id": ticket_id,            }                        if rating_category not in grouped:                grouped[rating_category] = [entry]            else:                grouped[rating_category].append(entry)
    return grouped

def main():
    # Define the start date for filtering survey responses (MM-DD-YYYY)    start_date = "01-01-2024"
    # Fetch responses starting at the specified date    data = fetch_survey_responses(start_date)    if data is None:        print("No data fetched.")        return
    survey_responses = data['survey_responses']    if not survey_responses:        print("No survey responses found.")        return
    # Print total number of survey responses found    print(f"Total survey responses found since {start_date}: {len(survey_responses)}")
    # Group ratings by category    grouped_ratings = find_all_ratings_grouped_by_category(survey_responses)
    # Display grouped results or message if no ratings found    if grouped_ratings:        for category, entries in grouped_ratings.items():            print(f"\nRating category: '{category}' ({len(entries)} entries)")            for item in entries:                print(item)    else:        print("No rating answers found in survey responses.")

if __name__ == "__main__":    main()

Example output

Total survey responses found since 01-01-2024: 4
Rating category: 'bad' (3 entries){'rating': 1, 'rating_category': 'bad', 'question_type': 'rating_scale_numeric', 'survey_id': '01J9SGDYMNQ6JP4PS1VJDQAKM6', 'ticket_id': '362'}{'rating': 1, 'rating_category': 'bad', 'question_type': 'rating_scale_numeric', 'survey_id': '01J9SGDYMNQ6JP4PS1VJDQAKM6', 'ticket_id': '370'}{'rating': 1, 'rating_category': 'bad', 'question_type': 'rating_scale_numeric', 'survey_id': '01J9SGDYMNQ6JP4PS1VJDQAKM6', 'ticket_id': '396'}
Rating category: 'neutral' (1 entries){'rating': 2, 'rating_category': 'neutral', 'question_type': 'rating_scale_numeric', 'survey_id': '01J9SGDYMNQ6JP4PS1VJDQAKM6', 'ticket_id': '365'}