MDM Protocol Reference
MDM Protocol Reference
Protocol Reference
Developer
Contents
2
DeviceLock Command Locks the Device Immediately . . . . . . . . . . . . . . . . . . . . . . . . 43
RestartDevice Commands Restart Devices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
ShutDownDevice Commands Shut Down Devices . . . . . . . . . . . . . . . . . . . . . . . . . . 44
ClearPasscode Commands Clear the Passcode for a Device . . . . . . . . . . . . . . . . . . . . . 45
EraseDevice Commands Remotely Erase a Device . . . . . . . . . . . . . . . . . . . . . . . . . . 45
RequestMirroring and StopMirroring Control AirPlay Mirroring . . . . . . . . . . . . . . . . . . . . 45
Restrictions Commands Get a List of Installed Restrictions . . . . . . . . . . . . . . . . . . . . . . 47
Shared iPad User Commands Manage User Access . . . . . . . . . . . . . . . . . . . . . . . . . 49
MDM Lost Mode Helps Lock and Locate Lost Devices . . . . . . . . . . . . . . . . . . . . . . . . 50
Managed Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Installed Books . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Managed Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Managed App Configuration and Feedback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
AccountConfiguration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Firmware (EFI) Password Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
SetAutoAdminPassword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
DeviceConfigured . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Software Update . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Extension Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
Support for macOS Requests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Error Codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
MCProfileErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
MCPayloadErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
MCRestrictionsErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
MCInstallationErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
MCPasscodeErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
MCKeychainErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
MCEmailErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
MCWebClipErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
MCCertificateErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
MCDefaultsErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
MCAPNErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
MCMDMErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
MCWiFiErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
MCTunnelErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
MCVPNErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
MCSubCalErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
MCCalDAVErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
MCDAErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
MCLDAPErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
MCCardDAVErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
MCEASErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
MCSCEPErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
MCHTTPTransactionErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
MCOTAProfilesErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
MCProvisioningProfileErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
MCDeviceCapabilitiesErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
MCSettingsErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
3
MCChaperoneErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
MCStoreErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
MCGlobalHTTPProxyErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
MCSingleAppErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
MCSSOErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
MCFontErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
MCCellularErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
MCKeybagErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
MCDomainsErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
MCWebContentFilterErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
MCNetworkUsageRulesErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
MCOSXServerErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
MCHomeScreenLayoutErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
MCNotificationSettingsErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
MCEDUClassroomErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
MCSharedDeviceConfigurationErrorDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
4
retireVPPUserSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
manageVPPLicensesByAdamIdSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
associateVPPLicenseSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
associateVPPLicenseWithVPPUserSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
disassociateVPPLicenseSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
disassociateVPPLicenseFromVPPUserSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
editVPPUserSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
VPPClientConfigSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
VPPServiceConfigSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Request to VPPServiceConfigSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Request to getVPPLicensesSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Request to getVPPUsersSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
Request to getVPPUserSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
Request to registerVPPUserSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
Request to editVPPUserSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
Request to retireVPPUserSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
Request to getVPPAssetsSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
Request to VPPClientConfigSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
Request to manageVPPLicensesByAdamIdSrv . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
5
Responses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
Course Roster Sync Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
Error Responses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
6
About Mobile Device Management
Beta Software
This documentation contains preliminary information about an API or technology in development. This information is
subject to change, and software implemented according to this documentation should be tested with final operating
system software.
The Mobile Device Management (MDM) protocol provides a way for system administrators to send device
management commands to managed iOS devices running iOS 4 and later, macOS devices running macOS v10.7 and
later, and Apple TV devices running iOS 7 (Apple TV software 6.0) and later. Through the MDM service, an IT
administrator can inspect, install, or remove profiles; remove passcodes; and begin secure erase on a managed
device.
The MDM protocol is built on top of HTTP, transport layer security (TLS), and push notifications. The related MDM
check-in protocol provides a way to delegate the initial registration process to a separate server.
MDM uses the Apple Push Notification Service (APNS) to deliver a “wake up” message to a managed device. The
device then connects to a predetermined web service to retrieve commands and return results.
To provide MDM service, your IT department needs to deploy an HTTPS server to act as an MDM server, then
distribute profiles containing the MDM payload to your managed devices.
A managed device uses an identity to authenticate itself to the MDM server over TLS (SSL). This identity can be
included in the profile as a Certificate payload or it can be generated by enrolling the device with SCEP.
Note
For information about about SCEP, see the draft SCEP specification located at http://datatracker.ietf.org/doc/
draft-nourse-scep/.
The MDM payload can be placed within a configuration profile (.mobileconfig) file distributed using email or a
webpage, as part of the final configuration profile delivered by an over-the-air enrollment service, or automatically
using the Device Enrollment Program. Only one MDM payload can be installed on a device at any given time.
Configuration profiles and provisioning profiles installed through the MDM service are called managed profiles.
These profiles are automatically removed when the MDM payload is removed. Although an MDM service may have
the rights to inspect the device for the complete list of configuration profiles or provisioning profiles, it may only
7
remove apps, configuration profiles, and provisioning profiles that it originally installed. Accounts installed using
managed profiles are called managed accounts.
In addition to managed profiles, you can also use MDM to install apps. Apps installed through the MDM service are
called managed apps. The MDM service has additional control over how managed apps and their data are used on
the device.
Devices running iOS 5 and later can be designated as supervised when they are being prepared for deployment with
Apple Configurator 2. Additionally, devices running iOS 7 and later can be supervised using the Device Enrollment
Program. A supervised device provides an organization with additional control over its configuration and restrictions.
In this document, if any configuration option is limited to supervised devices, its description notes that limitation.
Unless the profile is installed using the Device Enrollment Program, a user may remove the profile containing the
MDM payload at any time. The MDM server can always remove its own profile, regardless of its access rights. In
macOS v10.8 and later and iOS 5, the MDM client makes a single attempt to contact the server with the CheckOut
command when the profile is removed. In earlier OS versions, the device does not contact the MDM server when the
user removes the payload. See MDM Best Practices for recommendations on how to detect devices that are no
longer managed.
A profile containing an MDM payload cannot be locked unless it is installed using the Device Enrollment Program.
However, managed profiles installed through MDM may be locked. All managed profiles installed through MDM are
removed when the main MDM profile is removed, even if they are locked.
At a Glance
This document was written for system administrators and system integrators who design software for managing
devices in enterprise environments.
The MDM check-in protocol is used during initialization to validate a deviceʼs eligibility for MDM enrollment and to
inform the server that a deviceʼs device token has been updated.
The (main) MDM protocol uses push notifications to tell the managed device to perform specific functions, such as
deleting an app or performing a remote wipe.
For maximum effectiveness and security, follow MDM Best Practices and install a base profile that contains little
more than the most basic MDM management information, then install other profiles to the device after it is managed.
8
The Device Enrollment Program Lets You Configure Devices with the Setup Assistant
The HTTP-based Device Enrollment Program addresses the mass configuration needs of organizations purchasing
and deploying devices in large quantities, without the need for factory customization or pre-configuration of devices
prior to deployment.
The cloud service API provides profile management and mapping. With this API, you can create profiles, update
profiles, delete profiles, obtain a list of devices, and associate those profiles with specific devices.
The Volume Purchase Program Lets You Assign App Licenses to Users and Devices
The Volume Purchase Program provides a number of web services that MDM servers can call to associate volume
purchases with a particular user or device.
Apple Push Notification Certificates Can Be Generated Through the Apple Push Certificates Portal
Before you receive a CSR from your customer, you must download an “MDM Signing Certificate” and the associated
trust certificates via the iOS Provisioning Portal. Then, you must use that certificate to sign your customersʼ
certificates. For more information, see MDM Vendor CSR Signing Overview.
See Also
For discussions about Mobile Device Management, visit the MDM Developer Forum.
9
MDM Check-in Protocol
The MDM check-in protocol is used during initialization to validate a deviceʼs eligibility for MDM enrollment and to
inform the server that a deviceʼs push token has been updated.
If a check-in server URL is provided in the MDM payload, the check-in protocol is used to communicate with that
check-in server. If no check-in server URL is provided, the main MDM server URL is used instead.
Note
MDM configuration profiles can be stored in and read from Apple Open Directory servers.
After successfully negotiating this secure connection, the device sends an HTTP PUT request in this format:
10
The server must send a 200 (OK) status code to indicate success or a 401 (Unauthorized) status code to
indicate failure. The body of the reply is ignored.
While the user is installing an MDM payload, the device sends an authenticate message that contains at least three
key-value pairs in its property list:
The device may also send the following key-value pairs if it is running iOS 9 or later and if it has the Device
Information access right:
Server Response
The server should not assume that the device has installed the MDM payload at this time, as other payloads in the
profile may still fail to install. When the device has successfully installed the MDM payload, it sends a token update
message.
11
TokenUpdate Message
A device sends a token update message to the check-in server whenever its device push token, push magic, or
unlock token change. These fields are needed by the server to send the device push notifications or passcode
resets.
The TokenUpdate message contains these key-value pairs in its property list:
The device sends an initial token update message to the server when it has installed the MDM payload. The server
should send push messages to the device only after receiving the first token update message. If the device reports
that it is AwaitingConfiguration, the MDM server is expected to send a DeviceConfigured MDM command
before the device can allow the user to proceed in Setup Assistant. This gives the MDM server the opportunity to do
some setup via MDM commands.
In addition to sending the initial TokenUpdate message, the iOS device may now send additional TokenUpdate
messages to the check-in server at any time while it has a valid MDM enrollment.
The use of PushMagic constrains the device to a unique MDM relationship. When a user removes the MDM profile,
the device should no longer listen to the former relationship, even if the user reestablishes a management
relationship with the same server topic. Note that only the push topic is the same in this case; the serverʼs address
could have changed. This also helps when a user restores a device from backup that contains an older relationship.
The use of PushMagic also ensures that the server that receives the CheckIn message is owned by the same
enterprise as the computer sending push notifications. This is important because there is no way of knowing if the
push topic belongs to the owner of the checkin server. It is conceivable that Apple could revoke a push token for one
12
party, only to have that party re-enroll people piggybacking on some other topic thatʼs actively pushing. The fact
that all MDM push topics reside in the namespace com.apple.mgmt.* helps prevent this.
Note
The PushMagic or UnlockToken fields of subsequent TokenUpdate messages may be identical to those
in previous messages or may be different (and may differ in size from previous values). If different, the server
should update its record for the device to the new value provided by the message. Failure to do so results in the
server being unable to send push notifications or perform passcode resets.
While the UnlockToken message can be sent multiple times by the device, it is possible it may only be sent once if
PushMagic or UnlockToken values change. Implementations should not rely on repeated messages to update lost
server-side data or to recover from a failure to process a previous TokenUpdate message.
Note
The topic string for the MDM check-in protocol must start with com.apple.mgmt.* where * is a unique suffix.
CheckOut
In iOS 5.0 and later, and in macOS v10.9, if the CheckOutWhenRemoved key in the MDM payload is set to true, the
device attempts to send a CheckOut message when the MDM profile is removed.
In macOS v10.8, the device attempts to send a CheckOut message when the MDM profile is removed regardless of
the value of this key (or its absence).
If network conditions do not allow the message to be delivered successfully, the device makes no further attempts to
send the message.
13
Mobile Device Management Protocol
The Mobile Device Management (MDM) protocol provides a way to tell a device to execute certain management
commands remotely. The way it works is straightforward.
During installation:
• The user or administrator tells the device to install an MDM payload. The structure of this payload is
described in Structure of MDM Payloads.
• The device connects to the check-in server. The device presents its identity certificate for authentication,
along with its UDID and push notification topic.
Note
Although UDIDs are used by MDM, the use of UDIDs is deprecated for iOS apps.
Also, in the future, the UDID will not always be 41 characters—it could be longer or shorter. It may also
contain other characters, like dashes. Do not hard code assumptions into your product. If you do, enroll-
ments may fail in the future.
If the server accepts the device, the device provides its push notification device token to the server. The
server should use this token to send push messages to the device. This check-in message also contains a
PushMagic string. The server must remember this string and include it in any push messages it sends to the
device.
• The server (at some point in the future) sends out a push notification to the device.
• The device polls the server for a command in response to the push notification.
• The device contacts the server to report the result of the last command and to request the next command.
From time to time, the device token may change. When a change is detected, the device automatically checks in
with the MDM server to report its new push notification token.
Note
14
The device polls only in response to a push notification; it does not poll the server immediately after installation.
The server must send a push notification to the device to begin a transaction.
The device initiates communication with the MDM server in response to a push notification by establishing a TLS
connection to the MDM server URL. The device validates the serverʼs certificate, then uses the identity specified in
its MDM payload as the client authentication certificate for the connection.
Note
MDM follows HTTP 3xx redirections without user interaction. However, it does not remember the URL given by
HTTP 301 (Moved Permanently) redirections. Each transaction begins at the URL specified in the MDM
payload.
Mobile Device Management, as its name implies, was originally developed for embedded systems. To support
environments where a computer is bound to an Open Directory server and various network users may log in,
extensions to the MDM protocol were developed to identify and authenticate the network user logging in so that any
network user is also managed by the MDM server (via their user profiles). The extensions made to the MDM protocol
are described in MDM Protocol Extensions.
Note
Login may be blocked momentarily while the MDM server is contacted for its latest settings. Device enrollment
can also be performed later, after the computer is connected to the Internet.
15
Structure of MDM Payloads
The Mobile Device Management (MDM) payload, a simple property list, is designated by the com.apple.mdm value
in the PayloadType field. This payload defines the following keys specific to MDM payloads:
IdentityCertificateUUID String Mandatory. UUID of the certificate payload for the deviceʼs
identity. It may also point to a SCEP payload.
Topic String Mandatory. The topic that MDM listens to for push
notifications. The certificate that the server uses to send push
notifications must have the same topic in its subject. The topic
must begin with the com.apple.mgmt. prefix.
ServerURL String Mandatory. The URL that the device contacts to retrieve device
management instructions. Must begin with the https:// URL
scheme, and may contain a port number (:1234, for example).
ServerCapabilities Array Optional. An array of strings indicating server capabilities. If
the server manages macOS devices or a Shared iPad, this field
is mandatory and must contain the value
com.apple.mdm.per-user-connections. This indicates
that the server supports both device and user connections.
See MDM Protocol Extensions.
SignMessage Boolean Optional. If true, each message coming from the device
carries the additional Mdm-Signature HTTP header. Defaults
to false.
See Passing the Client Identity Through Proxies for details.
CheckInURL String Optional. The URL that the device should use to check in
during installation. Must begin with the https:// URL
scheme and may contain a port number (:1234, for example).
If this URL is not given, the ServerURL is used for both
purposes.
CheckOutWhenRemoved Boolean Optional. If true, the device attempts to send a CheckOut
message to the check-in server when the profile is removed.
Defaults to false.
Note: macOS v10.8 acts as though this setting is always true.
Availability: Available in iOS 5.0 and later
16
Key Type Content
17
In addition, four standard payload keys must be defined:
Key Value
PayloadType com.apple.mdm.
PayloadVersion 1.
PayloadIdentifier A value must be provided.
PayloadUUID A globally unique value must be provided.
These keys are documented in “Payload Dictionary Keys Common to All Payloads” in Configuration Profile
Reference.
For the general structure of the payload and an example, see “Configuration Profile Key Reference” in Configuration
Profile Reference.
Note
Profile payload dictionary keys that are prefixed with “Payload” are reserved key names and must never be
treated as managed preferences. Any other key in the payload dictionary may be considered a managed prefer-
ence for that preference domain.
To cause the device to poll the MDM server for commands, the MDM server sends a notification through the APNS
gateway to the device. The message sent with the push notification is JSON-formatted and must contain the
PushMagic string as the value of the mdm key. For example:
{”mdm”:”PushMagicValue”}
In place of PushMagicValue above, substitute the actual PushMagic string that the device sends to the MDM
server in the TokenUpdate message. That should be the whole message. There should not be an aps key. (The
aps key is used only for third-party app push notifications.)
The device responds to this push notification by contacting the MDM server using HTTP PUT over TLS (SSL). This
message may contain an Idle status or may contain the result of a previous operation. If the connection is severed
while the device is performing a task, the device will try to report its result again once networking is restored.
18
<?xml version=”1.0” encoding=”UTF-8”?>
<!DOCTYPE plist PUBLIC ”-//Apple//DTD PLIST 1.0//EN” ”http://www.apple.com/DTDs/
PropertyList-1.0.dtd”>
<plist version=”1.0”>
<dict>
<key>UDID</key>
<string>...</string>
<key>CommandUUID</key>
<string>9F09D114-BCFD-42AD-A974-371AA7D6256E</string>
<key>Status</key>
<string>Acknowledged</string>
</dict>
</plist>
The server responds by sending the next command that the device should perform by enclosing it in the HTTP reply.
MDM response payload example shows an example of the serverʼs response payload.
The device performs the command and sends its reply in another HTTP PUT request to the MDM server. The MDM
server can then reply with the next command or end the connection by sending a 200 status (OK) with an empty
response body.
Note
An empty response body must be zero bytes in length, not an empty property list.
If the connection is broken while the device is performing a command, the device caches the result of the command
and re-attempts connection to the server until the status is delivered.
19
It is safe to send several push notifications to the device. APNS coalesces multiple notifications and delivers only the
last one to the device.
You can monitor the MDM activity in the device console using Xcode or Apple Configurator 2. A healthy (but empty)
push activity should look like this:
The content of the Command dictionary must include the following required key, as well as other keys defined by
each command.
Status String Status. Legal values are described in MDM status codes below.
20
Key Type Content
The ErrorChain key contains an array. The first item is the top-level error. Subsequent items in the array are the
underlying errors that led up to that top-level error.
The ErrorDomain and ErrorCode keys contain internal codes used by Apple that may be useful for diagnostics.
Your host should not rely on these values, as they may change between software releases. However, for reference,
the current codes are listed in Error Codes.
Unlike iOS clients, a macOS client on an MDM server enrolls devices and users as separate entities. macOS
supports several extensions to the MDM protocol to allow managing the device and logged-in user independently.
When enrolled in this manner, the MDM server receives requests for the device and for each logged-in user.
21
Device requests are sent from the mdmclient daemon, while user requests are sent from the mdmclient agent. If
multiple users are logged in, there is one instance of an mdmclient agent for each logged-in user, and each may be
sending requests concurrently in addition to device requests from the daemon.
Devices and users are assigned different push tokens. The server can use this difference to determine whether the
device or a specific user is to contact the server with an Idle request.
To indicate that an MDM server supports both device and user connections, its MDM enrollment payload must
contain the string com.apple.mdm.per-user-connections; see Structure of MDM Payloads. The MDM
enrollment profile should be delivered as any other manually-installed profile, but MDM promotes it to a device
profile once it is installed. This will have the following consequences:
• No other local users will be managed. The server will never get requests from a local user other than the one
that installed the enrollment profile.
• Network users logging into the device will be managed if the server responds successfully to their
UserAuthenticate messages. If the server does not want to manage a network client, it should return a
410 HTTP status code.
During enrollment, the client sends the standard Authenticate request to the CheckInURL specified in the MDM
payload. Once that request completes, the client sends one TokenUpdate request for the device and another for
the user that performed the enrollment. The same client certificate is used to authenticate both device and user
connections.
To help the server differentiate requests coming from a device versus a user, user requests contain additional keys in
their request plists:
<key>UDID</key>
<string>23EB7CD8-5567-5E97-827F-06E4E4C456B2</string>
<key>UserID</key>
<string>F17C470A-3ADC-47EC-A7CC-D432867F4793</string>
<key>UserLongName</key>
<string>Jimmy Smith</string>
<key>UserShortName</key>
<string>jimmys</string>
<key>NeedSyncResponse</key>
<boolean>true</boolean>
• NeedSyncResponse is optional. If it is present and true, it indicates that the client is in a state where the user
is waiting for the completion of an MDM transaction. In macOS 10.9 and later versions, this key is added
during user login when the login is blocked while the client checks in with the MDM server to ensure it has the
latest settings and profiles. The key is meant as a hint to the server that it should send all commands in the
current set of Idle/Acknowledged/Error transactions instead of relying on push notifications. During login, the
client blocks the transaction only until the server sends an empty response to an Idle/Acknowledged/Error
sequence.
22
• UserConfiguration is optional. If it is present and true, it indicates that the macOS client is trying to obtain
user-specific settings while in Setup Assistant during Device Enrollment (see Device Enrollment Program).
After a macOS client obtains device-specific settings, it also attempts to determine if the server has any
user-specific settings that may affect Setup Assistant. Currently, only password policies fall into this category.
The password policies are used if Setup Assistant prompts to create a local user account. After the client
receives a DeviceConfigured command on the device connection, it starts a normal Idle/Acknowledged/Error
connection on the user connection. If the server sends commands or profiles during this time, nothing the
client receives persists, because the user account hasnʼt been created on the system yet. The client always
responds NotNow to any commands it received during this time. It continues to respond with NotNow until it
receives a reply with no additional commands (an empty body) or a DeviceConfigured command on the
user connection. The client passes any password policies to Setup Assistant and discards everything else.
After Setup Assistant creates the user account and the user logs in, the client initiates a new series of
Idle/Acknowledged/Error connections. The server should then resend all commands and profiles. The client
processes them normally and they will persist.
To support environments where a macOS computer is bound to an Open Directory server and various network users
may log in, extensions to the MDM protocol were developed to identify and authenticate the network user logging in.
This way, network users are also managed by the MDM server via their user profiles.
At login time, if the user is a network user or has a mobile home, the MDM client issues a request to the server to
authenticate the current user to the MDM server and obtain an AuthToken value that is used in subsequent
requests made by this user to the server.
The authentication happens using a transaction similar in structure to existing transactions with the server, as an
HTTP PUT request to the CheckInURL address specified in the MDM payload.
The first request to the server is sent to the CheckInURL specified in the MDM payload, with the same identity used
for all other MDM requests. The message body contains a property list with the following keys:
If the macOS device being enrolled has an owner, the UserID key may designate a local user instead of a network
user. If the local request succeeds, an X-MDM-is-owned header is added to the response to all requests to the
checkinURL, except CheckOut requests where it is optional. To this header may be added a value of 1 to indicate
the device is owned; this is also the default behavior if the header is omitted. Only if the header is present with a
value of 0 will requests from the client be optimized.
23
If the server provides a 200 response but a zero-length DigestChallenge value, the server does not require any
AuthToken to be generated for this user.
Otherwise, with a 200 response and DigestChallenge value that is non-empty, the client generates a digest from
the userʼs shortname, the userʼs clear-text password, and the DigestChallenge value obtained from the server.
The resulting digest is sent in a second request to the server, which validates the response and returns an
AuthToken value that is sent on subsequent requests to the server.
If the server does not want to manage this user, it should return a 410 HTTP status code. The client will not make
any additional requests to the server on behalf of this user for the duration of this login session. The next time that
user logs in, however, the client will again send a UserAuthenticate request and the server can optionally return
410 again.
The second request to the server is also sent to the CheckInURL specified in the MDM payload and sent with the
same identity used for all other MDM requests. The message body contains:
If the server responds with a 200 response and a non-empty AuthToken value is present, the AuthToken value is
sent to the server on subsequent requests. The AuthToken value is included in the message body of subsequent
requests along with the additional keys:
It is assumed that the AuthToken remains valid until the next time the client sends a UserAuthenticate request.
The client initiates a UserAuthenticate handshake each time a network user logs in.
If the server rejects the DigestResponse value because of an invalid password, it returns a 200 response and an
empty AuthToken value.
24
<dict>
<key>MessageType</key>
<string>UserAuthenticate</string>
<key>UDID</key>
<string>23EB7CD8-5567-5E97-827F-06E4E4C456B2</string>
<key>UserID</key>
<string>16C0477E-EB2F-4B5E-AAFD-92B2B91C4B16</string>
</dict>
// From this point on, all user requests from that network user will include an
AuthToken key:
<dict>
<key>AuthToken</key>
<string>uEOcQRJrXGbMJUDAkDZSCny5e90=</string>
<key>Status</key>
<string>Idle</string>
<key>UDID</key>
<string>23EB7CD8-5567-5E97-827F-06E4E4C456B2</string>
<key>UserID</key>
<string>16C0477E-EB2F-4B5E-AAFD-92B2B91C4B16</string>
<key>UserLongName</key>
<string>Net One</string>
<key>UserShortName</key>
25
<string>net1</string>
</dict>
For push notifications, the client uses different push tokens for device and user connections. Each token is sent to
the server using the TokenUpdate request. The server can tell for whom the token is intended based on the UDID
and UserID values in the request. If the user is a network/mobile user, the AuthToken is provided.
Warning
These push tokens should not be confused with the “AuthToken” mentioned above.
A device running iOS 9.3 or later, and its logged-in users, can be managed independently as a Shared iPad, using a
technique similar to Network User Authentication Extensions. The device and its users are assigned different push
tokens. The server can use this difference to determine whether the device or a specific user is to contact the server
with an Idle request.
In general, the following types of MDM commands can be sent on the user channel:
• ProfileList
• InstallProfile
• RemoveProfile
• Restrictions
• InviteToProgram
• DeviceInformation
To indicate that an MDM server supports both device and user connections, the ServerCapabilities array in its
MDM enrollment payload must contain the string com.apple.mdm.per-user-connections, indicating support
for Shared iPad. Then when a user logs in, the device sends a TokenUpdate request on the user channel.
To help the server differentiate requests coming from a device versus a user, user requests must contain additional
keys:
If the server is configured to manage the user, it stores the user push token and returns a 200 response. At this point
the device polls the server for a command on the user channel.
If the server is not configured to manage the user, it should return a 410 HTTP status code. The client will not make
any additional requests to the server on behalf of this user for the duration of the login session. The next time the
26
user logs in, however, the client will again send a UserAuthenticate request and the server can optionally return
a 410 code again.
Error Handling
There are certain times when the device is not able to do what the server requests. For example, databases cannot
be modified while the device is locked with Data Protection. When a device cannot perform a command due to
situations like this, it sends a NotNow status without performing the command. The server may send another
command immediately after receiving this status. See “Handling a NotNow Response,” below, for more details.
The following commands are guaranteed to execute in iOS, and never return NotNow:
• DeviceInformation
• ProfileList
• DeviceLock
• EraseDevice
• ClearPasscode
• CertificateList
• ProvisioningProfileList
• InstalledApplicationList
• Restrictions
• The system is in Power Nap (dark wake) and a command other than DeviceLock or EraseDevice is
received.
• An InstallProfile or RemoveProfile request is made on the user connection and the userʼs keychain is
locked.
In macOS, the client may respond with NotNow if it is blocking the userʼs login while it contacts the server, and if the
server sends a request that may take a long time to answer (such as InstalledApplicationList or
DeviceInformation).
27
Handling a NotNow Response
If the deviceʼs response to the previous command sent has a status of NotNow, your server has two response
choices:
• It may immediately stop sending commands to the device. In this case the device automatically polls your
server when conditions change and it is able to process the last requested command. The server does not
need to send another push notification in response to this status. However, the server may send another push
notification to the device to have it poll the server immediately. The device does not cache the command that
was refused. If the server wants the device to retry the command, it must send the command again when the
device polls the server.
• It may send another command on the same connection, but if this new command returns anything other than
a NotNow response, the device will not automatically poll the server as it would have with the first response
choice. The server must send a push notification at a later time to make the device reconnect. The device
polls the server in response to a NotNow status only if that is the last status sent by the device to the server.
Example 1: The final command results in the server receiving a NotNow response. The device will poll the server
later, when the InstallApplication command might succeed.
28
Example 2: The final command results in the server receiving something other than a NotNow response. The device
will not poll the server later, because the last response was not NotNow.
Example 3: The connection to the device is unexpectedly interrupted. Because the last status the server received
was not NotNow, the server should send a push notification to the device to retry the InstallApplication
command. The server must not assume that the device will automatically poll the server later.
29
Request Types
This section describes the MDM protocol request types for Apple devices that run iOS. Support for the equivalent
request types used with Apple computers that run macOS is summarized in Support for macOS Requests.
To send a ProfileList command, the server sends a dictionary containing the following keys:
The device replies with a property list that contains the following key:
Each entry in the ProfileList array contains a dictionary with a profile. For more information about profiles, see
Configuration Profile Reference.
Note
ProfileList queries are available only if the MDM host has an Inspect Profile Manifest access right.
If you want to update a profile in place by installing a new one where there is already an existing one, follow these
rules:
• The new MDM profile must be signed with the same identity as the existing profile.
The profile to install may be encrypted using any installed device identity certificate. The profile may also be signed.
To send an InstallProfile command, the server sends a dictionary containing the following keys:
30
Note that in the definition of the InstallProfile command, the Payload is of type Data, meaning that the entire Payload
must be base64-encoded, including the XML headers. This is true for any Data type items in a property list. See
“Understanding XML Property Lists” in Property List Programming Guide for more information.
Note
This query is available only if the MDM host has a Profile Installation and Removal access right.
By sending the RemoveProfile command, the server can ask the device to remove any profile originally installed
through MDM.
To send a RemoveProfile command, the server sends a dictionary containing the following keys:
Note
This query is available only if the MDM host has a Profile Installation and Removal access right.
To send a ProvisioningProfileList command, the server sends a dictionary containing the following keys:
ProvisioningProfileList Array Array of dictionaries. Each entry describes one provisioning profile.
31
Note
This query is available only if the MDM host has an Inspect Provisioning Profiles access right.
To send an InstallProvisioningProfile command to an iOS device, the server sends a dictionary containing
the following keys:
Note
This query is available only if the MDM host has a Provisioning Profile Installation and Removal access right.
To send a RemoveProvisioningProfile command to an iOS device, the server sends a dictionary containing the
following keys:
Note
This query is available only if the MDM host has a Provisioning Profile Installation and Removal access right.
To send a CertificateList command, the server sends a dictionary containing the following keys:
32
The device replies with:
Each entry in the CertificateList array is a dictionary containing the following fields:
Note
The CertificateList command requires that the server have the Inspect Profile Manifest privilege.
To send an InstalledApplicationList command, the server sends a dictionary containing the following keys:
33
Table 3.28: InstalledApplicationList dictionary keys
34
DeviceInformation Commands Get Information About the Device
To send a DeviceInformation command, the server sends a dictionary containing the following keys:
QueryResponses Dictionary Contains a series of key-value pairs. Each key is a query string from
General queries, Device information queries, or Network information
queries. The associated value is the response for that query.
Queries for which the device has no response or that are not permitted by the MDM hostʼs access rights are dropped
from the response dictionary.
The queries described in General queries are available without any special access rights:
35
Query Reply Type Comment
The queries in iTunes Store account queries are available if the MDM host has an Install Applications access right:
iTunesStoreAccountIsActive Boolean true if the user is currently logged into an active iTunes
Store account.
Availability:Available in iOS 7 and later and in macOS
10.9.
iTunesStoreAccountHash String Returns a hash of the iTunes Store account currently
logged in. This string is identical to the itsIdHash
returned by the VPP App Assignment web service.
Availability: Available in iOS 8.0 and later and macOS
10.10 and later.
The queries in Device information queries are available if the MDM host has a Device Information access right:
36
Query Reply Type Comment
37
Query Reply Type Comment
CatalogURL String The URL to the software update catalog currently in use by the client.
IsDefaultCatalog Boolean
PreviousScanDate Date
PreviousScanResult Integer
PerformPeriodicCheck Boolean
AutomaticCheckEnabled Boolean
BackgroundDownloadEnabled Boolean
AutomaticAppInstallationEnabled Boolean
AutomaticOSInstallationEnabled Boolean
AutomaticSecurityUpdatesEnabled Boolean
38
Network Information Queries Provide Hardware Addresses, Phone Number, and SIM Card and Cellular Network Info
The queries in Network information queries are available if the MDM host has a Network Information access right.
Note
Not all devices understand all queries. For example, queries specific to GSM (IMEI, SIM card queries, and so
on) are ignored if the device is not GSM-capable. The macOS MDM client responds only to BluetoothMAC,
WiFiMAC, and EthernetMAC.
ICCID String The ICC identifier for the installed SIM card.
BluetoothMAC String Bluetooth MAC address.
WiFiMAC String Wi-Fi MAC address.
EthernetMACs Array of strings Ethernet MAC addresses.
Availability: Available in iOS 7 and later.
EthernetMAC String Primary Ethernet MAC address.
Availability: Available in macOS v10.7 and later.
CurrentCarrierNetwork String Name of the current carrier network.
SIMCarrierNetwork String Name of the home carrier network. (Note: this query is
supported on CDMA in spite of its name.)
SubscriberCarrierNetwork String Name of the home carrier network. (Replaces
SIMCarrierNetwork.)
Availability: Available in iOS 5.0 and later.
CarrierSettingsVersion String Version of the currently-installed carrier settings file.
PhoneNumber String Raw phone number without punctuation, including country
code.
VoiceRoamingEnabled Boolean The current setting of the Voice Roaming setting. This is only
available on certain carriers.
Availability: iOS 5.0 and later.
DataRoamingEnabled Boolean The current setting of the Data Roaming setting.
IsRoaming Boolean Returns whether the device is currently roaming.
Availability: Available in iOS 4.2 and later. See note below.
PersonalHotspotEnabled Boolean True if the Personal Hotspot feature is currently turned on.
This value is available only with certain carriers.
Availability: iOS 7.0 and later.
SubscriberMCC String Home Mobile Country Code (numeric string).
Availability: Available in iOS 4.2.6 and later.
SubscriberMNC String Home Mobile Network Code (numeric string).
Availability: Available in iOS 4.2.6 and later.
CurrentMCC String Current Mobile Country Code (numeric string).
CurrentMNC String Current Mobile Network Code (numeric string).
39
Query Reply Type Comment
Note
For older versions of iOS, if the SIMMCC/SMMNC combination does not match the CurrentMCC/CurrentMNC
values, the device is probably roaming.
To send a SecurityInfo command, the server sends a dictionary containing the following keys:
Response:
40
Key Type Content
41
Key Type Content
FDE_PersonalRecoveryKey String If FileVault PRK escrow is enabled and a recovery key has
DeviceKey been set up, this key contains a short string that is displayed
to the user in the EFI login window as part of the help
message if the user enters an incorrect password three
times. The server can use this string as an index when
saving the device PRK. Currently, this string is the device
serial number, which replaces the recordNumber that was
returned by the server in the earlier escrow mechanism.
Availability: Available in macOS 10.13 and later.
FirewallSettings Dictionary The current Firewall settings. This information will be
returned only when the command is sent to the device
channel. The response is a dictionary with the following
keys:
• FirewallEnabled (Boolean): Set to true if firewall
is on.
• BlockAllIncoming (Boolean): Set to true if all
incoming connections are blocked.
• StealthMode (Boolean): Set to true if stealth
mode is enabled.
• Applications (Array of Dictionaries): Blocking
status for specific applications. Each dictionary
contains these keys:
– BundleID (String) : Identifies the application
– Allowed (Boolean) : Set to true if incoming
connections are allowed
– Name (String) : descriptive name of the
application for display purposes only (may be
missing if no corresponding app is found on the
client computer).
Availability: Available in macOS 10.12 and later.
SystemIntegrityProtection Boolean Device channel only. Set to true if System Integrity
Enabled Protection is enabled on the device. In macOS 10.11 or later,
this information may also be retrieved using a
DeviceInformation query.
Availability: Available in macOS 10.12 and later.
FirmwarePasswordStatus Dictionary State of EFI firmware password; see EFI firmware status
values.
Availability: Available in macOS 10.13 and later.
42
Key Type Content
Hardware encryption capabilities are described using the logical OR of the values in HardwareEncryptionCaps
bitfield values. Bits set to 1 (one) indicate that the corresponding feature is present, enabled, or in effect.
Value Feature
1 Block-level encryption.
2 File-level encryption.
EFI firmware status is returned as a dictionary that contains the fields listed below.
Note
Security queries are available only if the MDM host has a Security Query access right.
The DeviceLock command is intended to lock lost devices remotely; it should not be used for other purposes. To
send one, the server sends a dictionary containing the following keys:
43
Key Type Content
Note
This command requires both Device Lock and Passcode Removal access rights.
If a passcode has been set on the device, the device is locked and the text and phone number passed with the
DeviceLock command are displayed on the locked screen. The device returns a Status of Acknowledged and a
MessageResult of Success. If a passcode has not been set on the device, the device is locked but the message
and phone number are not displayed on the screen. The device returns a Status of Acknowledged and a
MessageResult of NoPasscodeSet.
This command is supervised only and requires the Device Lock access right. The device will restart immediately.
Available in iOS 10.3 and macOS 10.13 and later. Passcode-locked iOS devices do not rejoin Wi-Fi networks after
restarting, so they may not be able to communicate with the server.
This command is supervised only and requires the Device Lock access right. The device will shut down immediately.
Available in iOS 10.3 and macOS 10.13 and later.
44
ClearPasscode Commands Clear the Passcode for a Device
To send a ClearPasscode command, the server sends a dictionary containing the following keys:
Note
This command requires both Device Lock and Passcode Removal access rights.
Upon receiving this command, the device immediately erases itself. No warning is given to the user. This command
is performed immediately even if the device is locked.
The device attempts to send a response to the server, but unlike other commands, the response cannot be resent if
initial transmission fails. Even if the acknowledgement did not make it to the server (due to network conditions), the
device will still be erased.
Note
In iOS 7 and later and in macOS 10.10 and later, the MDM server can send the RequestMirroring and
StopMirroring commands to start and stop AirPlay mirroring.
45
Note
To send a RequestMirroring command, the server sends a dictionary containing the following keys:
Note
MirroringResult String The result of this request. The returned value is one of:
• Prompting: The user is being prompted to share his or her
screen.
• DestinationNotFound: The destination cannot be
reached by the device.
• Cancelled: The request was cancelled.
• Unknown: An unknown error occurred.
To send a StopMirroring command, the server sends a dictionary containing the following keys:
46
Restrictions Commands Get a List of Installed Restrictions
This command allows the server to determine what restrictions are being enforced by each profile on the device, and
the resulting set of restrictions from the combination of profiles.
The GlobalRestrictions dictionary and each entry in the ProfileRestrictionList dictionary contains the
following keys:
The restriction names (keys) in the dictionary correspond to the keys in the Restriction and Passcode Policy
payloads. For more information, see Configuration Profile Key Reference.
47
Note
The restriction names (keys) in the dictionary correspond to the keys in the Restriction and Passcode Policy
payloads.
With intersected restrictions, new restrictions can only reduce the number of strings in the set. With unioned
restrictions, new restrictions can add to the set.
The ClearRestrictionsPassword command allows the server to clear the restrictions password and restrictions
set by the user on the device. Supervised only.
48
Shared iPad User Commands Manage User Access
Three MDM Protocol commands—UsersList, LogOutUser, and DeleteUser—let the MDM server exercise
control over the access of users to MDM devices in an educational environment. These commands are all available in
iOS 9.3 and later and may be used only in Shared iPad mode.
UserList
This command allows the server to query for a list of users that have active accounts on the current device.
The device replies with either an error response of code 12070 if the device cannot return a list of users, or the
following response dictionary:
For iOS, each entry in the Users array contains the following dictionary:
For macOS 10.13 or later, each entry in the Users array contains the following dictionary:
49
UnlockUserAccount
This command lets the server unlock a local user account that has been locked for too many failed password
attempts. It requires the Device Lock and Passcode Removal Right and it may be sent only on the device channel.
Available in macOS 10.13 and later.
LogOutUser
This command allows the server to force the current user to log out.
DeleteUser
This command allows the server to delete a user that has an active account on the device. With iOS it is available in
Education Mode only; with macOS it requires DEP enrollment.
With macOS and iOS, the status of the response to DeleteUser is either Acknowledged, or Error with code 12071 if
the specified user does not exist, 12072 if the specified user is logged in, 12073 if the specified user has data to
sync and ForceDeletion is false or not specified, or 12074 if the specified user could not be deleted. With macOS,
12074 is also returned if an attempt was made to delete the last admin user.
When a device is erased, Lost Mode is disabled. To re-enable Lost Mode on the device, the MDM server should store
the deviceʼs Lost Mode state before erasing it. If the device is enrolled again, the MDM server can then restore the
correct Lost Mode state.
50
When a device is in MDM Lost mode, invalid commands sent to it may return an Error with code 12078.
EnableLostMode
This command allows the server to put the device in MDM lost mode, with a message, phone number, and footnote
text. A message or phone number must be provided.
The response status is either Acknowledged or it is Error with code 12066 if MDM Lost Mode could not be enabled.
This command allows the server to tell the device to play a sound if it is in MDM Lost Mode. The sound will play until
the device is either removed from Lost Mode or a user disables the sound at the device.
The response status is either Acknowledged, or Error with code 12067 if the device is not in MDM Lost Mode, or
Error with code 12080 if the sound could not be played.
DisableLostMode
This command allows the server to take the device out of MDM lost mode.
The response status is either Acknowledged or it is Error with code 12069 if MDM Lost Mode could not be disabled.
DeviceLocation
This command allows the server to ask the device to report its location if it is in MDM lost mode.
51
Key Type Content
The device replies with either an error response with code 12067 if the device is not in MDM Lost Mode, code 12068
if the location could not be determined, or the following response dictionary:
Managed Applications
Running iOS 5 and later, an MDM server can manage third-party applications from the App Store as well as custom
in-house enterprise applications. The server can specify whether the app and its data are removed from the device
when the MDM profile is removed. Additionally, the server can prevent managed app data from being backed up to
iTunes and iCloud.
In iOS 7 and later, an MDM server can provide a configuration dictionary to third-party apps and can read data from a
feedback dictionary provided by third-party apps. See Managed App Configuration and Feedback for details.
On devices running iOS earlier than iOS 9, apps from the App Store cannot be installed on a userʼs device if the App
Store has been disabled. With iOS 9 and later, VPP apps can be installed even when the App Store is disabled (see
VPP App Assignment).
To install a managed app on an iOS device, the MDM server sends an installation command to the userʼs device.
Unless the device is supervised, the managed apps then require a userʼs acceptance before they are installed.
When a server requests the installation of a managed app from the App Store, if the app was not purchased using
App Assignment (that is, if the original InstallApplication requestʼs Options dictionary contained a
PurchaseMethod value of 0), the app “belongs” to the iTunes account that is used at the time the app is installed.
Paid apps require the server to send in a Volume Purchasing Program (VPP) redemption code that purchases the app
for the end user. For more information on VPP, go to http://www.apple.com/business/vpp/.
The macOS MDM client does not support managed applications. However, it does support the parts of the
InstallApplication, InstallMedia, and InviteToProgram MDM commands related to VPP enrollment and
installation.
52
InstallApplication Commands Install an Application
To send an InstallApplication command, the server sends a request containing the following keys:
If the application is not already installed and the ChangeManagementState is set to Managed, the app will be
installed and managed.
If the application is installed unmanaged on an unsupervised device, the user will be prompted to allow management
of the app. If accepted, the application becomes managed.
If the application is installed unmanaged on a supervised device, the user will not be prompted and the application
becomes managed.
The request must contain exactly one of the following fields: Identifier, iTunesStoreID, or ManifestURL
value.
53
The options dictionary can contain the following keys:
iOS App Installation Here is an example of an iOS InstallApplication command for a per-device VPP app
that uses the ChangeManagementState option:
If the request is accepted by the user, the device responds with an Acknowledged response and the following fields:
If the app cannot be installed, the device responds with an Error status, with the following fields:
54
Key Type Content
macOS App Installation macOS apps are installed through MDM as packages. Using productbuild, each
package must be signed with an appropriate certificate (such as a TLS/SSL certificate with signing usage) that is
verifiable on the client. Only the package needs to be signed, not the app; Appleʼs Gatekeeper doesnʼt check apps
installed through MDM.
You will also need to generate a manifest which specifies where the package is to be downloaded from and provides
hashes to verify the integrity of the package. The manifest needs to contain:
sha256 hashes are supported on macOS 10.13.6 and later. Older versions of the OS require md5 hashes.
Historically, the hashes are provided as an array because you can ”chunk” the pkg and provide hashes for each
chunk. However, itʼs simpler just to hash the entire pkg:
$ md5 /tmp/myPackage.pkg
$ shasum -a 256 /tmp/myPackage.pkg
55
<plist version=”1.0”>
<dict>
<key>items</key>
<array>
<dict>
<key>assets</key>
<array>
<dict>
<key>kind</key>
<string>software-package</string>
<key>md5-size</key>
<integer>10864648</integer>
<key>md5s</key>
<array>
<string>c207426ca2df482596e0ea6c8291d0f2</string>
</array>
<key>sha256-size</key>
<integer>10864648</integer>
<key>sha256s</key>
<array>
<string>
49f6554726ae98521b02d89a86f2a7eea5611295fa2f67bf8bc44f679c121a2d
</string>
</array>
<key>url</key>
<string>https://myserver.myenterprise.com/MDM_Test/MyApp.pkg</string>
</dict>
<dict>
<key>kind</key>
<string>display-image</string>
<key>needs-shine</key>
<false/>
<key>url</key>
<string>https://myserver.myenterprise.com/MDM_Test/Server.png</string>
</dict>
<dict>
<key>kind</key>
<string>full-size-image</string>
<key>needs-shine</key>
<false/>
<key>url</key>
<string>https://myserver.myenterprise.com/MDM_Test/Server.png</string>
</dict>
</array>
<key>metadata</key>
<dict>
<key>bundle-identifier</key>
<string>com.myenterprise.MyAppPackage</string>
56
<key>bundle-version</key>
<string>1.1</string>
<key>kind</key>
<string>software</string>
<key>sizeInBytes</key>
<integer>10864648</integer>
<key>subtitle</key>
<string>My Enterprise</string>
<key>title</key>
<string>Example Enterprise Install</string>
<key>items</key>
<array>
<dict>
<key>bundle-identifier</key>
<string>com.myenterprise.MyAppNotMAS</string>
<key>bundle-version</key>
<string>1.7.5</string>
</dict>
</array>
</dict>
</dict>
</array>
</dict>
</plist>
57
InstallEnterpriseApplication Commands Install an Enterprise Application
To send an InstallEnterpriseApplication command, the server sends a request containing the following
keys:
The request must contain either Manifest or ManifestURL. When using Manifest the pinning options are
ignored. When using ManifestURL, specifying the pinning options is recommended to increase security.
If a redemption code is needed during app installation, the server can use the ApplyRedemptionCode command to
complete the app installation:
Note
It is an error to send a redemption for an app that doesnʼt require a redemption code.
58
ManagedApplicationList Commands Provide the Status of Managed Applications
The ManageApplicationList command allows the server to query the status of managed apps.
Note
Certain statuses are transient. Once they are reported to the server, the entries for the apps are removed from
the next query.
To send a ManagedApplicationList command, the server sends a dictionary containing the following keys:
The keys of the ManagedApplicationList dictionary are the app identifiers for the managed apps. The
corresponding values are dictionaries that contain the following keys:
Status String The status of the managed app; see Managed app statuses for
possible values.
ManagementFlags Integer Management flags. (See InstallApplication command above for
a list of flags.)
UnusedRedemptionCode String If the user has already purchased a paid app, the unused
redemption code is reported here. This code can be used again
to purchase the app for someone else. This code is reported
only once.
HasConfiguration Boolean If true, the app has a server-provided configuration. For
details, see Managed App Configuration and Feedback.
Availability: Available in iOS 7 and later.
HasFeedback Boolean If true, the app has feedback for the server. For details, see
Managed App Configuration and Feedback.
Availability: Available in iOS 7 and later.
IsValidated Boolean If true, the app has validated as allowed to run and is able to
run on the device. If an app is enterprise-distributed and is not
validated, it will not run on the device until validated.
Availability: Available in iOS 9.2 and later.
59
Key Type Content
ExternalVersionIdentifier Integer The applicationʼs external version ID. It can be used for
comparison in the iTunes Search API to decide if the application
needs to be updated. Compare this value to the externalId
value in the contentMetadataLookupUrl response.
If the current external version identifier of an app on the store
does not match the external version identifier reported by the
device, there may be an app update available for the device.
However, note that the version in the store may not be available
for installation on the device for a variety of reasons, including
that the deviceʼs software or hardware is incompatible with the
current version of the app.
Availability: Available in iOS 11 and macOS 13.10 and later.
Value Description
NeedsRedemption The app is scheduled for installation but needs a redemption code to complete
the transaction.
Redeeming The device is redeeming the redemption code.
Prompting The user is being prompted for app installation.
PromptingForLogin The user is being prompted for App Store credentials.
Installing The app is being installed.
ValidatingPurchase An app purchase is being validated.
Managed The app is installed and managed.
ManagedButUninstalled The app is managed but has been removed by the user. When the app is
installed again (even by the user), it will be managed once again.
PromptingForUpdate The user is being prompted for an update.
PromptingForUpdateLogin The user is being prompted for App Store credentials for an update.
PromptingForManagement The user is being prompted to change an installed app to be managed.
Updating The app is being updated.
ValidatingUpdate An app update is being validated.
Unknown The app state is unknown.
The following statuses are transient and are reported only once:
UserInstalledApp The user has installed the app before managed app installation could take
place.
UserRejected The user rejected the offer to install the app.
UpdateRejected The user rejected the offer to update the app.
ManagementRejected The user rejected management of an already installed app.
Failed The app installation has failed.
60
RemoveApplication Commands Remove Installed Managed Applications
The RemoveApplication command is used to remove managed apps and their data from a device. Applications not
installed by the server cannot be removed with this command. To send a RemoveApplication command, the
server sends a dictionary containing the following commands:
InviteToProgram Lets the Server Invite a User to Join a Volume Purchasing Program
In iOS 7 and later, this command allows a server to invite a user to join the Volume Purchase Program for per-user
VPP app assignment. After this command issues an invitation, you can use the iTunesStoreAccountIsActive
query to get the hash of the iTunes Store account currently logged in.
To send an InviteToProgram command, the server sends a dictionary containing the following keys:
This command yields a NotNow status until the user exits Setup Assistant.
This command allows the server to force validation of the free developer and universal provisioning profiles
associated with an enterprise app.
61
Key Type Content
Identifiers Array of Strings Optional. An array of app identifiers. If provided, the enterprise apps
whose identifiers appear in this array have their provisioning profiles
validated. If not, only installed managed apps have their provisioning
profiles validated.
Installed Books
Books obtained from Apple Books can be installed on a device. These books will be backed up, will sync to iTunes,
and will remain after the MDM profile is removed. Books not obtained from Apple Books will not sync to iTunes and
will be removed when the MDM profile is removed.
Books obtained from Apple Books must be purchased using VPP Licensing. Installing a book from Apple Books on a
device that already has that book installed causes the book to be visible to the MDM server.
Installation of books requires the App Installation right. The App Store must be enabled for Apple Books media
installation to work. The App Store need not be enabled to install books retrieved using a URL.
To send an InstallMedia command (in iOS 8 or later), the server sends a dictionary containing the following keys:
If a MediaURL is provided, the URL must lead to a PDF, gzipped epub, or gzipped iBooks Author document. The
following fields are provided to define this document:
62
Installing a book not from Apple Books with the same PersistentID as an existing book not from Apple Books
replaces the old book with the new. Installing an Apple Books book with the same iTunesStoreID as an existing
installed book updates the book from Apple Books.
The user is not prompted for book installation or update unless user interaction is needed to complete an Apple
Books transaction.
If the request is accepted, the device responds with an Acknowledged response and the following fields:
iTunesStoreID Integer The bookʼs iTunes Store ID, if it was provided in the command.
MediaURL String The bookʼs URL, if it was provided in the command.
PersistentID String Persistent ID, if it was provided in the command.
MediaType String The media type.
State String The installation state of this media. This value can be one of the
following:
• Queued
• PromptingForLogin
• Updating
• Installing
• Installed
• Uninstalled
• UserInstalled
• Rejected
The following states are transient and are reported only once:
• Failed
• Unknown
If the book cannot be installed, an Error status is returned, which may contain an error chain. In addition, a
RejectionReason field of type String is returned, containing one of these values:
• CouldNotVerifyITunesStoreID
• AppStoreDisabled
• WrongMediaType
To send a ManagedMediaList command, the server sends a dictionary containing the following key:
63
If the request is accepted, the device responds with an Acknowledged response and the following field:
Each entry in the ManagedMedia array is a dictionary with the following keys:
iTunesStoreID Integer The itemʼs iTunes Store ID, if the item was retrieved from the iTunes
Store.
State String The installation state of this media. This value can be one of the
following:
• Queued
• PromptingForLogin
• Updating
• Installing
• Installed
• Uninstalled
• UserInstalled
• Rejected
PersistentID String Provided if available.
Kind String Provided if available.
Version String Provided if available.
Author String Provided if available.
Title String Provided if available.
This command allows an MDM server to remove installed media. This command returns Acknowledged if the item
is not found.
To send a RemoveMedia command, the server sends a dictionary containing the following keys:
64
Managed Settings
In iOS 5 or later, this command allows the server to set settings on the device. These settings take effect on a
one-time basis. The user may still be able to change the settings at a later time. This command requires the Apply
Settings right.
Each entry in the Settings array must be a dictionary. The specific values in that dictionary are described in the
documentation for the specific setting.
Unless the command is invalid, the Settings command always returns an Acknowledged status. However, the
response dictionary contains an additional key-value pair:
In the response, the Settings array contains a result dictionary that corresponds with each command that
appeared in the original Settings array (in the request). These dictionaries contain the following keys and values:
Status String Status of the command. Only Acknowledged and Error are reported.
ErrorChain Array Optional. An array representing the chain of errors that occurred.
Identifier String Optional. The app identifier to which this error applies. Availability: Available in iOS 7 and later.
Each entry in the ErrorChain array is a dictionary containing the same keys found in the top level ErrorChain
dictionary of the protocol.
To send a VoiceRoaming command, the server sends a dictionary containing the following keys:
65
PersonalHotspot Modifies the Personal Hotspot Setting
To send a PersonalHotspot command, the server sends a dictionary containing the following keys:
Note
A wallpaper change (in iOS 8 or later) is a one-time setting that can be changed by the user at will. This command is
supported in supervised mode only.
To send a Wallpaper command, the server sends a dictionary containing the following keys:
To send a DataRoaming command, the server sends a dictionary containing the following keys:
66
Bluetooth Modifies the Bluetooth Setting
To send a Bluetooth command, the server sends a dictionary containing the following keys:
To set or update the attributes for a managed application, send a Settings command with the following dictionary
as an entry:
Note
This setting requires the App Management right. Also, on an unsupervised device, an app is not considered
managed until a user accepts its installation.
The keys that can appear in the Attributes dictionary are listed below:
To send a DeviceName command (available only on supervised devices or devices running macOS v10.10 or later),
the server sends a dictionary containing the following keys:
67
Key Type Content
DeviceName String The requested computer name and local host name for the device.
On macOS, the DeviceName command sets only the computer name and local host name of the device. To set the
HostName of the device (available only on macOS 10.11 or later), the server sends a dictionary containing the
following keys:
To send an MDMOptions command (available only in iOS 7 and later), the server sends a dictionary containing the
following keys:
Shared iPad Mode only. The PasscodeLockGracePeriod command sets the time the screen must be locked
before needing a passcode to unlock it. Changing to a less restrictive value will not take effect until the user logs out.
68
MaximumResidentUsers Sets Maximum Number of Users for a Shared iPad
Shared iPad Mode only. Sets the maximum number of users that can use a Shared iPad. This can be set only when
the iPad is in the AwaitingConfiguration phase, before the DeviceConfigured message has been sent to
the device. If MaximumResidentUsers is greater than the maximum possible number of users supported on the
device, the device is configured with the maximum possible number of users instead.
Shared iPad Mode only. Sets the user preference of diagnostic submission.
Shared iPad Mode only. Sets the user preference of sharing analytics with app developers.
In iOS 7 and later, an MDM server can use configuration and feedback dictionaries to communicate with and
configure third-party managed apps.
Note
The managed app configuration and feedback dictionaries are stored as unencrypted files. Do not store pass-
69
words or private keys in these dictionaries.
The configuration dictionary provides one-way communication from the MDM server to an app. An app can access
its (read-only) configuration dictionary by reading the key com.apple.configuration.managed using the
NSUserDefaults class. A managed app can respond to new configurations that arrive while the app is running by
observing the NSUserDefaultsDidChangeNotification notification.
A managed app can also store feedback information that can be queried over MDM. An app can store new values for
this feedback dictionary by setting the com.apple.feedback.managed key using the NSUserDefaults class.
This dictionary can be read or deleted over MDM. An app can respond to the deletion of the feedback dictionary by
observing the NSUserDefaultsDidChangeNotification notification.
Note
The ManagedApplicationConfiguration command requires that the server have the App Management
right.
Each member of the ApplicationConfigurations array is a dictionary with the following keys:
70
ApplicationConfiguration Sets or Updates the App Configuration for a Managed Application
In iOS 7 and later, to set or update the app configuration for a managed application, send a Settings command
with the following dictionary as an entry:
Note
This setting requires the App Management right. Also, on an unsupervised device, an app is not considered
managed until a user accepts its installation.
In iOS 7 and later, attributes can be set on managed apps. These attributes can be changed over time.
The device replies with a dictionary that contains the following keys:
Each member of the ApplicationAttributes array is a dictionary with the following keys:
The keys that can appear in the Attributes dictionary are listed below:
71
ManagedApplicationFeedback Retrieves Managed App Feedback
To send a ManagedApplicationFeedback command, the server sends a dictionary containing the following keys:
Note
The ManagedApplicationFeedback command requires that the server have the App Management right.
Queries about apps that are not managed are ignored.
Each member of the ManagedApplicationFeedback array is a dictionary with the following keys:
AccountConfiguration
When a macOS (v10.11 and later) device is configured via DEP to enroll in an MDM server and the DEP profile has the
await_device_configuration flag set to true, the AccountConfiguration command can be sent to the
device to have it create the local administrator account (thereby skipping the page to create this account in Setup
Assistant). This command can only be sent to a macOS device that is in the AwaitingConfiguration state.
72
Key Type Content
The passwordHash data objects should be created on the server using the CommonCrypto libraries or equivalent
as a salted SHA512 PBKDF2 dictionary containing three items: entropy is the derived key from the password hash
(an example is from CCKeyDerivationPBKDF()), salt is the 32 byte randomized salt (from
CCRandomCopyBytes()), and iterations contains the number of iterations (from CCCalibratePBKDF())
using a minimum hash time of 100 milliseconds (or if not known, a number in the range 20,000 to 40,000 iterations).
This dictionary of the three keys should be placed into an outer dictionary under the key SALTED-SHA512-PBKDF2
and converted to binary data before being set into the configuration dictionary passwordHash key value.
Starting with macOS 10.13, two commands, SetFirmwarePassword and VerifyFirmwarePassword, let MDM
manage firmware passwords.
Note
There is no way through software to clear an EFI password without knowing the current password. Therefore,
if an EFI password is set before MDM can manage it, there is no way for MDM to change it unless the server
provides a way of prompting an administrator to enter the current password.
73
SetFirmwarePassword
This command changes or clears the firmware password for the device. It requires the Device Lock and Passcode
Removal Right and may be sent only on the device channel.
This command will force the firmware password mode to a value of command. It will prompt the user only if MDM is
attempting to option+boot to a different volume.
The characters in NewPassword must consist of low-ASCII printable characters (0x20 .. 0x7E) to ensure that all
characters can be entered on the EFI login screen. This is a subset of the characters allowed in the EFI login window.
However, since the exact allowed character set is not well-defined, the SetFirmwarePassword command is
conservative in limiting the characters it allows.
The device imust be restarted for the new firmware password to take effect. This command will fail and return an
error in ErrorChain if the device has a firmware change pending; see ChangePending in EFI firmware status
values.
This command will return an error if it is called again within 30 seconds after providing an incorrect password.
VerifyFirmwarePassword
This command verifies the deviceʼs firmware password. It may be sent only on the device channel.
74
Key Type Content
PasswordVerified Boolean Whether or not the provided password matches the firmware
password set for the device.
This command delays for 30 seconds so it wonʼt execute too often. If another request is received within that interval,
this command will return false and set an error in ErrorChain.
SetAutoAdminPassword
SetAutoAdminPassword allows changing the password of a local admin account that was created by Setup
Assistant during DEP enrollment via the AccountConfiguration command. It is available in macOS v10.11 and
later.
The passwordHash data objects should be created on the server using the CommonCrypto libraries or equivalent
as a salted SHA512 PBKDF2 dictionary containing three items: entropy is the derived key from the password hash
(an example is from CCKeyDerivationPBKDF()), salt is the 32 byte randomized salt (from
CCRandomCopyBytes()), and iterations contains the number of iterations (from CCCalibratePBKDF())
using a minimum hash time of 100 milliseconds (or if not known, a number in the range 20,000 to 40,000 iterations).
This dictionary of the three keys should be placed into an outer dictionary under the key SALTED-SHA512-PBKDF2
and converted to binary data before being set into the configuration dictionary passwordHash key value.
DeviceConfigured
DeviceConfigured informs the device that it can continue past DEP enrollment. It works only on devices in DEP
that have their cloud configuration set to await configuration.
Software Update
The Software Update commands allow an MDM server to perform software updates. In macOS, a variety of system
software can be updated. In iOS, only OS updates are supported.
75
On macOS, all supported Software Update commands except the AvailableOSUpdates query require DEP
enrollment.
On iOS 10.3 and later, supported Software Update commands require supervision but not DEP enrollment. If there is
a passcode on the device, a user must enter it to start a software update. Prior to iOS 10.3, the supervised devices
need to be DEP-enrolled and have no passcode.
On Shared iPad devices, these update commands are not available when any user is logged in.
The MDM server must have the App Installation right to perform these commands.
ScheduleOSUpdate
ScheduleOSUpdate requests that the device update its OS. This command overrides the
forceDelayedSoftwareUpdates restrictions for the user.
The Updates array contains dictionaries with the following keys and values:
76
Key Type Content
77
Key Type Content
Status String The status of the software update. Possible values are:
• Idle: No action is being taken on this software update.
• Downloading: The software update is being downloaded.
• DownloadFailed: The download has failed.
• DownloadRequiresComputer: The device must be
connected to a computer to download this update (iOS only).
• DownloadInsufficientSpace: There is not enough space
to download the update.
• DownloadInsufficientPower: There is not enough power
to download the update.
• DownloadInsufficientNetwork: There is insufficient
network capacity to download the update.
• Installing: The software update is being installed.
• InstallInsufficientSpace: There is not enough space
to install the update.
• InstallInsufficientPower: There is not enough power
to install the update.
• InstallPhoneCallInProgress: Installation has been
rejected because a phone call is in progress.
• InstallFailed: Installation has failed for an unspecified
reason.
ErrorChain Array Array of dictionaries describing the error that occurred.
The device may return a different InstallAction than the one that was requested.
Because software updates may happen immediately, the device may not have the opportunity to respond to an
installation command before it restarts for installation. When this happens, the MDM server should resend the
ScheduleOSUpdate request when the device checks in again. The device does not return a result dictionary in
UpdateResults for an update when it has already been installed and is no longer applicable.
ScheduleOSUpdateScan
ScheduleOSUpdateScan requests that the device perform a background scan for OS updates.
ScanInitiated Boolean Returns true if the scan was successfully initiated (macOS only).
78
This command is needed by macOS only. iOS devices respond with an Acknowledged status on success.
AvailableOSUpdates
In macOS, a ScheduleOSUpdateScan must be performed to update the results returned by this query.
In iOS and tvOS, the list will contain only the latest update available.
Each element in the AvailableOSUpdates array contains a dictionary with the following keys and values:
79
A total of DownloadSize + InstallSize bytes is needed to successfully install a software update.
OSUpdateStatus
Each entry in the OSUpdateStatus array is a dictionary with the following keys and values:
Extension Management
ActiveNSExtensions
ActiveNSExtensions returns information about the active NSExtensions for a particular user. NSExtensions are
installed and enabled at the user level; there is no concept of “device” NSExtensions.
Requires access rights to inspect installed apps. Supported only on the user channel.
80
Key Type Content
The response will be an array of dictionaries with the following keys and values:
Extensions that have been restricted from executing (via the com.apple.NSExtension configuration profile
payload or Application Launch Restrictions) will not appear in the response list.
NSExtensionMappings
NSExtensionMappings returns information about the installed extensions for a user. This command is useful when
building the set of extension identifiers and extension points for the com.apple.NSExtension profile payloads.
Requires access rights to inspect installed apps. Supported only on the user channel.
The response will be an array of dictionaries with the following keys and values:
The returned list will be a superset of the list returned by the ActiveNSExtensions command. This list may
81
contain extensions that will never be enabled on the system due to various restrictions.
The table below lists the MDM protocol request types that are available for Apple devices that run macOS. The
interfaces of these requests to macOS are similar to the iOS interfaces described in the rest of this chapter.
82
Command Min OS User/Device Comments
The RotateFileVaultKey command requires the access right “Device Lock and Passcode Removal” and is
processed only if sent to the device channel. To send a RotateFileVaultKey command, the server sends a
dictionary containing the following keys:
To unlock a device by means of a password, KeyType must be set to personal and the FileVaultUnlock
dictionary must contain this key:
Password String A FileVault userʼs password, or if using a CoreStorage volume, the current
Personal Recovery Key (PRK).
To unlock a device using the institutional recovery key, KeyType must be set to institutional and the
FileVaultUnlock dictionary must contain the following keys:
PrivateKeyExport Data The data for a .p12 export of the private key for the current
institutional recovery key.
PrivateKeyExportPassword String The password for the PrivateKeyExport.p12 data (see
above).
If the device is unlocked by means of a personal password, the response sent back to MDM server will be embedded
within a RotateResult dictionary containing the following key:
83
Key Type Content
If the device is unlocked using the institutional recovery key, no response will be needed and no dictionary will be
sent.
Error Codes
The following sections list the error codes currently returned by iOS and macOS devices. Your software should not
depend on these values, because they may change in future operating system releases. They are provided solely for
informational purposes.
MCProfileErrorDomain
Code Meaning
MCPayloadErrorDomain
Code Meaning
84
MCRestrictionsErrorDomain
Code Meaning
MCInstallationErrorDomain
Code Meaning
85
MCPasscodeErrorDomain
Code Meaning
MCKeychainErrorDomain
Code Meaning
MCEmailErrorDomain
Code Meaning
86
MCWebClipErrorDomain
Code Meaning
MCCertificateErrorDomain
Code Meaning
MCDefaultsErrorDomain
Code Meaning
MCAPNErrorDomain
Code Meaning
MCMDMErrorDomain
Code Meaning
87
Code Meaning
88
Code Meaning
MCWiFiErrorDomain
Code Meaning
89
Code Meaning
MCTunnelErrorDomain
Code Meaning
MCVPNErrorDomain
Code Meaning
MCSubCalErrorDomain
Code Meaning
MCCalDAVErrorDomain
Code Meaning
MCDAErrorDomain
90
Code Meaning
MCLDAPErrorDomain
Code Meaning
MCCardDAVErrorDomain
Code Meaning
MCEASErrorDomain
Code Meaning
MCSCEPErrorDomain
Code Meaning
91
Code Meaning
MCHTTPTransactionErrorDomain
Code Meaning
MCOTAProfilesErrorDomain
Code Meaning
MCProvisioningProfileErrorDomain
Code Meaning
MCDeviceCapabilitiesErrorDomain
Code Meaning
92
Code Meaning
MCSettingsErrorDomain
Code Meaning
MCChaperoneErrorDomain
Code Meaning
MCStoreErrorDomain
Code Meaning
MCGlobalHTTPProxyErrorDomain
Code Meaning
MCSingleAppErrorDomain
Code Meaning
MCSSOErrorDomain
93
Code Meaning
MCFontErrorDomain
Code Meaning
MCCellularErrorDomain
Code Meaning
MCKeybagErrorDomain
Code Meaning
MCDomainsErrorDomain
Code Meaning
MCWebContentFilterErrorDomain
Code Meaning
94
MCNetworkUsageRulesErrorDomain
Code Meaning
MCOSXServerErrorDomain
Code Meaning
MCHomeScreenLayoutErrorDomain
Code Meaning
MCNotificationSettingsErrorDomain
Code Meaning
MCEDUClassroomErrorDomain
Code Meaning
MCSharedDeviceConfigurationErrorDomain
Code Meaning
95
Device Enrollment Program
In iOS 7 and later and macOS v10.9 and later, the Device Enrollment Program (DEP) helps to address the mass
configuration needs of organizations purchasing and deploying devices in large quantities, without the need for
factory customization or pre-configuration of devices prior to deployment.
In iOS 11 support for DEP devices that are not supervised was deprecated. In iOS 11 and later, DEP configured
devices should always be supervised. And in a future release, the OS will ignore the DEP is_supervised flag
completely.
Note
A device enrolled in the Device Enrollment Program prompts the user to enroll in MDM during the initial device setup
process. Additionally, devices enrolled in the program can be supervised over the air. Although Appleʼs servers store
information about the deviceʼs participation in this program, the MDM profile and login challenge are served by the
organizationʼs server.
Note
When the server makes a DEP request during the initial device setup process, the device is not yet enrolled and
hence does not yet have a client certificate to present. At that time, engaging the device in additional security
processes that require a certificate will cause an NSURLErrorDomain (-1012) error.
The cloud service API provides profile management and mapping. With this API, you can obtain a list of devices,
obtain information about those devices, and associate MDM enrollment profiles with those devices.
1. Set up an account for your MDM server if you have not already done so.
2. Use the Fetch Devices endpoint to obtain devices associated with the MDM serverʼs account.
96
Note
Your server should periodically use the Sync Devices endpoint to obtain updated information about exist-
ing devices and new devices.
3. Assign a profile to the device. You can do this in one of the following ways:
• Use the Define Profile endpoint to create a new MDM server profile and associate it with one or more
devices.
• Use the Assign Profile endpoint to associate an existing MDM server profile with one or more devices.
4. Remove the profile from the device when appropriate by using the Remove Profile endpoint.
To obtain a DEP server token, the user must complete the steps outlined below. Your MDM server product can help
by automating specific steps.
1. Generate a public/private key pair in PEM format for the MDM server, and store the private key securely on the
server.
(c) Upload a PEM-encoded X.509 certificate containing the PEM public key that was generated in Step 1.
(d) Download the S/MIME encrypted token file generated by the program web portal.
Automatically
The MDM (physical) server must automatically decrypt this token file when itʼs uploaded into the system, using the
private key for the DEP web service.
97
Manually
Use the private key and provide an S/MIME encryption utility to manually decrypt the encrypted token file before it is
uploaded to the MDM server. The MDM server then ingests a plain text token file for use with the DEP web service.
MIAGCSqGSIb3DQEHA6CAMIACAQAxggGeMIIBmgIBADCBgTB1MQswCQYDVQQGEwJVUzESMBAGA1UE
ChMJWmlwcG8gSW5jMSgwJgYDVQQDEx9Qcm9maWxlIE1hbmFnZXIgUy9NSU1FIElkZW50aXR5MSgw
JgYJKoZIhvcNAQkBFhlsb2NhbEB6aXBwb2luYzIuYXBwbGUuY29tAgiDS17MvQ95HDANBgkqhkiG
9w0BAQEFAASCAQC/ukglifm8tk/OjyKBWwPbm+uDNHPG+sXLRrwfTlHKRo1jnvYrqKx1bRrpV/GR
mN7WJPBZLOkFat+LoiEmrBUiUs3PnZ+U1FUAnHR66hnomKoX0JBgfuHBGYz9jeyiu1chQShgdOOe
bYQdaFPJ/P57r98yQ2ZmyqcYOWwE0lOcqa77bfRab/YmMsMx2ZE1wUwnFPM71Yq3+vLIGLBRyvAb
4pBxDlRtgGbxs+2gZwEe0MZ4tx/97RGnZbkJt/26v5P4njGiyCvq2hZUwbria7THhMEvmJRjpZNZ
x5BfTjU8a0EHwvvwnYb67LRnjoSMn/JgelRP70O9fhdZ5Y56xhs6MIAGCSqGSIb3DQEHATAdBglg
hkgBZQMEAQIEEF5d7PQ1O8lxOLjSwjNHwFaggASCAeC9GWg9EDLpyO2g6eoOmeIVYXbWXrRt4JRY
TqCB2dWDqc9BJqOYuX5lnULjvkJ8btlBfAMhUXUb/lFF5xNXGxLTtVHvyVK9FUyhikJFweRohWqM
/xtu+7/1rPT9Nmlssla9wcTAh8GsWbs9ZyM7Pnok+o1XOwRLgh1dGvW8EGxlaPWjcHolleFBStV6
lGKJUrUyzgyBvSWo/6Y/Ojb/kfzq/kzS6H7h4YZI69/Js604rpOL6FAeOwKaJLISfUUp/yNHMBr6
wj772MNnoIdVEQs14/Fk+XVDb4xghD1zzeDow+eseb+qEfY7FkgYi2jpdebk9X4BpJ1WGvy4WiA8
biyKpst6zJb0jdJ4TE0zyIcjuVeOXuV/cD1c7YrYQty1Sh3nBsjFwVOsHq33YjapcHf2wuhXW+hh
HNzpkyMKrNcsEK1HpJva2O6vBtxtYZIn5/4kGDeALUiXxVjtvio1gS37lry5YKEwhYJ+cKKe3exZ
xhLfD67AINahDm868kEuKuHIl8gku+gSKAWlUVGNrPNt/M2rM+y4+4cm23R2f3VXYuNncnFFbulF
7VQuGd3wwtKncIACU5rze4b366rRBG1PCvB7abuRcmw9UrgzkRlH8tbOhORZ0Dgimd5knujsbKMA
AAAAAAAAAAAA
Content-Type: text/plain;charset=UTF-8
Content-Transfer-Encoding: 7bit
{”consumer_key”:”CK_9dcd8190dde27dfddd9272c657e011f7bec9761676b1b11e46a2f61d3c
b1e482ef22093c7d54b23252f3bdb4d19b4d49”,”consumer_secret”:”CS_27c083df1ab7271e
129cb23325dabaf0de95d087”,”access_token”:”AT_O365587095O8247e0b5288abcdee25642
311746d67b5858ea5cO1389734861908”,”access_secret”:”AS_8c3313de9a3462014c6c96f3
9dd7c3d4342b8cea”,”access_token_expiry”:”2015-01-14T21:27:41Z”}
98
Authentication and Authorization
To obtain OAuth access credentials for a server, download a server token file while the server is being created on the
portal. The token file contains a JSON object similar to the one shown below:
{
”consumer_key”: ”CK_00fadb3d36c6094cf479838455321b7c”,
”consumer_secret”: ”CS_5fb17e5676db0cf875211937e5166d0f662ea1f9”,
”access_token”: ”AT_O2109279022Oe03b641fd6f07d7face7894211d521fd8bef09c3O137392”,
”access_secret”: ”AS_837c228d968ff303837086a5a54be645314ef755”
”access_token_expiry”: ”2013-09-09T02:24:28Z”
}
Each service request to the MDM enrollment service must include an X-ADM-Auth-Session header.
If the request does not have a valid X-ADM-Auth-Session header, or the auth token has expired, the server returns
an HTTP 401 Unauthorized error.
UNAUTHORIZED
• consumer_key
• consumer_secret
• access_token
• access_secret
Your OAuth request must provide these pieces of information along with a timestamp (in seconds since January 1,
1970 00 00 00 GMT) and a cryptographically random nonce that must be unique for all requests made with a given
timestamp. The serverʼs time should be synchronized using time.apple.com or another trusted NTP provider.
For example:
99
oauth_token=”AT_O2109279022Oe03b641fd6f07d7face7894211d521fd8bef09c3O137392”,
oauth_signature_method=”HMAC-SHA1”,
oauth_signature=”wOJIO9A2W5mFwDgiDvZbTSMK%2FPY%3D”,
oauth_timestamp=”137131200”,
oauth_nonce=”4572616e48616d6d65724c61686176”,
oauth_version=”1.0”
Response Payload
The token service validates the request and replies with a JSON payload containing a single key,
auth_session_token, that contains the new X-ADM-Auth-Session token. For example:
HTTP/1.1 200 OK
Date: Thu, 28 Feb 2013 02:24:28 GMT
Content-Type: application/json;charset=UTF8
Content-Length: 47
Connection: close
{
”auth_session_token” : ”87a235815b8d6661ac73329f75815b8d6661ac73329f815”
}
Note
The Device Enrollment Program service periodically issues a new X-ADM-Auth-Session in its response to a
service call; the MDM server can use this new header value for any subsequent calls.
After a period of time, this token expires, and the service returns a 401 error code. At this point, the MDM server
must obtain a new session token from the https://mdmenrollment.apple.com/session endpoint.
An authentication error commonly results in either a 400, 401, or 403 error code.
100
• Invalid consumer key
• Invalid signature
• The MDM server does not have access to perform the specific request or the MDM serverʼs consumer key or
token does not have authorization to perform the specific request. In this case, the request body contains
ACCESS_DENIED.
• The organization has not accepted latest Terms and Conditions of the program. In this case, the request body
contains T_C_NOT_SIGNED.
For example, the following is the response when the MDM server is not authorized to perform a given request.
ACCESS_DENIED
Web Services
This section lists the services that Appleʼs servers provide to your MDM server. Except where otherwise specified, all
requests must be sent with the following HTTP headers:
Header Value
Note
Apple servers now run X-Server-Protocol-Version 2, which may include additional keys in the response body.
Clients running X-Server-Protocol-Version 1 should be programmed to ignore these keys.
For example:
101
User-Agent: ProfileManager-1.0
X-Server-Protocol-Version:2
X-ADM-Auth-Session: 87a235815b8d6661ac73329f75815b8d6661ac73329f815
Account Details
Each MDM server must be registered with Apple. This endpoint provides details about the server entity to identify it
uniquely throughout your organization. Each server can be identified by either its system-generated UUID or by a
user-provided name assigned by one of the organizationʼs users. Both the UUID and server name must be unique
within your organization.
URL https://mdmenrollment.apple.com/account
For example, your MDM server might make the following request:
Response Body In response, the MDM enrollment service returns a JSON dictionary with the following keys:
Key Value
102
Key Value
org_version Possible values: v1 or v2. v1 is for ADP organizations and v2 is for ASM organizations.
Currently v2 is applicable only to educational organizations. This key is available only in
protocol version 3 and later.
org_id DEP customer ID. This key is available only in protocol version 3 and later.
org_id_hash Returns the SHA hash of an org identifier. This helps MDMs match it with the
organizationIdHash key in the VPPClientConfigSrv API. This key is available only
in protocol version 3 and later.
Key Value
Key Value
For example, the server might send a response that looks like this:
HTTP/1.1 200 OK
Date: Thu, 28 Feb 2013 02:24:28 GMT
Content-Type: application/json;charset=UTF8
X-ADM-Auth-Session: 87a235815b8d6661ac73329f75815b8d6661ac73329f815
Content-Length: 640
X-Server-Protocol-Version: 3
Connection: close
{
”server_name” : ”IT Department Server”,
”server_uuid” : ”677cab70-fe18-11e2-b778-0800200c9a66”,
”admin_id” : ”[email protected]”,
”facilitator_id” : ”[email protected]”,
”org_name” : ”Sample Inc”,
”org_phone” : ”111-222-3333”,
”org_email” : ”[email protected]”,
”org_address”: ”12 Infinite Loop, Cupertino, California 95014”,
”urls” : [
{”uri”:”/account”,”http_method”:[”GET”]},
{”uri”:”/server/devices”,”http_method”:[”POST”],
”limit”:{”default”:100,”maximum”:1000}},
103
{”uri”:”/devices/sync”,”http_method”:[”POST”]},
”limit”:{”default”:100,”maximum”:1000}},
{”uri”:”/devices”,”http_method”:[”POST”]},
{”uri”:”/devices/disown”,”http_method”:[”POST”]},
{”uri”:”/profile”,”http_method”:[”POST”]},
{”uri”:”/profile/devices”,”http_method”:[”POST”]},
{”uri”:”/profile”,”http_method”:[”POST”]},
{”uri”:”/profile/devices”,”http_method”:[”GET”]},
{”uri”:”/profile/devices”,”http_method”:[”DELETE”]},
],
”org_type”:”edu”,
”org_version”:”v2”
”org_id”:”8938930387878”,
”org_id_hash”:”987559fe5f1ac383ed8ffffaa7699f80f178472f3d697104727d7c5314159d64”
}
Fetch Devices
This request fetches a list of all devices that are assigned to this MDM server at the time of the request. This service
should be used for loading an initial list of devices into the MDM serverʼs data store. Once the list of devices is
loaded, device sync requests should be used to synchronize the list with any further changes.
This request provides a limited number of entries per request, using cursors to provide position information across
requests.
Note
The server accepts only the application/json content type for this request.
URL https://mdmenrollment.apple.com/server/devices
Request Body The request body should contain a JSON dictionary with the following keys:
Key Value
cursor Optional. A hex string that represents the starting position for a request. This is used for retrieving the
list of devices that have been added or removed since a previous request. On the initial request, this
should be omitted.
limit Optional. The maximum number of entries to return. The default value is 100, and the maximum value
is 1000.
For example, your MDM server might make the following request:
104
POST /server/devices HTTP/1.1
User-Agent:ProfileManager-1.9
X-Server-Protocol-Version:2
Content-Type: application/json;charset=UTF8
X-ADM-Auth-Session: 87a235815b8d6661ac73329f75815b8d6661ac73329f815
{
”limit”: 100,
”cursor”: ”1ac73329f75815”
}
Response Body In response, the MDM enrollment service returns a JSON dictionary with the following keys:
Key Value
cursor Indicates when this request was processed by the enrollment server. The MDM server can
use this value in future requests if it wants to retrieve only records added or removed since
this request.
devices An array of dictionaries providing information about devices, sorted in chronological order
of enrollment from oldest to most recent.
fetched_until A timestamp indicating the progress of the device fetch request, in ISO 8601 format.
more_to_follow A Boolean value that indicates whether the requestʼs limit and cursor values resulted in only
a partial list of devices. If true, the MDM server should then make another request
(starting from the newly returned cursor) to obtain additional records.
Key Value
105
Key Value
device_family The deviceʼs Apple product family: iPad, iPhone, iPod, Mac, or AppleTV. This
key is valid in X-Server-Protocol-Version 2 and later.
For example, the server might send a response that looks like this:
HTTP/1.1 200 OK
Date: Thu, 9 May 2013 02:24:28 GMT
Content-Type: application/json;charset=UTF8
X-ADM-Auth-Session: 87a235815b8d6661ac73329f75815b8d6661ac73329f815
Content-Length: 640
Connection: Keep-Alive
{
”devices” : [
{
”serial_number” : ”C8TJ500QF1MN”,
”model” : ”IPAD”,
”description” : ”IPAD WI-FI 16GB”,
”color” : ”black”,
”asset_tag” : ”304214”,
”profile_status” : ”empty”,
”device_assigned_date” : ”2013-04-05T14:30:00Z”,
”device_assigned_by” : ”[email protected]”,
”os” : ”iOS”,
”device_family” : ”iPad”
},
{
”serial_number” : ”C8TJ500QF1MN”,
”model” : ”IPAD”,
”description” : ”IPAD WI-FI 16GB”,
”color” : ”white”,
”profile_status” : ”assigned”,
”profile_uuid” : ”88fc4e378fea4021a94b2d7268fbf767”,
”profile_assign_time” : ”2013-05-01T00:00:00Z”,
”device_assigned_date” : ”2013-04-05T15:30:00Z”,
”device_assigned_by” : ”[email protected]”,
”os” : ”iOS”,
”device_family” : ”iPad”
}
[email protected]
]
”fetched_until” : ”2013-05-09T02:24:28Z”,
”cursor” : ”1ac73329f75815”,
”more_to_follow” : ”false”
}
106
Request-Specific Errors In addition to the standard errors listed in Common Error Codes, this request can return
the following errors:
• A 400 error with INVALID_CURSOR in the response body indicates that an invalid cursor value was provided.
• A 400 error with EXHAUSTED_CURSOR in the response body indicates that the cursor had returned all devices
in previous calls.
Sync Devices
The sync service depends on a cursor returned by the fetch device service. It returns a list of all modifications
(additions or deletions) since the specified cursor. The cursor passed to this endpoint should not be older than 7
days.
This service may return the same device more than once. You must resolve duplicates by matching on the device
serial number and the op_type and op_date fields. The record with the latest op_date indicates the last known
state of the device in DEP.
Note
The server accepts only the application/json content type for this request.
URL https://mdmenrollment.apple.com/devices/sync
Request Body The request body should contain a JSON dictionary with the following keys:
Key Value
cursor A hex string returned by a previous request that represents the starting position for a request.
The request returns results that describe any changes or additions to devices that happened after this
starting position.
limit Optional. The maximum number of entries to return. The default value is 100, and the maximum value
is 1000.
For example, your MDM server might make the following request:
107
}
Response Body In response, the MDM enrollment service returns a JSON dictionary with the following keys:
Key Value
cursor Indicates when this request was processed by the server. The MDM server can use this
value in future requests if it wants to retrieve only records added or removed since this
request.
more_to_follow Indicates that the requestʼs limit and cursor values resulted in only a partial list of devices.
The MDM server should immediately make another request (starting from the newly
returned cursor) to obtain additional records.
devices An array of dictionaries providing information about devices, sorted in chronological order
by the time stamp of the operation performed on the device.
fetched_until A date stamp indicating the progress of the device fetch request, in ISO 8601 format.
Key Value
For example, the server might send a response that looks like this:
108
HTTP/1.1 200 OK
Date: Thu, 9 May 2013 03:24:28 GMT
Content-Type: application/json;charset=UTF8
X-ADM-Auth-Session: 87a235815b8d6661ac73329f75815b8d6661ac73329f815
Content-Length: 640
Connection: Keep-Alive
{
”devices” : [
{
”serial_number” : ”C8TJ500QF1MN”,
”model” : ”IPAD”,
”color” : ”black”,
”description” : ”IPAD WI-FI 16GB”,
”asset_tag” : ”304214”,
”profile_status” : ”empty”,
”op_type” : ”added”,
”op_date” : ”2013-05-09T14:30:00Z”,
”device_assigned_by” : ”[email protected]”,
”device_assigned_date” : ”2013-05-09T14:30:00Z”,
”os” : ”iOS”,
”device_family” : ”iPad”
},
{
”serial_number” : ”C8TJ500QF1MN”,
”model” : ”IPAD”,
”color” : ”white”,
”description” : ”IPAD WI-FI 16GB”,
”op_type” : ”deleted”,
”op_date” : ”2013-05-09T14:30:00Z”,
”device_assigned_by” : ”[email protected]”,
”device_assigned_date” : ”2013-05-09T14:30:00Z”,
”os” : ”iOS”,
”device_family” : ”iPad”
}
],
”more_to_follow” : false,
”cursor” : ”2ac73329f75815”
}
Request-Specific Errors In addition to the standard errors listed in Common Error Codes, this request can return
the following errors:
• A 400 error with CURSOR_REQUIRED in the response body indicates that no cursor value was provided.
• A 400 error with INVALID_CURSOR in the response body indicates that an invalid cursor value was provided.
109
• A 400 error with EXPIRED_CURSOR in the response body indicates that the provided cursor is older than 7
days.
Device Details
Note
The server accepts only the application/json content type for this request.
URL https://mdmenrollment.apple.com/devices
Request Body The request body should contain a JSON dictionary with the following keys:
Key Value
For example, your MDM server might make the following request:
{
”devices”:[”C8TJ500QF1MN”, ”B7CJ500QF1MA”]
}
Response Body In response, the MDM enrollment service returns a JSON dictionary of dictionaries. The outer
dictionary keys are the serial numbers from the original request. Each value is a dictionary with the following keys:
Key Value
110
Key Value
For example, the server might send a response that looks like this:
HTTP/1.1 200 OK
Date: Thu, 9 May 2013 03:24:28 GMT
Content-Type: application/json;charset=UTF8
X-ADM-Auth-Session: 87a235815b8d6661ac73329f75815b8d6661ac73329f815
Content-Length: 259
Connection: Keep-Alive
{
”devices”:
{
”C8TJ500QF1MN” :
{
<CodeLine xml:space=”preserve”> ”serial_number”:”C8TJ500QF1MN”,</CodeLine>
”response_status” : ”SUCCESS”,
”os” : ”iOS”,
”device_family” : ”iPad”,
”model” : ”IPAD”,
”description” : ”IPAD WI-FI 16GB”,
”color”: ”BLACK”,
”asset_tag” : ”304214”,
”device_assigned_by” : ”[email protected]”,
”device_assigned_date” : ”2013-01-01T14:30:00Z”,
”profile_uuid” : ”88fc4e378fea4021a94b2d7268fbf767”,
”profile_assign_time” : ”2013-01-01T00:00:00Z”,
”profile_push_time” : ”2013-02-01T00:00:00Z”
},
”B7CJ500QF1MA” : {
”response_status” : ”NOT_FOUND”
111
}
}
}
Request-Specific Errors In addition to the standard errors listed in Common Error Codes, this request can return
the following errors:
• A 200 error with NOT_FOUND in the response body indicates that the specified device is not accessible by the
MDM server.
• A 400 error with DEVICE_ID_REQUIRED in the response body indicates that the request did not contain any
devices.
Disown Devices
Tells Appleʼs servers that your organization no longer owns one or more devices.
Warning
Disowning a device is a permanent action. After a short grace period, a disowned device cannot be reassigned
to an MDM server in your organization.
Note
The server accepts only the application/json content type for this request.
URL https://mdmenrollment.apple.com/devices/disown
Request Body The request body should contain a JSON dictionary with the following keys:
Key Value
For example, your MDM server might make the following request:
112
X-ADM-Auth-Session: 87a235815b8d6661ac73329f75815b8d6661ac73329f815
{
”devices”:[”C8TJ500QF1MN”, ”B7CJ500QF1MA”]
}
Response Body In response, the MDM enrollment service returns a JSON dictionary with the following keys:
Key Value
devices A dictionary of devices. Each key in this dictionary is the serial number of a device in the original
request. Each value is one of the following values:
• SUCCESS: Device was successfully disowned.
• NOT_ACCESSIBLE: A device with the specified ID was not accessible by this MDM server.
• FAILED: Disowning the device failed for an unexpected reason. If three retries fail, the user
should contact Apple support.
If no devices were provided in the original request, this dictionary may be absent.
For example, the server might send a response that looks like this:
HTTP/1.1 200 OK
Date: Thu, 9 May 2013 03:24:28 GMT
Content-Type: application/json;charset=UTF8
X-ADM-Auth-Session: 87a235815b8d6661ac73329f75815b8d6661ac73329f815
Content-Length: 160
Connection: Keep-Alive
{
”devices”: {
”C8TJ500QF1MN”:”SUCCESS”,
”B7CJ500QF1MA”:”NOT_ACCESSIBLE”
}
}
Request-Specific Errors In addition to the standard errors listed in Common Error Codes, this request can return
the following errors:
• A 400 error code with DEVICE_ID_REQUIRED in the response body indicates that no device IDs (serial
numbers) were provided.
Activation Lock
Find My iPhone Activation Lock is a feature of iCloud that makes it harder for anyone to use or resell a lost or stolen
iOS device that has been enrolled under DEP.
113
The Activation Lock request is available in X-Server-Protocol-Version 2 and later to organizations that have enrolled
through the Apple School Manager portal or Apple Business Manager portal.
Request To lock a device, POST an HTTP request in application/json format to the following URL:
https://mdmenrollment.apple.com/device/activationlock. The request header must follow this
format:
Immediately following the request header, send these content keys and values in application/json format:
b325071e6deb84285a6bfb34”,
”lost_message”: ”Please phone 1-800-555-1212”
}
Response The Apple server responds to the Activation Lock request with the following two keys:
114
Key Type Content
Response Reason
NOT_ACCESSIBLE A device with this serial number is not accessible by this user.
ORG_NOT_SUPPORTED A device with this serial number is not supported because it is not present in the
new program.
DEVICE_NOT_SUPPORTED Device type is not supported like Mac.
DEVICE_ALREADY_LOCKED Device is already locked by someone.
FAILED Activation lock of the device failed for unexpected reason. If retry fails, the client
should contact Apple support.
HTTP/1.1 200 OK
Date: Thu, 9 May 2013 03:24:28 GMT
Content-Type: application/json;charset=UTF8
X-ADM-Auth-Session: 87a235815b8d6661ac73329f75815b8d6661ac73329f815
Content-Length: 160
Connection: Keep-Alive
{
”serial_number” : ”B7CJ500QF1MA”,
”response_status” : ”SUCCESS”
}
Server failures during activation lock attempts typically look like one of the following two examples:
A client failure during an activation lock attempt may look like this:
115
Date: Thu, 31 May 2012 21:23:57 GMT
Connection: close
<ERROR_CODE>
The combination of the ERROR_CODE in the response body shown above and the HTTP error typically indicates one
of the following reasons for a client failure during an activation lock attempt:
• UNAUTHORIZED + HTTP 401: The auth token has expired. The client should retry with a new auth token.
iOS 7.1 adds support for Activation Lock Bypass. This allows organizations to remove the Activation Lock from
supervised devices prior to device activation without knowing the userʼs personal Apple ID and password.
When an iOS device is configured as supervised it can generate a device-specific Activation Lock bypass code. A
cryptographically-secure hash of the bypass code is stored by Appleʼs activation server. This hash allows the
activation server to verify that the correct bypass code has been provided to the device. For further information see
Escrow Keys and Bypass Codes.
When the device creates a bypass code and hash, theyʼre stored in the deviceʼs keychain and marked as available
after first unlock and non-exportable.
To retrieve the bypass code, the MDM server uses the ActivationLockBypassCode query:
Note
The activation lock bypass code must be requested before the device receives the MDMOptions Sets Options
Related to the MDM Protocol setting that enables Activation Lock. If this sequence is not followed the user may
lock the device before MDM installs the bypass, in which case the bypass code will not work.
If a bypass code has never been created on the device, a new one is created when this query is received. If you have
cleared the bypass code, or it has expired, the server will receive an error noting that the code has expired. The error
code will be 12085.
Once retrieved and stored by the MDM server, the bypass code can be removed from the device using the
116
ClearActivationLockBypassCode command:
ClearActivationLock String Supervised only. Clears the activation lock bypass code from
BypassCode the device.
If the command is successful, an Acknowledged status is returned. If not removed, the bypass code is automatically
deleted from the device after 15 days.
Once a device is erased, the bypass code can be manually entered when prompted by the Setup Assistant, leaving
the username field empty. However, itʼs recommended that an MDM server should clear the activation lock, using
the web service described below, prior to erasing a device.
Authentication The MDM server must provide its APNS certificate when establishing the SSL connection with the
web service.
Request To remove an activation lock, provide the deviceʼs bypass code to the web service. The request should be
a standard HTTPS POST on port 443 to https://deviceservices-external.apple.com/
deviceservicesworkers/escrowKeyUnlock. The request must also have the contentType header set to
application/x-www-form-urlencoded.
The following arguments must be provided as part of the URL request string:
Argument Description
Argument Description
orgName Client-supplied value for auditing purposes: a string such as the name of the organization.
guid Client-supplied value for auditing purposes: a string that identifies the user requesting the removal
(email, LDAP ID, name, etc.).
escrowKey The deviceʼs bypass code. For further information see Escrow Keys and Bypass Codes.
Arguments provided in the message body should be formatted as parameters in a form submission. For example:
escrowKey=abcdefg&orgName=Acme+Inc&guid=123456
117
HTTP Response Codes The services can return any of the HTTP status codes, and the client is expected to
handle the range of status codes. The more common ones include:
Code Description
200 Success.
400 Failure: bad request; likely cause is a malformed request query or body.
404 Failure: device is not found, or escrowKey is invalid.
500 Unexpected server error; try again later.
Response Body Format The response body may contain diagnostic information useful when reporting issues to
Apple. Do not rely on specific codes, because they may change.
• The device-generated bypass code retrieved using the ActivationLockBypassCode device query. The
server should retain this code until it receives a different, non-empty code from the device.
• The bypass code the server creates when initiating an activation lock through MDM.
The server should try to unlock the device with the bypass code most likely to be active, then try the other code if the
first one fails. It is impossible for the server to be certain which code is active at a given time (or even to determine if
the device is locked at all) because the device can always be erased and its activation lock removed manually by
entering the correct Apple ID or password. The deviceʼs IsActivationLockEnabled value is not an accurate
reflection of its true activation lock state because the device can report either a false positive or a false negative.
Following is a sample of code that generates both an escrow key and a bypass code:
- (NSString*) _createNewActivationLockBypassCodeOutHash:(NSString**)outHash
{
#define RANDOM_BYTES_LENGTH 16
#define SALT_LENGTH 4
// Encode raw bytes
static const char kSymbols[] = ”0123456789ACDEFGHJKLMNPQRTUVWXYZ”;
// 00000000000000001111111111111111
// 0123456789abcdef0123456789abcdef
char rawBytes[MCBYPASS_RAW_BYTES_LENGTH];
char code[MCBYPASS_CODE_BUFFER_LENGTH];
118
uint8_t hash[MCBYPASS_HASH_LENGTH];
uint8_t salt[SALT_LENGTH] = {0, 0, 0, 0};
arc4random_buf(rawBytes, RANDOM_BYTES_LENGTH);
CCKeyDerivationPBKDF(kCCPBKDF2, rawBytes, RANDOM_BYTES_LENGTH, salt, SALT_LENGTH,
kCCPRFHmacAlgSHA256, 50000, hash, CC_SHA256_DIGEST_LENGTH);
if (outHash) {
int len = MCBYPASS_HASH_LENGTH;
NSMutableString* str = [NSMutableString stringWithCapacity:MCBYPASS_HASH_LENGTH
* 2 + 1];
const uint8_t* p = (const uint8_t*)hash;
while (len-- > 0) [str appendFormat:@”%02X”, *p++];
*outHash = [NSString stringWithString:str];
}
int outputCharacterCount = 0;
const int* nextDashPosition = kDashPositions;
char* outputCursor = code;
uint8_t* inputCursor = (uint8_t*)rawBytes;
int bitsProcessed = 0;
int bitOffsetIntoByte = 0;
while (bitsProcessed <= (INPUT_BITS - BITS_PER_SYMBOL)) {
int bitsThisByte = (bitOffsetIntoByte < BITS_PER_BYTE - BITS_PER_SYMBOL
? BITS_PER_SYMBOL : BITS_PER_BYTE - bitOffsetIntoByte);
int bitsNextByte = (bitsThisByte < BITS_PER_SYMBOL ? BITS_PER_SYMBOL
- bitsThisByte : 0);
bitOffsetIntoByte += BITS_PER_SYMBOL;
if (bitOffsetIntoByte >= BITS_PER_BYTE) {
bitOffsetIntoByte -= BITS_PER_BYTE;
inputCursor++;
}
if (bitsNextByte) {
value <<= bitsNextByte;
value |= (*inputCursor >> (BITS_PER_BYTE - bitsNextByte));
}
119
*outputCursor++ = kSymbols[value];
if (++outputCharacterCount == *nextDashPosition) {
++nextDashPosition;
*outputCursor++ = '-';
}
bitsProcessed += BITS_PER_SYMBOL;
} // while
Define Profile
Tells Appleʼs servers about a profile that can then be assigned to specific devices. This command provides
information about the MDM server that is assigned to manage one or more devices, information about the host that
the managed devices can pair with, and various attributes that control the MDM association behavior of the device.
URL https://mdmenrollment.apple.com/profile
Request Body The request body should contain a JSON dictionary with the following keys:
Key Value
120
Key Value
is_multi_user Optional. Boolean. If true, tells the device to configure for Shared iPad.
Default is false. This key is valid only for Apple School Manager
organizations using X-Server-Protocol-Version 2 and later.
Devices that do not meet the Shared iPad minimum requirements do not honor
this command. With iOS devices,
com.apple.mdm.per-user-connections must be added to the MDM
enrollment profileʼs ServerCapabilities. See iOS Support for Per-User
Connections.
is_mandatory Optional. Boolean. If true, the user may not skip applying the profile returned
by the MDM server. Default is false.
await_device_configured Optional. Boolean. If true, the device will not continue in Setup Assistant until
the MDM server sends a command stating that the device is configured (see
DeviceConfigured). Default is false. Ignored on iOS devices if
is_supervised is false. This key is valid in X-Server-Protocol-Version 2
and later.
is_mdm_removable If false, the MDM payload delivered by the configuration URL cannot be
removed by the user via the user interface on the device; that is, the MDM
payload is locked onto the device. This key can be set to false only if
is_supervised is set to true. Defaults to true.
support_phone_number Optional. String. A support phone number for the organization.
auto_advance_setup Optional. Boolean. If set to true, the device will tell tvOS Setup Assistant to
automatically advance though its screens. Default is false. This key is valid in
X-Server-Protocol-Version 2 and later.
support_email_address Optional. String. A support email address for the organization. This key is valid
in X-Server-Protocol-Version 2 and later.
org_magic A string that uniquely identifies various services that are managed by a single
organization.
anchor_certs Optional. Array of strings. Each string should contain a DER-encoded
certificate converted to Base64 encoding. If provided, these certificates are
used as trusted anchor certificates when evaluating the trust of the connection
to the MDM server URL. Otherwise, the built-in root certificates are used.
supervising_host_certs Optional. Array of strings. Each string contains a DER-encoded certificate
converted to Base64 encoding. If provided, the device will continue to pair
with a host possessing one of these certificates even when allow_pairing
is set to false. If is_supervised is false, this list is unused.
121
Key Value
skip_setup_items Optional. Array of strings. A list of setup panes to skip. The array may contain
one or more of the following strings:
• AppleID: Skips Apple ID setup.
• Biometric: Skips Touch ID setup.
• Diagnostics: Disables automatically sending diagnostic information.
• DisplayTone: Skips DisplayTone setup.
• Location: Disables Location Services.
• Passcode: Hides and disables the passcode pane.
• Payment: Skips Apple Pay setup.
• Privacy: Skips privacy pane.
• Restore: Disables restoring from backup.
• SIMSetup: Skips the add cellular plan pane.
• Siri: Disables Siri.
• TOS: Skips Terms and Conditions.
• Zoom: Skips zoom setup.
• Android: If the Restore pane is not skipped, removes the ”Move from
Android” option from the Restore pane on iOS.
• HomeButtonSensitivity: Skips the Home Button screen in iOS.
• iMessageAndFaceTime: Skips the iMessage and FaceTime screen in
iOS.
• OnBoarding: Skips on-boarding informational screens for user
education (“Cover Sheet, Multitasking & Control Center”, for example) in
iOS.
• ScreenTime: Skips the screen for Screen Time in iOS.
• SoftwareUpdate: Skips the mandatory software update screen in iOS.
• WatchMigration: Skips the screen for watch migration in iOS.
• Appearance: Skips the Choose Your Look screen in macOS.
• FileVault: Disables FileVault Setup Assistant screen in macOS.
• iCloudDiagnostics: Skips iCloud Analytics screen in macOS.
• iCloudStorage: Skips iCloud Documents and Desktop screen in
macOS.
• Registration: Disables registration screen in macOS.
• ScreenSaver: Skips the tvOS screen about using aerial screensavers
in ATV.
• TapToSetup: Skips the Tap To Set Up option in ATV about using an iOS
device to set up your ATV (instead of entering all your account
information and setting choices separately).
• TVHomeScreenSync: Skips TV home screen layout sync screen in
tvOS.
• TVProviderSignIn: Skips the TV provider sign in screen in tvOS.
• TVRoom: Skips the “Where is this Apple TV?” screen in tvOS.
department Optional. String. The user-defined department or location name.
devices Array of strings containing device serial numbers. (May be empty.)
122
Key Value
For example, your MDM server might make the following request:
{
”profile_name”: ”Test Profile”,
”url”:”https://mdm.acmeinc.com/getconfig”,
”is_supervised”:false,
”allow_pairing”:true,
”is_mandatory”:false,
”await_device_configured”:false,
”is_multi_user”:false,
”is_mdm_removable”:false,
”department”: ”IT Department”,
”org_magic”: ”913FABBB-0032-4E13-9966-D6BBAC900331”,
”support_phone_number”: ”1-555-555-5555”,
”anchor_certs”:[
”MIICkDCCAfmgAwIBAgIJAOAeuvyohALaMA0GCSqGSIb3DQEBBQUAMGExCzAJBgNVBAYT...”
],
”supervising_host_certs:[
”…AlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJQ3VwZXJ0aW5vMRowGAYDVQQKDBFB”
],
”skip_setup_items”:[
”Location”,
”Restore”,
”Android”,
”AppleID”,
”TOS”,
123
”Siri”,
”Diagnostics”,
”HomeButtonSensitivity”,
”Biometric”,
”Payment”,
”Zoom”,
”DisplayTone”,
”FileVault”,
”TapToSetup”,
”ScreenSaver”
],
”devices”:[”C8TJ500QF1MN”, ”B7CJ500QF1MA”]
}
Response Body In response, the MDM enrollment service returns a JSON dictionary with the following keys:
Key Value
For example, the server might send a response that looks like this:
HTTP/1.1 200 OK
Date: Thu, 9 May 2013 03:24:28 GMT
Content-Type: application/json;charset=UTF8
X-ADM-Auth-Session: 87a235815b8d6661ac73329f75815b8d6661ac73329f815
Content-Length: 160
Connection: Keep-Alive
{
”profile_uuid”: ”88fc4e378fea4021a94b2d7268fbf767”,
”devices”: {
”C8TJ500QF1MN”:”SUCCESS”,
”B7CJ500QF1MA”:”NOT_ACCESSIBLE”
}
}
124
Request-Specific Errors In addition to the standard errors listed in Common Error Codes, this request can return
the following errors:
• A 400 error code with CONFIG_URL_REQUIRED in the response body indicates that the MDM server URL is
missing in the profile.
• A 400 error code with CONFIG_NAME_REQUIRED in the response body indicates that the configuration name
is missing in the profile.
• A 400 error code with FLAGS_INVALID in the response body indicates that flags have been set incorrectly.
Flag is_mdm_removable can be set to false only if flag is_supervised is set to true.
• A 400 error code with CONFIG_URL_INVALID in the response body indicates that the URL field in the
uploaded profile is either empty or has exceeded the maximum allowed length (2000 URL encoded
characters). The syntax of the URL is defined by RFC 2396: Uniform Resource Identifiers (URI): Generic
Syntax, amended by RFC 2732: Format for Literal IPv6 Addresses in URLs.
• A 400 error code with CONFIG_NAME_INVALID in the response body indicates that the profile_name field
in the uploaded profile is either empty or has exceeded the maximum allowed length (125 UTF-8 characters).
• A 400 error code with DEPARTMENT_INVALID in the response body indicates that the department field in
the uploaded profile is either empty or has exceeded the maximum allowed length (125 UTF-8 characters).
• A 400 error code with SUPPORT_PHONE_INVALID in the response body indicates that the
support_phone_number field in the uploaded profile is either empty or has exceeded the maximum
allowed length (50 UTF-8 characters).
• A 400 error code with SUPPORT_EMAIL_INVALID in the response body indicates that the
support_email_address field in the uploaded profile is either empty or has exceeded the maximum
allowed length (250 UTF-8 characters).
• A 400 error code with MAGIC_INVALID in the response body indicates that the magic field in the uploaded
profile is either empty or has exceeded the maximum allowed length (256 UTF-8 characters).
• A 400 error code with LOCALE_INVALID in the response body indicates that the local fields combination is
invalid or unsupported.
Assign Profile
Tells Appleʼs severs that the specified devices should use a particular profile defined by the Define Profile command.
URL https://mdmenrollment.apple.com/profile/devices
Request Body The request body should contain a JSON dictionary with the following keys:
Key Value
profile_uuid The UUID (string) for the profile that you want to assign to the specified devices. This UUID
was returned by a previous Define Profile request.
125
Key Value
devices Array of strings containing device serial numbers. An empty array is considered a no-op.
For example, your MDM server might make the following request:
{
”profile_uuid”: ”88fc4e378fea4021a94b2d7268fbf767”,
”devices”:[”C8TJ500QF1MN”, ”B7CJ500QF1MA”]
}
Response Body In response, the MDM enrollment service returns a JSON dictionary with the following keys:
Key Value
For example, the server might send a response that looks like this:
HTTP/1.1 200 OK
Date: Thu, 9 May 2013 03:24:28 GMT
Content-Type: application/json;charset=UTF8
X-ADM-Auth-Session: 87a235815b8d6661ac73329f75815b8d6661ac73329f815
Content-Length: 160
Connection: Keep-Alive
{
”profile_uuid”: ”88fc4e378fea4021a94b2d7268fbf767”,
”devices”: {
”C8TJ500QF1MN”:”SUCCESS”,
”B7CJ500QF1MA”:”NOT_ACCESSIBLE”
}
126
}
Request-Specific Errors In addition to the standard errors listed in Common Error Codes, this request can return
the following errors:
• A 400 error with DEVICE_ID_REQUIRED in the body of the response indicates that the request did not
contain any device IDs.
• A 400 error with PROFILE_UUID_REQUIRED in the body of the response indicates that the request did not
contain a profile ID.
• A 404 error with NOT_FOUND in the body of the response indicates that the profile with the specified UUID
could not be found.
Fetch Profile
URL https://mdmenrollment.apple.com/profile
Request Query The query string should contain the following keys:
Key Value
For example, your MDM server might make the following request:
Response Body In response, the MDM enrollment service returns a JSON dictionary with the following keys:
Key Value
127
Key Value
is_supervised Optional. Boolean. If true, the device must be supervised. Defaults to false.
In iOS 11, DEP devices that are not supervised have been deprecated. In a
future release, all DEP devices will be supervised and the OS will ignore the
is_supervised flag completely.
is_multi_user Optional. Boolean. If true, tells the device to configure for Shared iPad.
Default is false. This key is valid only for Apple School Manager
organizations using X-Server-Protocol-Version 2 and later.
Devices that do not meet the Shared iPad minimum requirements do not honor
this command. With iOS devices,
com.apple.mdm.per-user-connections must be added to the MDM
enrollment profileʼs ServerCapabilities. See iOS Support for Per-User
Connections.
is_mandatory Optional. Boolean. If true, the user may not skip applying the profile returned
by the MDM server. Default is false.
await_device_configured Optional. Boolean. If true, the device will not continue in Setup Assistant until
the MDM server sends a command stating that the device is configured (see
DeviceConfigured). Default is false. Ignored on iOS devices if
is_supervised is false. This key is valid in X-Server-Protocol-Version 2
and later.
is_mdm_removable If false, the MDM payload delivered by the configuration URL cannot be
removed by the user using the user interface on the device; that is, the MDM
payload is locked onto the device. Defaults to true.
support_phone_number Optional. String. A support phone number for the organization.
support_email_address Optional. String. A support email address for the organization. This key is valid
in X-Server-Protocol-Version 2 and later.
org_magic A string that uniquely identifies various services that are managed by a single
organization.
anchor_certs Optional. Array of strings. Each string should contain a DER-encoded
certificate converted to Base64 encoding. If provided, these certificates are
used as trusted anchor certificates when evaluating the trust of the connection
to the MDM server URL. Otherwise, the built-in root certificates are used.
supervising_host_certs Optional. Array of strings. Each string contains a DER-encoded certificate
converted to Base64 encoding. If provided, the device will continue to pair
with a host possessing one of these certificates even when allow_pairing
is set to false. If is_supervised is false, this list is unused.
128
Key Value
skip_setup_items Optional. Array of strings. A list of setup panes to skip. The array may contain
one or more of the following strings:
• AppleID: Skips Apple ID setup.
• Biometric: Skips Touch ID setup.
• Diagnostics: Disables automatically sending diagnostic information.
• DisplayTone: Skips DisplayTone setup.
• Location: Disables Location Services.
• Passcode: Hides and disables the passcode pane.
• Payment: Skips Apple Pay setup.
• SIMSetup: Skips the add cellular plan pane.
• Privacy: Skips privacy pane.
• Restore: Disables restoring from backup.
• Siri: Disables Siri.
• TOS: Skips Terms and Conditions.
• Zoom: Skips zoom setup.
• Android: If the Restore pane is not skipped, removes the ”Move from
Android” option from the Restore pane on iOS.
• HomeButtonSensitivity: Skips the Home Button screen in iOS.
• iMessageAndFaceTime: Skips the iMessage and FaceTime screen in
iOS.
• OnBoarding: Skips on-boarding informational screens for user
education (“Cover Sheet, Multitasking & Control Center”, for example) in
iOS.
• ScreenTime: Skips the screen for Screen Time in iOS.
• SoftwareUpdate: Skips the mandatory software update screen in iOS.
• WatchMigration: Skips the screen for watch migration in iOS.
• Appearance: Skips the Choose Your Look screen in macOS.
• FileVault: Disables FileVault Setup Assistant screen in macOS.
• iCloudDiagnostics: Skips iCloud Analytics screen in macOS.
• iCloudStorage: Skips iCloud Documents and Desktop screen in
macOS.
• Registration: Disables registration screen in macOS.
• ScreenSaver: Skips the tvOS screen about using aerial screensavers
in ATV.
• TapToSetup: Skips the Tap To Set Up option in ATV about using an iOS
device to set up your ATV (instead of entering all your account
information and setting choices separately).
• TVHomeScreenSync: Skips TV home screen layout sync screen in
tvOS.
• TVProviderSignIn: Skips the TV provider sign in screen in tvOS.
• TVRoom: Skips the “Where is this Apple TV?” screen in tvOS.
department Optional. The user-defined department or location name.
129
Key Value
For example, the server might send a response that looks like this:
HTTP/1.1 200 OK
Date: Thu, 28 Feb 2013 02:24:28 GMT
Content-Type: application/json;charset=UTF8
X-ADM-Auth-Session: 87a235815b8d6661ac73329f75815b8d6661ac73329f815
Content-Length: 160
Connection: Keep-Alive
{
”profile_uuid”: ”88fc4e378fea4021a94b2d7268fbf767”,
”profile_name”: ”Test Profile”,
”url”:”https://mdm.acmeinc.com/getconfig”,
”is_supervised”:false,
”allow_pairing”:true,
”is_mandatory”:false,
”await_device_configured”:false,
”is_mdm_removable”:false,
”department”: ”IT Department”,
”org_magic”: ”913FABBB-0032-4E13-9966-D6BBAC900331”,
”support_phone_number”: ”1-555-555-5555”,
”support_email_address”: ”[email protected]”,
”anchor_certs”:[
”MIICkDCCAfmgAwIBAgIJAOAeuvyohALaMA0GCSqGSIb3DQEBBQUAMGExCzAJBgNVBAYT...”
],
”supervising_host_certs:[
”…AlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJQ3VwZXJ0aW5vMRowGAYDVQQKDBFB”
],
”skip_setup_items”:[
”Location”,
”Restore”,
”Android”,
”AppleID”,
”TOS”,
”Siri”,
130
”Diagnostics”,
”Biometric”,
”Payment”,
”Zoom”,
”FileVault”,
”TapToSetup”,
”ScreenSaver”
]
}
Request-Specific Errors In addition to the standard errors listed in Common Error Codes, this request can return
the following errors:
• A 400 error with PROFILE_UUID_REQUIRED in the body of the response indicates that the request did not
contain a profile UUID.
• A 404 error with NOT_FOUND in the body of the response indicates that a profile cannot be found for the
requested profile UUID.
• A 400 error code with LOCALE_INVALID in the response body indicates that the local fields combination is
invalid or unsupported.
Request to a Profile URL When a url value is provided in the profile response, the device makes an HTTPS POST
call to that URL. The requesthas a Content-Type of application/pkcs7-signature. The following dictionary is
sent as the body of the request. The dictionary is encoded as an XML plist and then CMS-signed and DER-encoded:
The plist is CMS-signed with the device identity certificate. The deviceʼs certificate and all necessary intermediate
certificates are included. The certificate chain should validate against the Apple Root CA.
The server may respond with a 401 (Unauthorized) status message to prompt the user for a login. If this response is
sent, the WWW-Authenticate header must contain the Digest authentication method. In iOS 7.1, the
WWW-Authenticate header may also contain the Basic authentication method as outlined in RFC2617. When the
user enters a username and password, the request is retried with the appropriate Authorization header.
If a 401 status is sent, the content of the response is shown above the prompt for the username and password. If the
content is empty, a default message is displayed.
The server may respond with a 200 (OK) status to indicate a successful retrieval of the configuration profile. The
131
configuration profile containing the MDM payload and one or more SCEP or certificate payloads must be included in
the message body.
Remove Profile Removes profile mapping from the list of devices from Appleʼs servers. After this call, the devices
in the list will have no profiles associated with them. However, if those devices have already obtained the profile, this
has no effect until the device is wiped and activated again.
URL https://mdmenrollment.apple.com/profile/devices
Request Body The request body should contain a JSON dictionary with the following keys:
Key Value
For example, your MDM server might make the following request:
{
”devices”:[”C8TJ500QF1MN”, ”B7CJ500QF1MA”]
}
Response Body In response, the MDM enrollment service returns a JSON dictionary with the following keys:
Key Value
devices A dictionary of devices. Each key in this dictionary is the serial number of a device in the original
request. Each value in this dictionary is one of the following strings:
• SUCCESS: Profile was removed from the device.
• NOT_ACCESSIBLE: A device with the specified serial number was not found.
• FAILED: Removing the profile failed for an unexpected reason. If three retries fail, the user
should contact Apple support.
For example, the server might send a response that looks like this:
132
HTTP/1.1 200 OK
Date: Thu, 9 May 2013 03:24:28 GMT
Content-Type: application/json;charset=UTF8
X-ADM-Auth-Session: 87a235815b8d6661ac73329f75815b8d6661ac73329f815
Content-Length: 160
Connection: Keep-Alive
{
”devices”: {
”C8TJ500QF1MN”:”SUCCESS”,
”B7CJ500QF1MA”:”NOT_ACCESSIBLE”
}
}
Request-Specific Errors In addition to the standard errors listed in Common Error Codes, this request can return
the following errors:
• A 400 error with DEVICE_ID_REQUIRED in the body of the response indicates that the request did not
contain any device serial numbers.
• An HTTP 400 error with MALFORMED_REQUEST_BODY in the response body indicates that the request body
was not valid JSON.
• An HTTP 401 error with UNAUTHORIZED in the response body indicates that the authentication token has
expired. This error indicates that the MDM server should obtain a new auth token from the
https://mdmenrollment.apple.com/session endpoint.
• An HTTP 403 error with FORBIDDEN in the response body indicates that the authentication token is invalid.
• An HTTP 405 error means that the method (query type) is not valid.
For example, the following is the response when an authentication token has expired.
UNAUTHORIZED
133
Note
The Device Enrollment Program service periodically issues a new X-ADM-Auth-Session in its response to a
service call; the MDM server can use this new header value for any subsequent calls.
After a period of extended inactivity, this token expires, and the MDM server must obtain a new auth token from the
https://mdmenrollment.apple.com/session endpoint.
All responses may return a new X-ADM-Auth-Session token, which the MDM server should use in subsequent
requests.
134
VPP App Assignment
In iOS 7 and later or macOS v10.9 and later, Volume Purchase Program (VPP) App Assignment allows an organization
to assign apps to users. At a later date, if a user no longer needs an app, you can reclaim the app license and assign
it to a different user. In iOS 9 and later or macOS v10.11 and later, VPP can assign a license to the device serial
number, so no Apple ID is required to download the app.
The Volume Purchase Program provides a number of web services that MDM servers can use to associate volume
purchases with particular users or devices. The following services are currently supported:
• Create a user in the iTunes Store representing a user in the MDM system, against which licenses and an
iTunes Store account may be linked: registerVPPUserSrv.
• Determine the current iTunes account status of one or more VPP users: getVPPUserSrv or getVPPUsersSrv.
• List the VPP assets for which an organization has licenses, including counts of assigned and unassigned
licenses for each asset: getVPPAssetsSrv.
• Query the iTunes Store for information about apps and books: contentMetadataLookupUrl.
• Disassociate a VPP user from their iTunes account and release their revocable licenses: retireVPPUserSrv.
• Perform batch associations or disassociations of multiple VPP users or devices with their licenses:
manageVPPLicensesByAdamIdSrv.
• Fetch or update a VPP userʼs email address and optionally link to a Managed Apple ID: editVPPUserSrv.
• Store and/or return organization-specific information to/from the VPP server: VPPClientConfigSrv.
• Fetch the current list of VPP web service URLs and error numbers: VPPServiceConfigSrv.
• Determine the statuses of a VPP userʼs current licenses for software and other products: getVPPLicensesSrv.
Please note that this service will be deprecated and its use should be avoided.
135
To support location based assets, VPP in Apple School Manager uses location tokens. The location tokens are used
by content managers the same way as the legacy VPP tokens are used. Content managers download the location
token from the settings page in Apple School Manager and upload it into their MDM. The MDM then has access to
the licenses available at that location. Allocating the licenses within the MDM uses the same workflow for both types
of licenses.
VPP will continue to support legacy user based sTokens. Depending on the type of token used, VPP will return either
the new location-based response or the existing user-based response. VPP API responses that differ by token type
will have both the legacy and location based responses documented below.
Migrating to VPP in Apple School Manager is recommended, but optional. Licenses assigned when using the legacy
token must be managed by the content managerʼs legacy token until they are transferred to a location. Therefore,
MDMs will need to support both models of licensing at the same time. Failure to support the legacy and location
based models of tokens will create discrepancies between user experiences in Apple School Manager and their
MDM.
To update your MDM to support location based tokens, these steps must be taken:
• Update API calls to handle the location information being returned for the new VPP in Apple School Manager
features. Licenses assigned with the legacy token will not have a location. All of the assets purchased with
VPP in Apple School Manager will have additional location information in their API responses. Specifically,
these API have been updated to return location information: getVPPAssetsSrv, VPPClientConfigSrv.
• Update the MDM UI to show location names for the tokens and assets. Location names are not unique (many
schools may have the same name) but location UIDs are unique to a specific location. Displaying the location
name to the user is particularly important when location token is about to expire.
• Refresh license status at appropriate times to maintain an accurate UI. Since licenses can be reallocated in the
Apple School Manager, license counts will change outside of the MDM. Refreshing on each page load is
recommended.
• Use getVPPAssetsSrv, not getVPPLicensesSrv, to get license counts. getVPPAssetsSrv is more efficient and
will return a summary of adamIds and counts instead of all the licenses.
• Handle when duplicate tokens are uploaded by different content managers. There is just one location token
that needs to be stored, instead of a token per VPP account.
136
https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/<serviceName>
It is recommended that you obtain the service URLs from the VPPServiceConfigSrv service rather than using
hard-coded values in the client. All service URLs are subject to change except for the VPPServiceConfigSrv URL.
Providing Parameters
Parameters to the service requests should be provided as a JSON string in the request body, and the
Content-Type header value should contain application/json.
The value of a parameter can be in primitive type or string type. When the web services receive input parameters, all
primitive types are converted to string type first before they are parsed into primitive types as required by the
specific parameter. For example, licenseId requires a long type; the input in JSON format can be either
{”licenseId”:1} or {”licenseId”:”1”}. The responses of the services use primitive type for non-string
values.
Authentication
All services except VPPServiceConfigSrv require an sToken parameter to authenticate the client user. This
parameter takes a secret token (in string format). A Program Facilitator can obtain such a token by logging in to
https://vpp.itunes.apple.com/.
On the Account Summary page, click the Download button to generate and download a text file containing the new
token. Each token is valid for one year from the time you generate it. Once created, tokens are listed on the Account
Summary page.
The MDM server should store the userʼs token along with its other private, protected properties and should send this
token value in the sToken field of all VPP requests described in this chapter.
The sToken blob itself is a JSON object in Base64 encoding. When decoded, the resulting JSON object contains
three fields: token, expDate, and orgName. For example, the following is an sToken value (with line breaks
inserted):
eyJ0b2tlbiI6InQxWG9VenBMRXRwZGxhK25zeENkd3JjdDBS
andkaWNOaGRreW5STW05VVAyc2hSYTBMUnVGcVpQM0pLQmJU
TWxDSE42ajNta1R6WVlQbVVkVXJXV2x3PT0iLCJleHBEYXRl
IjoiMjAxNC0wOC0xNVQxODoxMzo1Mi0wNzAwIiwib3JnTmFt
ZSI6Ik9SRy4yMDA5MDcxNjAwIn0=
After Base64 decoding, this is the JSON string (with line breaks inserted):
{”token”:”t1XoUzpLEtpdla+nsxCdwrct0RjwdicNhdkynRMm9UP
2shRa0LRuFqZP3JKBbTMlCHN6j3mkTzYYPmUdUrWWlw==”,
”expDate”:”2014-08-15T18:13:52-0700”,
”orgName”:”ORG.2009071600”}
The expDate field contains the expiration date of the token in ISO 8601 format. The orgName field contains the
name of the organization for which the token is issued.
137
Service Response
As a convention, fields with null values are not included in the response. For example, the user object has an
email field that is optional. The following example doesnʼt have the email field in the user object, so the email
field value is null.
”user”:{
”userId”:1,
”clientUserIdStr”:”810C9B91-DF83-41DA-80A1-408AD7F081A8”,
”itsIdHash”:”C2Wwd8LcIaE2v6f2/mvu82Gs/Lc=”,
”status”:”Associated”,
”licenses”:[
{
”licenseId”:2,
”adamId”:408709785,
”productTypeId”:7,
”pricingParam”:”STDQ”,
”productTypeName”:”Software”,
”isIrrevocable”:false
},
{
”licenseId”:4,
”adamId”:497799835,
”productTypeId”:7,
”pricingParam”:”STDQ”,
”productTypeName”:”Software”,
”isIrrevocable”:false
}
]
}
Note the licenses associated with the user are returned as an array. If the user doesnʼt have a license, the “licenses”
field does not show up. The license object in this context is a subfield of the user object. To avoid a cyclic reference,
the user object is not included in the license object. But if the license is the top object returned, it includes a user
object with id and clientUserIdStr fields and, if the user is already associated with an iTunes account, an
itsIdHash field.
JSON escapes some special characters including slash (/). So a URL returned in JSON looks like:
”https:\/\/fanyv88.com:443\/https\/vpp.itunes.apple.com\/WebObjects\/MZFinance.woa\/wa\/registerVPPUserSrv”.
For any service that requires authentication with an sToken value, if the provided token is within the expiration
warning period (currently 15 days before the expiration date), then the response contains an additional field,
tokenExpDate. The value of this field is the expiration date in ISO 8601 format. For example:
”tokenExpDate”:”2013-07-26T18 12 09-0700”
If this field is present in the response, it should serve as a reminder that it is time to get a new sToken blob in order
to avoid any service disruption.
138
Retry-After Header
The VPP service may return a 503 Service Unavailable status to clients whose requests result in an unusually high
load on the VPP service, or when the VPP service is experiencing loads beyond its current capacity to respond to
requests. A Retry-After header may be included in this response, indicating how long the client must wait before
making additional requests. Clients who make requests before this time may be rejected for even longer periods of
time, or (in extreme cases) may have their VPP account suspended.
Avoid triggering the Retry-After header by setting the assignedOnly parameter true in calls to
getVPPLicensesSrv.
The Retry-After response-header field may also be used with any 3xx (Redirection) response to indicate the
minimum time the user-agent is asked to wait before issuing the redirected request (see RFC 2616: HTTP/1.1,
Section 14.37). The value of this field can be either an HTTP-date or an integer number of seconds (in decimal) after
the time of the response.
Retry-After: 120
It is reasonable behavior for a product that manages VPP app assignments to reset the VPP account by retiring all
users and revoking all app assignments when it is first configured to use a VPP account. Therefore, it is very
important that your product always sets the clientContext data as documented below so that other products
that manage VPP accounts can know that the VPP account is being managed by another product and not reset the
VPP account without warning.
To ensure that a VPP account is not being managed by another product, follow these steps every time your product
starts a VPP session:
• During initial setup, check the clientContext attribute returned from the VPPClientConfigSrv request.
– If clientContext is empty, create a JSON string with these keys and values:
{”hostname”:<my.servername.com>, ”guid”:<random_uuid>}
The UUID should be a standard 8-4-4-4-12 formatted UUID string and must be unique for each
installation of your product.
Write this JSON string to clientContext to claim this VPP account for your product.
– If clientContext is not empty and does not match the guid value of your product, report the
hostname returned by clientContext and confirm that your product should take over from it. Do not
rely on hostname to confirm that your product still has a proper claim on the VPP account.
• At the start of every subsequent VPP session, check clientContext to ensure that it still represents the
correct installation of your product.
139
• If clientContext no longer refers to your product, do not make any further requests to the VPP service for
that VPP account until the account has been reactivated by administrator commands. Your product should
report this isolation action to an administrator, giving the hostname of the server that now claims to manage
the VPP account.
It is not necessary to sync every single app license for a specific VPP account. In fact, you only need to track the
assigned licenses. The recommended procedure for importing assigned licenses is to skip importing all of the
licenses and instead start importing license counts and then changes. This can be accomplished in the following
way:
1. Send a request using getVPPAssetsSrv with includeLicenseCounts : true. This returns the current
license count by adamID.
2. Send one request using getVPPLicensesSrv. Record the batchToken and totalBatchCount. Always
set assignedOnly=true.
3. Send another request to getVPPLicensesSrv using the batchToken value from Step 2 and an
overrideIndex value equal to totalBatchCount. Always set assignedOnly=true.
4. Record the sinceModifiedToken value and begin syncing license updates and changes instead of all
licenses. Always set assignedOnly=true.
Note: Using sinceModifiedToken can result in batches with zero records in them. This is not an error or an end
signal; just move to the next batch.
productTypeId Codes
Some service requests may return the ID of an Apple product type as a decimal integer, with one of these values:
productTypeId Meaning
7 macOS software.
8 iOS or macOS App Store app.
10 book.
Managed Apple IDs were introduced in iOS 9.3. These accounts can be tied to the same organization as the VPP
Program Facilitator users who manage licenses. When this is the case, the MDM server may choose to instruct the
VPP service to associate Managed Apple IDs with given VPP users. This removes the need to send out an invitation
(email or push) to users and wait for them to join by going through an acceptance process.
Managed Apple IDs are implemented through the following services by adding an optional parameter,
managedAppleIDStr:
• registerVPPUserSrv
140
• editVPPUserSrv
Apple uses the Apple ID passed in managedAppleIDStr to look up the userʼs organizationId. If the VPP
Program Facilitator account associated with the sToken making the request is also a Managed Apple ID and that
Apple IDʼs organizationId is the same as the userʼs, the VPP user will be linked to that Apple ID.
If the user cannot be found in the iTunes database, or the user is found but the userʼs organizationId does not
match the organizationId of the sTokenʼs associated user, the service response returns error 9635,
APPLE_ID_CANT_BE_USED.
Program Facilitators
As described in Authentication, Program Facilitators obtain from the iTunes VPP website the sToken parameters
that must be passed in VPP service requests. Each sToken authenticates an organization through the associated
Program Facilitator account that generated it.
Managed Apple IDs make it possble for multiple Program Facilitators to be linked together into a group. Each Program
Facilitator in the group is assigned a facilitatorMemberId. An sToken can use this facilitatorMemberId
to access and change data associated with different Program Facilitators as long as the other Program Facilitators
are in the same group. Using VPPClientConfigSrv, the MDM server can discover member info about all the other
Program Facilitators whose data its sToken can access, including the facilitatorMemberId of each member.
All VPP service calls, except VPPClientConfigSrv, accept an optional facilitatorMemberId parameter. It is
subject to these rules:
• If a service request passes the facilitatorMemberId of a Program Facilitator that was never associated
with the requesting organization, or left it, or is no longer managed, an error is returned.
Here is an example of a VPPClientConfigSrv response when the sToken passed to it is associated with a group
of three users, each of which has a different Program Facilitator:
{
”apnToken”: ”aJQGSAd+H7FrmIZn9K4IbRbXpge3ySkchugcfYK/ZXg=”,
”appleId”: ”[email protected]”,
”clientContext”: ”{\”guid\”:\”e91e570f-3eba-4b43-97d3-0f39450c8b92\”,
\”hostname\”:\”vpp-integrations2.apple.com\”,\”ac2\”:1}”,
”countryCode”: ”US”,
”email”: ”[email protected]”,
”facilitatorMemberId”: 200841,
”organizationId”: 2168850000179778,
”status”: 0,
”vppGroupMembers”: [
{
”appleId”: ”[email protected]”,
”clientContext”: ”test123test123test123”,
”email”: ”[email protected]”,
”facilitatorMemberId”: 200844,
”organizationId”: 2168850000179778,
141
”locationId”: 2167975000001686,
”locationName”: ”Central School”
},
{
”appleId”: ”[email protected]”,
”clientContext”: ”{\”guid\”:\”e91e570f-3eba-4b43-97d3-0f39450c8b92\”,
\”hostname\”:\”vpp-integrations2.apple.com\”,\”ac2\”:1}”,
”email”: ”[email protected]”,
”facilitatorMemberId”: 200841,
”organizationId”: 2168850000179778,
”locationId”: 2167975000001686,
”locationName”: ”Central School”
},
{
”appleId”: ”[email protected]”,
”email”: ”[email protected]”,
”facilitatorMemberId”: 200843,
”organizationId”: 2168850000179778,
”locationId”: 2167975000001686,
”locationName”: ”Central School”
}
]
}
Note that vppGroupMembers contains all of the members of the Program Facilitatorʼs group, including the calling
member.
Read-Only Access
Using Apple School Manager and Managed Apple IDs, you can tailor different sets of privileges for individual
Program Facilitators. This allows a finer range of control on what such users can do. For example, a Program
Facilitator that has only the “Read Only” privilege can use the getVPPUserSrv, getVPPUsersSrv, and
getVPPAssetsSrv services but not use retireVPPUserSrv, disassociateVPPLicenseSrv, or
manageVPPLicensesByAdamIdSrv. You can also assign Program Facilitators “Can Purchase” and/or “Can
Manage” privileges, so an individual Program Facilitator could manage licenses but not buy them. (Note that
purchasing users and managing users automatically have read privileges.)
Error Codes
When a service request results in error, there are normally two fields containing the error information in the response:
an errorNumber field and an errorMessage field. There could be additional fields depending on the error. The
errorMessage field contains human-readable text explaining the error. The errorNumber field is intended for
software to interpret. Any errorMessage value uniquely maps to an errorNumber value, but not the other way
around. The possible errorNumber values are defined as follows:
142
errorNumber Meaning
143
errorNumber Meaning
9638 Facilitator account that generated sToken has no Managed ID organization ID and cannot
manipulate the facilitator member requested.
9639 No facilitator member could be found for the facilitator member ID requested.
9640 Account details of the facilitator member ID requested could not be recovered (likely a transient
issue).
9641 Apple ID already associated to registered user.
9642 Apple ID passed cannot be used at this time because itʼs a VPP manager and the iTunes Store
account not yet created and such creation requires user to agree to Terms.
Error number 9616 is returned when an attempt is made to assign a license to a user that already has a license for
the specified app or book, in which case there is no need to retry the assignment.
Additional information is returned to MDM when a 9616 error occurs. Sometimes itʼs because the specific user in the
request is already assigned to the item in question. When that happens the 9616 error is accompanied by a
licenseAlreadyAssigned entry with details about the user and the license. For example,
{”licenseAlreadyAssigned”:{”pricingParam”:”STDQ”,”itsIdHash”:
”XuHVGvasXcfEVUUn4EP2wjHEUK00s=”,”userId”:9918783273,”productTypeId”:8,
”isIrrevocable”:false,”adamIdStr”:”778658393”,”userIdStr”:”9918783273”,
”licenseIdStr”:”99147599840”,”productTypeName”:”Application”,
”clientUserIdStr”:”xxutt8-e079-4b05-b403-a0792890”,
”licenseId”:9147599840,”adamId”:778658393,”status”:”Associated”},
”errorMessage”:”License already assigned”,”errorNumber”:9616,”status”:-1}
Alternatively, a 9616 error may have a regUsersAlreadyAssigned entry in the response with information about
the one or more other users who already have the item in question. In these cases, the VPP user specified by the
user ID or the clientUserIdStr does not have the item, but some other users in the organization associated with
the same iTunes Store account has the item. If that happens, the server returns 9616 and information about those
other users:
The Services
The following are the web services exposed to the Internet that can be requested by your client.
144
registerVPPUserSrv
clientUserIdStr is a string field. It can be, for example, the GUID of the user. The clientUserIdStr strings
must be unique within the organization and may not be changed once a user is registered. It should not, for example,
be an email address, because an email address might be reused by a future user.
When a user is first registered, the userʼs initial status is Registered. If the user has already been registered, as
identified by clientUserIdStr, the following occurs:
• If the userʼs status is Registered or Associated, that active user account is returned.
• If the userʼs status is Retired and the user has never been assigned to an iTunes account, the accountʼs
status is changed to Registered and the existing user is returned.
• If the userʼs status is Retired and the user has previously been assigned to an iTunes account, a new
account is created.
Thus, it is possible for more than one user record to exist for the same clientUserIdStr value—one for each
iTunes account that the clientUserIdStr value has been associated with in the past (in addition to a currently
active record or a retired and never-associated record). Each of these users has a unique userId value. Over time,
with iTunes Store assignment, retirement, and reassignment, it is possible for the userId value of the active user for
a given clientUserIdStr to change.
Further, if two user identifiers exist for a given clientUserIdStr, one assigned to an iTunes account and the other
unassigned, and a user accepts an invitation to be associated, it is possible for the user to use the same iTunes
account that he or she used previously. If the user does, the unassigned user record gets marked with the Retired
status, and the formerly retired user record gets moved to the Associated status.
145
Field Name Example of Value
user {
”userId”:100014,
”email”:”[email protected]”,
”status”:”Registered”,
”inviteUrl”:
”https:\/\/fanyv88.com:443\/https\/buy.itunes.apple.com\/WebObjects\/MZFinance.woa\/
wa\/associateVPPUserWithITSAccount?inviteCode=
9e8d1ecc57924d9da13b42b4f772a066&mt=8”,
”inviteCode”:”9e8d1ecc57924d9da13b42b4f772a066”,
”clientUserIdStr”:”810C9B91-DF83-41DA-80A1-408AD7F081A8”,
}
errorMessage ”\”clientUserIdStr\” or \”email\” is required input parameter”.
facilitatorMember {
”appleId”:”[email protected]”,
”countryCode”:”US”,
”email”:”[email protected]”,
”facilitatorMemberId”:200843,
”organizationId”:2168850000179778,
},
errorNumber 9600.
getVPPUserSrv
If a value is passed for clientUserIdStr, an itsIdHash (iTunes Store ID hash) value may be passed, but is
optional. If a value is passed for userId is passed, that value is used, and clientUserIdStr and itsIdHash are
ignored.
The getVPPUserSrv request returns users with any status—Registered, Associated, Retired, and
Deleted, as described below:
• A Registered status indicates the user has been created in the system by making a
registerVPPUserSrv request, but is not yet associated with an iTunes account.
• An Associated status indicates that the user has been associated with an iTunes account. When a user is
146
associated with an iTunes account, an itsIdHash value is generated for the user record.
• A Retired status indicates that the user has been retired by making a retireVPPUserSrv request.
• A Deleted status indicates that a VPP user is retired and its associated iTunes user has since been invited
and associated with a new VPP user that shares the same clientUserIdStr. Because there are two VPP
users with distinct userId values but the same clientUserIdStr value, the Deleted status is used to
ensure database consistency.
This status appears only in the getVPPUserSrv service response, and only when a userId value is used to
get a VPP user instead of a clientUserIdStr value. A user with a Deleted status, fetched by userId,
will never change status again; its sole purpose is to ensure that your software can recognize that the userId
is no longer associated with the clientUserIdStr record, and can update any internal references
appropriately.
Thus, it is possible for more than one user record to exist for the same clientUserIdStr value—one for each
iTunes account that the clientUserIdStr value has been associated with in the past (in addition to a currently
active record or a retired and never-associated record). However, no more than one of these records can be active at
any given time.
When a new record is associated with a clientUserIdStr value that has previously been associated with a
different user, because the clientUserIdStr is still associated with the same iTunes user when it is retired and
associated again, any irrevocable licenses originally associated with the retired VPP user, if any, are moved to the
new VPP user (as identified by userId) automatically.
If you use a clientUserIdStr value to fetch the VPP user after such a reassociation, the status of that user
changes from Retired to Associated. If you use userId values to fetch the VPP users after the association, the
status of the first VPP user changes from Retired to Deleted, and the status of the second VPP user changes
from Registered to Associated.
To obtain only the record for the currently active user matching a clientUserIdStr value, your MDM server
passes the clientUserIdStr by itself. If no users for the clientUserIdStr are active (all are retired or no
matching record exists), getVPPUserSrv returns a ”result not found” error number.
To obtain an old, retired user record that was previously associated with an iTunes Store account, your MDM server
can pass either the userId for that record or the clientUserIdStr and itsIdHash for that record.
All user record responses for this request include an itsIdHash if the user is associated with an iTunes account.
147
Field Name Example of Value
user {
”userId”:2,
”email”:”[email protected]”,
”status”:”Associated”,
”clientUserIdStr”: ”810C9B91-DF83-41DA-80A1-408AD7F081A8”,
”itsIdHash”:”C2Wwd8LcIaE2v6f2/mvu82Gs/Lc=”,
”licenses”:[
{
”licenseId”:4,
”adamId”:497799835,
”productTypeId”:7,
”pricingParam”:”STDQ”,
”productTypeName”:”Software”,
”isIrrevocable”: false
}
]
}
facilitatorMember {
”appleId”:”[email protected]”,
”countryCode”:”US”,
”email”:”[email protected]”,
”facilitatorMemberId”:200843,
”organizationId”: 2168850000179778,
},
errorMessage ”Result not found”.
errorNumber 9604.
The itsIdHash field is omitted if the account is not yet associated with an iTunes Store account.
Note the user object returned includes a list of licenses assigned to the user.
getVPPUsersSrv
148
The batchToken and sinceModifiedToken values are generated by the server, and the batchToken value can
be several kilobytes in size.
You can use this endpoint to obtain a list of all known users from the server and to keep your MDM system
up-to-date with changes made on the server. To use this endpoint, your MDM server does the following:
This request returns all user records associated with the provided sToken.
• If the number of users exceeds a server controlled limit (on the order of several hundred), a batchToken
value is included in the response, along with the first batch of users. Your MDM server should pass this
batchToken value in subsequent requests to get the next batch. As long as additional batches remain, the
server returns a new batchToken value in its response.
• Once all records have been returned for the request, the server includes a sinceModifiedToken value in
the response. Your MDM server should pass this token in subsequent requests to get users modified since
that token was generated.
Even if no records are returned, the response still includes a sinceModifiedToken for use in subsequent
requests.
The includeRetired value contains 1 if retired users should be included in the results, otherwise it contains 0.
Note
The batchToken value encodes the original value of includeRetired; therefore, if a batchToken value is
present on the request, the includeRetired field (if passed) is ignored.
149
Field Name Example of Value
users [
{
”userId”:2,
”email”:”[email protected]”,
”status”:”Associated”,
”clientUserIdStr”:”810C9B91-DF83-41DA-80A1-408AD7F081A8”,
”itsIdHash”:”C2Wwd8LcIaE2v6f2/mvu82Gs/Lc=”
},
{
”userId”:3,
”email”:”[email protected]”,
”status”:”Registered”,
”inviteUrl”:
”https:\/\/fanyv88.com:443\/https\/buy.itunes.apple.com\/WebObjects\/MZFinance.woa\/wa\/
associateVPPUserWithITSAccount?inviteCode=
f551b37da07146628e8dcbe0111f0364&mt=8”,
”inviteCode”:”f551b37da07146628e8dcbe0111f0364”,
”clientUserIdStr”:”293C9B02-DF83-41DA-20B7-203KD7F083C9”
}
]
Note that the inviteUrl field is present only for users whose status is
Registered, not for users whose status is Associated or Retired status.
facilitatorMember {
”appleId”:”[email protected]”,
”countryCode”:”US”,
”email”:”[email protected]”,
”facilitatorMemberId”:200843,
”organizationId”:2168850000179778,
},
totalCount 5
Note that this value is returned only for requests that do not include a
batchToken value.
errorMessage ”Result not found”.
errorNumber 9604.
batchToken EkZQCWOwhDFCwgQsUFJZkAoUU0pKLEnOUAIKZOalpFYAR
YzA7OSc0pTUoNSSzKLUFJAyQ6CSWgCS88JnkgAAAA==
Note that this field is present only if there are more entries left to read.
sinceModifiedToken 0zJTU5SAEplpMF4wWCozJyezGKjS0NjM0tjUwtTA3MzQ
1FqhFgBuLPH3TgAAAA==
Note that this field is present only if batchToken is not (that is, only after the last
batch of users has been returned).
The itsIdHash field is omitted if the account is not yet associated with an iTunes Store account.
The totalCount field contains an estimate of the total number of records that will be returned.
150
getVPPLicensesSrv
The batchToken and sinceModifiedToken values are generated by the server, and the batchToken value can
be several kilobytes in size.
You can use this endpoint to obtain a list of licenses from the server and to keep your MDM system up-to-date with
changes made on the server. To use this endpoint, your MDM server does the following:
This request returns all licenses associated with the provided sToken.
• If the number of licenses exceeds a server controlled limit (on the order of several hundred), a batchToken
value is included in the response, along with the first batch of users. Your MDM server should pass this
batchToken value in subsequent requests to get the next batch. As long as additional batches remain, the
server returns a new batchToken value in its response.
• Once all records have been returned for the request, the server includes a sinceModifiedToken value in
the response. Your MDM server should pass this token in subsequent requests to get licenses modified since
that token was generated.
Even if no records are returned, the response still includes a sinceModifiedToken for use in subsequent
requests.
Note
The batchToken and sinceModifiedToken encode whether adamId and pricingParam were originally
passed; therefore, if the batchToken or sinceModifiedToken is present on the request, the adamId and
pricingParam fields (if passed) are ignored.
151
If pricingParam is specified, adamId must be specified. Otherwise, the pricing parameter is ignored.
If serialNumber is specified, only licenses assigned to that serial number are returned.
If the assignedOnly parameter is set to true, only licenses currently associated with an Apple ID or a device serial
number are returned. When the assignedOnly parameter is omitted, all license records are returned regardless of
association status. It is highly recommended to set the assignedOnly parameter to true, for performance
reasons.
The parameters userAssignedOnly and deviceAssignedOnly are exclusive. They should never both be true in
the same request.
If a pricingParam parameter is not passed in the getVPPLicensesSrv request, the VPP service returns all
licenses (both PLUS and STDQ pricingParam values).
”clientUserIdStr”:”810C9B91-DF83-41DA-80A1-408AD7F081A8”,
”itsIdHash”:”C2Wwd8LcIaE2v6f2/mvu82Gs/Lc=”
}
].
totalCount 10
Note that this value is returned only for requests that do not include a token.
totalBatchCount 3
Indicates the total number of round trips that will be necessary to get the full result
set.
152
Field Name Example of Value
facilitatorMember {
”appleId”:”[email protected]”,
”countryCode”:”US”,
”email”:”[email protected]”,
”facilitatorMemberId”:200843,
”organizationId”:2168850000179778,
},
errorMessage ”Result not found”.
errorNumber 9604.
batchToken EkZQCWOwhDFCwgQsUFJZkAoUU0pKLEnOUAIKZOalpFYAR
YzA7OSc0pTUoNSSzKLUFJAyQ6CSWgCS88JnkgAAAA==
Note that this field is present only if there are more entries left to read.
sinceModifiedToken 0zJTU5SAEplpMF4wWCozJyezGKjS0NjM0tjUwtTA3MzQ
1FqhFgBuLPH3TgAAAA==
Note that this field is present only if batchToken is not (that is, only after the last
batch of users has been returned).
Licenses that are assigned to a user contain userId, clientUserIdStr, and itsIdHashfield fields, as shown
in the second example above. The totalBatchCount field contains the total number of round trips that are
necessary to get all records in the request. This can be used to provide a progress indicator when compared to the
number of batches processed so far.
Note
The totalCount value is returned only on the request that started the batch process (the listing request issued
without any tokens), because the actual number of licenses or users returned can be different by the time the
client has finished.
One of a set of sequential getVPPLicensesSrv batch requests may return an error. It is also possible to get a
response from a listing call that includes no token but also no error number. Because all listing API requests should
return either a batch or sinceModified token, do not interpret an error or the lack of a token for an individual batch
to mean that the last batch has been received. The last batch is signified by the inclusion of a
sinceModifiedToken. If an individual batch request fails, the MDM server should retry the same batch using the
same batchToken.
Receiving a 9603 'Internal Error' response typically indicates that the VPP server couldnʼt provide timely
processing. Nothing is necessarily wrong with the request. When the MDM server receives this response, it should
send the current request again. If it continues to receive 9603 errors after more than five attempts, it may mean that
the VPP service is unexpectedly down and further retries should be scheduled for minutes later, instead of seconds.
Both the getVPPLicensesSrv and getVPPUsersSrv services can accept multiple requests in parallel, instead of
sequentially, which can significantly reduce the amount of time required to request all licenses and users. You start
153
by making an initial request to receive a batchToken. Subsequent requests can be submitted in parallel by
submitting the same batchToken and including an overrideIndex value from 1 to totalBatchCount, which is
now returned with getVPPLicensesSrv requests. The request in which the overrideIndex value is equal to the
totalBatchCount returns the new sinceModifiedToken.
getVPPAssetsSrv
This service returns an enumeration of the assets ({adamIdStr, pricingParam} tuples) for which an
organization has licenses, along with an optional count of the total number of licenses and the number of licenses
available for each asset.
If includeLicenseCounts is set to true, the total number of licenses, the number of licenses assigned, and the
number of licenses unassigned are included with the response for each asset.
if pricingParam is specified, only assets purchased with that pricing parameter will be included in the result.
154
Field Name Example of Value
assets [
{
”adamIdStr”:”375380948”,
”assignedCount”:2,
”availableCount”:8,
”deviceAssignable”:true,
”isIrrevocable”:false,
”pricingParam”:”STDQ”,
”productTypeId”:8,
”productTypeName”:”Application”,
”retiredCount”:0,
”totalCount”:10
},
{
”adamIdStr”:”435160039”,
”assignedCount”:2,
”availableCount”:8,
”deviceAssignable”:false,
”isIrrevocable”:true,
”pricingParam”:”PLUS”,
”productTypeId”:10,
”productTypeName”:”Publication”,
”retiredCount”:0,
”totalCount”:10
}
]
facilitatorMember {
”appleId”:”[email protected]”,
”countryCode”:”US”,
”email”:”[email protected]”,
”facilitatorMemberId”:200843,
”organizationId”:2168850000179778,
},
totalCount 4
errorMessage ”Result not found”
errorNumber 9604
location {
”locationId”: 22222222222,
”locationName”: ”Lincoln High School”
}
The location field is only returned when using a location token with an account that has migrated to VPP in Apple
School Manager.
155
contentMetadataLookupUrl
The contentMetadataLookupUrl in the VPPServiceConfigSrv response allows an MDM server to query the
iTunes Store for app and book metadata. When the VPP sToken is included in the request as a cookie, an MDM
server can also get authenticated app metadata for B2B apps already owned by the VPP account, as well as apps
that can still be redownloaded but can no longer be purchased.
The URL query string tells the content metadata lookup service what app or book to look up. The VPP sToken must
be included as a cookie named itvt to access the authenticated metadata.
Content is filtered by platform. The useful platform values for the query parameter are: enterprisestore for apps
in the enterprise store and volumestore for apps in the educational store. For example, to get B2B app content,
append platform=enterprisestore to your query string.
{
”isAuthenticated”: false,
”results”: {
”361309726”: {
”artistId”: ”284417353”,
”artistName”: ”Apple”,
”artistUrl”: ”https://itunes.apple.com/us/artist/apple/id284417353?mt=8”,
”artwork”: {
”bgColor”: ”ffb800”,
”height”: 1024,
”supportsLayeredImage”: false,
”textColor1”: ”161616”,
”textColor2”: ”161616”,
”textColor3”: ”453712”,
”textColor4”: ”453712”,
”url”: ”http://is5.mzstatic.com/image/thumb/ Purple3/v4/72/7d/38/727d38ee
-9245-eda6-1188-3458133bd99a/source/{w}x{h}bb.{f}”,
”width”: 1024
},
”bundleId”: ”com.apple.Pages”,
”contentRatingsBySystem”: {
”appsApple”: {
”name”: ”4+”,
”rank”: 1,
”value”: 100
}
},
”copyright”: ”\u00a9 2010 - 2015 Apple Inc.”,
”description”: {
”standard”: ”Pages is the most beautiful word processor you\u2019ve ever
156
seen on a mobile device. This powerful word processor helps you
create gorgeous reports, resumes, and documents in minutes. Pages has
been designed exclusively for the iPad, iPhone, and iPod touch with
support for Multi-Touch gestures and Smart Zoom.\n\nGet a quick start
by using one of over 60 Apple-designed templates. Or use a blank
document and easily add text, images, shapes, and more with a few
taps. Then format using beautiful preset styles and fonts. And use
advanced features like change tracking, comments, and highlights to
easily review changes in a document.\n\nWith iCloud built in, your
documents are kept up-to-date across all your devices. You can
instantly share a document using just a link, giving others the
latest version and the ability to edit it directly from www.icloud.
com using a Mac or PC browser.\n\nPages 2.0 is updated with a
stunning new design and improved performance. And with a new unified
file format across Mac, iOS, and web, your documents are consistently
beautiful everywhere you open them.\n\nGet started quickly\n\u2022
Choose from over 60 Apple-designed templates to instantly create
beautiful reports, resumes, cards, and posters\n\u2022 Import and
edit Microsoft Word and plain text files using Mail, a WebDAV service
, or iTunes File Sharing\n\u2022 Quickly browse your document using
the page navigator and see a thumbnail preview of each page\n\u2022
Turn on Coaching Tips for guided in-app help\n\nCreate beautiful
documents\n\u2022 Write and edit documents using the onscreen
keyboard or a wireless keyboard with Bluetooth\n\u2022 Format your
document with gorgeous styles, fonts, and textures\n\u2022 Your most
important text formatting options are right in your keyboard, and
always just a tap or two away\n\u2022 Easily add images and video to
your document using the Media Browser\n\u2022 Use auto-text wrap to
flow text around images\n\u2022 Animate data with new interactive
column, bar, scatter, and bubble charts\n\u2022 Print wirelessly with
AirPrint, including page range selection, number of copies, and two-
sided printing\n\nSome features may require Internet access;
additional fees and terms may apply.\nPages does not include support
for some Chinese, Japanese, or Korean (CJK) text input features such
as vertical text.\nPages for iCloud beta is currently available in
English only.”
},
”deviceFamilies”: [
”iphone”,
”ipad”,
”ipod”
],
”editorialArtwork”: {
”originalFlowcaseBrick”: {
”bgColor”: ”ffb700”,
”height”: 600,
”supportsLayeredImage”: false,
”textColor1”: ”161616”,
157
”textColor2”: ”161616”,
”textColor3”: ”453612”,
”textColor4”: ”453612”,
”url”: ”http://is4.mzstatic.com/image/ thumb/Features5/v4
/22/60/94/226094a4-ed02-a234-7576-6de696ead0ba/source/{w}x{h}{c}.{
f}”,
”width”: 3200
}
},
”editorialBadgeInfo”: {
”editorialBadgeType”: ”staffPick”,
”nameForDisplay”: ”Essentials”
},
”genreNames”: [
”Productivity”,
”Business”
],
”genres”: [
{
”mediaType”: ”8”,
”name”: ”Productivity”,
”url”: ”https://itunes.apple.com/us/genre/id6007”
},
{
”mediaType”: ”8”,
”name”: ”Business”,
”url”: ”https://itunes.apple.com/us/genre/id6000”
}
],
”id”: ”361309726”,
”kind”: ”iosSoftware”,
”latestVersionReleaseDate”: ”Sep 15, 2015”,
”name”: ”Pages”,
”nameRaw”: ”Pages”,
”offers”: [
{
”actionText”: {
”downloaded”: ”Installed”,
”downloading”: ”Installing”,
”long”: ”Buy App”,
”medium”: ”Buy”,
”short”: ”Buy”
},
”assets”: [
{
”flavor”: ”iosSoftware”,
”size”: 278782033
}
158
],
”buyParams”: ”productType=C&price=9990&
salableAdamId=361309726&pricingParameters=STDQ&appExtVrsId=813292538”,
”price”: 9.99,
”priceFormatted”: ”$9.99”,
”type”: ”buy”,
”version”: {
”display”: ”2.5.5”,
”externalId”: 813292538
}
}
],
”releaseDate”: ”2010-04-01”,
”shortUrl”: ”https://appsto.re/us/EysIv.i”,
”url”: ”https://itunes.apple.com/us/app/pages/id361309726?mt=8”,
”userRating”: {
”ratingCount”: 24848,
”ratingCountCurrentVersion”: 236,
”value”: 3.5,
”valueCurrentVersion”: 3
},
”whatsNew”: ”This update contains stability improvements and bug fixes.”
}
},
”version”: 2
}
retireVPPUserSrv
This service disassociates a VPP user from its iTunes account and releases the revocable licenses associated with
the VPP user. Currently, ebook licenses are irrevocable. The revoked licenses can then be assigned to other users in
the organization. A retired VPP user can be reregistered, in the same organization, by making a
registerVPPUserSrv request.
If the user passes the userId value for an already-retired user, this request returns an error that indicates that the
user has already been retired.
159
The response contains some of these fields:
facilitatorMember {
”appleId”:”[email protected]”,
”countryCode”:”US”,
”email”:”[email protected]”,
”facilitatorMemberId”:200843,
”organizationId”:2168850000179778,
},
status 0 for success, -1 for error.
errorMessage ”Result not found”.
errorNumber 9604.
The itsIdHash field is omitted if the account is not yet associated with an iTunes Store account.
manageVPPLicensesByAdamIdSrv
adamIdStr Required.
pricingParam Required.
associateClientUserIdStrs One (and only one) of these is required to associate licenses.
associateSerialNumbers
disassociateClientUserIdStrs One (and only one) of these is required to disassociate licenses.
disassociateLicenseIdStrs
disassociateSerialNumbers
notifyDisassociation Not required.; defaults to true.
sToken Required.
facilitatorMemberId Not required.
adamIdStr ”408709785”
pricingParam ”STDQ”
associateClientUserIdStrs [”810C9B91-...-408AD7F081A8”, ”d735c1cc-...-
c74571007ef6”,...]
associateSerialNumbers [”C17DK6D9DDQW”, ”DLXL6044FPH8”,...]
160
Parameter Name Example
The request operates on a single asset (specified by the {adamIdStr, pricingParam} tuple) for multiple
associations and disassociations in a single request. Licenses are disassociated from all users specified by the
disassociateClientUserIdStrs array, the devices specified by the disassociateSerialNumbers array, or
the licenses specified by the disassociateLicenseIdStrs array (which must only specify licenses assigned to
the specified asset). At most one of these disassociate* arrays may be specified per request. Then licenses are
associated either with the users specified by the associateClientUserIdStrs array or the devices specified by
the associateSerialNumbers array. You must specify either zero or one associate* and zero or one
disassociate* array per request. Specifying more than one of either associate* or disassociate* arrays
result in undefined behavior.
The maximum number of entries allowed in the associate* and disassociate* arrays are indicated by the
maxBatchAssociateLicenseCount or maxBatchDisassociateLicenseCount fields added to the
VPPServiceConfigSrv response. Any request that exceeds these limits is immediately rejected with an error.
If notifyDisassociation is set to false, notifications regarding the disassociation of the license are not sent to
devices.
status 0 for success, -1 if the request failed completely, -3 if any licenses could not be
changed as requested.
adamIdStr ”408709785”
pricingParam ”STDQ”
productTypeId 7 (see productTypeId Codes)
productTypeName ”Software”
isIrrevocable false
161
Field Name Example of Value
associations [{
”clientUserIdStr”: ”810C9B91-...-408AD7F081A8”,
”licenseIdStr”:”2”
},{
”clientUserIdStr”: ”d735c1cc-...-c74571007ef6”,
”licenseIdStr”:”3”,
”errorMessage”: ”License already assigned”,
”errorNumber”: 9616
},{
”serialNumber”:”C17DK6D9DDQW”,
”licenseIdStr”:”4”
},{
”serialNumber”:”DLXL6044FPH8”,
”errorMessage”:”License not found”,
”errorNumber”: 9610
}, ...]
disassociations [{
”clientUserIdStr”:”810C9B91-...-408AD7F081A8”
},{
”clientUserIdStr”:”d735c1cc-...-c74571007ef6”,
”errorMessage”:”Registered user not found”,
”errorNumber”: 9609
},{
”serialNumber”:”C17DK6D9DDQW”
},{
”serialNumber”:”DLXL6044FPH8”,
”errorMessage”:”License not associated”,
”errorNumber”: 9619
}, ...]
License Counts
The following fields are added to the VPPServiceConfigSrv response to indicate the maximum number of entries
allowed in the associateClientUserIdStrs, associateSerialNumbers,
disassociateClientUserIdStrs, disassociateSerialNumbers, or disassociateLicenseIdStrs
arrays:
maxBatchAssociateLicenseCount 20
maxBatchDisassociateLicenseCount 20
162
'Invalid Argument', and no work is done. If you receive this error code query VPPServiceConfigSrv to
retrieve new maxBatchAssociateLicenseCount and maxBatchDisassociateLicenseCount values,
correct the last request that was rejected and resend the request.
associateVPPLicenseSrv
Note
associateVPPLicenseWithVPPUserSrv
Note
disassociateVPPLicenseSrv
Note
disassociateVPPLicenseFromVPPUserSrv
Note
editVPPUserSrv
163
The email field is updated only if the value is provided in the request.
VPPClientConfigSrv
This service allows the client to store some information on the server on a per-organization basis. The information
that currently can be stored is a clientContext string. The clientContext string is any JSON string less than
256 bytes in length. For format information, see Service Response.
If a value is provided for clientContext, the value is stored by the server and the response contains the current
value of this field. To clear the field value, provide an empty string as the input value; that is, ””. If
”verbose”:true” is included in the request, the response contains the appleId field.
164
Field Name Example of Value
The countryCode value in the response is the ISO 3166-1 two-letter code designating the country where the VPP
account is located. For example, ”US” for United States, ”CA” for Canada, ”JP” for Japan, and so on.
The location field is only returned when using a location token with an account that has migrated to VPP in Apple
School Manager.
The uId field is the unique library identifier. When querying assets using multiple tokens that may share libraries,
use the uId field to filter duplicates.
VPPServiceConfigSrv
This service returns the full list of web service URLs, the registration URL used in the user invitation email, and a list
of error numbers that can be returned from the web services. No parameters or authentication is necessary.
Clients should make a VPPServiceConfigSrv request to retrieve the list of service URLs at the appropriate
moment (client restart) to ensure they are up-to-date, because the URLs may change under certain circumstances.
The VPPServiceConfigSrv service exists to provide a level of indirection so that other service URLs can be
changed in a way that is transparent to the clients.
The response contains the URLs to be used to register VPP users and other web services.
165
Field Name Example of Value
invitationEmailUrl ”https://buy.itunes.apple.com/WebObjects/
MZFinance.woa/wa/associateVPPUserWithITSAccount?
inviteCode=%inviteCode%&mt=8”
Your MDM server should replace %inviteCode% with the actual
invitation code.
registerUserSrvUrl ”https://vpp.itunes.apple.com/WebObjects/
MZFinance.woa/wa/registerVPPUserSrv”.
editUserSrvUrl ”https://vpp.itunes.apple.com/WebObjects/
MZFinance.woa/wa/editVPPUserSrv”.
getUserSrvUrl ”https://vpp.itunes.apple.com/WebObjects/
MZFinance.woa/wa/getVPPUserSrv”.
retireUserSrvUrl ”https://vpp.itunes.apple.com/WebObjects/
MZFinance.woa/wa/retireVPPUserSrv”.
getUsersSrvUrl ”https://vpp.itunes.apple.com/WebObjects/
MZFinance.woa/wa/getVPPUsersSrv”.
getLicensesSrvUrl ”https://vpp.itunes.apple.com/WebObjects/
MZFinance.woa/wa/getVPPLicensesSrv”.
getVPPAssetsSrvUrl ”https://vpp.itunes.apple.com/WebObjects/
MZFinance.woa/wa/getVPPAssetsSrv”.
manageVPPLicensesByAdamIdSrvUrl ”https://vpp.itunes.apple.com/WebObjects/
MZFinance.woa/wa/manageVPPLicensesByAdamIdSrv”.
associateLicenseSrvUrl ”https://vpp.itunes.apple.com/WebObjects/
MZFinance.woa/wa/associateVPPLicenseWithVPPUserSrv”.
disassociateLicenseSrvUrl ”https://vpp.itunes.apple.com/WebObjects/
MZFinance.woa/wa/disassociateVPPLicenseFromVPPUserSrv”.
errorCodes [
{”errorMessage”:”Missing required argument”,
”errorCode”:9600},
{”errorMessage”:”Login required”,
”errorCode”:9601},
{”errorMessage”:”Invalid argument”,
”errorCode”:9602},
{”errorMessage”:”Internal error”,
”errorCode”:9603},
{”errorMessage”:”Result not found”,
”errorCode”:9604},
. . .
]
clientConfigSrvUrl ”https://vpp.itunes.apple.com/WebObjects/
MZFinance.woa/wa/VPPClientConfigSrv”.
maxBatchAssociateLicenseCount 20
maxBatchDisassociateLicenseCount 20
166
Examples
The following are examples of requests and responses of each service. The requests are made with the curl
command from the command line. The response JSON are all formatted with beautifier to facilitate viewing. They
were one string without line breaks when received from the web services.
WIth the introduction of location based libraries, the API responses may differ depending on whether the request
was made with a new location-based token or the legacy user-based token. Where responses differ, examples of
both are provided.
Request to VPPServiceConfigSrv
curl https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/VPPServiceConfigSrv
The response:
{
”associateLicenseSrvUrl”:”https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa
/associateVPPLicenseSrv”,
”clientConfigSrvUrl”:”https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/
VPPClientConfigSrv”,
”contentMetadataLookupUrl”:”https://uclient-api.itunes.apple.com/WebObjects/
MZStorePlatform.woa/wa/lookup”,
”disassociateLicenseSrvUrl”:”https://vpp.itunes.apple.com/WebObjects/MZFinance.woa
/wa/disassociateVPPLicenseSrv”,
”editUserSrvUrl”:”https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/
editVPPUserSrv”,
”errorCodes”:[
{
”errorMessage”:”Missing required argument”,
”errorNumber”:9600
},
{
”errorMessage”:”Login required”,
”errorNumber”:9601
},
{
”errorMessage”:”Invalid argument”,
”errorNumber”:9602
},
{
”errorMessage”:”Internal error”,
”errorNumber”:9603
},
{
”errorMessage”:”Result not found”,
167
”errorNumber”:9604
},
{
”errorMessage”:”Account storefront incorrect”,
”errorNumber”:9605
},
{
”errorMessage”:”Error constructing token”,
”errorNumber”:9606
},
{
”errorMessage”:”License is irrevocable”,
”errorNumber”:9607
},
{
”errorMessage”:”Empty response from SharedData service”,
”errorNumber”:9608
},
{
”errorMessage”:”Registered user not found”,
”errorNumber”:9609
},
{
”errorMessage”:”License not found”,
”errorNumber”:9610
},
{
”errorMessage”:”Admin user not found”,
”errorNumber”:9611
},
{
”errorMessage”:”Failed to create claim job”,
”errorNumber”:9612
},
{
”errorMessage”:”Failed to create unclaim job”,
”errorNumber”:9613
},
{
”errorMessage”:”Invalid date format”,
”errorNumber”:9614
},
{
”errorMessage”:”OrgCountry not found”,
”errorNumber”:9615
},
{
”errorMessage”:”License already assigned”,
168
”errorNumber”:9616
},
{
”errorMessage”:”The user has already been retired.”,
”errorNumber”:9618
},
{
”errorMessage”:”License not associated”,
”errorNumber”:9619
},
{
”errorMessage”:”The user has already been deleted.”,
”errorNumber”:9620
},
{
”errorMessage”:”The token has expired. You need to generate a new token
online using your organization's account at https://vpp.itunes.apple.com
.”,
”errorNumber”:9621
},
{
”errorMessage”:”Invalid authentication token”,
”errorNumber”:9622
},
{
”errorMessage”:”Invalid APN token”,
”errorNumber”:9623
},
{
”errorMessage”:”License was refunded and is no longer valid.”,
”errorNumber”:9624
},
{
”errorMessage”:”The sToken has been revoked”,
”errorNumber”:9625
},
{
”errorMessage”:”License already assigned to other user”,
”errorNumber”:9626
},
{
”errorMessage”:”License disassociation fail due to frequent reassociation”,
”errorNumber”:9627
},
{
”errorMessage”:”License not eligible for device assignment.”,
”errorNumber”:9628
},
169
{
”errorMessage”:”The sToken is inapplicable to batchToken”,
”errorNumber”:9629
},
{
”errorMessage”:”Too many recent identical calls were made to assign a
license that failed due to license being already assigned to the user or
device”,
”errorNumber”:9630
},
{
”errorMessage”:”Too many recent identical calls were made to assign a
license that failed due to no license being being available.”,
”errorNumber”:9631
},
{
”errorMessage”:”Too many recent calls to manage licenses with identical
requests”,
”errorNumber”:9632
},
{
”errorMessage”:”No batch data recovered for token.”,
”errorNumber”:9633
},
{
”errorMessage”:”Service removed.”,
”errorNumber”:9634
},
{
”errorMessage”:”Apple ID can't be associated with registered user.”,
”errorNumber”:9635
},
{
”errorMessage”:”No registered user found.”,
”errorNumber”:9636
},
{
”errorMessage”:”Facilitator operation not allowed.”,
”errorNumber”:9637
},
{
”errorMessage”:”Facilitator missing Organization ID.”,
”errorNumber”:9638
},
{
”errorMessage”:”Facilitator group member not found.”,
”errorNumber”:9639
},
170
{
”errorMessage”:”Facilitator group member look-up failed.”,
”errorNumber”:9640
},
{
”errorMessage”:”Apple ID already associated to registered user.”,
”errorNumber”:9641
},
{
”errorMessage”:”Apple ID passed cannot be used at this time because it's a
VPP manager and the iTunes Store account not yet created and such
creation requires user to agree to Terms.”,
”errorNumber”:9642
},
{
”errorMessage”:”Volume Purchase Program is currently in maintenance mode.
Please try again later.”,
”errorNumber”:9644
}
],
”getLicensesSrvUrl”:”https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/
getVPPLicensesSrv”,
”getUserSrvUrl”:”https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/
getVPPUserSrv”,
”getUsersSrvUrl”:”https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/
getVPPUsersSrv”,
”getVPPAssetsSrvUrl”:”https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/
getVPPAssetsSrv”,
”invitationEmailUrl”:”https://buy.itunes.apple.com/WebObjects/MZFinance.woa/wa/
associateVPPUserWithITSAccount?cc=us&inviteCode=%25inviteCode%25&mt=8”,
”manageVPPLicensesByAdamIdSrvUrl”:”https://vpp.itunes.apple.com/WebObjects/
MZFinance.woa/wa/manageVPPLicensesByAdamIdSrv”,
”maxBatchAssociateLicenseCount”:100,
”maxBatchDisassociateLicenseCount”:100,
”registerUserSrvUrl”:”https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/
registerVPPUserSrv”,
”retireUserSrvUrl”:”https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/
retireVPPUserSrv”,
”status”:0,
”vppWebsiteUrl”:”https://vpp.itunes.apple.com/”
}
Request to getVPPLicensesSrv
{”sToken”:”h40Gte9aQnZFDNM39IUkRPCsQDxBxbZB4Wy34pxefOuQkeeb3h2
171
a5Rlopo4KDn3MrFKf4CM3OY+WGAoZ1cD6iZ6yzsMk1+5PVBNc66YS6ZQ=”}
curl https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/getVPPLicensesSrv -d
@get_licenses.json
The response:
[
{
”adamId”:408709785,
”adamIdStr”:”408709785”,
”clientUserIdStr”:”9a17b450-9820-471e-b232-13a479ddede0”,
”isIrrevocable”:false,
”itsIdHash”:”LsrJ6NhzbsOzQXShrpUTWGnD/X8=”,
”licenseId”:102547,
”licenseIdStr”:”102547”,
”pricingParam”:”STDQ”,
”productTypeId”:8,
”productTypeName”:”Application”,
”status”:”Associated”,
”userId”:10715446,
”userIdStr”:”10715446”
},
{
”adamId”:435160039,
”adamIdStr”:”435160039”,
”clientUserIdStr”:”9a17b450-9820-471e-b232-13a479ddede0”,
”isIrrevocable”:true,
”itsIdHash”:”LsrJ6NhzbsOzQXShrpUTWGnD/X8=”,
”licenseId”:795047681,
”licenseIdStr”:”795047681”,
”pricingParam”:”PLUS”,
”productTypeId”:10,
”productTypeName”:”Publication”,
”status”:”Associated”,
”userId”:6561022,
”userIdStr”:”6561022”
},
{
”adamId”:645859810,
”adamIdStr”:”645859810”,
”isIrrevocable”:false,
”licenseId”:967494668,
”licenseIdStr”:”967494668”,
”pricingParam”:”STDQ”,
”productTypeId”:8,
”productTypeName”:”Application”,
172
”serialNumber”:”C39N3035G68P”,
”status”:”Associated”
}
]
Request to getVPPUsersSrv
{”sToken”:”h40Gte9aQnZFDNM39IUkRPCsQDxBxbZB4Wy34pxefOuQkeeb3h2
a5Rlopo4KDn3MrFKf4CM3OY+WGAoZ1cD6iZ6yzsMk1+5PVBNc66YS6ZQ=”}
curl https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/getVPPUsersSrv -d
@get_users.json
The response:
{
”users”:[
{
”userId”:1,
”email”:”[email protected]”,
”clientUserIdStr”:”200006”,
”status”:”Associated”
”itsIdHash”:”C2Wwd8LcIaE2v6f2/mvu82Gs/Lc=”
},
{
”userId”:2,
”email”:”[email protected]”,
”clientUserIdStr”:”200007”,
”status”:”Associated”
”itsIdHash”:”*leSKk3IaE2vk2KLmv2k3/200D3=”
},
{
”userId”:3,
”email”:”[email protected]”,
”clientUserIdStr”:”[email protected]”,
”status”:”Registered”,
”inviteCode”:”f551b37da07146628e8dcbe0111f0364”
”inviteUrl”:”https:\/\/fanyv88.com:443\/https\/buy.itunes.apple.com\/WebObjects\/MZFinance.woa\/wa\/
associateVPPUserWithITSAccount?inviteCode=
f551b37da07146628e8dcbe0111f0364&mt=8”,
},
{
”userId”:4,
”email”:”[email protected]”,
173
”clientUserIdStr”:”[email protected]”,
”status”:”Registered”,
”inviteUrl”:”https:\/\/fanyv88.com:443\/https\/buy.itunes.apple.com\/WebObjects\/MZFinance.woa\/wa\/
associateVPPUserWithITSAccount?inviteCode=
859c5aa3485a48918a5f4f70c5629ec8&mt=8”,
”inviteCode”:”859c5aa3485a48918a5f4f70c5629ec8”
}
],
”status”:0,
”totalCount”:4
}
Request to getVPPUserSrv
{”userId”: 1, ”sToken”:”h40Gte9aQnZFDNM39IUkRPCsQDxBxbZB4Wy34pxefOuQ
keeb3h2a5Rlopo4KDn3MrFKf4CM3OY+WGAoZ1cD6iZ6yzsMk1+5PVBNc66YS6ZQ=”}
curl https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/getVPPUserSrv -d
@get_user.json
The response:
{
”status”:0,
”user”:{
”userId”:1,
”email”:”[email protected]”,
”clientUserIdStr”:”200006”,
”status”:”Associated”,
”itsIdHash”:”C2Wwd8LcIaE2v6f2/mvu82Gs/Lc=”
”licenses”:[
{
”licenseId”:2,
”adamId”:408709785,
”productTypeId”:7,
”pricingParam”:”STDQ”,
”productTypeName”:”Software”,
”isIrrevocable”:false
},
{
”licenseId”:4,
”adamId”:497799835,
”productTypeId”:7,
”pricingParam”:”STDQ”,
174
”productTypeName”:”Software”,
”isIrrevocable”:false
}
]
}
}
Request to registerVPPUserSrv
curl https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/registerVPPUserSrv -d
@reg_user.json
The response:
{
”status”:0,
”user”:{
”userId”:100014,
”email”:”[email protected]”,
”status”:”Registered”,
”inviteUrl”: ”https:\/\/fanyv88.com:443\/https\/buy.itunes.apple.com\/WebObjects\/MZFinance.woa\/
wa\/associateVPPUserWithITSAccount?inviteCode=
89e8d1ecc57924d9da13b42b4f772a066&mt=8”,
”inviteCode”:”9e8d1ecc57924d9da13b42b4f772a066”,
”clientUserIdStr”:”200002”
}
}
Request to editVPPUserSrv
The command:
175
curl https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/editVPPUserSrv -d
@edit_user.json
The response:
{
”status”:0,
”user”:{
”userId”:100014,
”email”:”[email protected]”,
”status”:”Registered”,
”inviteUrl”: ”https:\/\/fanyv88.com:443\/https\/buy.itunes.apple.com\/WebObjects\/MZFinance.woa\/
wa\/associateVPPUserWithITSAccount?inviteCode=
9e8d1ecc57924d9da13b42b4f772a066&mt=8”,
”inviteCode”:”9e8d1ecc57924d9da13b42b4f772a066”,
”clientUserIdStr”:”200015”,
”itsIdHash”:”C2Wwd8LcIaE2v6f2/mvu82Gs/Lc=”
}
}
Request to retireVPPUserSrv
{”userId”: 1, ”sToken”:
”h40Gte9aQnZFDNM39IUkRPCsQDxBxbZB4Wy34pxefOuQkeeb3h2a5Rlopo4KDn3MrFKf4CM3OY+
WGAoZ1cD6iZ6yzsMk1+5PVBNc66YS6ZQ=” }
The command:
curl https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/retireVPPUserSrv -d
@retire_user.json
The response:
{
”status”:0,
”user”:{
”userId”:1,
”email”:”[email protected]”,
”clientUserIdStr”:”200006”,
”status”:”Retired”,
”licenses”:[
{
”licenseId”:2,
176
”adamId”:408709785,
”productTypeId”:10,
”pricingParam”:”STDQ”,
”productTypeName”:”Publication”,
”isIrrevocable”:true
}
]
}
}
Request to getVPPAssetsSrv
The command:
curl https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/getVPPAssetsSrv -d
@get_assets.json
{
”assets”: [
{
”adamIdStr”: ”748057890”,
”assignedCount”: 0,
”availableCount”: 25,
”deviceAssignable”: true,
”isIrrevocable”: false,
”pricingParam”: ”STDQ”,
”productTypeId”: 8,
”productTypeName”: ”Application”,
”retiredCount”: 0,
”totalCount”: 25
},
{
”adamIdStr”: ”635851129”,
”assignedCount”: 0,
”availableCount”: 40,
”deviceAssignable”: true,
”isIrrevocable”: false,
”pricingParam”: ”STDQ”,
”productTypeId”: 8,
”productTypeName”: ”Application”,
”retiredCount”: 0,
”totalCount”: 40
},
{
”adamIdStr”: ”284035177”,
177
”assignedCount”: 0,
”availableCount”: 0,
”deviceAssignable”: false,
”isIrrevocable”: false,
”pricingParam”: ”STDQ”,
”productTypeId”: 8,
”productTypeName”: ”Application”,
”retiredCount”: 10,
”totalCount”: 0
}
],
”location”: {
”locationId”: 22222222222,
”locationName”: “”LocationName
},
”status”: 0,
”totalCount”: 3,
”uId”: ”103614”
}
The response using a legacy token (migrated or non-migrated to VPP in ASM account):
{
”assets”: [
{
”adamIdStr”: ”748057890”,
”assignedCount”: 0,
”availableCount”: 10,
”deviceAssignable”: true,
”isIrrevocable”: false,
”pricingParam”: ”STDQ”,
”productTypeId”: 8,
”productTypeName”: ”Application”,
”retiredCount”: 0,
”totalCount”: 10
}
],
”status”: 0,
”totalCount”: 1,
”uId”: ”103299”
}
Request to VPPClientConfigSrv
The command:
178
curl https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/VPPClientConfigSrv -d
@client_config.json
{
”appleId”: “testuser1@test.”org,
”countryCode”: ”US”,
”email”: ”[email protected]”,
”location”: {
”locationId”: 22222222222,
”locationName”: “”LocationName
},
”organizationId”: 2000000001630588,
”organizationIdHash”: ”0420773
fb70e423ef77916dee3b381987e6c3fb4d8f19d1fd071b0c48c0cd380”,
”status”: 0,
”uId”: ”103614”
}
The response using a legacy token for an account which has not been migrated to VPP in ASM:
{
”apnToken”: ”4IbRbXpge3ySkchugcf”,
”appleId”: “test1@test.”org,
”clientContext”: ”{\”guid\”:\”b92\”,\”hostname””\:\test.test.org””\,\ac2\”:1}”,
”countryCode”: ”US”,
”email”: “test1@test.”org,
”facilitatorMemberId”: 123456,
”libraryId”: 123456,
”organizationId”: 2222222222,“”
organizationIdHash”:2555009
cd3e53bd69b50723d2baec9f49558cbd90de2a1aa420dacdbff12cc8e”,
”status”: 0,
”uId”: “”123456
}
The response using a legacy token for an account which has been migrated to VPP in ASM:
{
”appleId”: “test2@test.”org,
”countryCode”: ”US”,
”email”: ”[email protected]”,
”facilitatorMemberId”: 11111,
”libraries”: [
{
”appleId”: “test3@test3.”org,
”email”: ”[email protected]”,
”libraryId”: 11112,
179
”location”: {
”locationId”: 2222221,
”locationName”: “Elementary ”School
}
},
{
”appleId”: “test4@test.”org,
”email”: ”[email protected]”,
”libraryId”: 11113,
”location”: {
”locationId”: 2222221,
”locationName”: “Elementary ”School
}
},
{
”appleId”: “test2@test.”org,
”email”: ”[email protected]”,
”libraryId”: 11111,
”location”: {
”locationId”: 2222221,
”locationName”: “Elementary ”School
}
},
{
”appleId”: “test2@test.”org,
”email”: ”[email protected]”,
”libraryId”: 11114,
”location”: {
”locationId”: 2222222,
”locationName”: “Middle ”School
}
},
”libraryId”: 11111,
”organizationId”: 200000000,
”organizationIdHash”: ”7a002fe8b88fc00738c4d74382b94a1e464b65”,
”status”: 0,
”uId”: ””11111,
”vppGroupMembers”: [
{
”appleId”: ”[email protected]”,
”email”: ”[email protected]”,
”facilitatorMemberId”: 11112,
”locationId”: 2222221,
”locationName”: “Elementary “School,
”organizationId”: 200000000
},
{
”appleId”: ”[email protected]”,
180
”email”: ”[email protected]”,
”facilitatorMemberId”: 11113,
”locationId”: 2222221,
”locationName”: ”Elementary School”,
”organizationId”: 200000000
},
{
”appleId”: ”[email protected]”,
”email”: ”[email protected]”,
”facilitatorMemberId”: 11111,
”locationId”: 2222221,
”locationName”: ”Elementary School”,
”organizationId”: 200000000
},
{
”appleId”: ”[email protected]”,
”email”: ”[email protected]”,
”facilitatorMemberId”: 11114,
”locationId”: 2222222,
”locationName”: “Middle “School,
”organizationId”: 200000000
}
]
}
Request to manageVPPLicensesByAdamIdSrv
The command:
curl https://vpp.itunes.apple.com/WebObjects/MZFinance.woa/wa/
manageVPPLicensesByAdamIdSrv -d @manage.json
{
”associations”: [
{
”adamId”: 869183446,
”clientUserIdStr”: ”userIdStr”,
”isIrrevocable”: false,
”licenseId”: 840998,
”pricingParam”: ”STDQ”,
”productTypeId”: 8,
”productTypeName”: ”Application”,
”status”: ”Associated”,
”userId”: 204701
}
181
],
”status”: 0,“”
uId””:111123
}
{
”associations”: [
{
”adamId”: 869183446,
”isIrrevocable”: false,
”licenseId”: 840999,
”pricingParam”: ”STDQ”,
”productTypeId”: 8,
”productTypeName”: ”Application”,
”serialNumber”: ”MERD1”,
”status”: ”Associated”
},
{
”adamId”: 869183446,
”isIrrevocable”: false,
”licenseId”: 841000,
”pricingParam”: ”STDQ”,
”productTypeId”: 8,
”productTypeName”: ”Application”,
”serialNumber”: ”MERD2”,
”status”: ”Associated”
}
],
”status”: 0,“”
uId””:11234
}
182
Managed Apps and Updates
This chapter describes the process and supporting services needed to manage the apps and OS updates on
supervised devices.
Managing Applications
MDM is the recommended way to manage applications for your enterprise. You can use MDM to help users install
enterprise apps, and in iOS 5.0 and later, you can also install App Store apps purchased using the Volume Purchase
Program (VPP). The way that you manage these applications depends on the version of iOS that a device is running.
In iOS 9.0 and later, you can use MDMʼs app assignment feature to assign app licenses to device serial numbers.
MDM can then be used to push a VPP app to a device regardless of whether an iTunes account is signed in. You can
later remove those licenses and use them with other devices.
In iOS 7.0 and later, you can use MDMʼs app assignment feature to assign app licenses to iTunes accounts. MDM can
then be used to push a VPP app to a device that is signed in to that iTunes account. You can later remove those
licenses and use them with other iTunes accounts.
Also, in iOS 7.0 and later, an MDM server can provide configuration dictionaries to managed apps and can read
response dictionaries from those apps. Apps can take advantage of this functionality to preconfigure themselves in
a supervised environment, such as a classroom setting.
In iOS 5.0 and later, using MDM to manage apps gives you several advantages:
• You can purchase apps for users without manually distributing redemption codes.
• You can notify the user that an app is available for installation. (The user must agree to installation before the
app is installed.)
183
• A managed app can be excluded from the userʼs backup. This prevents the appʼs data from leaving the device
during a backup.
• The app can be configured so that the app and its data are automatically removed when the MDM profile is
removed. This prevents the appʼs data from persisting on a device unless it is managed.
An app purchased from the App Store and installed on a userʼs device is “owned” by the iTunes account used at the
time of installation. This means that the user may install the app (not its data) on unmanaged devices.
An app internally developed by an enterprise is not backed up. A user cannot install such an app on an unmanaged
device.
In order to support this behavior, your internally hosted enterprise app catalog must use the InstallApplication
command instead of providing a direct link to the app (with a manifest URL or iTunes Store URL). This allows you to
mark the app as managed during installation.
To disable enterprise apps, you can remove the provisioning profile that they depend on. However, as mentioned in
Provisioning Profiles Can Be Installed Using MDM, do not rely solely on that mechanism for limiting access to your
enterprise applications for two reasons:
• Removing a provisioning profile does not prevent the app from launching until the device is rebooted.
• The provisioning profile is likely to have been synced to a computer, and thus will probably be reinstalled
during the next sync.
• Have an online method of authenticating users when they launch your app. Use either a password or identity
certificate to authenticate the user.
• Store local app data in your applicationʼs Caches folder to prevent the data from being backed up.
• When you decide that the user should no longer have access to the applicationʼs data, mark the userʼs
account on the server inactive in some way.
• When your app detects that the user is no longer eligible to access the app, if the data is particularly sensitive,
it should erase the local app data.
• If your application has an offline mode, limit the amount of time users can access the data before
reauthenticating online. Ensure that this timeout is enforced across multiple application launches.
If desired, you can also limit the number of launches to prevent time server forging attacks.
Be sure to store any information about the last successful authentication in your Caches folder (or in the
keychain with appropriate flags) so that it does not get backed up. If you do not, the user could potentially
modify the time stamp in a backup file, resync the device, and continue using the application.
These guidelines assume that all the applicationʼs data is replicated on your server. If you have data that resides only
on the device (including offline edits), preserve a copy of the userʼs changes on the server. Be sure to do so in a way
that protects the integrity of the serverʼs data against disgruntled former users.
184
Managing OS Software Updates
MDM commands can restrict updates or initiate updates of the operating system on managed devices. The Apple
Software Lookup Service provides a list of available OS versions across platforms to help determine which OS to use.
Restricting Updates
Administrators can delay the availability of OS updates on the device via the Restrictions Payload. Use the
forceDelayedSoftwareUpdates key to enable the feature and the enforcedSoftwareUpdateDelay to
define how many days the update should be delayed.
Software Updates
Send Software Update commands to the device to update to a specific OS version on the device. Administrators can
also control when the device should be updated.
The JSON repsonse contains two lists of available software releases. The AssetSets list contains all the releases
available for MDMs to push to their supervised devices. The other list, PublicAssetSets contains the latest
releases available to the general public (non-supervised devices) if they try to upgrade. The PublicAssetSets is a
subset of the AssetSets list.
Each element in the list contains the product version number of the OS, the posting date, the expiration date, and a
list of supported devices for that release. The device list will match the ProductName values from the device, which
is returned in the initial Authenticate request or the DeviceInformation response.
The expiration date is typically set to 180 days after the posting date. When subsequent releases are made, previous
releases could have their expiration dates updated. If an expiration date is not provided, the release has not expired.
A release has expired only when it has an expiration date in the past.
{
”PublicAssetSets”: {
”iOS”: [
{“
ProductVersion”: ”10.0.2”,
”PostingDate”: ”2017-11-29”,
”ExpirationDate”: ”2018-05-26”,
”SupportedDevices”: [”iPad3,4”, ”iPad3,5”, ”iPhone5,1”, ”iPhone5,2”, ”iPod7,1”]
},
{
”ProductVersion”: ”7.0.1”,
”PostingDate”: ”2017-11-29”,
”ExpirationDate”: ”2018-05-26”,
185
”SupportedDevices”: [”AppleTV2,1”]
}
]
},
”AssetSets”: {
”iOS”: [
{
”ProductVersion”: ”10.0.2”,
”PostingDate”: ”2017-11-29”,
”ExpirationDate”: ”2018-05-26”,
”SupportedDevices”: [”iPad3,4”, ”iPad3,5”, ”iPhone5,1”, ”iPhone5,2”, ”iPod7,1”]
},
{
”ProductVersion”: ”7.0.1”,
”PostingDate”: ”2017-11-29”,
”ExpirationDate”: ”2018-05-26”,
”SupportedDevices”: [”AppleTV2,1”]
},
{
”ProductVersion”: ”10.0.1”,
”PostingDate”: ”2017-11-10”,
”ExpirationDate”: ”2018-05-07”,
”SupportedDevices”: [”iPad3,4”, ”iPad3,5”, ”iPhone5,1”, ”iPhone5,2”, ”iPod7,1”]
}
]
}
}
Use the product version list to determine which versions are greater than the deviceʼs current OS version. Provide
that list of versions to the administrator as potential OS update candidates.
The assets are grouped by OS platform. Currently, all the assets are under iOS, including tvOS and watchOS.
When the allowOpenFromManagedToUnmanaged restriction is specified, an Open In sheet started from within a
managed app or account shows only other managed apps and accounts. When the
allowOpenFromUnmanagedToManaged restriction is specified, an Open In sheet started from within an
unmanaged app or account shows only other unmanaged apps and accounts.
The Open In sheet shown by Safari and AirDrop continues to show all apps and accounts even when these
restrictions are specified.
It is a best practice to use these restrictions to manage data and attachments on a userʼs device.
186
Class Rosters
This chapter describes a system of MDM APIs, introduced with iOS 9.3, that retrieve roster information for schools
and other personnel-based organizations. These APIs form an extension to the Device Enrollment Program API, so
the DEP initial authentication steps are required before sending requests to the roster service.
Roster information does not require extra security beyond that provided by DEP tokens submitted to any MDM server.
See DEP Server Tokens.
Note
The Roster APIs are read-only. It is not possible to change roster information using MDM.
Requests
To access this information, POST a request in JSON format and UTF-8 charset to the following URL:
https://mdmenrollment.apple.com/roster/class.
The request body should contain a JSON dictionary with the following keys:
cursor String Optional. A hex string that represents the starting position for a request. This is
used for pagination. On the initial request, this should be omitted.
limit Integer Optional. The maximum number of entries to return. The default value is 1000 and
the maximum value is 1000.
187
X-ADM-Auth-Session: 87a235815b8d6661ac73329f75815b8d6661ac73329f815
Content-Type: application/json;charset=UTF8
Content-Length: <Content-Length>
<CodeLine>Host: [&#60;]vip-name[&#62;]</CodeLine>
<CodeLine>Cookie: ...</CodeLine>
{
”limit”: 1000,
”cursor”: ”1ac73329f75817”
}
Responses
In response, the MDM service returns a JSON dictionary with following keys:
cursor String Optional. A hex string that should be used for the next request to
paginate. This field data type has a maximum length of 512 UTF-8
characters.
more_to_follow Boolean Indicates whether the requestʼs limit and cursor values resulted in only a
partial list of classes. If true, the MDM server should then make another
request (starting from the newly returned cursor) to obtain additional
records.
classes Array of Provides information about classes, sorted in lexical order by a class
dictionaries source_system_identifier. The organization must provide this identifier to
Apple.
188
Key Type Content
Note
The value of source_system_identifier in this and other roster API responses is not guaranteed to be
unique and can potentially change.
name String Optional. Course name. Maximum length 1024 UTF-8 characters.
unique_identifier String Unique identifier for the course. Maximum length 256 UTF-8 characters.
The response contains a list of classes. Each class record contains the location where the class is held and the
instructors and students that are registered for that class. It also identifies the course with which the class is
associated. The more_to_follow Boolean indicates if more class information remains to be fetched. The client
should read this flag to determine if subsequent requests are necessary to get the next batch of classes.
The class list could be huge. If modifications are performed while the response is being returned, it will not return
any classes created after it started responding. If any updates are applied on any of the entities or attributes, you
must send the request again to get the latest snapshot of classes.
{
”classes”: [
{
”unique_identifier”: ”UNICLS1003”,
”source”: ”SIS”,
”source_system_identifier”: ”CLSBIO101”,
”name”: ”Miss Smith's Biology 101”,
189
”class_number”: ”1A”,
”room”: ”Hall 101”,
”location”: {
”unique_identifier”: ”UNILOC1003”,
”name”: ”Biology department”
},
”instructor_unique_identifiers”: [
”UNIINSTID1003”,
”UNIINSTID1003”
],
”student_unique_identifiers”: [
”UNISTUDID1003”,
”UNISTUDID1004”
],
”course”: {
”unique_identifier”: ”UNICOURID1003”,
”name”: ”Biology 101”
}
}
],
”cursor”: ”1ac73329f75816”,
”more_to_follow”: ”false”
}
This sync service uses a cursor returned by the full class roster service. It returns a list of all modifications (additions
or deletions) made since the cursor date, up to 7 days.
This service may return the same class more than once. You can identify duplicates by matching their
unique_identifier values.
Requests
To access this information, POST a request in JSON format and UTF-8 charset to the following URL:
https://mdmenrollment.apple.com/roster/class/sync. The request body should contain a JSON
dictionary with the following keys:
cursor String Optional. A hex string that represents the starting position for a request, used for
pagination. This position should not be older than 7 days. On the initial request, it
should be omitted.
limit Integer Optional. The maximum number of entries to return. The default value is 1000 and
the maximum value is 1000.
190
With its required header, a typical request looks like this:
Only content of type application/json in UTF-8 charset will be accepted by the server.
Responses
In response, the MDM service returns a JSON dictionary with following keys:
cursor String Optional. A hex string that should be used for the next request to
paginate. This field data type has a maximum length of 512 UTF-8
characters.
more_to_follow Boolean Indicates whether the requestʼs limit and cursor values resulted in only a
partial list of classes. If true, the MDM server should then make another
request (starting from the newly returned cursor) to obtain additional
records.
fetched_until String A time and date stamp in ISO 8601 format specifying the latest date of
data being fetched.
classes Array of Provides information about classes, sorted in lexical order by a class
dictionaries source_system_identifier. The organization must provide this
identifier to Apple.
191
Key Type Content
name String Optional. Course name. Maximum length 1024 UTF-8 characters.
unique_identifier String Unique identifier for the course. Maximum length 256 UTF-8 characters.
One record in a typical successful Class Roster Sync Service response might look like this:
{
”classes”: [
{
”unique_identifier”: ”UNICLS1003”,
”source”: ”SIS”,
”source_system_identifier”: ”CLSBIO101”,
”name”: ”Miss Smith's Biology 101”,
”room”: ”Hall 101”,
”class_number”: ”1A”,
”location”: {
”unique_identifier”: ”UNILOC1003”,
”name”: ”Biology department”
192
},
”instructor_unique_identifiers”: [
”UNIINSTID1003”,
”UNIINSTID1003”
],
”student_unique_identifiers”: [
”UNISTUDID1003”,
”UNISTUDID1004”
],
”course”: {
”unique_identifier”: ”UNICOURID1003”,
”name”: ”Biology 101”
}
}
],
”cursor”: ”1ac73329f75816”,
”more_to_follow”: ”false”
”fetched_until”: ”2016-05-09T02:30:00Z”
}
• The response contains a list of classes. Each class record contains the location where the class is held and
the instructors and students that are registered for that class. It also identifies the course with which the class
is associated.
• The more_to_follow Boolean indicates if more class information remains to be fetched. The client should
read this flag to determine if subsequent requests are necessary to get the next batch of classes.
• The server will issue a cursor in all responses. If the cursor is sent in the next request, the server will return
next set of records in chronological order and issue a new cursor.
• Data changes will be recognized up to the fetched_until time, which may be a few minutes behind real
time.
• This service does not return deleted data. The client is expected to do a full sync and compare once every few
days to identify deletes.
• For a discussion of potential problems with using the Class Roster Sync Service, see Error Responses.
Requests
To access this information, POST a request in JSON format and UTF-8 charset to the following URL:
https://mdmenrollment.apple.com/roster/class/person. The request body should contain a JSON
193
dictionary with the following keys:
cursor String Optional. A hex string that represents the starting position for a request. This is
used for pagination. On the initial request, this should be omitted.
limit Integer Optional. The maximum number of entries to return. The default value is 1000 and
the maximum value is 1000.
Responses
In response, the MDM service returns a JSON dictionary with following keys:
cursor String Optional. A hex string that should be used for the next request to
paginate. This field data type has a maximum length of 512 UTF-8
characters.
more_to_follow Boolean Indicates whether the requestʼs limit and cursor values resulted in only a
partial list of persons. If true, the MDM server should then make another
request (starting from the newly returned cursor) to obtain additional
records.
persons Array of Provides information about persons, both teachers and students, sorted
dictionaries in lexical order by a person source_system_identifier. The organization
must provide this identifier to Apple.
194
Key Type Content
first_name String Personʼs first name. Maximum length 1024 UTF-8 characters.
Available in protocol version 3 and above.
middle_name String Optional. Personʼs middle name. Maximum length 1024 UTF-8
characters. Available in protocol version 3 and above.
last_name String Personʼs last name. Maximum length 1024 UTF-8 characters.
Available in protocol version 3 and above.
name String Personʼs name. Maximum length 1024 UTF-8 characters.
managed_apple_id String Managed Apple ID for the person. Maximum length 1024
UTF-8 characters.
unique_identifier String Unique identifier for the person. Maximum length 256 UTF-8
characters.
passcode_type String The password policy of the person. Possible values are
“complex”, “four”, or “six”. Available in protocol version 3 and
above.
source String Data source where class was created. Possible values include
“iTunes U,” “SIS,” “CSV,” ”SFTP,” ”SYSTEM,” and “MANUAL.”
Maximum length is 64 UTF-8 characters.
source_system_identifier String Identifier configured by organization for the person. Maximum
length 256 UTF-8 characters.
grade String Optional; not used for instructors. Student grade information.
Maximum length 256 UTF-8 characters. Value can be null.
status String Indicates the status of the person. Possible values are Active
and InActive.
Availability: Available in X-Protocol Version 3 and later.
person_id String Optional. Indicates the personid of the person as displayed
in ASM.
Availability: Available in X-Protocol Version 4 and later.
sis_username String Optional. Indicates the SIS usernname of the person as
displayed in ASM.
Availability: Available in X-Protocol Version 5 and later.
email_address String Optional. Indicates the email address of the person as
displayed in ASM.
Availability: Available in X-Protocol Version 5 and later.
The response contains a list of persons. The more_to_follow Boolean indicates if more information about
persons remains to be fetched. The client should read this flag to determine if subsequent requests are necessary to
get the next batch of persons.
The person list could be huge. If modifications are performed while the response is being returned, it will not return
any persons enrolled after it started responding. If any updates are applied on any of the entities or attributes, you
must send the request again to get the latest snapshot of personnel.
HTTP/1.1 200 OK
Date: Mon,12 Oct 2015 02:25:30 GMT
Content-Type: application/json;charset=UTF8
195
X-ADM-Auth-Session: 87a235815b8d6661ac73329f75815b8d6661ac73329f815
Content-Length: ...
Connection: Keep-Alive
{
”persons”: [
{
”unique_identifier”: ”UNIINSTID1003”,
”source”: ”CSV”,
”source_system_identifier”: ”INSTID1003”,
”name”: ”Miss Will Smith”,
”managed_apple_id”: ”[email protected]”
”first_name”: ”Miss”,
”middle_name”: ”Will”,
”last_name”: ”Smith”,
”passcode_type”: ”complex”,
”person_id”: ”6378376667”,
”status”: ”Active”
},
{
”unique_identifier”: ”UNISTUDID1003”,
”source”: ”SIS”,
”source_system_identifier”: ”INSTSTUDID1003”,
”name”: ”John Smith”,
”managed_apple_id”: ”[email protected]”,
”grade”: ”K”
”first_name”: ”John”,
”last_name”: ”Smith”,
”passcode_type”: ”four”,
”person_id”: ”4909090667”,
”status”: ”Active”
}
],
”cursor”: ”1ac73329f75816”,
”more_to_follow”: ”false”
}
This sync service uses a cursor returned by the full person roster service. It returns a list of all modifications
(additions or deletions) made since the cursor date, up to 7 days.
This service may return the same person more than once. You can identify duplicates by matching their
unique_identifier values.
196
Requests
To access this information, POST a request in JSON format and UTF-8 charset to the following URL:
https://mdmenrollment.apple.com/roster/class/person/sync. The request body should contain a
JSON dictionary with the following keys:
cursor String Optional. A hex string that represents the starting position for a request, used for
pagination. This position should not be older than 7 days. On the initial request, it
should be omitted.
limit Integer Optional. The maximum number of entries to return. The default value is 1000 and
the maximum value is 1000.
Only content of type application/json in UTF-8 charset will be accepted by the server.
Responses
In response, the MDM service returns a JSON dictionary with following keys:
cursor String Optional. A hex string that should be used for the next request to
paginate. This field data type has a maximum length of 512 UTF-8
characters.
fetched_until String A time and date stamp in ISO 8601 format specifying the latest date of
data being fetched.
more_to_follow Boolean Indicates whether the requestʼs limit and cursor values resulted in only a
partial list of persons. If true, the MDM server should then make another
request (starting from the newly returned cursor) to obtain additional
records.
197
Key Type Content
persons Array of Provides information about persons, both teachers and students, sorted
dictionaries in lexical order by a person source_system_identifier. The organization
must provide this identifier to Apple.
One record in a typical successful Person Roster Sync Service response might look like this:
198
{
”persons”: [
{
”unique_identifier”: ”UNIINSTID1003”,
”source”: ”CSV”,
”source_system_identifier”: ”INSTID1003”,
”name”: ”Miss Will Smith”,
”managed_apple_id”: ”[email protected]”
”first_name”: ”Miss”,
”middle_name”: ”Will”,
”last_name”: ”Smith”,
”passcode_type”: ”complex”,
”person_id”: ”627626672”,
”status”: ”Active”
},
{
”unique_identifier”: ”UNISTUDID1003”,
”source”: ”SIS”,
”source_system_identifier”: ”INSTSTUDID1003”,
”name”: ”John Smith”,
”managed_apple_id”: ”[email protected]”,
”grade”: ”K”
”first_name”: ”John”,
”last_name”: ”Smith”,
”passcode_type”: ”four”,
”person_id”: ”7873878737”,
”status”: ”Active”
}
],
”cursor”: ”1ac73329f75816”,
”more_to_follow”: ”false”
”fetched_until”: ”2016-05-09T02:30:00Z”
}
• The more_to_follow Boolean indicates if more information remains to be fetched. The client should read
this flag to determine if subsequent requests are necessary to get the next batch of persons.
• The server will issue a cursor in all responses. If the cursor is sent in the next request, the server will return
next set of records in chronological order and issue a new cursor.
• This service does not return deleted data. The client is expected to do a full sync and compare once every few
days to identify deletes.
• For a discussion of potential problems with using the Person Roster Sync Service, see Error Responses.
199
Location Information
This API returns information for an organization about the locations where any classes are held.
Requests
To access this information, POST a request in JSON format and UTF-8 charset to the following URL:
https://mdmenrollment.apple.com/roster/class/location. The request body should contain a JSON
dictionary with the following keys:
cursor String Optional. A hex string that represents the starting position for a request. This is
used for pagination. On the initial request, this should be omitted.
limit Integer Optional. The maximum number of entries to return. The default value is 1000 and
the maximum value is 1000.
Responses
In response, the MDM service returns a JSON dictionary with the following keys:
cursor String Optional. A hex string that should be used for the next request to
paginate. This field data type has a maximum length of 512 UTF-8
characters.
more_to_follow Boolean Indicates whether the requestʼs limit and cursor values resulted in only a
partial list of locations. If true, the MDM server should then make another
request (starting from the newly returned cursor) to obtain additional
records.
200
Key Type Content
locations Array of Provides information about locations, sorted in lexical order by a location
dictionaries source_system_identifier. The organization must provide this identifier to
Apple.
The response contains a list of locations. The more_to_follow Boolean indicates if more information about
locations remains to be fetched. The client should read this flag to determine if subsequent requests are necessary
to get the next batch of locations.
If modifications to locations are performed while the response is being returned, it will not return any locations
rostered after it started responding. If any updates are applied on any of the entities or attributes, you must send the
request again to get the latest snapshot of locations in use.
HTTP/1.1 200 OK
Date: Mon,12 Oct 2015 02:25:30 GMT
Content-Type: application/json;charset=UTF8
X-ADM-Auth-Session: 87a235815b8d6661ac73329f75815b8d6661ac73329f815
Content-Length: ...
Connection: Keep-Alive
{
”locations”: [
{
”unique_identifier”: ”UNILOC1003”,
”source”: ”SIS”,
”source_system_identifier”: ”INSTLOCID1003”,
”name”: ”Biology department”
}
],
”cursor”: ”1ac73329f75816”,
”more_to_follow”: ”false”
}
201
Location Roster Sync Service
This sync service uses a cursor returned by the full location roster service. It returns a list of all modifications
(additions or deletions) made since the cursor date, up to 7 days.
This service may return the same location more than once. You can identify duplicates by matching their
unique_identifier values.
Requests
To access this information, POST a request in JSON format and UTF-8 charset to the following URL:
https://mdmenrollment.apple.com/roster/class/location/sync. The request body should contain a
JSON dictionary with the following keys:
cursor String Optional. A hex string that represents the starting position for a request, used for
pagination. This position should not be older than 7 days. On the initial request, it
should be omitted.
limit Integer Optional. The maximum number of entries to return. The default value is 1000 and
the maximum value is 1000.
Only content of type application/json in UTF-8 charset will be accepted by the server.
Responses
In response, the MDM service returns a JSON dictionary with following keys:
202
Key Type Content
cursor String Optional. A hex string that should be used for the next request to
paginate. This field data type has a maximum length of 512 UTF-8
characters.
fetched_until String A time and date stamp in ISO 8601 format specifying the latest date of
data being fetched.
more_to_follow Boolean Indicates whether the requestʼs limit and cursor values resulted in only a
partial list of locations. If true, the MDM server should then make
another request (starting from the newly returned cursor) to obtain
additional records.
locations Array of Provides information about locations, sorted in lexical order by a location
dictionaries source_system_identifier. The organization must provide this
identifier to Apple.
One record in a typical successful Location Roster Sync Service response might look like this:
{
”locations”: [
{
”unique_identifier”: ”UNILOC1003”,
”source”: ”SIS”,
”source_system_identifier”: ”INSTLOCID1003”,
”name”: ”Biology department”,
}
],
”cursor”: ”1ac73329f75816”,
”more_to_follow”: ”false”
”fetched_until”: ”2016-05-09T02:30:00Z”
}
203
Note these features and cautions:
• The more_to_follow Boolean indicates if more locations remain to be fetched. The client should read this
flag to determine if subsequent requests are necessary to get the next batch of locations.
• The server will issue a cursor in all responses. If the cursor is sent in the next request, the server will return
next set of records in chronological order and issue a new cursor.
• This service does not return deleted data. The client is expected to do a full sync and compare once every few
days to identify deletes.
• For a discussion of potential problems with using the Location Roster Sync Service, see Error Responses.
Requests
To access this information, POST a request in JSON format and UTF-8 charset to the following URL:
https://mdmenrollment.apple.com/roster/course. The request body should contain a JSON dictionary
with the following keys:
cursor String Optional. A hex string that represents the starting position for a request. This is
used for pagination. On the initial request, this should be omitted.
limit Integer Optional. The maximum number of entries to return. The default value is 1000 and
the maximum value is 1000.
204
Responses
In response, the MDM service returns a JSON dictionary with following keys:
cursor String Optional. A hex string that should be used for the next request to
paginate. This field data type has a maximum length of 512 UTF-8
characters.
more_to_follow Boolean Indicates whether the requestʼs limit and cursor values resulted in only a
partial list of courses. If true, the MDM server should then make another
request (starting from the newly returned cursor) to obtain additional
records.
courses Array of Provides information about courses, sorted in lexical order by a course
dictionaries source_system_identifier. The organization must provide this identifier to
Apple.
The response contains a list of courses. The more_to_follow Boolean indicates if more information about courses
remains to be fetched. The client should read this flag to determine if subsequent requests are necessary to get the
next batch of courses.
If modifications to the course catalog are performed while the response is being returned, it will not return any
courses rostered after it started responding. If any updates are applied on any of the entities or attributes, you must
send the request again to get the latest snapshot of courses.
HTTP/1.1 200 OK
Date: Mon,12 Oct 2015 02:25:30 GMT
Content-Type: application/json;charset=UTF8
X-ADM-Auth-Session: 87a235815b8d6661ac73329f75815b8d6661ac73329f815
Content-Length: ...
Connection: Keep-Alive
205
”courses”: [
{
”unique_identifier”: ”UNICOURID1003”,
”source”: ”SIS”,
”source_system_identifier”: ”INSTCOURSEID1003”,
”name”: ”Biology 101”
}
],
”cursor”: ”1ac73329f75816”,
”more_to_follow”: ”false”
}
This sync service uses a cursor returned by the full course roster service. It returns a list of all modifications
(additions or deletions) made since the cursor date, up to 7 days.
This service may return the same course more than once. You can identify duplicates by matching their
unique_identifier values.
Requests
To access this information, POST a request in JSON format and UTF-8 charset to the following URL:
https://mdmenrollment.apple.com/roster/course/sync. The request body should contain a JSON
dictionary with the following keys:
cursor String Optional. A hex string that represents the starting position for a request, used for
pagination. This position should not be older than 7 days. On the initial request, it
should be omitted.
limit Integer Optional. The maximum number of entries to return. The default value is 1000 and
the maximum value is 1000.
206
”cursor”: ”1ac73329f75817”
}
Only content of type application/json in UTF-8 charset will be accepted by the server.
Responses
In response, the MDM service returns a JSON dictionary with following keys:
cursor String Optional. A hex string that should be used for the next request to
paginate. This field data type has a maximum length of 512 UTF-8
characters.
fetched_until String A time and date stamp in ISO 8601 format specifying the latest date of
data being fetched.
more_to_follow Boolean Indicates whether the requestʼs limit and cursor values resulted in only a
partial list of courses. If true, the MDM server should then make another
request (starting from the newly returned cursor) to obtain additional
records.
courses Array of Provides information about courses, sorted in lexical order by a course
dictionaries source_system_identifier. The organization must provide this
identifier to Apple.
One record in a typical successful Course Roster Sync Service response might look like this:
{
”courses”: [
{
”unique_identifier”: ”UNICOURID1003”,
”source”: ”SIS”,
207
”source_system_identifier”: ”INSTCOURSEID1003”,
”name”: ”Biology 101”,
}
],
”cursor”: ”1ac73329f75816”,
”more_to_follow”: ”false”
”fetched_until”: ”2016-05-09T02:30:00Z”
}
• The more_to_follow Boolean indicates if more course information remains to be fetched. The client should
read this flag to determine if subsequent requests are necessary to get the next batch of courses.
• The server will issue a cursor in all responses. If the cursor is sent in the next request, the server will return
next set of records in chronological order and issue a new cursor.
• This service does not return deleted data. The client is expected to do a full sync and compare once every few
days to identify deletes.
• For a discussion of potential problems with using the Course Roster Sync Service, see Error Responses, below.
Error Responses
Instead of the information responses described earlier in this chapter, MDM roster requests may return system errors.
You must read and respond to three kinds of errors:
• Server failures
• Client failures
• MDM errors
Server failures are mainly HTTP 500 and HTTP 503 errors:
208
Client failures are HTTP 4xx-series or HTTP 429 errors:
<ERROR CODE>
<ERROR CODE>
Client failures may return MDM error codes. When combined with HTTP codes, these errors give you the following
information:
• UNAUTHORIZED + HTTP 401: Auth token has expired. The client should retry with a new auth token.
• TOO_MANY_REQUESTS + HTTP 429: Too many requests. Retry after time mentioned in “Retry-After” HTTP
response header as per RFC 6585.
209
MDM Best Practices
Although there are many ways to deploy mobile device management, the techniques and policies described in this
chapter make it easier to deploy MDM in a sensible and secure fashion.
The initial profile deployed to a device should contain only the following payloads:
• A client identity certificate for use by the MDM payload (either a PKCS#12 container, or an SCEP payload). An
SCEP payload is recommended.
Once the initial profile is installed, your server can push additional managed profiles to the device.
In a single-user environment in macOS, installing an MDM profile causes the device to be managed by MDM (via
device profiles) and the user that installed the profile (via user profiles), but any other local user logging into that
machine will not be managed (other than via device profiles).
Multiple network users bound to Open Directory servers can also have their devices managed, assuming the MDM
server is configured to recognize them.
Configure each managed profile with a related pair of restrictions and capabilities (the proverbial carrots and sticks)
so that the user gets specific benefits (access to an account, for instance) in exchange for accepting the associated
restrictions.
210
For example, your IT policy may require a device to have a 6-character passcode (stick) in order to access your
corporate VPN service (carrot). You can do this in two ways:
• Deliver a single managed profile with both a passcode restriction payload and a VPN payload.
• Deliver a locked profile with a passcode restriction, optionally poll the device until it indicates compliance, and
then deliver the VPN payload.
Either technique ensures that the user cannot remove the passcode length restriction without losing access to the
VPN service.
Do not group multiple accounts together into a single profile. Having a separate profile for each account makes it
easier to replace and repair each accountʼs settings independently, add and delete accounts as access needs
change, and so on.
This advantage becomes more apparent when your organization uses certificate-based account credentials. As
client certificates expire, you can replace those credentials one account at a time. Because each profile contains a
single account, you can replace the credentials for that account without needing to replace the credentials for every
account.
Similarly, if a user requests a password change on an account, your servers could update the password on the
device. If multiple accounts are grouped together, this would not be possible unless the servers keep an
unencrypted copy of all of the userʼs other account passwords (which is dangerous).
To do this, deliver the provisioning profiles through MDM instead of distributing them through your corporate web
portal or bundled with the application.
Note
Although an MDM server can remove provisioning profiles, you should not depend on this mechanism to revoke
access to your enterprise applications for two reasons:
• An application continues to be usable until the next device reboot even if you remove the provisioning
profile.
• Provisioning profiles are synchronized with iTunes. Thus, they may get reinstalled the next time the user
syncs the device.
211
Passcode Policy Compliance
Because an MDM server may push a profile containing a passcode policy without user interaction, it is possible that
a userʼs passcode must be changed to comply with a more stringent policy. When this situation arises, a 60-minute
countdown begins. During this grace period, the user is prompted to change the passcode when returning to the
Home screen, but can dismiss the prompt and continue working. After the 60-minute grace period, the user must
change the passcode in order to launch any application on the device, including built-in applications.
An MDM server can check to see if a user has complied with all passcode restrictions using the SecurityInfo
command. An MDM server can wait until the user has complied with passcode restrictions before pushing other
profiles to the device.
Deployment Scenarios
There are several ways to deploy an MDM payload. Which scenario is best depends on the size of your organization,
whether an existing device management system is in place, and what your IT policies are.
• It is best practice to register VPP users and assign apps/books to those users before sending invitations to the
users. This makes each assignment faster because it does not need to put the item in the userʼs purchases at
the time of assignment. Also, because an invitation acceptance will likely occur well before an MDM
InstallApplication command is issued, the odds are higher that all licenses will have long since propagated to
the userʼs iTunes Store purchase history on the userʼs clients, which is a necessary step for
the InstallApplication command to succeed.
• It is best practice to invite an individual user to each VPP organization only once. By checking the
itsIdHash, MDM servers can detect when a single Apple ID accepts multiple invitations. Attempting to
assign licenses for the same item to multiple VPP users with the same itsIdHash results in an “Already
Assigned” error (code 9616).
• It is best practice to provide a helpful error message when receiving error 403, T_C_NOT_SIGNED, such as
“Terms and Conditions must be accepted. Please log into the Device Enrollment Program to accept the new
Terms and Conditions on behalf of your organization.”
You may use over-the air enrollment to deliver a profile to a device. This option allows your servers to validate a
userʼs login, query for more information about the device, and validate the deviceʼs built-in certificate before
delivering a profile containing an MDM payload.
When a profile is installed through over-the air enrollment, it is also eligible for updates. In iOS 7 and later, profiles
can be updated even after expiration, as described in Updating Expired Profiles. In older versions of iOS, when a
certificate in the profile is about to expire, an “Update” button appears that allows the user to fetch a more recent
copy of the profile using his or her existing credentials.
212
Device Enrollment Program
The Device Enrollment Program, when combined with an MDM server, makes it easier to deploy configuration
profiles over the air to devices that you own. When performed at the time of purchase, devices enrolled in this
program can prompt the user to begin the MDM enrollment process as soon as the device is first activated, removing
the need for preconfiguring each device.
The Device Enrollment Program allows devices to be supervised during activation. Supervised devices allow an
MDM server to apply additional restrictions and to send certain configuration commands that you otherwise cannot
send, such as setting the deviceʼs language and locale, starting and stopping AirPlay Mirroring, and so on. Also,
MDM profiles delivered using the Device Enrollment Program cannot be removed by the user.
MDM vendors can take advantage of web services provided by the Device Enrollment Program, integrating its
features with their services.
Vendor-Specific Installation
Third-party vendors may install the MDM profile in a variety of other ways that are integrated with their management
systems.
You may include the root certificate and any intermediate certificates in the same profile that contains the MDM
payload. Certificate payloads are installed before the MDM payload.
Your MDM server should replace the profile that contains the MDM payload well before any of the certificates in that
profile expire. Remember: If any certificate in the SSL trust chain expires, the device cannot connect to the server to
receive its commands. When this occurs, you lose the ability to manage the device.
Consult your organizationʼs Public Key Infrastructure policy to determine which method is appropriate for your
installation.
Identifying Devices
An MDM server should identify a connecting device by examining the deviceʼs client identity certificate. The server
should then cross-check the UDID reported in the message to ensure that the UDID is associated with the certificate.
213
The deviceʼs client identity certificate is used to establish the SSL/TLS connection to the MDM server. If your server
sits behind a proxy that strips away (or does not ask for) the client certificate, read Passing the Client Identity
Through Proxies.
If the value of the SignMessage field in the MDM payload is set to true, each message coming from the device
carries an additional HTTP header named Mdm-Signature. This header contains a BASE64-encoded CMS
Detached Signature of the message.
Your server can validate the body with the detached signature in the SignMessage header. If the validation is
successful, your server can assume that the message came from the signer, whose certificate is stored in the
signature.
Keep in mind that this option consumes a lot of data relative to the typical message body size. The signature is sent
with every message, adding almost 2 KB of data to each outgoing message from the device. Use this option only if
necessary.
To do this, your server should send a push notification periodically to ensure that managed devices are still listening
to your push notifications. If the device fails to respond to push notifications after some time, the device can be
considered inactive. A device can become inactive for several reasons:
Note
Your security report on each managed device should specify whether or not MDM is set to be non-removable.
This information is returned by the profile query, as described in Define Profile.
The time that your server should wait before deciding that a device is inactive can be varied according to your IT
policy, but a time period of several days to a week is recommended. While itʼs harmless to send push notifications
214
once a day or so to make sure the device is responding, it is not necessary. Appleʼs push notification servers cache
your last push notification and deliver it to the device when it comes back on the network.
When a device becomes inactive, your server may take appropriate action, such as limiting the deviceʼs access to
your organizationʼs resources until the device starts responding to push notifications once more.
The Feedback service should be considered unreliable for detecting device inactivity, because you may not receive
feedback in certain cases. Your server should use timeouts as the primary means of determining device
management status.
Dequeueing Commands
Your server should not consider a command accepted and executed by the device until you receive the
Acknowledged or Error status with the command UUID in the message. In other words, your server should leave
the last command on the queue until you receive the status for that command.
It is possible for the device to send the same status twice. You should examine the CommandUUID field in the
deviceʼs status message to determine which command it applies to.
• Remove the profile that contains the MDM payload. An MDM server can always remove this profile, even if it
does not have the access rights to add or remove configuration profiles.
• Respond to any device request with a 401 Unauthorized HTTP status. The device automatically removes
the profile containing the MDM payload upon receiving a 401 status code.
To replace an installed profile, install a new profile that has the same top-level PayloadIdentifier as an installed
profile.
Replacing an MDM profile with a new profile restarts the check-in process. If an SCEP payload is included, a new
client identity is created. If the update fails, the old configuration is restored.
215
Dealing with Restores
A user can restore his or her device from a backup. If the backup contains an MDM payload, MDM service is
reinstated and the device is automatically scheduled to deliver a TokenUpdate check-in message. MDM service is
reinstated only if the backup is restored to the same device. It is not reinstated if the user restores a backup to a new
device.
Your server can either accept the device by replying with a 200 status or reject the device with a 401 status. If your
server replies with a 401 status, the device removes the profile that contains the MDM payload.
It is good practice to respond with a 401 status to any device that the server is not actively managing.
If your MDM payload specifies the Device Lock correctly, the device includes an UnlockToken data blob in the
TokenUpdate message that it sends your server after installing the profile. This data blob contains a cryptographic
package that allows the device to be unlocked. Treat this data as the equivalent of a “master passcode” for the
device. Your IT policy should specify how this data is stored, who has access to it, and how the ClearPasscode
command can be issued and accounted for.
Do not send the ClearPasscode command until you have verified that the deviceʼs owner has physical ownership
of the device. You should never send the command to a lost device.
Key Value
dep_enrollment_url This is the URL the device should contact to begin MDM enrollment with the MDM
server. It should have the same value the server would send for the url key when
defining a DEP profile via https://mdmenrollment.apple.com/profile, as
described in Define Profile.
216
Key Value
dep_anchor_certs_url This is the URL that a client can use to obtain the certificates required to trust the
URL specified by the dep_enrollment_url key. It is the exact same format as
the anchor_certs value in the DEP profile, except the body needs to be UTF-8
JSON-encoded for transfer. The decoded body of the response from this URL
should be usable in a DEP profile under the anchor_certs key without any
modification. If the MDM server is using a trusted SSL certificate (so no additional
certs are required), this URL should still be provided but the body of the response
to the URL should either be empty (Content-Length: 0) or the JSON string for an
empty array ('[]').
trust_profile_url This is the URL a client can use to obtain a Trust Profile for the MDM server. This
should be a fully formed .mobileconfig profile with only payloads of type
com.apple.security.root. If the server is using trusted certificates (so no
Trust Profile is required), this key should be omitted from the response. Do not
return a URL that would generate an empty profile.
Note
Although the foregoing keys are individually optional, it is recommended that dep_enrollment_url and
dep_anchor_certs_url be implemented or not as a pair.
Examples
Request Format
GET https://mdm.example.com/MDMServiceConfig
Response Body
{
”dep_enrollment_url”: ”https://mdm.example.com/devicemanagement/mdm/dep_mdm_enroll
”,
”dep_anchor_certs_url”: ”https://mdm.example.com/devicemanagement/mdm/
dep_anchor_certs”,
”trust_profile_url”: ”https://certs.example.com/mdm/trust_profile”
}
It is not required that the URLs refer to the same host as the /MDMServiceConfig request, as illustrated by the
example for trust_profile_url.
217
The dep_anchor_certs_url Key
Request Format
GET https://mdm.example.com/devicemanagement/mdm/dep_anchor_certs
[”MIIEKDCCAxCgAwIBAgIEOjznoTALBgkqhkiG9w0BAQswfjEkMCIGA1UEAwwbU3ly
\nYWggQ2VydGlmaWNhd...SVVTo9ll1Lv3OJGqBkxPl9TCC\nfYYnArwzlk4qm1tP\n”]
Request Format
GET https://certs.example.com/mdm/trust_profile
218
<key>PayloadType</key>
<string>com.apple.security.root</string>
<key>PayloadUUID</key>
<string>B90FA650-5A7D-496A-8C84-0D81C9EBCE6E</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</array>
<key>PayloadDescription</key>
<string>Configures your device to trust the MDM server.</string>
<key>PayloadDisplayName</key>
<string>Trust Profile for Example Corp</string>
<key>PayloadIdentifier</key>
<string>com.apple.config.mdm.example.com.ssl</string>
<key>PayloadScope</key>
<string>System</string>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadUUID</key>
<string>94cdf5c0-bde0-0131-1ed5-005056831d08</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</plist>
219
MDM Vendor CSR Signing Overview
The process of generating an APNS push certificate can be completed using the Apple Push Notification Portal.
2. This process should take place within the instance of your MDM service that your customer has access to.
Note
The private key associated with this CSR should remain within the instance of your MDM service that the
customer has access to. This private key is used to sign the MDM push certificate. The MDM service
instance should not make this private key available to you (the vendor).
Via your setup process, the CSR should be uploaded to your internal infrastructure to be signed as outlined below.
Next, you must create a script based on the instructions below to sign the customerʼs CSR:
2. Sign the CSR (in binary format) with the private key of the MDM Signing Cert using the SHA1WithRSA signing
algorithm.
Note
Do not share the private key from your MDM Signing Cert with anyone, including customers or resellers
of your solution. The process of signing the CSR should take place within your internal infrastructure and
220
should not be accessible to customers.
Be certain that the PushCertCertificateChain value contains a complete certificate chain all the way
back to a recognized root certificate (including the root certificate itself). This means it must contain your
MDM signing certificate, the WWDR intermediate certificate (available from
http://developer.apple.com/certificationauthority/AppleWWDRCA.cer), and the Apple Inc. root certificate
(available from http://www.apple.com/appleca/AppleIncRootCertificate.cer).
Also, be sure that every certificate complies with PEM formatting standards; each line except the last must
contain exactly 64 printable characters, and the last line must contain 64 or fewer printable characters.
It may be helpful to save the certificate and its chain into a file ending in .pem and then verify your certificate
chain with the certtool (certtool -e < filename.pem) or openssl (openssl verify
filename.pem) command-line tools. To learn more about certificates and chains of trust, read the Apple
book Security Overview, available at https://developer.apple.com/library/content/documentation/Security/
Conceptual/Security_Overview/Introduction/Introduction.html.
Refer to the code samples in Sample Java Code, Sample .NET Code, and Sample Request property list for
additional instructions.
Note
To minimize the risk of errors, you should use Xcode or the standalone Property List Editor application
when editing property lists.
Alternatively, on the command line, you can make changes to property lists with the plutil tool or check
the validity of property lists with the xmllint tool.
6. Deliver the Push Certificate Request plist file created in Step 5 back to the customer and direct the customer
to https://identity.apple.com/pushcert to upload it to Apple.
Be sure to use a separate push certificate for each customer. There are two reasons for this:
• If multiple customers shared the same push topic, they would be able to see each otherʼs device tokens.
• When a push certificate expires, gets invalidated or revoked, gets blocked, or otherwise becomes unusable,
any customers sharing that certificate lose their ability to use MDM.
All devices for the same customer should share a single push certificate. This same certificate should also be used
to connect to the APNS feedback service.
221
Creating the APNS Certificate for MDM (Customer Action)
Once you have delivered the signed CSR back to the customer, the customer must log in to
https://identity.apple.com/pushcert using a verified Apple ID and upload the CSR to the Apple Push Certificates
Portal.
The portal creates a certificate titled “MDM__Certificate.pem.” At this point, the customer returns to your setup
process to upload the APNS Certificate for MDM.
222
Code Samples
The following code snippets demonstrate the CSR signing process.
/**
* Signature actually uses two algorithms--one to calculate a message digest and one
to encrypt the message digest
* Here is Message Digest is calculated using SHA1 and encrypted using RSA.
* Initialize the Signature with the signer's private key using initSign().
* Use the update() method to add the data of the message into the signature.
*
* @param privateKey Private key used to sign the data
* @param data Data to be signed.
* @return Signature as byte array.
* @throws Exception
*/
private byte[] signCSR( PrivateKey privateKey, byte[] data ) throws Exception{
Signature sig = Signature.getInstance(”SHA1WithRSA”);
sig.initSign(privateKey);
sig.update(data);
byte[] signatureBytes = sig.sign();
return signatureBytes;
}
223
Listing 9.2: Sample .Net Code
var privateKey = new PrivateKey(PrivateKey.KeySpecification.AtKeyExchange, 2048,
false, true);
var caCertificateRequest = new CaCertificateRequest();
string csr = caCertificateRequest.GenerateRequest(”cn=test”, privateKey);
224
Listing 9.3: Sample Property List
<?xml version=”1.0” encoding=”UTF-8”?>
<!DOCTYPE plist PUBLIC ”-//Apple//DTD PLIST 1.0//EN” ”http://www.apple.com/DTDs/
PropertyList-1.0.dtd”>
<plist version=”1.0”>
<dict>
<key>PushCertRequestCSR</key>
<string>
MIIDjzCCAncCAQAwDzENMAsGA1UEAwwEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQAD
</string>
<key>PushCertCertificateChain</key>
<string>
-----BEGIN CERTIFICATE-----
MIIDkzCCAnugAwIBAgIIQcQgtHQb9wwwDQYJKoZIhvcNAQEFBQAwUjEaMBgGA1UE
AwwRU0FDSSBUZXN0IFJvb3QgQ0ExEjAQBgNVBAsMCUFwcGxlIElTVDETMBEGA1UE
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDlTCCAn2gAwIBAgIIBInl9fQbaAkwDQYJKoZIhvcNAQEFBQAwXDEkMCIGA1UE
AwwbU0FDSSBUZXN0IEludGVybWVkaWF0ZSBDQSAxMRIwEAYDVQQLDAlBcHBsZSBJ
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDpjCCAo6gAwIBAgIIKRyFYgyyFPgwDQYJKoZIhvcNAQEFBQAwXDEkMCIGA1UE
AwwbU0FDSSBUZXN0IEludGVybWVkaWF0ZSBDQSAxMRIwEAYDVQQLDAlBcHBsZSBJ
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDiTCCAnGgAwIBAgIIdv/cjbnBgEgwDQYJKoZIhvcNAQEFBQAwUjEaMBgGA1UE
AwwRU0FDSSBUZXN0IFJvb3QgQ0ExEjAQBgNVBAsMCUFwcGxlIElTVDETMBEGA1UE
-----END CERTIFICATE-----
</string>
<key>PushCertSignature</key>
<string>
CGt6QWuixaO0PIBc9dr2kJpFBE1BZx2D8L0XH0Mtc/DePGJOjrM2W/IBFY0AVhhEx
</string>
225
Revision History
Date Notes
226
Date Notes
227
Copyright and Notices
Apple Inc.
Copyright © 2018 Apple Inc.
All rights reserved.
No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, electronic, photocopying,
recording, or otherwise, without prior written permission of Apple Inc., with the following exceptions: Any person is hereby authorized to store documentation
on a single computer or device for personal use only and to print copies of documentation for personal use provided that the documentation contains Appleʼs
copyright notice.
No licenses, express or implied, are granted with respect to any of the technology described in this document. Apple retains all intellectual property rights
associated with the technology described in this document. This document is intended to assist application developers to develop applications only for
Apple-branded products.
Apple Inc.
One Apple Park Way
Cupertino, CA 95014
USA
408-996-1010
Apple is a trademark of Apple Inc., registered in the U.S. and other countries.
APPLE MAKES NO WARRANTY OR REPRESENTATION, EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS DOCUMENT, ITS QUALITY, ACCURACY,
MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. AS A RESULT, THIS DOCUMENT IS PROVIDED ”AS IS,” AND YOU, THE READER, ARE
ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND ACCURACY.
IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES RESULTING FROM ANY DEFECT,
ERROR OR INACCURACY IN THIS DOCUMENT, even if advised of the possibility of such damages.
Some jurisdictions do not allow the exclusion of implied warranties or liability, so the above exclusion may not apply to you.
228