HeadSpin Documentation
Documentation

iOS Device API

Overview

HeadSpin provides a convenient REST API interface for idevice, a tool to natively communicate with iOS devices. HeadSpin allows you to run idevice commands through an API interface so you can easily target and perform actions on your iOS devices.

The prerequisite to using the HeadSpin API is an API token. You can create an API token from your user settings.

Base URL

All URLs referenced in the API documentation have the following base URL structure:


https://api-dev.headspin.io/v0/idevice/

Available parameters:

  • timeout: wait for devices until they come back online or timeout is reached (unit: second / default: 0.0)

Example:


curl -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{ios-device-id}/screenshot?timeout=60 -o ./my-screenshot.png

Your API token is passed in the request header as the Authorization Bearer. Here's an example of this expressed in Python, which you can use as a reference to adapt to your language of choice:


import requests

api_token = "<your_api_token>" # We pre-filled your API Token here
device_serial = "{ios-device-id}" # Replace this with the UDID for your target device 


def get_ios_device_app_list(api_token, udid):
    headers = {
        "Authorization": "Bearer {}".format(api_token)
    }

    request_url = "https://api-dev.headspin.io/v0/idevice/{}/installer/list?json".format(udid)
    r = requests.get(request_url, headers=headers)
    data = r.json()

    return data

To ensure data privacy, our REST API are served over HTTPS. For on-premise deployments your Base URL may vary based on your environment. Please reach out to your HeadSpin contact or support@headspin.io for your exact Base URL details.

Note: The examples in this guide will be expressed as cURL commands to make it easy to follow cross-platform and independent of programming language. For cURL commands we can use a convenient base URL syntax, where your API token is placed in the Base URL as such:


-H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/id

API Guide

This section will introduce how to use the HeadSpin iOS Device API through several examples:

  • Take a screenshot
  • Retrieve the iOS syslog
  • Install a provisioning profile
  • Install or uninstall an iOS app
  • Get a list of installed apps on a device

The examples cover popular use cases and explain how to use the API. The subsequent section will be a full reference of available iOS API.

Take a screenshot

API

You can take a screenshot of an iOS device by sending a GET request to the iOS Screenshot API. You can also specify an output path where the image can be stored on your client machine.


curl -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{device-udid}/screenshot

For example:


curl -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{ios-device-id}/screenshot -o ./my-screenshot.png

Retrieve the iOS syslog

API

Syslog is the iOS system logger that contains all of the log file data from an iOS device. Since there can be numerous syslog events on a given device, HeadSpin provides a convenient query string parameter to retrieve a certain number of lines.


curl -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{device-udid}/syslog?n={number-of-lines} 

For example:


curl -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{ios-device-id}/syslog?n=50 

Install a provisioning profile

API

Development builds of iOS apps have to be signed by Apple first before they can be installed on a given device. The first step is to install your provisioning profile on the device. A provisioning profile acts as a link between the device and the developer account. In your Apple Developer Account, you can select which devices can run your app with your provisioning profile. A provisioning profile must be installed on each device on which you wish to run your application code. HeadSpin provides API for installing your provisioning profile. As a prerequiste to using this API, download your iOS provisioning profile from your Apple Developer Account.


curl -X POST -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{device-udid}/provision/install --data-binary "@{your-provisioning-profile}"

For example:


curl -X POST -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{ios-device-id}/provision/install  --data-binary "@/Users/example/myexample.mobileprovision"

Install or uninstall an iOS app

Install

API

To install a previously uploaded iOS app on a device, make a POST request with the app id.


curl -X POST -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v1/app/{app_id}/install/{ios-device-id} 

Uninstall

API

To uninstall a previously uploaded iOS app on a device, make a POST request with the app id.


curl -X POST -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v1/app/{app_id}/uninstall/{ios-device-id} 

Get a list of installed apps on a device

You can retrieve a list of installed apps on a given device using the following endpoint. Furthermore, there is a query string parameter to specify if you would like the response in JSON or in the native plist XML format.


curl -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{ios-device-id}/installer/list?{json-or-xml} 

For example:


curl -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{ios-device-id}/installer/list?json 

API Reference

List all iOS devices

Get a device's information

Install a provisioning profile

List all apps on a device

Install an app on a device by app ID

Uninstall an app from a device by app ID

Installing dSYMs with App Management

View a device's syslog

Get a screenshot from a device

Save a screenshot to the cloud

Restart a device

Lock a device

Unlock a device

Dismiss popups on a device

Using Pintap to solve PIN entry screen

List all iOS devices

Route Method
/v0/idevice/id GET

Example


curl -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/id 

Response

JSON object, each key is the address of a device. The address is in the form of <code class="dcode">{the iOS device's UDID (Unique Device Identifier)}@{host}</code>.


{
  "d138cc4ef3109179902444f33e5229ad68883db9@staging-us-mv-0-proxy-2.headspin.io": {
    "status": "device",
    "serial": "DNPQ2JDTG5MP",
    "os": "ios",
    "host": "staging-us-mv-0-proxy-2.headspin.io",
    "device_id": "d138cc4ef3109179902444f33e5229ad68883db9"
  },
  "ef472902906914b6edccff300852b92175c13622@staging-us-mv-0-proxy-3.headspin.io": {
    "status": "device",
    "serial": "F2LWK0B7JCLF",
    "os": "ios",
    "host": "staging-us-mv-0-proxy-3.headspin.io",
    "device_id": "ef472902906914b6edccff300852b92175c13622"
  }
}

Get a device's information

Route Method
/v0/idevice/{device_id}/info GET

Optional parameters

  • <code class="dcode">/{device_id}/info?json</code>: get the results in JSON
  • <code class="dcode">/{device_id}/info?flags=--xml</code>: get the results in XML

Example


curl -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{ios-device-id}/info 

Response

By default, the response is in plaintext.

If the optional <code class="dcode">?json</code> parameter is used, the response is a JSON object that looks like the following:


{
  "BasebandVersion": "6.30.04",
  "EthernetAddress": "d0:25:98:31:1a:87",
  "UniqueDeviceID": "{ios-device-id}",
  "CPUArchitecture": "arm64",
  "PkHash": "5OQIGNymupBn16zMKPujMp3562XDnNFkULy+gshbERM=",
  "ChipID": 28672,
  "BasebandMasterKeyHash": "8CB15EE4C8002199070D9500BB8FB183B02713A5CA2A6B92DB5E75CE15536182",
  "SoftwareBehavior": "AQAAAAAAAAAAAAAAAAAAAA==",
  "ProximitySensorCalibration": "T00EAA0LODgQA7wCsATMALwC/AACAMoQ9gMCALqr+gLuAl8AKQKnASvI/xoAAAAA4QCVAAQCAADrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
  "SIMStatus": "kCTSIMSupportSIMStatusNotInserted",
  "ModelNumber": "MG4H2",
  "DeviceColor": "#e1e4e3",
  "ProductType": "iPhone7,2",
  "TimeZone": "Asia/Jakarta",
  "BasebandKeyHashInformation": {
    "SKeyHash": "u+/tcCwvaQ+1Y9t40I4yegCEmB28mALlaROhaIVGBWo=",
    "SKeyStatus": 0,
    "AKeyStatus": 2
  },
  "FirstFreePairExpired": true,
  "BluetoothAddress": "d0:25:98:31:1a:86",
  "BrickState": false,
  "DeviceName": "Proxy Box’s iPhone",
  "kCTPostponementStatus": "kCTPostponementStatusActivated",
  "TrustedHostAttached": true,
  "HasSiDP": true,
  "TimeZoneOffsetFromUTC": 25200,
  "UseRaptorCerts": true,
  "CarrierBundleInfoArray": [],
  "MobileSubscriberNetworkCode": "",
  "HardwarePlatform": "t7000",
  "RegionInfo": "PA/A",
  "SBLockdownEverRegisteredKey": true,
  "BasebandChipID": 8343777,
  "kCTPostponementInfoServiceProvisioningState": false,
  "MLBSerialNumber": "C07519507F3FQJYF",
  "HardwareModel": "N61AP",
  "BasebandRegionSKU": "BQAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
  "BasebandActivationTicketVersion": "V2",
  "FirmwareVersion": "iBoot-4076.30.43",
  "DeviceClass": "iPhone",
  "kCTPostponementInfoPRLName": 0,
  "PasswordProtected": false,
  "SerialNumber": "C39PP04BG5MT",
  "UniqueChipID": 599087876023334,
  "TelephonyCapability": true,
  "BoardId": 6,
  "ProtocolVersion": "2",
  "FusingStatus": 3,
  "BasebandCertId": 3840149528,
  "ActivationState": "Activated",
  "WiFiAddress": "d0:25:98:31:1a:85",
  "ChipSerialNo": "FC4T9A==",
  "ProductVersion": "11.2",
  "BasebandStatus": "BBInfoAvailable",
  "kCTPostponementInfoPRIVersion": "0.0.0",
  "ProductionSOC": true,
  "ActivationStateAcknowledged": true,
  "MobileEquipmentIdentifier": "35928606708121",
  "BasebandSerialNumber": "FC4T9A==",
  "HostAttached": true,
  "CertID": 3840149528,
  "SoftwareBundleVersion": "",
  "TimeIntervalSince1970": 1553106896.753065,
  "SIMTrayStatus": "kCTSIMSupportSIMTrayInsertedNoSIM",
  "ProductName": "iPhone OS",
  "BuildVersion": "15C114",
  "SupportedDeviceFamilies": [
    1
  ],
  "InternationalMobileEquipmentIdentity": "359286067081218",
  "WirelessBoardSerialNumber": "F417CE336DC",
  "Uses24HourClock": false,
  "DieID": 599087876023334,
  "MobileSubscriberCountryCode": "",
  "PartitionType": "GUID_partition_scheme",
  "NonVolatileRAM": {
    "com.apple.System.tz0-size": "MHhDMDAwMDA=",
    "auto-boot": "dHJ1ZQ==",
    "backlight-level": "MTU0MA==",
    "boot-args": ""
  }
}

If the optional <code class="dcode">?flags=--xml</code> parameter is used, the response is instead an XML object that looks like the following:


<?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>ActivationState</key>
    <string>Activated</string>
    <key>ActivationStateAcknowledged</key>
    <true/>
    <key>BasebandActivationTicketVersion</key>
    <string>V2</string>
    <key>BasebandCertId</key>
    <integer>3840149528</integer>
    <key>BasebandChipID</key>
    <integer>8343777</integer>
    <key>BasebandKeyHashInformation</key>
    <dict>
        <key>AKeyStatus</key>
        <integer>2</integer>
        <key>SKeyHash</key>
        <data>
        u+/tcCwvaQ+1Y9t40I4yegCEmB28mALlaROhaIVGBWo=
        </data>
        <key>SKeyStatus</key>
        <integer>0</integer>
    </dict>
    <key>BasebandMasterKeyHash</key>
    <string>8CB15EE4C8002199070D9500BB8FB183B02713A5CA2A6B92DB5E75CE15536182</string>
    <key>BasebandRegionSKU</key>
    <data>
    BQAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAA==
    </data>
    <key>BasebandSerialNumber</key>
    <data>
    FC4T9A==
    </data>
    <key>BasebandStatus</key>
    <string>BBInfoAvailable</string>
    <key>BasebandVersion</key>
    <string>6.30.04</string>
    <key>BluetoothAddress</key>
    <string>d0:25:98:31:1a:86</string>
    <key>BoardId</key>
    <integer>6</integer>
    <key>BrickState</key>
    <false/>
    <key>BuildVersion</key>
    <string>15C114</string>
    <key>CPUArchitecture</key>
    <string>arm64</string>
    <key>CarrierBundleInfoArray</key>
    <array>
    </array>
    <key>CertID</key>
    <integer>3840149528</integer>
    <key>ChipID</key>
    <integer>28672</integer>
    <key>ChipSerialNo</key>
    <data>
    FC4T9A==
    </data>
    <key>DeviceClass</key>
    <string>iPhone</string>
    <key>DeviceColor</key>
    <string>#e1e4e3</string>
    <key>DeviceName</key>
    <string>Proxy Box’s iPhone</string>
    <key>DieID</key>
    <integer>599087876023334</integer>
    <key>EthernetAddress</key>
    <string>d0:25:98:31:1a:87</string>
    <key>FirmwareVersion</key>
    <string>iBoot-4076.30.43</string>
    <key>FirstFreePairExpired</key>
    <true/>
    <key>FusingStatus</key>
    <integer>3</integer>
    <key>HardwareModel</key>
    <string>N61AP</string>
    <key>HardwarePlatform</key>
    <string>t7000</string>
    <key>HasSiDP</key>
    <true/>
    <key>HostAttached</key>
    <true/>
    <key>InternationalMobileEquipmentIdentity</key>
    <string>359286067081218</string>
    <key>MLBSerialNumber</key>
    <string>C07519507F3FQJYF</string>
    <key>MobileEquipmentIdentifier</key>
    <string>35928606708121</string>
    <key>MobileSubscriberCountryCode</key>
    <string></string>
    <key>MobileSubscriberNetworkCode</key>
    <string></string>
    <key>ModelNumber</key>
    <string>MG4H2</string>
    <key>NonVolatileRAM</key>
    <dict>
        <key>auto-boot</key>
        <data>
        dHJ1ZQ==
        </data>
        <key>backlight-level</key>
        <data>
        MTU0MA==
        </data>
        <key>boot-args</key>
        <string></string>
        <key>com.apple.System.tz0-size</key>
        <data>
        MHhDMDAwMDA=
        </data>
    </dict>
    <key>PartitionType</key>
    <string>GUID_partition_scheme</string>
    <key>PasswordProtected</key>
    <false/>
    <key>PkHash</key>
    <data>
    5OQIGNymupBn16zMKPujMp3562XDnNFkULy+gshbERM=
    </data>
    <key>ProductName</key>
    <string>iPhone OS</string>
    <key>ProductType</key>
    <string>iPhone7,2</string>
    <key>ProductVersion</key>
    <string>11.2</string>
    <key>ProductionSOC</key>
    <true/>
    <key>ProtocolVersion</key>
    <string>2</string>
    <key>ProximitySensorCalibration</key>
    <data>
    T00EAA0LODgQA7wCsATMALwC/AACAMoQ9gMCALqr+gLuAl8AKQKnASvI/xoAAAAA4QCV
    AAQCAADrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
    </data>
    <key>RegionInfo</key>
    <string>PA/A</string>
    <key>SBLockdownEverRegisteredKey</key>
    <true/>
    <key>SIMStatus</key>
    <string>kCTSIMSupportSIMStatusNotInserted</string>
    <key>SIMTrayStatus</key>
    <string>kCTSIMSupportSIMTrayInsertedNoSIM</string>
    <key>SerialNumber</key>
    <string>C39PP04BG5MT</string>
    <key>SoftwareBehavior</key>
    <data>
    AQAAAAAAAAAAAAAAAAAAAA==
    </data>
    <key>SoftwareBundleVersion</key>
    <string></string>
    <key>SupportedDeviceFamilies</key>
    <array>
        <integer>1</integer>
    </array>
    <key>TelephonyCapability</key>
    <true/>
    <key>TimeIntervalSince1970</key>
    <real>1553107066.929317</real>
    <key>TimeZone</key>
    <string>Asia/Jakarta</string>
    <key>TimeZoneOffsetFromUTC</key>
    <real>25200.000000</real>
    <key>TrustedHostAttached</key>
    <true/>
    <key>UniqueChipID</key>
    <integer>599087876023334</integer>
    <key>UniqueDeviceID</key>
    <string>{ios-device-id}</string>
    <key>UseRaptorCerts</key>
    <true/>
    <key>Uses24HourClock</key>
    <false/>
    <key>WiFiAddress</key>
    <string>d0:25:98:31:1a:85</string>
    <key>WirelessBoardSerialNumber</key>
    <string>F417CE336DC</string>
    <key>kCTPostponementInfoPRIVersion</key>
    <string>0.0.0</string>
    <key>kCTPostponementInfoPRLName</key>
    <integer>0</integer>
    <key>kCTPostponementInfoServiceProvisioningState</key>
    <false/>
    <key>kCTPostponementStatus</key>
    <string>kCTPostponementStatusActivated</string>
</dict>
</plist>

Install a provisioning profile

A provisioning profile ties your developer team to the devices your team uses for development and testing. If your app is not signed and distributed, you sometimes have to install your provisioning profile on a device before you can install your app on that device to test.

Route Method
/v0/idevice/{device_id}/provision/install POST

Request Body

The request's body should include the content of your <code class="dcode">.mobileprovision</code> file. To include the binary in your <code class="dcode">curl</code> request, use the <code class="dcode">--data-binary <file_name></code> flag.

See Apple's guide for more information on your provisioning profile.

Example


curl -X POST -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{ios-device-id}/provision/install -H "Content-type: text/plain" --data-binary provisioning_profile 

Response

  • <code class="dcode">HTTP response: 400, missing mobile provision data</code> if the provisioning data is not included in the body.

List all apps on a device

Route Method
/v0/idevice/{device_id}/installer/list GET

Optional Parameters

  • <code class="dcode">{device_id}/installer/list?json</code>: get the results in JSON
  • <code class="dcode">/{device_id}/installer/list?flags=--xml</code>: get the results in XML

Example


curl -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{ios-device-id}/installer/list 

Response

The response is a plaintext document in CSV format that looks like the following:


CFBundleIdentifier, CFBundleVersion, CFBundleDisplayName
com.apple.itunesu, "2488", "iTunes U"
com.apple.Pages, "6091", "Pages"
com.apple.Numbers, "6091", "Numbers"
com.apple.Keynote, "6091", "Keynote"
io.headspin.masterhand.app, "15", "masterhand"
com.apple.iMovie, "4147.7.82", "iMovie"
com.apple.test.WebDriverAgentRunner-Runner, "1", "WebDriverAgentRunner-Runner"
com.apple.mobilegarageband, "4878.17", "GarageBand"

If the optional <code class="dcode">?json</code> parameter is used, the response is a JSON object that looks like the following:


{
  "data": [
    {
      "DTPlatformVersion": "12.1",
      "UIRequiresFullScreen": true,
      "CFBundleNumericVersion": 0,
      "Container": "/private/var/mobile/Containers/Data/Application/42A0FFC4-973F-4692-902B-D42C23CF9B2B",
      "ParallelPlaceholderPath": true,
      "CFBundleIcons": {
        "CFBundlePrimaryIcon": {
          "CFBundleIconName": "AppIcon",
          "CFBundleIconFiles": [
            "AppIcon29x29",
            "AppIcon40x40",
            "AppIcon60x60"
          ]
        }
      },
      "ApplicationDSID": 8434493456,
      "CFBundleInfoDictionaryVersion": "6.0",
      "UIBackgroundStyle": "UIBackgroundStyleTransparent",
      "DTXcodeBuild": "10B61",
      "EnvironmentVariables": {
        "HOME": "/private/var/mobile/Containers/Data/Application/42A0FFC4-973F-4692-902B-D42C23CF9B2B",
        "CFFIXED_USER_HOME": "/private/var/mobile/Containers/Data/Application/42A0FFC4-973F-4692-902B-D42C23CF9B2B",
        "TMPDIR": "/private/var/mobile/Containers/Data/Application/42A0FFC4-973F-4692-902B-D42C23CF9B2B/tmp"
      },
      "CFBundleSupportedPlatforms": [
        "iPhoneOS"
      ],
      "CFBundleIdentifier": "com.apple.itunesu",
      "CFBundleDocumentTypes": [
        {
          "CFBundleTypeIconFiles": [
            "mat-thumb_ipad_pdf"
          ],
          "CFBundleTypeName": "PDF",
          "LSItemContentTypes": [
            "com.adobe.pdf"
          ],
          "LSHandlerRank": "Alternate"
        },
        {
          "CFBundleTypeName": "Keynote",
          "LSItemContentTypes": [
            "com.apple.keynote.key",
            "com.apple.iwork.keynote.key"
          ],
          "LSHandlerRank": "Alternate"
        },
        {
          "CFBundleTypeName": "Pages",
          "LSItemContentTypes": [
            "com.apple.pages.pages",
            "com.apple.iwork.pages.pages"
          ],
          "LSHandlerRank": "Alternate"
        },
       ....
       ....
       ....
  ]
}

If the optional <code class="dcode">?flags=--xml</code> parameter is used, the response is an XML object with the same content.

Install an app on a device by app ID

Route Method
/v1/app/{app_id}/install/{device_id} POST

Note

This command is a part of our App Management API. For more information and additional API command sets, please navigate to the link above. App Management API is consistent across all platforms, so this command will work for XAPK as well as APK and IPA files.

Automated Signing

Your IPA will be signed by us to ensure that it can install on the target device. If you would like to manage signing yourself, register the device UDID in your Apple Developer Account and add the device to a provisioning profile. An IPA provisioned for the target device will disable automated signing but you can explicitly disable it with the optional ?sign=false parameter. Automated signing does not support app capabilities.

Apps provisioned with an Enterprise profile are not subject to deployment restrictions and therefore HeadSpin disables Automated Signing for these apps. If an app requires features that are only available with non-Enterprise profiles, please select an alternative distribution method in Xcode when exporting the IPA, such as Ad Hoc or Development. This will allow Automated Signing to manage signing as expected.

Optional Parameters

  • <code class="dcode">/v1/app/{app_id}/install/{device_id}?sign=false</code>: disable Automated Signing. iOS only, see above for signing documentation.

Example

Install a previously uploaded app:


curl -X POST -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v1/app/{app_id}/install/{ios-device-id} 

Uninstall an app from a device by app ID

Route Method
/v1/app/{app_id}/uninstall/{device_id} POST

Note

This command is a part of our App Management API. For more information and additional API command sets, please navigate to the link above. App Management API is consistent across all platforms, so this command will work for XAPK as well as APK and IPA files.

Example


curl -X POST -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v1/app/{app_id}/uninstall/{ios-device-id} 

Installing dSYMs with App Management

In order to upload dSYMs, use the 'upload additional app file' method available in App Management.

Package your dSYMs

When you archive your app in Xcode to export an IPA, Xcode will generate Debug Symbol files (dSYMs) for that build. You should be able to find your archive in Xcode's Organizer (right-click it and select Show in Finder, then right-click the .xcarchive itself to Show Package Contents.) Right-click the dSYMs directory and select Compress "dSYMs" or do so via the command line with zip -r dSYMs.zip dSYMs. A debuggable IPA and matching debug symbols are required to generate a Function Call Timeline for a given app. If not using the Automated Signing feature, you must sign the app with an iOS App Development profile.

View a device's syslog

Streams the content of the connected device's syslog.

Route Method
/v0/idevice/{device_id}/syslog GET

Optional Parameters

  • <code class="dcode">{device_id}/syslog?n={lines back}</code>: Instead of streaming, retrieve only the last 'n' lines from the device's syslog. For example, <code class="dcode">/syslog?n=30</code> retrieves the last 30 lines.

Example


curl -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{ios-device-id}/syslog 

Response

The device's syslog is sent to the requesting user in <code class="dcode">text/plain</code>. The content is streamed and sent in chunks.

Get a screenshot from a device

Capture a screenshot of the device's current screen in PNG format.

Route Method
/v0/idevice/{device_id}/screenshot GET

Optional Parameters

  • To save the captured screenshot as an image, append <code class="dcode">> {local path}/{filename}.png</code> to the end of the command.

Example


curl -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{ios-device-id}/screenshot > test.png 

Response

An <code class="dcode">image/png</code> object.

Save a screenshot to the cloud

Similar to the <code class="dcode">.../screenshot</code> route explained above, the <code class="dcode">.../screenshot_url</code> route will take a screenshot in PNG format, but additionally the screenshot will be uploaded to the HeadSpin services. The result of the <code class="dcode">.../screenshot_url</code> route is another URL that can be used to retrieve the uploaded screenshot. Note that the URL returned from this API is only valid for 24 hours.

Route Method
/v0/idevice/{device_id}/screenshot_url GET

Example


curl -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{ios-device-id}/screenshot_url 
  https://another-url...

curl https://another-url... -o ./my-screenshot.png

Response

A URL.

Restart a device

Route Method
/v0/idevice/{device_id}/diagnostics/restart POST

Example


curl -X POST -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{ios-device-id}/diagnostics/restart 

Response

A JSON object.

  • <code class="dcode">{"status": 0, "returncode": 0, "stdout": "Restarting device.\n", "summary": "ok"}</code> if the device is restarted successfully.

Lock a device

Route Method
/v0/idevice/{device_id}/lock POST

Example


curl -X POST -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{ios-device-id}/lock 

Optional Parameters

  • <code class="dcode">{device_id}/lock/?timeout={timeout seconds}</code>: If the locking attempt fails, the server will keep retrying until the <code class="dcode">timeout seconds</code> have elapsed. If there's no <code class="dcode">?timeout</code> parameter, or <code class="dcode">timeout seconds</code> is <code class="dcode">0</code>, then this returns immediately after the first attempt to lock.
  • <code class="dcode">{device_id}/lock/?idleTimeout={timeout seconds}</code>: Unlock automatically if the device is inactive for <code class="dcode">timeout seconds</code>.

Response

JSON object:

  • <code class="dcode">{"status": 0, "message": "<device_address> locked."}</code> if the lock attempt was successful.
  • <code class="dcode">{"status": 1, "message": "Did not lock."}</code> if the lock attempt was unsuccessful. The device might be locked by another user.

Notes

  • This route is incompatible with the reservation system. If your company is using the reservation system, use the <code class="dcode">/v0/devices/</code> route instead.

Unlock a device

Unlocks a targeted device in the platform, if the lock is owned by the requesting user.

Route Method
/v0/idevice/{device_id}/unlock POST

Example


curl -X POST -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{ios-device-id}/unlock 

Response

JSON object:

  • <code class="dcode">{"status": 0, "message": "<device_address> unlocked."}</code> if the unlock attempt was successful.
  • <code class="dcode">{"status": 1, "message": "Did not unlock."}</code> if the unlock attempt was unsuccessful. The device might not be locked by the requesting user.

Dismiss pop-ups on a device

Dismiss pop-ups on the device. If there are no pop-ups, it does nothing.

If the device isn't already locked by the requesting user, calling this API route will lock the device. If the device is locked by someone else, this route will not work.

Note that some pop-ups prevent XCTest from starting on the device, resulting in xcodebuild waiting for the pop-up to be dismissed. Call this before running XCTest to ensure reliable startup.

Route Method
/v0/idevice/{device_id}/poptap POST

Example


curl -X POST -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{ios-device-id}/poptap 

Response

  • <code class="dcode">{"status": 0, "message": "Poptap success", "value": {"success": true}}</code> if existing pop-ups was dismissed successfully.

Using Pintap to solve PIN entry screen

Uses Pintap to enter a code to solve the PIN entry screen. This performs the same actions as Pintap in Remote Control UI.

Route Method
/v0/idevice/{device_id}@{host}/pintap POST

Optional Parameters

The PIN code can be specified by including a JSON object as the request body.

Key Name Description
pin The PIN code to use with Pintap (optional).

Example


curl -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{ios-device-id}@{host}/pintap 

curl -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevice/{ios-device-id}@{host}/pintap -d '{"pin":"1234"}' 

Response

The server will reply after Pintap has finished execution, which may take several seconds, or when there is an issue.

  • <code class="dcode">HTTP 200</code> when Pintap finishes execution.
  • <code class="dcode">HTTP 400</code> if there was a problem with the request.
  • <code class="dcode">HTTP 404</code> if no eligible device matches the requested device address.
  • <code class="dcode">HTTP 500</code> if Pintap encounters an error.

Multiple Device Access

A limited set of commands are available to run across multiple devices in parallel. The commands accept an address pattern called a selector, that follows the standard selector syntax used throughout the platform. The selector syntax runs on each device object and matches the fields in the device object.

Read more about selectors in the selectors doc.

The emtpy selector matches all devices.

API Reference

Get all devices matching a selector

Route Method
/v0/idevicem/{selector}/id GET

Example


curl -H "Authorization: Bearer <your_api_token>" https://api-dev.headspin.io/v0/idevicem/os:ios/id 

Response

A JSON object, with each key being a device address matching the selector.


{
  "049456f85e142e8dfd7ada8aebc068480dcc47ac@proxy-us-nyc-6.headspin.io": {
    "status": "device",
    "host": "proxy-us-nyc-6.headspin.io",
    "serial": "F2LW41BTHFM2",
    "os": "ios",
    "present": "True",
    "device_id": "049456f85e142e8dfd7ada8aebc068480dcc47ac"
  },
  "d9e562b48b9388b4eb24d56ab88a8ab68c3202b9@proxy-gb-lhr-0.headspin.io": {
    "status": "device",
    "host": "proxy-gb-lhr-0.headspin.io",
    "serial": "C39S20DVH2XK",
    "os": "ios",
    "present": "True",
    "device_id": "d9e562b48b9388b4eb24d56ab88a8ab68c3202b9"
  }
}