MSP
MSP (Managed Service Provider) contains multiple Organizations.
MSP
Create MSP
POST /api/v1/msps
Request
{
"name": "MSP"
}
Update an MSP
PUT /api/v1/msps/:msp_id
Request
{
"name": "MSP"
}
For advanced tier (uMSPs), custom url is also available
{
"name": "MSP",
"url": "https://.."
}
Get MSP Detail
GET /api/v1/msps/:msp_id
Response
{
"id": "9520c63a-f7b3-670c-0944-727774d5a722",
"name": "MSP",
"tier": "base"
}
{
"id": "9520c63a-f7b3-670c-0944-727774d5a722",
"name": "MSP",
"tier": "advanced",
"url": "https://..",
"logo_url": "https://...."
}
Upload Logo (only for advanced MSP tier)
POST /api/v1/msps/:msp_id/logo
Delete Logo
DELETE /api/v1/msps/:msp_id/logo
Delete MSP
Deleting MSP removes the MSP and OrgGroup under the MSP as well as all privileges associated with them.
It does not remove any Org or Admins
DELETE /api/v1/msps/:msp_id
Create an Org under MSP
POST /api/v1/msps/:msp_id/orgs
Request
{
"name": "Motel 6",
"orggroup_ids": [ "507f1bab-13ba-73e2-f291-2bcb8d1362b0" ]
}
Assign Org to MSP
PUT /api/v1/msps/:msp_id/orgs
Request
{
"op": "assign"
"org_ids": [
"2818e386-8dec-2562-9ede-5b8a0fbbdc71"
]
}
Parameters
Name |
Type |
Description |
op |
string |
operation (assign/unassign) |
org_ids |
list |
list of org_id |
Response
Status: 200 OK
Remove Org from MSP
PUT /api/v1/msps/:msp_id/orgs
Request
{
"op": "unassign"
"org_ids": [
"2818e386-8dec-2562-9ede-5b8a0fbbdc71"
]
}
Parameters
Name |
Type |
Description |
op |
string |
operation (assign/unassign) |
org_ids |
list |
list of org_id |
Response
Status: 200 OK
Get Orgs in MSP
GET /api/v1/msps/:msp_id/orgs
Org Group
Org Group Schema
{
"name": "West"
}
Get Org Groups in a MSP
GET /api/v1/msps/:msp_id/orggroups
Create Org Group
POST /api/v1/msps/:msp_id/orggroups
Get an Org Group in MSP
GET /api/v1/msps/:msp_id/orggroups/:orggroup_id
Update an Org Group in MSP
PUT /api/v1/msps/:msp_id/orggroups/:orggroup_id
Delete an Org Group
DELETE /api/v1/msps/:msp_id/orggroups/:orggroup_id
Search Org in MSP
GET /api/v1/msps/:msp_id/orgs/search?sub_insufficient=true
Supported Filters
Name |
Type |
Description |
name |
string |
org name |
org_id |
string |
org id |
trial_enabled |
boolean |
if this org is under trial period |
usage_types |
list |
a list of types that enabled by usage |
sub_insufficient |
boolean |
if this org has sufficient subscription |
Response
{
"results": [
{
"sub_ana_required": 9,
"sub_ast_required": 3,
"sub_ex12_required": 1,
"sub_eng_required": 3,
"sub_man_required": 9,
"sub_ast_entitled": 5,
"sub_vna_entitled": 1,
"num_unassigned_aps": 1,
"num_sites": 5,
"num_aps": 9,
"timestamp": 1614322563.513937,
"num_switches": 1,
"org_id": "bb1a8bf6-4064-4bbd-83dc-8053a663cf65",
"name": "Test Org",
"msp_id": "d287e62f-9689-4c05-85d8-f2b9ba0a531f",
"sub_insufficient": true,
"trial_enabled" : false,
"usage_types" : [
"sub_eng"
]
},
{
"sub_ana_required": 1,
"sub_man_required": 1,
"sub_ana_entitled": 1,
"sub_man_entitled": 1,
"num_sites": 1,
"num_aps": 1,
"timestamp": 1614309876.500955,
"org_id": "0fb81690-7b74-4a56-b984-9596d1d1534f",
"name": "Rogue Test1",
"msp_id": "d287e62f-9689-4c05-85d8-f2b9ba0a531f",
"sub_insufficient": false
}
],
"start": 1613778578.4365668,
"end": 1614383378.4365287,
"limit": 10,
"total": 2
}
Search for Org in MSP
GET /api/v1/msps/:msp_id/search?type=orgs&q=stan&limit=10&page=2
Request
Name |
Type |
Description |
type |
string |
orgs |
q |
string |
search string |
Response
{
"page": 1,
"limit": 10,
"total": 60,
"results": [
{
"type": "orgs",
"text": "Stanford",
"id": "37cff3c6-a361-deea-2c79-114ebb76c1f8"
},
...
]
}
License
Get License
GET /api/v1/msps/:msp_id/licenses
Response
{
"licenses": [
{
"order_id": "00000464",
"subscription_id": "SUB-0000144",
"type": "SUB-MAN",
"start_time": 1504828800,
"end_time": 1520380800,
"quantity": 180
},
{
"order_id": "00000464",
"subscription_id": "SUB-0000145",
"type": "SUB-MAN",
"start_time": 1504828800,
"end_time": 1520380800,
"quantity": 30
}
{
"order_id": "00000464",
"subscription_id": "SUB-0000146",
"type": "SUB-LOC",
"start_time": 1504828800,
"end_time": 1520380800,
"quantity": 120
}
],
"amendments": [
{
"id": "2b9116ab-cd1e-e897-6e08-31fccd88e792",
"subscription_id": "SUB-0000144",
"type": "SUB-MAN",
"start_time": 1504828800,
"end_time": 1520380800,
"quantity": -30
},
{
"id": "4e974f27-fcbc-03cb-caa4-688e20aa539f",
"subscription_id": "SUB-0000146",
"type": "SUB-LOC",
"start_time": 1504828800,
"end_time": 1520380800,
"quantity": 75
},
],
"entitled": {
"SUB-MAN": 180,
"SUB-LOC": 195
}
}
Definitions
Name |
Type |
Description |
licenses |
list |
list of licenses |
type |
string |
subscription type, SUB-MAN / SUB-LOC / SUB-AST / SUB-VNA / SUB-DATA |
start_time |
long |
start date of the license term |
end_time |
long |
end date of the license term |
quantity |
int |
number of devices entitled for this license |
entitled |
object |
currently entitled for each license type |
Claim an Order by Activation Code
POST /api/v1/msps/:msp_id/claim
Example
{
"code": "ZHT3K-H36DT-MG85D-M61AC"
}
Parameters
Name |
Type |
Description |
code |
string |
activation code |
Response of the license(s) that are successfully claimed and applied
{
"license_added": [
{
"type": "SUB-MAN",
"start": 1504828800,
"end": 1520380800,
"quantity": 180
},
{
"type": "SUB-LOC",
"start": 1504828800,
"end": 1520380800,
"quantity": 120
}
],
"license_duplicated": [
{
"type": "SUB-MAN",
"start": 1504828800,
"end": 1520380800,
"quantity": 180
}
],
"license_error": [
{
"order": "00000464",
"reason": ""
}
]
}
Response when the key is invalid (or already used)
Status: 400 Bad Request
Move License from MSP to another Org under the MSP
PUT /api/v1/msps/:msp_id/licenses
Request
{
"op": "amend",
"subscription_id": "SUB-0000144",
"dst_org_id": "3eff35f7-c218-894e-bca2-24e5325601cc",
"quantity": 10
}
Parameters
Name |
Type |
Description |
op |
string |
operation (amend/unamend/delete/annotate) |
subscription_id |
string |
license id |
dst_org_id |
string |
destination org id |
quantity |
int |
quantity |
Undo the License Move
PUT /api/v1/msps/:msp_id/licenses
Request
{
"op": "unamend",
"amendment_id": "2b9116ab-cd1e-e897-6e08-31fccd88e792",
}
Delete License
PUT /api/v1/msps/:msp_id/licenses
Request
{
"op": "delete",
"subscription_id": "SUB-0000144"
}
Annotate a License
PUT /api/v1/msps/:msp_id/licenses
Request
{
"op": "annotate",
"subscription_id": "SUB-000144",
"notes": "customer notes"
}
Audit Logs
Audit logs records all administrative activities in a MSP
Get a list of change logs for the current MSP
GET /api/v1/msps/:msp_id/logs?start=1431298000&end=1431384000&limit=100
Supported Filters
Name |
Type |
Description |
org_id |
string |
org id |
admin_name |
string |
admin name or email |
message |
string |
message |
Response
The logs are always sorted by time in descending order
{
"start": 1431298000,
"end": 1431384000,
"limit": 100,
"total": 135,
"results": [
{
"timestamp": 1431382121,
"org_id": "2818e386-8dec-2562-9ede-5b8a0fbbdc71",
"msp_id": "d287e62f-9689-4c05-85d8-f2b9ba0a531f",
"admin_id": "72bfa2bd-e58a-4670-9d20-a1468f7a6f58",
"admin_name": "test@mistsys.com",
"message": "TEST AUDIT",
"id": "c6f9347b-b0a4-4a23-b927-fa9249f2ffb2"
}
]
}
Name |
Type |
Description |
timestamp |
long |
start time, in epoch |
org_id |
string |
org id |
msp_id |
string |
msp id |
admin_id |
string |
admin id |
admin_name |
string |
name of the admin that performs the action |
message |
string |
log message |
before |
object |
field values prior to the change |
after |
object |
field values after the change |
Count by Distinct Attributes of Audit Logs
GET /api/v1/msps/:msp_id/logs/count?distinct=admin_name
Request
Name |
Type |
Description |
distinct |
string |
admin_id / admin_name / message / org_id, default is admin_name |
Response
{
"start": 1511967600,
"end": 1513177200,
"limit": 10,
"distinct": "admin_name",
"total": 2,
"results": [
{
"admin_name": "John Smith john.smith@corp.com",
"count": 61
},
{
"admin_name": "Eric Sky eric@corp.com",
"count": 44
}
]
}
MSP Insights
Get Insight Metrics
See GET AVAILABLE_INSIGHT METRICS for metrics description of MSP Scope
GET /api/v1/msps/:msp_id/insights/:metric
Response
{
"start": 1428939600,
"end": 1428954000,
"interval": 3600,
// data
"results": [
{
// results depends on :metric
},
...
],
}
MSP Admins
Get MSP Admins
Get a list of people who can manage the MSP/Org(s) under the MSP
GET /api/v1/msps/:msp_id/admins
Response
[
{
"admin_id": "456b7016-a916-a4b1-78dd-72b947c152b7",
"first_name": "Joe",
"last_name": "Smith",
"two_factor_verified": true,
"privileges": [
{ "scope":"msp", "role": "admin" },
{ "scope":"org", "org_id": "2818e386-8dec-2562-9ede-5b8a0fbbdc71", "role": "admin" },
{ "scope":"orggroup", "orggroup_id": "507f1bab-13ba-73e2-f291-2bcb8d1362b0", "role": "read" }
]
}
]
Response Definition
Name |
Type |
Description |
admin_id |
string |
admin id |
first_name |
string |
first name |
last_name |
string |
last name |
two_factor_verified |
boolean |
two factor status |
privileges |
list |
list of privileges the admin has on the MSP / Orgs / OrgGroups |
scope |
string |
msp / org / orggroup |
role |
string |
admin / write / read / helpdesk |
Update MSP Admins
Update admin privileges under the Org
PUT /api/v1/msps/:msp_id/admins/:admin_id
Request
{
"privileges": [
{ "scope":"msp", "role": "admin" },
{ "scope":"org", "org_id": "2818e386-8dec-2562-9ede-5b8a0fbbdc71", "role": "admin" },
{ "scope":"orggroup", "orggroup_id": "507f1bab-13ba-73e2-f291-2bcb8d1362b0", "role": "read" }
]
}
Revoke Admin
This removes all privileges this admin has against the MSP. This goes deep all the way to the sites
DELETE /api/v1/msps/:msp_id/admins/:admin_id
Invite MSP Admin
A MSP admin can invite other admin to manage (admin or read) the MSP and/or Org(s) under the MSP.
POST /api/v1/msps/:msp_id/invites
Request
{
"email": "joe@abc.com",
"name": "Richard",
"hours": 24,
"privileges": {
{ "scope":"msp", "role": "admin" },
{ "scope":"org", "org_id": "2818e386-8dec-2562-9ede-5b8a0fbbdc71", "role": "admin" },
{ "scope":"orggroup", "orggroup_id": "507f1bab-13ba-73e2-f291-2bcb8d1362b0", "role": "read" }
}
}
Parameters
Name |
Type |
Description |
email |
string |
email - admin_id is not exposed |
name |
string |
name, used in the invitation text |
privileges |
list |
list of privileges the admin has on the MSP / Orgs / OrgGroups |
scope |
string |
msp / org / orggroup |
role |
string |
admin / write / read |
hours |
int |
optional, how long the invite should be valid, default is 1 day, maximum is 1 week. |
Response
Status: 200 OK
An email will also be sent to the user with a link to https://manage.mist.com/verify/invite?token=:token
Verify Invitation
POST /api/v1/invite/verify/:token
Response if successful
Status: 200 OK
NOTE: another call to GET /api/v1/self
is required to see the new set of privileges
Un-invite Admin
DELETE /api/v1/msps/:msp_id/invites/:invite_id
Update the Invite
PUT /api/v1/msps/:msp_id/invites/:invite_id
Request
{
"hours": 24,
"privileges": {
{ "scope":"org", "org_id": "2818e386-8dec-2562-9ede-5b8a0fbbdc71", "role": "read" }
}
}
Parameters
Name |
Type |
Description |
hours |
int |
optional, how long the invite should be valid, default is 1 day, maximum is 1 week. |
privileges |
list |
list of privileges the admin has on the MSP / Orgs / OrgGroups |
scope |
string |
msp / org / orggroup |
SSO / SAML
Create SSO
POST /api/v1/msps/:msp_id/ssos
Request
{
"name": "onelogin",
"issuer": "https://app.onelogin.com/saml/metadata/138130"
"idp_cert": "-----BEGIN CERTIFICATE-----\nMIIFZjCCA06gAwIBAgIIP61/1qm/uDowDQYJKoZIhvcNAQELBQE\n-----END CERTIFICATE-----",
"idp_sign_algo": "sha256",
"idp_sso_url": "https://yourorg.onelogin.com/trust/saml2/http-post/sso/138130",
"nameid_format": "email",
"ignore_unmatched_roles": false,
"default_role": null,
// some IdP support a custom logout URL that is different from SP-initiated SLO process
"custom_logout_url": "https://6.4.5.7/saml/idp/SingleLogoutService.php?param1=value1"
}
Definition
Name |
Type |
Description |
name |
string |
name |
issuer |
string |
IDP issuer URL |
idp_cert |
string |
IDP Cert (used to verify the signed response) |
idp_sso_url |
string |
IDP Single-Sign-On URL |
nameid_format |
string |
email (default) / unspecified |
ignore_unmatched_roles |
boolean |
ignore any unmatched roles provided in assertion. By default, an assertion is treated as invalid for any unmatched role |
default_role |
string |
default role to assign if there’s no match. By default, an assertion is treated as invalid when there’s no role matched |
role_attr_from |
string |
optional, name of the attribute in SAML Assertion to extract role from (defaults to Role ) |
role_attr_extraction |
string |
optional, user defined role parsing scheme. See Supported Role Parsing Schemes |
custom_logout_url |
string |
optional, a URL we will redirect the user after user logout from Mist (for some IdP which supports a custom logout URL that is different from SP-initiated SLO process) |
Supported Role Parsing Schemes
Name |
Scheme |
cn |
- The expected role attribute format in SAML Assertion is “CN=cn,OU=ou1,OU=ou2,…”
- CN (the key) is case insensitive and exactly 1 CN is expected (or the entire entry will be ignored)
E.g. if role attribute is “CN=cn,OU=ou1,OU=ou2” then parsed role value is “cn” |
GET /api/v1/msps/:msp_id/ssos
Response
[
{
"name": "onelogin",
"issuer": "https://app.onelogin.com/saml/metadata/138130"
"idp_cert": "-----BEGIN CERTIFICATE-----\nMIIFZjCCA06gAwIBAgIIP61/1qm/uDowDQYJKoZIhvcNAQELBQE\n-----END CERTIFICATE-----",
"idp_sign_algo": "sha256",
"idp_sso_url": "https://yourorg.onelogin.com/trust/saml2/http-post/sso/138130"
}
]
Update SSO
PUT /api/v1/msps/:msp_id/ssos/:sso_id
Delete SSO
DELETE /api/v1/msps/:msp_id/ssos/:sso_id
GET /api/v1/msps/:msp_id/ssos/:sso_id/metadata
Response
{
"entity_id": "https://api.mist.com/api/v1/saml/llDfa13f/login",
"acs_url": "https://api.mist.com/api/v1/saml/llDfa13f/login",
"logout_url": "https://api.mist.com/api/v1/saml/llDfa13f/logout",
"metadata_xml": "<?xml version="1.0" encoding="UTF-8"?><md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://api.mist.com/api/v1/saml/llDfa13f/login" validUntil="2027-10-12T21:59:01Z" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat><md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://api.mist.com/api/v1/saml/llDfa13f/login" index="0" isDefault="true"/></md:SPSSODescriptor></md:EntityDescriptor>"
}
GET /api/v1/msps/:msp_id/ssos/:sso_id/metadata.xml
Response
<?xml version="1.0" encoding="UTF-8"?><md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://api.mist.com/api/v1/saml/5hdF5g/login" validUntil="2027-10-12T21:59:01Z" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://api.mist.com/api/v1/saml/5hdF5g/logout" />
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://api.mist.com/api/v1/saml/5hdF5g/login" index="0" isDefault="true"/>
<md:AttributeConsumingService index="0">
<md:ServiceName xml:lang="en-US">Mist</md:ServiceName>
<md:RequestedAttribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" isRequired="true"/>
<md:RequestedAttribute Name="FirstName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" isRequired="false"/>
<md:RequestedAttribute Name="LastName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" isRequired="false"/>
</md:AttributeConsumingService>
</md:SPSSODescriptor>
</md:EntityDescriptor>
Get Latest SSO Failures
GET /api/v1/msps/:msp_id/ssos/:sso_id/failures
Response
{
"results": [
{
"timestamp": 1431382121,
"detail": "Role attribute missing",
"saml_assertion_xml": "<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:nam..."
}
]
}
Create SSO Role
POST /api/v1/msps/:msp_id/ssoroles
Request
{
"name": "NOC",
"privileges": [
{ "scope":"msp", "role": "admin" },
{ "scope":"org", "org_id": "2818e386-8dec-2562-9ede-5b8a0fbbdc71", "role": "admin" },
{ "scope":"orggroup", "orggroup_id": "507f1bab-13ba-73e2-f291-2bcb8d1362b0", "role": "read" }
]
}
Definition
Name |
Type |
Description |
name |
string |
name that would match the Role from SSO Login. unique per Org, maximum length is 32 |
privileges |
list |
list of privileges the admin has on the MSP / Orgs / OrgGroups |
scope |
string |
msp / org / orggroup |
Update SSO Role
PUT /api/v1/msps/:msp_id/ssoroles/:ssorole_id
Request
{
"name": "NOC",
"privileges": [
{ "scope":"msp", "role": "admin" },
{ "scope":"org", "org_id": "2818e386-8dec-2562-9ede-5b8a0fbbdc71", "role": "admin" },
{ "scope":"orggroup", "orggroup_id": "507f1bab-13ba-73e2-f291-2bcb8d1362b0", "role": "read" }
]
}
Get All SSO Roles
GET /api/v1/msps/:msp_id/ssoroles
Delete SSO Role
DELETE /api/v1/msps/:msp_id/ssoroles/:ssorole_id
Get Inventory by MAC
GET /api/v1/msps/:msp_id/inventory/:mac
Response
{
"serial": "FXLH2015150025",
"model": "AP200",
"type": "ap",
"mac": "5c5b35000018",
"org_id": "2818e386-8dec-2562-9ede-5b8a0fbbdc71",
"site_id": "4ac1dcf4-9d8b-7211-65c4-057819f0862b"
}
Tickets
Get Tickets of a MSP
GET /api/v1/msps/:msp_id/tickets?start=1546300800&end=-1d
Parameters
Name |
Type |
Description |
start |
string |
start datetime, can be epoch or relative time like -1d, -1w; -1d if not specified |
end |
string |
end datetime, can be epoch or relative time like -1d, -2h |
duration |
string |
duration like 7d, 2w |
NOTE: end & duration if both specified, will take precedence over start time
Response
[
{
"id": "00000000-0000-0000-0000-00000000000c",
"org_id": "9291176a-0000-000-0000-002e208b2d3f",
"created_at": 1453908369,
"updated_at": 1453908369,
"subject": "Please add me",
"status": "open",
"type": "question",
"requester": "John Smith"
}
]
Definitions
Name |
Type |
Description |
id |
string |
id of the ticket |
org_id |
string |
id of the Org |
created_at |
int |
when the ticket was created |
updated_at |
int |
when the ticket was last updated |
type |
string |
question (default) / bug / critical |
subject |
string |
subject |
status |
string |
open / pending / solved / closed |
requester |
string |
name of the requester |
Ticket Status
open
: ticket is open, Mist is working on it
pending
: ticket is open and Requester attention is needed (e.g. Mist is asking for some more information)
solved
: ticket is marked as solved / considered by Mist (requester can update it, causing it to re-open; or rate it)
closed
: ticket is archived and cannot be changed
Count tickets
GET /api/v1/msps/:msp_id/tickets/count?distinct=status
Definitions
Name |
Type |
Description |
distinct |
string |
status (default) / type / org_id |
Response
{
"limit": 1000,
"distinct": "status",
"total": 5,
"results": [
{
"status": "closed",
"count": 24
},
{
"status": "open",
"count": 12
},
{
"status": "solved",
"count": 15
},
{
"status": "pending",
"count": 10
},
{
"status": "hold",
"count": 3
}
]
}
Marvis Action
Count Marvis actions
GET /api/v1/msps/:msp_id/suggestion/count?distinct=org_id
Definitions
Name |
Type |
Description |
distinct |
string |
org_id (default) |
Response
{
"limit": 1000,
"distinct": "status",
"total": 3,
"results": [
{
"status": "002e176a-0000-000-1111-002e208b20e1",
"count": 24
},
{
"status": "2d3f176a-0000-000-2222-002e208f176a",
"count": 12
},
{
"status": "08b2176a-0000-000-3333-002e208b2d3f",
"count": 15
},
]
}