API integration (v2)
To access the M360 Customer API you have to first activate it by logging in to your dashboard and setting the API status to Testing or Live. If you wish to disable your API access later, you can set the API status on your dashboard to Disabled. To enable and use your M360 Customer API account you will need a valid and active M360 licence.
Testing mode
Calling any API endpoint in Testing mode will never cause any data changes. Also, responses in this mode will be randomly generated but syntactically correct data structures. You can use this mode to safely experiment with the M360 Customer API and test your integration. Once you have tested your system and feel confident you can switch to Live mode.
Most endpoints can be called in testing mode even if your API is live, by providing the optional testing request parameter and setting its value to true. This will result in exactly the same behaviour and response as if your API was in Testing mode.
Request structure
To call any M360 Customer API endpoint just issue an HTTP POST request with an application/json content type to the URL of the endpoint. The body of the request should be a simple JSON object containing the input parameters shown at the endpoint's documentation.
Authentication
With every /v2 API request you must provide the correct authentication information which is different from your M360 login username and password. You need to use an Authorization header, with a bearer token. Your bearer token is simply your authCode and authToken, concatenated with a - (dash) character:
POST https://m360soft.com/api/customer/v2/getHistory
User-Agent: curl/7.54.1
Authorization: Bearer a167b9ae-948d-490c-9995-932984fbb223-f3e1016b87d4d11d7994d39050ac5d05ef475bc422131b0916337f0c0a424be3
{
"limit": 100
}
The authCode parameter is the unique identifier of your M360 Customer API account and the authToken is the secret key of it. You can access both of them on your dashboard at the API information section. For safety reasons the authToken can only be viewed or regenerated after providing your M360 password (the one you use to log in to your dashboard).
Response structure
Every M360 Customer API response will be a JSON object containing two properties: data and meta.
The data object will be populated with the specific information that the called API endpoint provides, so its structure and content varies between endpoints. For example a successful but empty /v2/getHistory response will be like this:
{
"data": {
"records": [],
"hasMore": false
},
"meta": {
"success": true
}
}
The meta object has a more rigid structure and always contains the boolean status property success, and in case of any error the errors object. The errors object has 3 properties: code, title and details. The code is the ID of the error, while the title is a human-readable description of it. If you would like to handle specific errors, always build your logic on the code error property instead of the title.
Example error response:
{
"data": [],
"meta": {
"success": false,
"errors": {
"code": "auth:forbidden",
"title": "Access forbidden with the given credentials",
"details": []
}
}
}
Rate limiting
There is a limit on the number of requests you can make to any Customer API endpoints, which is based on your active licences and upgrades. You can make 1 request / second / workstations. So if you have a Professional Licence with 2 additional workstation upgrades then you are limited to a total of 5 requests / second. If you encounter a rate limit error, you will receive a 429 Too Many Requests HTTP status code, and a JSON error response containing the effective rate limit of your account:
{
"data": [],
"meta": {
"success": false,
"errors": {
"code": "customer_api:too_many_requests",
"title": "Too many requests",
"details": {
"maximumRequestsPerSecond": 5
}
}
}
}
Versioning and backward compatibility
The M360 Customer API is a versioned API. The current version is v2. We will support the previous versions for a reasonable time, but we encourage you to always use the latest version of the API. We will announce the deprecation of a version at least 6 months before the end of support.
We introduce new versions of the API when we make breaking changes to the existing endpoints or the API in general. Between versions, we may introduce non-breaking changes, such as new endpoints or new properties in the response objects. We will document these changes in the changelog.
Breaking changes
A breaking change is a change that can cause existing integrations to stop working and may require changes to the client code.
Examples of breaking changes include:
- Removing, renaming or changing the type of a request parameter or response property.
- Removing functionality from an endpoint.
- Adding stricter validation for a field.
- Global changes like requiring a new authentication method.
Non-breaking changes
A non-breaking change is a change that does not require changes to the client code.
Examples of non-breaking changes include:
- Adding a new endpoint.
- Adding a new property to a response object.
- Adding a new optional request parameter.
- Adding a new error code.
- Adding a new value to an existing enumeration.
- Changing the order of properties in a response object.
Migrating from v1 API
Migrating from the v1 to the v2 version of the M360 Customer API should be straightforward, but there are some major changes you need to be aware of.
Authentication changes
The v2 API uses a different authentication method. You need to use an Authorization header with a bearer token instead of the authCode and authToken request parameters. The bearer token is simply your authCode and authToken, concatenated with a - (dash) character.
getHistory endpoint changes
The /getHistory endpoint has been significantly changed, both in the request and response structure.
Input parameters:
- Formerly, in the v1 API, the
imeifilter accepted a serial number too. In the v2 API, there is a separateserialfilter for this purpose. Theimeifilter now only accepts IMEI numbers. - The
imeifilter is now an array instead of a single string. You can provide and search for multiple IMEI numbers in a single request. - The
m360idfilter is now an array instead of a single string. You can provide and search for multiple M360 IDs in a single request. - There is a new
customIdfilter which allows you to search for devices using the custom ID you have saved as sticky data for the device. - The
marketingNamefilter was renamed tofriendlyNameto reflect the name change of the relevant property in the response object. - Now you can provide the
timeZoneparameter to get the timestamps in the response in the specified time zone. The default is UTC. - There is a
calculateTotalCountparameter which allows you to request the calculation of the number of matching rows. The default value isfalse.
Response data:
- The
totalCountproperty is not populated in the response object by default. You can use thehasMoreproperty to check if there are more records available or if you need this value you can set thecalculateTotalCountrequest parameter totrue. But keep in mind that even if you request the calculation of the number of matching rows, the total count will never be more than 10000. If you have more records, please use filtering to get a smaller result set.
DeviceSession object:
- The
marketingNameandalternativeMarketingNamesproperties were renamed tofriendlyNameandalternativeFriendlyNamesrespectively in the response object. However, there is a newmarketingNameproperty, which is different from thefriendlyName. ThemarketingNameproperty contains the original marketing name of the device, without color or storage size information. At the moment this value is only available for Apple devices. - The
imei1property was renamed toimei. - The
imei3property was removed. - The
batteryHealthproperty was removed. - The
historicalStickyDataproperty was renamed tostickyData. - The
blacklistChecksproperty was removed. Instead of this, there is a newblacklistCheckResultproperty which contains the result of the last IMEI blacklist check at the time of the session. - The
reportsproperty was renamed todiagnosticsReports. - Multiple other new properties were added to the DeviceSession response object:
brandAccounts,simLock,soc,brand,ecid,internalStorage,iosSalesRegion,MDMState,batteryCycles,batteryDesignCapacity,fullChargeCapacity,rooted,secureLocked,memoryCard,iosRegulatoryModel,deviceColor,iosJailbreak,encryptionState,encryptionType,deviceExpense,gradingPhotos,simLockCheckResult.
Device object:
- The
idproperty was removed. Instead you can use them360idproperty to identify the device. - Multiple new properties were added to the Device response object:
actualGradingResult,actualGradingPhotos,actualDeviceExpense.
StickyData object:
- The
customerInfoproperty was removed. - Instead of the
customerInfothere is a newclientproperty. Theclientobject is either a Company or a Person object, depending on the type of the client. You can use thetypeproperty to determine the type of the client.
DiagnosticsResult object:
- The
clientTimeproperty was renamed tofinishTime. - All TestResult type properties were removed. Instead, there is a new
testsproperty which contains the test results in an array. - The individual tests are now DiagnosticsResultTest objects, instead of TestResult objects.
DiagnosticsResultTest object:
- This object corresponds to the former TestResult objects, but there are some differences.
- The new
testIdproperty now holds the ID of the test, instead of the former approach where the test ID was the key of the object. - The new
resultproperty is similar to the formerstatusproperty, but the possible values are different. The new possible valuesNA,Passed,Failed, andSkipped. - The new
detailsproperty is a list of DiagnosticsResultDetail objects, which hold details of test results.
DiagnosticsResultDetail object:
-
The purpose of this new object is similar to the
detailsproperty of the TestResult object of the v1 API, but its structure is different. It holds a single, additional detail of a diagnostics test. For example the battery test can provide details about the original capacity of the battery, temperature, voltage, etc. In the v1 API these were all different keys of thedetailsobject, now these are provided as individual details objects. For example:v1 API:
"batteryHealth": { "status": "passed", "details": { "cycles": "254", "designCapacityCapacity": "4395 mAh" } }v2 API:
{ "testId": "Battery", "result": "Passed", "details": [ { "context": "BatteryOriginalCapacity", "title": "Original Capacity", "result": "NA" "value": "4395 mAh" }, { "context": "BatteryCycles", "title": "Battery Cycles", "result": "NA" "value": "254" } ] } -
The following table provides a mapping between the old details keys and the new context IDs:
| Test | Old key | New context ID |
|---|---|---|
| Battery | temperature | BatteryTemperature |
| Battery | voltage | BatteryVoltage |
| Battery | technology | BatteryTechnology |
| Battery | designCapacity | BatteryOriginalCapacity |
| Battery | fullCapacity | BatteryCurrentCapacity |
| Battery | cycles | BatteryCycles |
| Battery | batteryDrainPercent | BatteryDrainPercentLost |
| Storage | total | StorageTotal |
| Storage | free | StorageFree |
| Storage | used | StorageUsed |
OemCheckResult object:
- This object has a new
isAuthenticflag that tells whether the device is authentic or not. - The check results of the individual device parts are now provided as a list of OemCheckResultPart objects in the
result. - You can use the
idproperty of the OemCheckResultPart object to identify the part, instead of the old method of using the key of the object. - Also, a
nameproperty was added to the object to provide a human-readable name of the part.
GradingResult object:
- The
clientTimeproperty was renamed tomodificationTimestamp. - The
caseproperty was renamed tophoneCase. - The
coverproperty was renamed toback.
BlacklistCheckResult object:
- This object replaces the BlacklistCheck object of the v1 API. It contains the result of the last IMEI blacklist check at the time of the session. Only finished blacklist checks are included in the response. Because of this, the
statusproperty was removed.