Migration from LogicMonitor REST API v1 to API v3
Last updated on 20 June, 2025LogicMonitor REST API v3 is far more advance than API v1. All enhancements and fixes are done only to API v3. The following are key highlights why you must migrate to API v3:
- API v3 version header updates
- Support for token-based authentication
- Support for filter syntax
- Support for the
PATCH
method - API URL updates
Requirements for Migration from LogicMonitor REST API v1 to API v3
To migrate to API v3, you need the following:
- A valid LMv1 API token or bearer token for authentication.
- Access to Swagger documentation from LogicMonitor for API v3 reference.
LogicMonitor REST API v1 to API v3 Changes
You must note the following changes in both the API v1 and API v3:
- Authentication updates
- Support for
PATCH
method to partially update an endpoint - Updates to the version header
- Updates to success and error response format
Support for Token-based Authentication
Starting with API v2, LogicMonitor no longer supports basic authentication. It is done to encourage use of API tokens for authentication. The API tokens are secure, they help in separation of LogicMonitor portal and LogicMonitor REST API access, and audit log entries.
To encourage use of taken-based authentication, LogicMonitor supports LMv1 API and bearer token for API v2 and API v3. For more information, see REST API Authentication.
Support for PATCH Method
API v3 includes support for PATCH
method for most of the API endpoints. You may find this useful for updating specific fields of an endpoint, instead of using the PUT
method for updating all the fields (that is, the entire API endpoint). For more information, see REST API v3 Swagger Documentation.
Version Header for REST API v1 to API v3
You can make API v3 request using one of the following version headers:
- Header X-version with value 3. For example, “X-version: 3”
- API query parameter
v
with value 3. For example, “v=3”
For more information, see REST API v3 Swagger Documentation.
Adding Version Header using cURL
Enter the following command and use -H
or --header
followed by the header name and value:
curl -H "X-version: 3" https://COMPANY.logicmonitor.com/santaba/rest/device/devices/1
curl --header "X-version: 3" https://COMPANY.logicmonitor.com/santaba/rest/device/devices/1
curl "https://COMPANY.logicmonitor.com/santaba/rest/device/devices/1?v=3"
Adding Version Header using Python
Enter the following command and use the headers
parameter in the requests
library.
headers = {'X-Version':'3'}
response = requests.get("https://COMPANY.logicmonitor.com/santaba/rest/device/devices/1", headers=headers)
response = requests.get("https://COMPANY.logicmonitor.com/santaba/rest/device/devices/1?v=3")
API Response Format for REST API v1 to API v3
The following are the key updates to API response format:
- Removal of Wrapper fields
- The
status
,errmsg
, anddata
fields are removed from the API v3 response. - All fields from
data
are now directly included in the root of the JSON response. - Added new fields
errorMessage
,errorCode
, anderrorDetail
to the error response format.
- The
- Updates to parsing logic
- You do not have to parse the
data
field to access the API response data value. - You can directly consume field value from the root of the JSON response.
- You do not have to parse the
- Updates to error handling
- Added new fields
errorMessage
,errorCode
, anderrorDetail
to the error response format. - The error code in API v3 may differ from that in API v1 for the same API endpoint.
- Added new fields
Examples of Success Response Format for REST API v1 and API v3
The response payload of API v1 is different from API v3, hence the parsing of response has been changed. When the API successfully fetches the response, the response format is as follows:
- API v1 success response
{
"status": 200,
"errmsg": "OK",
"data": {
<API specific data fields and value>
}
}
- API v3 success response
{
<API specific data, same data that we are returning in "data" field of API V1 response>
}
Examples of Error Response Format for REST API v1 and API v3
In case of error response, the format is as follows:
- API v1 error response
{
"data": null,
"errmsg": <ERROR_MESSAGE>,
"status": <ERROR_CODE>
}
- API v3 error response
{
"errorMessage": <ERROR_MESSAGE>,
"errorCode": <ERROR_CODE>,
"errorDetail": null
}
Comparison of Parameter Differences between REST API v1 and API v3
When migrating from API v1 to API v3, you must consider the differences in API URL, error codes, and filter syntax.
Filter Syntax | API v1 Parameter Value | API v3 Parameter Value |
Enclose value in double quotes (“”) | GET /device/devices?filter=name:127.0.0.1 | GET /device/devices?filter=name:"127.0.0.1" |
Encode twice values with special character “+” | GET /device/devices?filter=name:Prod+Server | GET /device/devices?filter=name:"Prod%252BServer" |
Encode once values with special characters EXCEPT “+” (&, -, and so on) | GET /device/devices?filter=name:Prod&Server | GET /device/devices?filter=name:"Prod%26Server" |
API URL Updates for REST API v1 and API v3
When migrating from API v1 to API v3, you must replace the API v1 URL with the API v3 URL. Some API URLs for components such as Collectors and Websites have changed. The mapping between the v1 and v3 URLs is given in the following table:
Component | API v1 URL | API v3 URL |
Collectors | POST /setting/collectors | POST /setting/collector/collectors |
GET /setting/collectors | GET /setting/collector/collectors | |
GET /setting/collectors/id/installers/id | GET /setting/collector/collectors/id/installers/id | |
POST /setting/collectors/id/ackdown | POST /setting/collector/collectors/id/ackdown | |
DELETE /setting/collectors/id | DELETE /setting/collector/collectors/id | |
PUT /setting/collectors/id | PUT /setting/collector/collectors/id | |
PATCH /setting/collectors/id | PATCH /setting/collector/collectors/id | |
GET /setting/collectors/id | GET /setting/collector/collectors/id | |
Collector Groups | GET /setting/collectors/groups/id | GET /setting/collector/groups/{id} |
DELETE /setting/collectors/groups/id | DELETE /setting/collector/groups/{id} | |
PUT /setting/collectors/groups/id | PUT /setting/collector/groups/id | |
GET /setting/collectors/groups | GET /setting/collector/groups | |
POST /setting/collectors/groups | POST /setting/collector/groups | |
Website | GET /service/smcheckpoints | GET /website/smcheckpoints |
GET /service/services/id/sdts | GET /website/websites/id/sdts | |
GET /service/services/id/properties | GET /website/websites/{id}/properties | |
GET /service/services/id/graphs/id/data | GET /website/websites/id/graphs/id/data | |
GET /service/services/id/checkpoints/id/graphs/id/data | GET /website/websites/id/checkpoints/id/graphs/id/data | |
GET /service/services/id/checkpoints/id/data | GET /website/websites/id/checkpoints/id/data | |
GET /service/services/id/alerts | GET /website/websites/id/alerts | |
DELETE /service/services/id | DELETE /website/websites/id | |
PATCH /service/services/id | PATCH /website/websites/id | |
PUT /service/services/id | PUT /website/websites/id | |
GET /service/services/id | GET /website/websites/{id} | |
POST /service/services | POST /website/websites | |
GET /service/services | GET /website/websites | |
Website Groups | GET /service/groups/id/services | GET /website/groups/id/websites |
GET /service/groups/id/sdts | GET /website/groups/id/sdts | |
DELETE /service/groups/id | DELETE /website/groups/id | |
PATCH /service/groups/id | PATCH /website/groups/id | |
GET /service/groups/id | GET /website/groups/{id} | |
PUT /service/groups/id | PUT /website/groups/id | |
POST /service/groups | POST /website/groups | |
GET /service/groups | GET /website/groups |
Error Code Updates for REST API v1 and API v3
LogicMonitor has updated some error codes in API v3. When migrating from API v1 to API v3, you must consider the API v3 error codes. The mapping between the v1 and v3 error codes is given in the following table:
Note:
- The error code list may include additional rows.
- The error message may differ as per the API endpoint.
API v1 Error Code | API v3 Error Code | Default New Error Message |
3403 | 1400 | Bad request |
2403 | 1404 | No such record |
1312 | 1400 | Bad request |
1310 | 14042 | No such company |
1304 | 14041 | No such record in TSDB |
1303 | 1400 | Bad request |
1302 | 1404 | No such record |
1301 | 1400 | Bad request |
1300 | 14002 | Partial success |
1201 | 14002 | Partial success |
1104 | 14001 | Resource dependency |
1101 | 15001 | Query timeout |
1100 | 1429 | Too many requests |
1091 | 1429 | Too many requests |
1079 | 1400 | Bad request |
1078 | 1400 | Bad request |
1077 | 1400 | Bad request |
1076 | 1400 | Bad request |
1075 | 1413 | The request entity is too large |
1074 | 1074 | Report refuse to view as timely |
1073 | 1400 | Bad request |
1069 | 1404 | No such record |
1065 | 1404 | No such record |
1060 | 1404 | No such record |
1058 | 1404 | No such record |
1053 | 1404 | No such record |
1048 | 1404 | No such record |
1041 | 1403 | Permission denied |
1040 | 1400 | Bad request |
1037 | 1404 | No such record |
1035 | 1400 | Bad request |
1033 | 1404 | No such record |
1031 | 1400 | Bad request |
1027 | 1404 | No such record |
1026 | 1400 | Bad request |
1025 | 1400 | Bad request |
1022 | 1404 | No such record |
1020 | 1400 | Bad request |
1019 | 1400 | Bad request |
1018 | 1400 | Bad request |
1017 | 1400 | Bad request |
1016 | 1400 | Bad request |
1015 | 1404 | No such record |
1014 | 1400 | Bad request |
1013 | 1404 | No such record |
1010 | 1400 | Bad request |
1007 | 1400 | Bad request |
1004 | 1404 | No such record |
1001 | 1500 | Internal error |
1000 | 1500 | Internal error |
600 | 1409 | The record already exists |
503 | 1404 | No such record |
500 | 1500 | Internal error |
403 | 1401 | Authentication failed |
400 | 1401 | Authentication failed |
100 | 1202 | The task is running |
Error Code Update Examples for REST API v1 and API v3
Following are the examples of API v1 and API v3 of the Processing fields.
- API v1 Code Block
import json
# Success Response Handling
def handle_success_response_v1(json_response):
response = json.loads(json_response)
status = response['status']
errmsg = response['errmsg']
data = response['data']
# Process the fields from the data object
# Example: total = data['total']
# Error Response Handling
def handle_error_response_v1(json_response):
response = json.loads(json_response)
status = response['status']
errmsg = response['errmsg']
data = response['data']
# Process the error message and status
- API v1 Code Block of Processing Fields
#!/bin/env python
import requests
import json
import hashlib
import base64
import time
import hmac
import getpass
#Account Info: LogicMonitor recommends to NEVER hardcode the credentials. Instead, retrieve the values from a secure storage.
#Note: The below is provided for illustration purposes only.
AccessId = getpass.getpass("Enter your AccessId: ")
AccessKey = getpass.getpass("Enter your AccessKey: ")
Company = 'apiAccount'
#Request Info
httpVerb ='GET'
resourcePath = '/device/devices/1'
fields = 'id,name,displayName'
queryParams = '?fields=' + fields
data = ''
#Construct URL
url = 'https://'+ Company +'.logicmonitor.com/santaba/rest' + resourcePath + queryParams
#Get current time in milliseconds
epoch =str(int(time.time() * 1000))
#Concatenate Request details
requestVars = httpVerb + epoch + data + resourcePath
#Construct signature
digest = hmac.new(
AccessKey.encode('utf-8'),
msg=requestVars.encode('utf-8'),
digestmod=hashlib.sha256).hexdigest()
signature = base64.b64encode(digest.encode('utf-8')).decode('utf-8')
# Construct headers
auth = 'LMv1 ' + AccessId + ':' + str(signature) + ':' + epoch
# headers = {'Content-Type':'application/json','Authorization':auth}
headers = {'X-version':'1','Content-Type':'application/json','Authorization':auth}
#Make request
response = requests.get(url, data=data, headers=headers)
#body of response
response_body = json.loads(response.content.decode('utf-8'))
print ('Response Body:',response_body)
status = response_body['status']
if (status == 200):
#Fetch data from body of response
data = response_body['data']
#Read device fields value from data
device_name = data['name']
device_displayName = data['displayName']
print ("name:", device_name)
print ("displayName:", device_displayName)
else:
data = response_body['data']
errmsg = response_body['errmsg']
print ("Error status code:",status)
print ("Error data:",data)
print ("Error message:",errmsg)
- API v3 Code Block
import json
# Success Response Handling
def handle_success_response_v3(json_response):
response = json.loads(json_response)
# Process the fields directly from the response
# Example: total = response['total']
# Error Response Handling
def handle_error_response_v3(json_response):
response = json.loads(json_response)
error_message = response['errorMessage']
error_code = response['errorCode']
error_detail = response['errorDetail']
# Process the error message, code, and detail
- API v3 Code Block of Processing Fields
#!/bin/env python
import requests
import json
import hashlib
import base64
import time
import hmac
import getpass
#Account Info: LogicMonitor recommends to NEVER hardcode the credentials. Instead, retrieve the values from a secure storage.
#Note: The below is provided for illustration purposes only.
AccessId = getpass.getpass("Enter your AccessId: ")
AccessKey = getpass.getpass("Enter your AccessKey: ")
Company = 'apiAccount'
#Request Info
httpVerb ='GET'
resourcePath = '/device/devices/1'
fields = 'id,name,displayName'
queryParams = '?fields=' + fields
data = ''
#Construct URL
url = 'https://'+ Company +'.logicmonitor.com/santaba/rest' + resourcePath + queryParams
#Get current time in milliseconds
epoch =str(int(time.time() * 1000))
#Concatenate Request details
requestVars = httpVerb + epoch + data + resourcePath
#Construct signature
digest = hmac.new(
AccessKey.encode('utf-8'),
msg=requestVars.encode('utf-8'),
digestmod=hashlib.sha256).hexdigest()
signature = base64.b64encode(digest.encode('utf-8')).decode('utf-8')
# Construct headers
auth = 'LMv1 ' + AccessId + ':' + str(signature) + ':' + epoch
headers = {'X-version':'3','Content-Type':'application/json','Authorization':auth}
#Make request
response = requests.get(url, data=data, headers=headers)
#body of response
print ('Response Status:',response.status_code)
response_body = json.loads(response.content.decode('utf-8'))
print ('Response Body:',response_body)
status = response.status_code
if (status == 200):
#Read device fields value from response_body
device_name = response_body['name']
device_displayName = response_body['displayName']
print ("name:", device_name)
print ("displayName:", device_displayName)
else:
errorMessage = response_body['errorMessage']
errorCode = response_body['errorCode']
errorDetail = response_body['errorDetail']
print ("Error status code:",errorCode)
print ("Error details:",errorDetail)
print ("Error message:",errorMessage)