- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
09-23-2020 07:13 AM
Hi All,
I need to download files attached to any incident using REST API.
I will be sending incident detail from my postman.
Already Referred to attachment api reference docs but could'nt find a solution.
NOTE: I don't have the option to use ui action
Is this doable?
Thanks in Advance!
Solved! Go to Solution.
- Labels:
-
Scripting and Coding

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
09-29-2020 02:32 AM
I'm executing python script from the command line.
I may be missing some steps below but the general way to install python is as follows.
1. Install python
https://phoenixnap.com/kb/how-to-install-python-3-windows
2. Create subdirectory
mkdir servicenowapis
3. Move to the subdirectory
cd servicenowapis
4. Create a virtualenv
python-m venv venv
5. Activate venv
venv\Scripts\activate.bat
6. Install request module
pip install requests
7. Copy the script I've provided to the directory
8. Copy and paste content of Constants.py over import statements
9. Edit username, password
9. Edit table_api.py to use Incident number
e.g.
get_file_attachment('INC0000002')
10. Execute command
python test_api.py
import requests
SERVICENOW_URL = 'https://<instance>.service-now.com'
SERVICENOW_USER = '<username>'
SERVICENOW_PWD = '<password>'
DOWNLOAD_DIR = './downloads/'
REQUEST_HEADER = {"json": {"Content-Type": "application/xml", "Accept": "application/json"},
"png": {"Content-Type": "application/xml", "Accept": "application/png"},
"xml": {"Content-Type": "application/xml", "Accept": "application/xml"},
}
ATTACHMENT_API = '/api/now/attachment'
TABLE_API = '/api/now/table'
# TABLE_NAME = 'kb_knowledge'
TABLE_NAME = 'incident'
def get_table_data(table_name, param):
url = SERVICENOW_URL + TABLE_API + '/' + table_name + '?' + param
response = requests.get(url, auth=(SERVICENOW_USER, SERVICENOW_PWD), headers=REQUEST_HEADER.get('json'))
if response.status_code != 200: # if error, then exit
print('Status:', response.status_code, 'Headers:', response.headers, 'Error Response:', response.json())
exit()
return response.json()
def get_attachment_info(sys_id):
url = SERVICENOW_URL + ATTACHMENT_API + '/' + sys_id
response = requests.get(url, auth=(SERVICENOW_USER, SERVICENOW_PWD), headers=REQUEST_HEADER.get('json'))
if response.status_code != 200: # if error, then exit
print(f'Status: {response.status_code}, Headers:{response.headers}')
exit()
return response.json()
def get_attachment(att_sys_id, file_type, download_dir):
url = SERVICENOW_URL + '/' + ATTACHMENT_API + '/' + att_sys_id + '/file'
response = requests.get(url, auth=(SERVICENOW_USER, SERVICENOW_PWD), headers=REQUEST_HEADER.get(file_type))
if response.status_code != 200: # if error, then exit
print('Status:', response.status_code, 'Headers:', response.headers, 'Error Response:', response.json())
exit()
with open(download_dir, 'wb') as f:
for chunk in response:
f.write(chunk)
def get_file_attachment(record_number):
param = 'sysparm_query=number=' + record_number + '&sysparam_limit=1'
file_info = get_table_data(TABLE_NAME, param).get('result')
if len(file_info) < 1:
print(f'There is no attachment to sys_id:{record_number}')
return
attachment_sys_id = file_info[0].get('sys_id')
param = 'sysparm_query=table_sys_id=' + attachment_sys_id + '&sysparam_limit=1'
kb_attachments = get_table_data('sys_attachment', param)
result = kb_attachments.get('result')
for attach_file in result:
attach_sys_id = attach_file.get('sys_id')
content_type = attach_file.get('content_type').split('/')
file_ext = content_type[1]
file_name = attach_file.get('file_name')
get_attachment(attach_sys_id, file_ext, DOWNLOAD_DIR + file_name)
if __name__ == '__main__':
# get_file_attachment('KB0010062') # knowledge base number
get_file_attachment('INC0000002')
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
10-04-2020 11:23 PM
Hi Hozawa,
Thanks for the clarification!
Tried this in my PDI and this seems to be working fine.
However since this involves downloading python, i am checkin for other way as well as if we look from end user's perspective not everyone will have python installed.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
10-06-2020 07:35 PM
It seems a new question with the additional requirements was created already.
Would appreciate if this question would be closed now because the original question was answered. If I can develop a Scripted REST API to down files, I'll reply in the new thread.
Thanks.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
10-11-2020 10:29 PM
Hi Hitoshi,
Since i didnot mention in my question anything related to python, marking this as correct as it worked for me in my PDI.
Thanks!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
11-17-2022 10:22 PM
Hi Hitoshi,
I'm getting errors as the below while running this code. Seems attachments are not found in mentioned directory. Is that changed now?
line 71, in <module>
get_file_attachment('INC0010003')
line 66, in get_file_attachment
get_attachment(attach_sys_id, file_ext, DOWNLOAD_DIR + file_name)
line 44, in get_attachment
with open(download_dir, 'wb') as f:
FileNotFoundError: [Errno 2] No such file or directory: './downloads/test.txt'

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
09-29-2020 02:36 AM
To anyone who knows flask, it's possible to wrap the script in flask so it can be executed by calling an URL.
e.g. http://127.0.0.1:8080/downloadattachments?number=INC0000002
from flask import request
from servicenowapis import app
from servicenowapis.table_api import get_file_attachment
@app.route('/')
@app.route('/index')
def index():
"""
Sample home page used to test connectivity
:return: Sample string text to show the site is working.
created: 2020/0709 Hitoshi Ozawa
"""
message = "<html><body><h1>ServiceNow APIs</h1></body></html>"
return message
@app.route('/downloadattachments')
def download_attachments():
ticket_number = request.args.get('number')
get_file_attachment(ticket_number)
return "Downloaded attachments to ticket number:" + ticket_number