Last active
March 4, 2024 15:31
-
-
Save fpcorso/702b80f162b2984fbd87a273af1a6f85 to your computer and use it in GitHub Desktop.
Download conversations from a Help Scout mailbox and save as CSV file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Download conversations from a Help Scout mailbox and save to CSV file. | |
Be sure to replace the App ID and Secret in the authorization call as well | |
as the Mailbox ID in the conversations API call. | |
Python: 3.9.0 | |
""" | |
import csv | |
import datetime | |
import requests | |
# The token endpoint. | |
auth_endpoint = 'https://api.helpscout.net/v2/oauth2/token' | |
# Preparing our POST data. | |
post_data = ({ | |
'grant_type': 'client_credentials', | |
'client_id': YOUR_HELPSCOUT_APP_ID, | |
'client_secret': YOUR_HELPSCOUT_APP_SECRET | |
}) | |
# Send the data. | |
r = requests.post(auth_endpoint, data=post_data) | |
# Save our token. | |
token = r.json()['access_token'] | |
all_conversations = False | |
page = 1 | |
# Prepare our headers for all endpoints using token. | |
endpoint_headers = { | |
'Authorization': 'Bearer {}'.format(token) | |
} | |
# Creates our file, or rewrites it if one is present. | |
with open('conversations.csv', mode="w", newline='', encoding='utf-8') as fh: | |
# Define our columns. | |
columns = ['ID', 'Customer Name', 'Customer email addresses', 'Assignee', 'Status', 'Subject', 'Created At', | |
'Closed At', 'Closed By', 'Resolution Time (seconds)'] | |
csv_writer = csv.DictWriter(fh, fieldnames=columns) # Create our writer object. | |
csv_writer.writeheader() # Write our header row. | |
while not all_conversations: | |
# Prepare conversations endpoint with status of conversations we want and the mailbox. | |
conversations_endpoint = 'https://api.helpscout.net/v2/conversations?status=all&mailbox=YOUR_MAILBOX_ID&page={}'.format( | |
page | |
) | |
r = requests.get(conversations_endpoint, headers=endpoint_headers) | |
conversations = r.json() | |
# Cycle over conversations in response. | |
for conversation in conversations['_embedded']['conversations']: | |
# If the email is missing, we won't keep this conversation. | |
# Depending on what you will be using this data for, | |
# You might omit this. | |
if 'email' not in conversation['primaryCustomer']: | |
print('Missing email for {}'.format(customer_name)) | |
continue | |
# Prepare customer name. | |
customer_name = '{} {}'.format( | |
conversation['primaryCustomer']['first'], | |
conversation['primaryCustomer']['last'] | |
) | |
# Prepare assignee, subject, and closed date if they exist. | |
assignee = '{} {}'.format(conversation['assignee']['first'], conversation['assignee']['last']) \ | |
if 'assignee' in conversation else '' | |
subject = conversation['subject'] if 'subject' in conversation else 'No subject' | |
closed_at = conversation['closedAt'] if 'closedAt' in conversation else '' | |
# If the conversation has been closed, let's get the resolution time and who closed it. | |
closed_by = '' | |
resolution_time = 0 | |
if 'closedByUser' in conversation and conversation['closedByUser']['id'] != 0: | |
closed_by = '{} {}'.format( | |
conversation['closedByUser']['first'], conversation['closedByUser']['last'] | |
) | |
createdDateTime = datetime.datetime.strptime(conversation['createdAt'], "%Y-%m-%dT%H:%M:%S%z") | |
closedDateTime = datetime.datetime.strptime(conversation['closedAt'], "%Y-%m-%dT%H:%M:%S%z") | |
resolution_time = (closedDateTime - createdDateTime).total_seconds() | |
csv_writer.writerow({ | |
'ID': conversation['id'], | |
'Customer Name': customer_name, | |
'Customer email addresses': conversation['primaryCustomer']['email'], | |
'Assignee': assignee, | |
'Status': conversation['status'], | |
'Subject': subject, | |
'Created At': conversation['createdAt'], | |
'Closed At': closed_at, | |
'Closed By': closed_by, | |
'Resolution Time (seconds)': resolution_time | |
}) | |
if page == conversations['page']['totalPages']: | |
all_conversations = True | |
continue | |
else: | |
page += 1 |
Hello. Tell me why there is an empty array in the response {'_embedded': {'conversations': []}
A Ruby alternative.
https://github.com/nadirkhann487/helpscout-api-to-download-conversations
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello. Maybe you can answer. I've tried your code to download conversations from helpscout, but i've got an error
line r = requests.get(conversations_endpoint, headers=endpoint_headers) gets me this b'{"logRef":"ccd8d588-3c77-43b8-85f3-c619c1e5c980#7219551","message":"Bad request","_embedded":{"errors":[{"path":"mailbox","message":"must be comma separated list of ids","rejectedValue":"u3h423u4buoi43","source":"query parameter","_links":{"about":{"href":"http://developer.helpscout.net/mailbox-api/overview/errors#CommaSeparatedListOfLongs"}}}]},"_links":{"about":{"href":"http://developer.helpscout.net/mailbox-api/overview/errors"}}}'
u3h423u4buoi43 - mail_id (i've changed that, it is not real, but i've used real one). Do you know what could be wrong?