API access to Zscaler Client Connector Portal

I have got access to the ZCC Public API and have been sent the (beta) document detailing the API use. But I’m struggling with using the forceRemoveDevices method.
Specifically the syntax of the “deviceRemoveContract” attribute.

Anyone used this and can provide advice? I have a support call logged, but nothing useful from there just yet.

Thanks in advance
N.

Hey @BreezeNeil How did you get access to the beta documentation? I have opened two separate tickets with Zscaler but they just keep sending me documentation for either ZIA and ZPA’s APIs, or just sending me to the one ZCC Public API help page which is just to retrieve a key, but there is no API reference documentation for it on the public help site so I don’t know what endpoints are available, etc.

The document is called 545938_Client+Connector+Public+API+Early+Access.docx.
You need a Partner logon to get it from the ZS jira site (which I have, but it didn’t work). I got support to send me the document directly in the end. It’s got the endpoints you need, but the doc is over a year old and lots of it is incorrect. I have not managed to get an updated version from them (despite asking many times) but have figured out how to do most of what I need (the API is still quite limited!).
I would send the doc to you, but not sure if I’d be breaking ZS rules as I don’t think it’s a public-facing document. Best to ask support specifically for this doc.
I had the same problem- lots of standard responses about the ZIA API before they figured out what I needed.

Hello Neil,
You need to make sure to choose “Write” role when you create the API key in the Client Connector portal.

@BreezeNeil One of my Zscaler technical reps got me a document that has a similar name and seems to mostly be correct (the swagger json in it was updated in novemeber of 2021). But yeah, it is missing some stuff. I can get a JWT token easily with the public API keys, BUT, the documentation doesn’t seem to cover the required headers/params for using the token and the normal stuff like an Authorization/ Bearer authentication method like most APIs use doesn’t seem to work. How are you managing to actually auth with your token when hitting an endpoint like the get devices one? If you don’t mind :slight_smile:

Hi Chris
Here’s an anonymised export from my Postman environment that works for me.
You need to use your API key and secret to run the Auth Method. That will give you an AuthToken that you insert into the header of all following calls.
My first call does a GetDevices (returns all connected devices)
The second does a GetDevices but filtered by a username, to return just devices belonging to a specific user.
From either of these, you can get the UDID for a specific device
Then you can run “GetOTP” or “Remove Device” calls to either get the One Time Password for a specific UDID, o to ForceRemove it (forcing the user to re-authenticate)
I thought I could add an attachment here, but it looks like I can’t, so the code is below.
Good luck!

{
“info”: {
“_postman_id”: “3d5a2797-6bb4-4ea9-bb91-6406d99557cc”,
“name”: “ZCC RUN”,
“schema”: “https://schema.getpostman.com/json/collection/v2.1.0/collection.json”,
“_exporter_id”: “15198267”
},
“item”: [
{
“name”: “Authorization”,
“event”: [
{
“listen”: “prerequest”,
“script”: {
“exec”: [
“”
],
“type”: “text/javascript”
}
}
],
“request”: {
“method”: “POST”,
“header”: ,
“body”: {
“mode”: “raw”,
“raw”: “{\r\n "apiKey": "APIKEY",\r\n "secretKey": "SECREYKEY"\r\n}”,
“options”: {
“raw”: {
“language”: “json”
}
}
},
“url”: {
“raw”: “https://api-mobile.zscalertwo.net/papi/auth/v1/login”,
“protocol”: “https”,
“host”: [
“api-mobile”,
“zscalertwo”,
“net”
],
“path”: [
“papi”,
“auth”,
“v1”,
“login”
]
}
},
“response”:
},
{
“name”: “GetDevice for User”,
“event”: [
{
“listen”: “test”,
“script”: {
“exec”: [
“”
],
“type”: “text/javascript”
}
}
],
“protocolProfileBehavior”: {
“disableBodyPruning”: true
},
“request”: {
“method”: “GET”,
“header”: [
{
“key”: “auth-token”,
“value”: “AUTHTOKEN”,
“type”: “text”
}
],
“body”: {
“mode”: “raw”,
“raw”: “”,
“options”: {
“raw”: {
“language”: “json”
}
}
},
“url”: {
“raw”: “https://api-mobile.zscalertwo.net/papi/public/v1/getDevices?username=user@company.com”,
“protocol”: “https”,
“host”: [
“api-mobile”,
“zscalertwo”,
“net”
],
“path”: [
“papi”,
“public”,
“v1”,
“getDevices”
],
“query”: [
{
“key”: “username”,
“value”: “user@company.com
}
]
}
},
“response”:
},
{
“name”: “Get All Devices”,
“event”: [
{
“listen”: “test”,
“script”: {
“exec”: [
“”
],
“type”: “text/javascript”
}
}
],
“protocolProfileBehavior”: {
“disableBodyPruning”: true
},
“request”: {
“method”: “GET”,
“header”: [
{
“key”: “auth-token”,
“value”: “AUTHTOKEN”,
“type”: “text”
}
],
“body”: {
“mode”: “raw”,
“raw”: “”,
“options”: {
“raw”: {
“language”: “json”
}
}
},
“url”: {
“raw”: “https://api-mobile.zscalertwo.net/papi/public/v1/getDevices”,
“protocol”: “https”,
“host”: [
“api-mobile”,
“zscalertwo”,
“net”
],
“path”: [
“papi”,
“public”,
“v1”,
“getDevices”
]
}
},
“response”:
},
{
“name”: “GetOTP”,
“event”: [
{
“listen”: “test”,
“script”: {
“exec”: [
“”
],
“type”: “text/javascript”
}
},
{
“listen”: “prerequest”,
“script”: {
“exec”: [
“”
],
“type”: “text/javascript”
}
}
],
“protocolProfileBehavior”: {
“disableBodyPruning”: true
},
“request”: {
“method”: “GET”,
“header”: [
{
“key”: “auth-token”,
“value”: “AUTHTOKEN”,
“type”: “text”
}
],
“body”: {
“mode”: “raw”,
“raw”: “”,
“options”: {
“raw”: {
“language”: “json”
}
}
},
“url”: {
“raw”: “https://api-mobile.zscalertwo.net/papi/public/v1/getOtp?udid=UDID”,
“protocol”: “https”,
“host”: [
“api-mobile”,
“zscalertwo”,
“net”
],
“path”: [
“papi”,
“public”,
“v1”,
“getOtp”
],
“query”: [
{
“key”: “udid”,
“value”: “UDID”
}
]
}
},
“response”:
},
{
“name”: “ForceRemoveDevices”,
“request”: {
“method”: “POST”,
“header”: [
{
“key”: “auth-token”,
“value”: “AUTHTOKEN”,
“type”: “text”
}
],
“body”: {
“mode”: “raw”,
“raw”: “{\r\n "udids": [ "INSERTUDIDHERE" ]\r\n}”,
“options”: {
“raw”: {
“language”: “json”
}
}
},
“url”: {
“raw”: “https://api-mobile.zscalertwo.net/papi/public/v1/forceRemoveDevices”,
“protocol”: “https”,
“host”: [
“api-mobile”,
“zscalertwo”,
“net”
],
“path”: [
“papi”,
“public”,
“v1”,
“forceRemoveDevices”
]
}
},
“response”:
}
],
“event”: [
{
“listen”: “prerequest”,
“script”: {
“type”: “text/javascript”,
“exec”: [
“”,
“”
]
}
},
{
“listen”: “test”,
“script”: {
“type”: “text/javascript”,
“exec”: [
“”
]
}
}
]
}

Hey @BreezeNeil Thanks for the response :slight_smile: I had everything working with retrieving tokens its just that in the doc I had they don’t tell you that the header key for the token for subsequent API calls should be auth-token which is what I needed, so again thank you for that info. The ZPA API which I’ve used extensively uses the more standard “Authorization”: “Bearer ” header. (Also I don’t get what this embedding of your customer ID thing is in the body? Why?)

I am really glad to see such consistency in the design and implementation of their APIs. It really seems like they have a unified engineering team that talks to each other to make things easier for customers /s

Just a touch of sarcasm there @badlittlerobots !!
Yeah, the differences between the ZIA, ZPA and ZCC portals always surprises me. I get that they came from different places, but they don’t seem to have done anything to unify the experience in the many years I’ve been using the services.