When working with Jamf Pro, one way to save yourself a lot of clicking in the admin console is to use one of the two current Jamf Pro APIs. Both APIs are REST APIs, which means they can perform requests and receive responses via HTTP protocols like GET, PUT, POST and DELETE. That means that the curl tool can be used to send commands to and receive information from a Jamf Pro server.
The two APIs are as follows:
- Classic API
- Jamf Pro API (formerly known as the Universal API)
Classic API
This API is the original one which Jamf Pro started with and it is slated for eventual retirement. This API is designed to work with XML and JSON for both input and output.
The base URL for the Classic API is located at /JSSResource on your Jamf Pro server. If your Jamf Pro server is https://server.name.here:8443, that means that the API base URL is as follows:
https://server.name.here:8443/JSSResource
To help you become familiar with the API, Jamf includes documentation and “Try it out” functionality at the following URL on your Jamf Pro server:
https://server.name.here:8443/api
The Classic API is designed to work with usernames and passwords for authentication, with the username and password being passed as part of the curl command.
Examples: https://developer.jamf.com/apis/classic-api/index
Jamf Pro API
This API is in beta and is designed to be an eventual replacement for the Classic API. This API is designed to work with JSON for both input and output.
The base URL for the Jamf Pro API is located at /JSSResource on your Jamf Pro server. If your Jamf Pro server is https://server.name.here:8443, that means that the API base URL is as follows:
https://server.name.here:8443/uapi
To help you become familiar with the API, Jamf includes documentation and “Try it out” functionality at the following URL on your Jamf Pro server:
https://server.name.here:8443/uapi/docs
The Jamf Pro API is designed to work with token-based authentication, with a Jamf Pro username and password used to initially generate the necessary token. These tokens are time-limited and expire after 30 minutes. However, you can generate a new token for API authentication using the existing token’s credentials. The new token generation process does the following:
- Creates a new token with the same access rights as the existing token.
- Invalidates the existing token.
Jamf Pro API examples: https://developer.jamf.com/apis/jamf-pro-api/index
For more details, please see below the jump.
Of the two, the Classic API is the one currently most used by Jamf Pro admins and the one I’ll be focusing on how to use it, using XML for input and output. The reasons that the Classic API is most used at this time are the following:
- The Classic API has been around the longest, so more Jamf Pro admins are familiar with it.
- Both XML and JSON input and output are supported:
- There are various tools installed as part of macOS which allow XML parsing and manipulation when using Bash shell scripting.
- There are not tools installed as part of macOS which allow JSON parsing and manipulation when using Bash shell scripting.
There are tools available for macOS which allow easy JSON parsing and manipulation, with jq being an excellent example. However, they are not installed as part of macOS Catalina or earlier which means that its up to the Mac admin to make sure the relevant JSON parsing tools are installed and up to date on the Mac admin’s managed Macs.
In contrast, a number of XML parsing tools (like xmllint and xpath) are installed as part of macOS Catalina and earlier, which means that the Mac admin can currently rely on them being available if the Mac admin needs to run API-using scripts on managed Macs.
When using the Classic API, there are four commands available:
- DELETE
- GET
- PUT
- POST
DELETE = Deletes data from Jamf Pro
GET = Retrieves data from Jamf Pro
PUT = Updates data on Jamf Pro
POST = Creates new data on Jamf Pro
When sending one of these commands to Jamf Pro, you must include the following:
- Tool being used – In this case, we’re using curl
- Authentication – In this case, we’re using the username and password of a Jamf Pro user with the correct privileges to run the API command.
- URL – We’re using the API base URL followed by the specific API endpoint and data identifier
- -X or –request – We’re using the curl option for sending a request because we’re sending in a request for Jamf Pro to do something.
- Command being sent – This will be DELETE, GET, PUT or POST.
For all commands except DELETE, we also need to specify a header as this will specify for Jamf Pro if we’re using XML or JSON. Without this header specification, you should get XML but Jamf Pro may send back JSON instead. By specifying XML or JSON using the header, we avoid this issue.
The reason why DELETE is an exception is that we’re not sending or receiving any XML or JSON data. Instead, the Jamf Pro server receives and executes the command to delete the specified data.
Headers:
GET
The header should look like this for XML output:
-H "accept: application/xml"
The header should look like this for JSON output:
-H "accept: application/json"
PUT
The header should look like this for XML output:
-H "content-type: application/xml"
The header should look like this for JSON output:
-H "content-type: application/json"
POST
The header should look like this for XML output:
-H "content-type: application/xml"
The header should look like this for JSON output:
-H "content-type: application/json"
If you look closely, GET is using different headers than PUT and POST are:
GET
-H "accept: application/xml"
PUT / POST
-H "content-type: application/xml"
Why? It has to do with which way that data is expected to flow. With GET, you’re downloading data from the server and with PUT / POST, you’re uploading to the server. So with a GET command, setting accept: as part of the header lets the Jamf Pro server know how you’re planning to receive the data. For PUT / POST, setting content-type: as part of the header lets the Jamf Pro server know what to expect what kind of content it should be expecting for the data being uploaded to it.
Using GET
Let’s take a look at some GET examples, using Jamf’s tryitout.jamfcloud.com server. This server doesn’t require authentication, but I’m going to add the curl options for sending username and password as part of the command so that the command matches what a normal Jamf Pro server should be sent.
curl -su username:password "https://tryitout.jamfcloud.com/JSSResource/accounts" -H "accept: application/xml" -X GET
When I run that, I get the following XML output:
That could use some improvement for readability, so next let’s pipe it through xmllint’s formatting option to make it look nicer.
curl -su username:password "https://tryitout.jamfcloud.com/JSSResource/accounts" -H "accept: application/xml" -X GET | xmllint --format -
Note: When using xmllint’s formatting option, you need to specify the file being formatted: xmllint –format /path/to/filename.xml. In order to have it format standard input, like we’re trying to do in this example by piping the output to xmllint, the filename used is a single dash ( – ).
When I run that, I get the following output:
That output lists all accounts and gives me two pieces of information about each account:
- ID
- Name
Normally, the API only gives me the option about pulling additional data about something specific by using its ID number. However, for accounts, I’m also given the option of doing a lookup by account name.
- By ID: https://tryitout.jamfcloud.com/JSSResource/accounts/userid/id_number_goes_here
- By Name: https://tryitout.jamfcloud.com/JSSResource/accounts/username/username_goes_here
From there, I can pull out information about the following account using either the username or ID:
Username: jnuc
ID: 3
By ID: https://tryitout.jamfcloud.com/JSSResource/accounts/userid/3
curl -su username:password "https://tryitout.jamfcloud.com/JSSResource/accounts/userid/3" -H "accept: application/xml" -X GET | xmllint --format -
By Name: https://tryitout.jamfcloud.com/JSSResource/accounts/username/jnuc
curl -su username:password "https://tryitout.jamfcloud.com/JSSResource/accounts/username/jnuc" -H "accept: application/xml" -X GET | xmllint --format -
Since both API requests are ultimately referring to the same data, you should get identical output:
Using POST
When you want to upload all-new data to the Jamf Pro server via the API, you would use the POST command. This command requires that the data be sent along with the API command, so you would need to have either the XML written out as part of the API command or in a file. One important thing to know when using POST is that the ID used is always going to be the number 0. Jamf Pro will interpret an ID of zero as meaning that Jamf Pro should assign the next available ID number to the uploaded data.
For example, if you want to create a new department named Art on your Jamf Pro server, you could use a command like the one shown below:
In this example, the XML being used is pretty simple so we’re flattening out the necessary XML into one line and including it in the command. We’re also using curl’s -d option, which tells curl that it will be transmitting data along with the rest of the command.
If the data being sent along is a little unwieldy to include with the command, curl has a -T option for uploading a file. For example, if you wanted to create a smart group, you could write out the necessary XML into a file like the one shown below:
Once you have the file ready, you could use a command like the one shown below to create the smart group:
curl -su username:password "https://server.name.here/JSSResource/computergroups/id/0" -H "content-type: application/xml" -X POST -T /path/to/filename.xml
Using PUT
When you want to update existing data to the Jamf Pro server via the API, you would use the PUT command. When using this, you would be targeting some existing data and changing one of the data’s existing attributes. A good example would be if you want to change the status of a policy from enabled to disabled. To do this with a policy which has an ID number of 27, you could use a command like the one shown below:
Similar to the earlier POST example which uses a XML file, you can also used the -T option with PUT to upload a file. For example, if you wanted to update the distribution point associated with a network segment which has an ID number of 561, you could add the necessary data into an XML file like the one shown below:
Once you have the file ready, you could use a command like the one shown below to update the network segment:
curl -su username:password "https://server.name.here/JSSResource/networksegments/id/561" -H "content-type: application/xml" -X PUT -T /path/to/filename.xml
Using DELETE
When you want to delete data from the Jamf Pro server via the API, you would use the DELETE command. All you generally need with the DELETE command is the identifier for the data you want to remove, so the commands are simpler. No header info or specifying if you want to use XML or JSON is required.
For example, if you wanted to delete an existing computer inventory record which has the ID number of 1024, you can use a command like the one shown below to do so:
curl -su username:password "https://server.name.here/JSSResource/computers/id/1024" -X DELETE
Similarly, if you wanted to delete an existing network segment which has the ID number of 22, you could use a command like the one shown below:
curl -su username:password "https://server.name.here/JSSResource/networksegments/id/22" -X DELETE
Moving on to more advanced usage
You can use the Jamf Pro Classic API with scripting and other automation tools to accomplish some truly amazing administrative feats with Jamf Pro and the Jamf Pro API beta looks to build on that strong foundation. While the information in this post won’t solve all of your API-related issues, it does hopefully provide enough foundational support to get you started with using the Jamf Pro Classic API. Good luck!