SpotWalla Web API version 1.0

Contents

1.0 Introduction
2.0 Error Handling
3.0 User Service
     3.1 Authenticating Users
4.0 Device Service
     4.1 Obtaining a User's Device List
     4.2 Obtaining Device Detail
5.0 Message Service
     5.1 Request & Response Bodies
     5.2 Retrieving Messages
     5.3 Creating Messages
     5.4 Updating Messages
     5.5 Deleting Messages
6.0 Picture Service
7.0 Family Service
Appendix A - A Simple SWAPI Client Using PHP

1.0 Introduction

The SpotWalla Web API (SWAPI) is a collection of RESTful web services that allow third-party applications to interact with SpotWalla in a meaningful way by providing access to users, devices and a device's underlying message data. The intended audience of the SWAPI is not everyday users, but application developers. If you're not an application developer, this information may not be of much benefit to you. If you're an application developer, continue reading.

Being a RESTful API means third-party applications communicate with the SWAPI using the HTTP protocol and its various methods such as POST, GET, PUT and DELETE. If a service method requires data in order to fulfill a request, the request body will contain the required XML. All data into the SWAPI will be in XML. The SWAPI will respond to requests using XML by default, but can respond using JSON when instructed to do so.

Security is always a concern at SpotWalla. There are a number of security measures in place...

  1. The SWAPI only responds to requests made via HTTPS. Using HTTPS ensures all data sent between the application and the SWAPI is encrypted over the wire.
  2. To safeguard against rogue applications, SWAPI access is granted after we've had sufficient time to evaluate your application and determine how it intends to use the SWAPI. If your application is deemed appropriate, we will provide you with an API key. Your API key will accompany every invocation of a SWAPI service. To begin a discussion about obtaining an API key, please send an email to SpotWalla Support and let us know about your application and how you intend to use the SWAPI.
  3. Applications must create a session key by authenticating a SpotWalla user. The session key must accompany each subsequent request.
  4. Users must explicitly enable the SWAPI for one or more of their devices. Each enabled device has an assigned device key. For any device-related service invocation, the device key will be included in the request. Users are expected to only share their device keys with trusted applications. Trusted applications are expected to secure each user's device key.
  5. Users are able to generate a new device key on demand. This effectively disables the old key and renders it useless.
  6. Users can enable/disable the SWAPI for one of their devices at any time for any reason.
  7. SpotWalla can enable/disable an API key at any time for any reason.

Over time the SWAPI will mature to provide a broader set of services with richer functionality. Beta version 0.2 focuses primarily on user authentication, device management and message management.

2.0 Error Handling

When a SWAPI request is processed without error, the HTTP status is set to 200 just like any other successful HTTP request. When an error occurs while processing a SWAPI request, the HTTP status is set to a standard, common HTTP status other than 200. In addition to setting the HTTP status, the SWAPI will return a response body containing error XML with additional error information...

<?xml version="1.0"?>
<api>
    <version></version>           <!-- SWAPI Version -->
    <description></description>   <!-- your application's description -->
    <requestToken></requestToken> <!-- an optional client-assigned request token -->
    <error>
        <status></status>         <!-- HTTP status - included here for clarity. -->
        <code></code>             <!-- SWAPI-assigned error code -->
        <message></message>       <!-- detailed error message -->
    </error>
</api>
        

When evaluating the success or failure of a SWAPI request, it's imperative to first check the HTTP status of the request. If the request was successfully processed, the HTTP status will be 200. If the status is anything other than 200, then the response body will contain the error XML shown above. The error status, code and message will allow you to determine the cause of the error.

The sections in this document about specific service calls will provide detail information about each error that may occur while processing the request.

3.0 User Service

The user service allows applications to authenticate SpotWalla users and obtain a SWAPI session key. The session key is required in all calls to the device and message services discussed below.

The user service is invoked using the following URL:

https://spotwalla.com/api/<API key>/user

Where <API key> is the key assigned to your application. Clients can assign a request token to each user service call by adding a token parameter to the URL. For instance:

https://spotwalla.com/api/<API key>/user?token=<requestToken>

Where <requestToken> is an identifier the client assigns to this specific request. The SWAPI doesn't evaluate the request token. It simply returns the token to the client. Typically, clients will use the request token to assign a unique ID to each request. Depending upon your communication model with the SWAPI this could be valuable information. For instance, if all of your SWAPI calls are asynchronous, a request token will help you determine which requests succeed or fail.

3.1 Authenticating Users

To authenticate a user your application will invoke the user service using the HTTP POST method. In order to prevent the username and password from being exposed on the URL, your application will include the following XML in the request body...

<?xml version="1.0"?>
<api>
    <user>
        <email>test.user@null.com</email>
        <password>b0gUsPa$$w0rd</password>
    </user>
</api>
        

When successful the HTTP status code will be set to 200 and the following response XML will be returned:

<?xml version="1.0"?>
<api>
    <version>0.2 Beta</version>
    <description>SWAPI TEST</description>
    <requestToken>12340987</requestToken>
    <user>
        <sessionKey>a0b9c8d8e7f6</sessionKey>
        <firstName>Test</firstName>
        <lastName>User</lastName>
        <email>test.user@null.com</email>
    </user>
</api>
        

When not successful, the HTTP status code and error XML will reflect one of the errors below...

status code message
400 01 The request body contains invalid XML.
403 01 The API key is disabled. Contact SpotWalla Support for more information.
403 02 The SWAPI service was not invoked using HTTPS.
404 01 Invalid API key. Ensure you're using the correct API key.
404 04 User authentication failed. The email address and/or password are incorrect.

4.0 Device Service

The device service allows applications to work with a user's devices and is invoked using the following URL:

https://spotwalla.com/api/<API key>/user/<session key>/device

Where <API key> is the key assigned to your application and <session key> is the key assigned to the authenticated user as discussed in the previous example. Clients can assign a request token to each device service call by adding a token parameter to the URL. For instance:

https://spotwalla.com/api/<API key>/user/<session key>/device?token=<requestToken>

Where <requestToken> is an identifier the client assigns to this specific request. The SWAPI doesn't evaluate the request token. It simply returns the token to the client. Typically, clients will use the request token to assign a unique ID to each request. Depending upon your communication model with the SWAPI this could be valuable information. For instance, if all of your SWAPI calls are asynchronous, a request token will help you determine which requests succeed or fail.

4.1 Obtaining a User's Device List

To obtain a user's device list, simply invoke the device service using the HTTP GET method. A request body nor URL parameters are required. When successful, the HTTP status will be 200 and the response body will contain XML similar to:

<?xml version="1.0"?>
<api>
    <version>0.2 Beta</version>
    <description>SWAPI TEST</description>
    <requestToken>12340988</requestToken>
    <user>
        <sessionKey>a0b9c8d8e7f6</sessionKey>
        <firstName>Test</firstName>
        <lastName>User</lastName>
        <email>test.user@null.com</email>
        <devices>
            <device>
                <id>640</id>
                <key></key>
                <serialNumber>0-8055451</serialNumber>
                <description>Gen II - Orange</description>
                <isEnabled>Y</isEnabled>
            </device>
            <device>
                <id>730</id>
                <key></key>
                <serialNumber>9726794323</serialNumber>
                <description>Gen II - Orange</description>
                <isEnabled>Y</isEnabled>
            </device>
        </devices>
    </user>
</api>
        

This data is suitable for displaying a device list and allowing the user to select the one they want to use with your application. The isEnabled element indicates if the device is enabled for SWAPI access or not.

When not successful, the HTTP status code and error XML will reflect one of the errors below...

status code message
400 01 The request body contains invalid XML.
403 01 The API key is disabled. Contact SpotWalla Support for more information.
403 02 The SWAPI service was not invoked using HTTPS.
403 06 Session key has expired.
404 01 API key not found. Ensure you're using the correct API key.
404 03 Session key not found.

4.2 Obtaining Device Detail

To obtain a device's detail, including the device key, simply invoke the device service using the HTTP GET method and include the id parameter. For instance:

https://spotwalla.com/api/<API key>/user/<session key>/device?id=1

When successful, the HTTP status will be 200 and the response body will contain XML similar to:

<?xml version="1.0"?>
<api>
    <version>0.2 Beta</version>
    <description>SWAPI TEST</description>
    <requestToken>12340989</requestToken>
    <user>
        <sessionKey>a0b9c8d8e7f6</sessionKey>
        <firstName>Test</firstName>
        <lastName>User</lastName>
        <email>test.user@null.com</email>
        <devices>
            <device>
                <id>1</id>
                <key>q9w8e7r6t5y</key>
                <serialNumber>0-7396409</serialNumber>
                <description>Gen I</description>
                <isEnabled>Y</isEnabled>
            </device>
        </devices>
    </user>
</api>
        

Once a device's detail is obtained, your application will know its assigned key. As long as the user has enabled the SWAPI for the device, your application will be able to manipulate its messages using the message service discussed in the next section.

When not successful, the HTTP status code and error XML will reflect one of the errors below...

status code message
400 01 The request body contains invalid XML.
403 01 The API key is disabled. Contact SpotWalla Support for more information.
403 02 The SWAPI service was not invoked using HTTPS.
403 06 Session key has expired.
404 01 API key not found. Ensure you're using the correct API key.
404 02 Device key not found.
404 03 Session key not found.

5.0 Message Service

The message service allows applications to interact with a device's associated message data. This includes the ability to create, update, delete and list the device's messages. The message service is invoked using the following URL:

https://spotwalla.com/api/<API key>/user/<session key>/device/<device key>/message

Where <API key> is the key assigned to your application, <session key> is the session key assigned after user authentication and <device key> is the key assigned to a user's device. Clients can assign a request token to each message service call by adding a token parameter to the URL. For instance:

https://spotwalla.com/api/<API key>/user/<session key>/device/<device key>/message?token=<requestToken>

Where <requestToken> is an identifier the client assigns to this specific request. The SWAPI doesn't evaluate the request token. It simply returns the token to the client. Typically, clients will use the request token to assign a unique ID to each request. Depending upon your communication model with the SWAPI this could be valuable information. For instance, if all of your SWAPI calls are asynchronous, a request token will help you determine which requests succeed or fail.

The HTTP method used determines how the message service responds to the request. For instance, using GET allows an application to retrieve a device's messages. Using POST allows an application to create messages. Using PUT allows an application to update messages. And using DELETE allows an application to delete messages. Each of the service methods are discussed in detail below.

Note: During the beta period new and updated messages will not appear on location pages. They will appear on trips provided they don't fall within a secure zone, but will not update the trip's last update date.

5.1 Request & Response Bodies

All SWAPI request bodies, if required, will be sent in XML. All SWAPI response bodies will be sent as XML by default, but can be sent as JSON when the following Accept header is included in the request:

Accept: application/json

A complete request body has the following XML structure and elements...

<?xml version="1.0"?>
<api>
    <user>
        <devices>
            <device>
                <messages>
                    <message>
                        <id></id>                       <!-- the message's internal ID -->
                        <latitude></latitude>           <!-- latitude between -90 and 90 -->
                        <longitude></longitude>         <!-- longitude between -180 and 180 -->
                        <nearest></nearest>             <!-- the location's reverse geo-code -->
                        <messageText></messageText>     <!-- any associated message text -->
                        <messageType></messageType>     <!-- the type of message being sent -->
                        <categoryCode></categoryCode>   <!-- the message's category -->
                        <utcSeconds></utcSeconds>       <!-- UNIX timestamp - number of seconds since the epoch -->
                        <elevation></elevation>         <!-- location's elevation in meters -->
                        <speedMph></speedMph>           <!-- speed-related data -->
                        <speedKph></speedKph>
                        <speedKnots></speedKnots>
                        <bearing></bearing>             <!-- the bearing of this location compared to the previous location -->
                        <direction></direction>         <!-- the bearing's associated direction -->
                        <urlSmall></urlSmall>           <!-- typically a picture URL, but can be any URL -->
                        <urlLarge></urlLarge>           <!-- typically a larger picture URL -->
                        <batteryStatus></batteryStatus> <!-- a short description of the battery's status. -->
                    </message>
                </messages>
            </device>
        </devices>
    </user>
</api>
        

Not all of these elements are required in every request and some requests can handle multiple messages. In this case, simply include multiple <message> elements. The sections below will indicate the required elements.

All coordinate values should be in decimal notation. Valid latitude values are between -90 and 90. Valid longitude values are between -180 and 180.

Valid message types are...

messageType description
O OK
C Custom
H Help
T Tracking

Valid category codes are:

code description
B BONUS LOCATION
F FOOD
G GAS STOP
H HOTEL
N NO CATEGORY
P PERFORMANCE AWARD
R ROADSIDE REPAIR
S SIGHTSEEING

Speed and bearing information should be complete or nothing at all. So if you cannot send all of the speed elements as well as the bearing and direction, don't include these elements. If this information isn't present, SpotWalla will attempt to calculate it, although not interactively.

Valid bearing values are in the range of 0 to 359 degrees. Valid direction values are:

direction description
N North
NNE North Northeast
NE Northeast
ENE East Northeast
E East
ESE East Southeast
SE Southeast
SSE South Southeast
S South
SSW South Southwest
SW Southwest
WSW West Southwest
W West
WNW West Northwest
NW Northwest
NNW North Northwest

While there is no predefined set of acceptable battery status values, the value cannot be longer than 24 characters. If a battery status is not provided, the default of UNKNOWN will be applied.

All of the message service methods will return a response. Upon successful completion of the request, the response XML will be similar to...

<?xml version="1.0"?>
<api>
    <version>0.1 Beta</version>             <!-- SWAPI version -->
    <description>SWAPI</description>        <!-- your application's description -->
    <requestToken>12340990</requestToken>   <!-- a unique, client-assigned request ID -->
    <user>
        <sessionKey></sessionKey>           <!-- user's session key -->
        <firstName></firstName>             <!-- first name -->
        <lastName></lastName>               <!-- last name -->
        <email></email>                     <!-- email address -->
        <devices>
            <device>
                <id>1</id>                                  <!-- the device's internal id -->
                <serialNumber>0-7396409</serialNumber>      <!-- the device's serial number -->
                <description>Gen I</description>            <!-- the device's description -->
                <messages>
                    <message>
                    <id>7114976</id>                                        <!-- messsage's internal ID -->
                    <source>API</source>                                    <!-- where the message originated -->
                    <latitude>36.41327</latitude>                           <!-- location's latitude -->
                    <longitude>-86.72033</longitude>                        <!-- location's longitude -->
                    <nearest>Goodlettsville, TN 37072, USA</nearest>        <!-- reverse geo-code -->
                    <messageText></messageText>                             <!-- any test/message -->
                    <messageType>T</messageType>                            <!-- type of message -->
                    <messageTypeDescription>TRACK</messageTypeDescription>  <!-- type description -->
                    <utcSeconds>1351879559</utcSeconds>                     <!-- seconds since the epoch. -->
                    <elevation>233.93</elevation>                           <!-- elevation in meters -->
                    <speedMph>69.17</speedMph>                              <!-- speed in MPH -->
                    <speedKph>111.31</speedKph>                             <!-- speed in KPH -->
                    <speedKnots>60.11</speedKnots>                          <!-- speed in KNOTS -->
                    <bearing>6</bearing>                                    <!-- bearing in degrees -->
                    <direction>N</direction>                                <!-- direction of bearing -->
                    <urlSmall>http://nothing.com/images/1-th.png</urlSmall> <!-- small picture url -->
                    <urlLarge>http://nothing.com/images/1.png</urlLarge>    <!-- large picture url -->
                    <batteryStatus>LOW</batteryStatus>                      <!-- battery status short description -->
                    </message>
                </messages>
            </device>
        </devices>
    </user>
</api>
        

The message services will send back more information than what is received. For instance, detail about the application and Device are included plus all message elements.

5.2 Retrieving Messages

Applications can retrieve a device's messages by calling the message service using the HTTP GET method. This service method does not require a request body. The behavior is controlled using one or more of the following parameters...

parameter default description
last 1 Retrieves up to the last last messages. Must be a numeric value between 1 and 100. If last is greater than 100, it will be set to 100. If last is less than 1, it will be set to 1.

An example call to retrieve the last 2 messages for the device with a device key of 0123456789 and a session key of 983485760 that is participating in an application with an API key of 879879879 is...

https://spotwalla.com/api/879879879/user/983485760/device/0123456789/message?last=2

When successful the service returns an HTTP status of 200 and the response body will contain XML similar to...

<?xml version="1.0"?>
<api>
    <version>0.1 Beta</version>
    <description>SWAPI</description>
    <requestToken>12340995</requestToken>
    <user>
        <devices>
            <device>
                <id>1</id>
                <serialNumber>0-7396409</serialNumber>
                <description>Gen I</description>
                <messages>
                    <message>
                        <id>7114782</id>
                        <source>SPOT</source>
                        <latitude>36.11745</latitude>
                        <longitude>-86.72562</longitude>
                        <nearest>Interstate 24, Nashville, TN 37210, USA</nearest>
                        <messageText></messageText>
                        <messageType>T</messageType>
                        <messageTypeDescription>TRACK</messageTypeDescription>
                        <categoryCode>N</categoryCode>
                        <categoryDescription>NONE</categoryDescription>
                        <utcSeconds>1351878356</utcSeconds>
                        <elevation>168.40</elevation>
                        <speedMph>75.85</speedMph>
                        <speedKph>122.09</speedKph>
                        <speedKnots>65.91</speedKnots>
                        <bearing>318</bearing>
                        <direction>NW</direction>
                        <urlSmall></urlSmall>
                        <urlLarge></urlLarge>
                        <batteryStatus></batteryStatus>
                    </message>
                    <message>
                        <id>7114868</id>
                        <source>SPOT</source>
                        <latitude>36.24799</latitude>
                        <longitude>-86.74280</longitude>
                        <nearest>Interstate 65, Madison, TN 37115, USA</nearest>
                        <messageText></messageText>
                        <messageType>T</messageType>
                        <messageTypeDescription>TRACK</messageTypeDescription>
                        <categoryCode>N</categoryCode>
                        <categoryDescription>NONE</categoryDescription>
                        <utcSeconds>1351878961</utcSeconds>
                        <elevation>176.30</elevation>
                        <speedMph>53.97</speedMph>
                        <speedKph>86.88</speedKph>
                        <speedKnots>46.90</speedKnots>
                        <bearing>353</bearing>
                        <direction>N</direction>
                        <urlSmall></urlSmall>
                        <urlLarge></urlLarge>
                        <batteryStatus></batteryStatus>
                    </message>
                </messages>
            </device>
        </devices>
    </user>
</api>
        

When not successful, the HTTP status code and error XML will reflect one of the errors below...

status code message
403 01 The API key is disabled. Contact SpotWalla Support for more information.
403 02 The SWAPI service was not invoked using HTTPS.
403 03 The device key is disabled.
403 06 Session key has expired.
404 01 API key not found. Ensure you're using the correct API key.
404 02 Device key not found.
404 03 Session key not found.

5.3 Creating Messages

Applications can create messages by calling the message service using the HTTP POST method. The request body contains the messages to create. This example shows the minimum message data required...

<?xml version="1.0"?>
<api>
    <user>
        <devices>
        <device>
            <messages>
            <message>
                <latitude>39.41327</latitude>
                <longitude>-86.72033</longitude>
                <utcSeconds>1351879559</utcSeconds>
                <messageType>O</messageType>
            </message>
            </messages>
        </device>
        </devices>
    </user>
</api>
        

To create more than one message, simply add multiple message elements to the XML.

For a list of all possible message elements, see section 5.1 Request & Response Bodies.

When successful the return XML will look similar to...

<?xml version="1.0"?>
<api>
    <version>0.1 Beta</version>
    <description>SWAPI</description>
    <requestToken>12341000</requestToken>
    <user>
        <devices>
            <device>
                <id>1</id>
                <serialNumber>0-7396409</serialNumber>
                <description>Gen I</description>
                <messages>
                    <message>
                        <id>7147288</id>
                        <source>API</source>
                        <latitude>39.41327</latitude>
                        <longitude>-86.72033</longitude>
                        <nearest></nearest>
                        <messageText></messageText>
                        <messageType>O</messageType>
                        <messageTypeDescription>OK</messageTypeDescription>
                        <categoryCode>N</categoryCode>
                        <categoryDescription>NONE</categoryDescription>
                        <utcSeconds>1351879559</utcSeconds>
                        <elevation></elevation>
                        <speedMph></speedMph>
                        <speedKph></speedKph>
                        <speedKnots></speedKnots>
                        <bearing></bearing>
                        <direction></direction>
                        <urlSmall></urlSmall>
                        <urlLarge></urlLarge>
                        <batteryStatus></batteryStatus>
                    </message>
                </messages>
            </device>
        </devices>
    </user>
</api>
        

When not successful, the HTTP status code and error XML will reflect one of the errors below...

status code message
400 01 The request body is not in the correct format.
400 02 Cannot update messages in POST. Use PUT instead.
400 05 Invalid coordinates. Must be in decimal notation. Latitude between -90 and 90. Longitude between -180 and 180.
400 06 Invalid utcSeconds. Must be greater than or equal to zero. Number of seconds since the Epoch.
400 07 Invalid message type. Must be one of T, O, C or H. See SWAPI documentation for details.
400 08 Elevation must be a numeric value in meters.
400 09 MPH speed data must be numeric.
400 10 KPH speed data must be numeric.
400 11 KNOTS speed data must be numeric.
400 12 Bearing value must be between 0 and 359.
400 13 Invalid direction. See SWAPI documentation for details.
400 14 Small URL must begin with 'http://' or 'https://'
400 15 Large URL must begin with 'http://' or 'https://'
400 16 The categoryCode is invalid. Refer to the Web API documentation for a list of valid codes and their meaning.
400 17 The batteryStatus value cannot be more than 24 characters.
403 01 The API key is disabled. Contact SpotWalla Support for more information.
403 02 The SWAPI service was not invoked using HTTPS.
403 03 The device key is disabled.
403 06 Session key has expired.
404 01 API key not found. Ensure you're using the correct API key.
404 02 Device key not found.
404 03 Session key not found.

5.4 Updating Messages

Applications can update existing messages by calling the message service using the HTTP PUT method. The request body determines which message(s) are updated and what gets updated. The only required message element is the message ID.

<?xml version="1.0"?>
<api>
    <user>
        <devices>
            <device>
                <messages>
                    <message>
                        <id>7147288</id>
                        <latitude>39.41327</latitude>
                        <longitude>-86.72033</longitude>
                        <nearest>123 Main St, White House, TN 37188</nearest>
                        <messageText>All is well.</messageText>
                        <messageType>O</messageType>
                        <categoryCode>N</categoryCode>
                        <utcSeconds>1351879559</utcSeconds>
                        <elevation>809</elevation>
                        <speedMph>35</speedMph>
                        <speedKph>50</speedKph>
                        <speedKnots>21</speedKnots>
                        <bearing>5</bearing>
                        <direction>N</direction>
                        <urlSmall>http://some.com/img01-th.jpg</urlSmall>
                        <urlLarge>http://some.com/img01.jpg</urlLarge>
                        <batteryStatus>GOOD</batteryStatus>
                    </message>
                </messages>
            </device>
        </devices>
    <user>
</api>
        

In addition to the ID, only include those elements you want to update. If you want to update more than one message, simply include multiple <message> elements.

When successful, the return XML will include the entire message detail...

<?xml version="1.0"?>
<api>
    <version>0.1 Beta</version>
    <description>SWAPI</description>
    <requestToken>12341010</requestToken>
    <user>
        <devices>
            <device>
                <id>1</id>
                <serialNumber>0-7396409</serialNumber>
                <description>Gen I</description>
                <messages>
                    <message>
                        <id>7147288</id>
                        <source>API</source>
                        <latitude>39.41327</latitude>
                        <longitude>-86.72033</longitude>
                        <nearest>123 Main St, White House, TN 37188</nearest>
                        <messageText>All is well.</messageText>
                        <messageType>O</messageType>
                        <messageTypeDescription>O</messageTypeDescription>
                        <categoryCode>N</categoryCode>
                        <categoryDescription>NONE</categoryDescription>
                        <utcSeconds>1351879559</utcSeconds>
                        <elevation>809</elevation>
                        <speedMph>35</speedMph>
                        <speedKph>50</speedKph>
                        <speedKnots>21</speedKnots>
                        <bearing>5</bearing>
                        <direction>N</direction>
                        <urlSmall>http://some.com/img01-th.jpg</urlSmall>
                        <urlLarge>http://some.com/img01.jpg</urlLarge>
                        <batteryStatus>GOOD</batteryStatus>
                    </message>
                </messages>
            </device>
        </devices>
    </user>
</api>
        

When not successful, the HTTP status code and error XML will reflect one of the errors below...

status code message
400 01 The request body is not in the correct format.
400 03 Cannot create messages in PUT. Use POST instead.
400 05 Invalid coordinates. Must be in decimal notation. Latitude between -90 and 90. Longitude between -180 and 180.
400 06 Invalid utcSeconds. Must be greater than or equal to zero. Number of seconds since the Epoch.
400 07 Invalid message type. Must be one of T, O, C or H. See SWAPI documentation for details.
400 08 Elevation must be a numeric value in meters.
400 09 MPH speed data must be numeric.
400 10 KPH speed data must be numeric.
400 11 KNOTS speed data must be numeric.
400 12 Bearing value must be between 0 and 359.
400 13 Invalid direction. See SWAPI documentation for details.
400 14 Small URL must begin with 'http://' or 'https://'
400 15 Large URL must begin with 'http://' or 'https://'
400 16 The categoryCode is invalid. Refer to the Web API documentation for a list of valid codes and their meaning.
400 17 The batteryStatus value cannot be more than 24 characters.
403 01 The API key is disabled. Contact SpotWalla Support for more information.
403 02 The SWAPI service was not invoked using HTTPS.
403 03 The device key is disabled.
403 04 Cannot update messages not owned by the current user and device.
403 06 Session key has expired.
404 01 API key not found. Ensure you're using the correct API key.
404 02 Device key not found.
404 03 Session key not found.

5.5 Deleting Messages

Applications can delete messages by calling the message service using the HTTP DELETE method. The message body is the XML that determines the messages to delete. An example is...

<?xml version="1.0"?>
<api>
    <user>
        <devices>
            <device>
                <messages>
                    <message>
                        <id>7147288</id>
                    </message>
                </messages>
            </device>
        </devices>
    </user>
</api>
        

Not all elements are required. At a minimum we need a non-zero ID. To delete more than one message, simply add multiple message elements to the XML.

When successful, the HTTP status will be 200 and the return XML look similar to...

<?xml version="1.0"?>
<api>
    <version>0.1 Beta</version>
    <description>SWAPI</description>
    <requestToken>12341020</requestToken>
    <user>
        <devices>
            <device>
                <id>1</id>
                <serialNumber>0-7396409</serialNumber>
                <description>Gen I</description>
                <messages>
                    <message>
                        <id>7147288</id>
                        <source>API</source>
                        <latitude></latitude>
                        <longitude></longitude>
                        <nearest></nearest>
                        <messageText></messageText>
                        <messageType>O</messageType>
                        <categoryCode>N</categoryCode>
                        <utcSeconds></utcSeconds>
                        <elevation></elevation>
                        <speedMph></speedMph>
                        <speedKph></speedKph>
                        <speedKnots></speedKnots>
                        <bearing></bearing>
                        <direction></direction>
                        <urlSmall></urlSmall>
                        <urlLarge></urlLarge>
                        <batteryStatus></batteryStatus>
                    </message>
                </messages>
            </device>
        </devices>
    </user>
</api>
        

When not successful, the HTTP status code and error XML will reflect one of the errors below...

status code message
400 01 The request body is not in the correct format.
400 04 You cannot delete messages that don't exist. At least one message has an ID that's less than or equal to zero.
403 01 The API key is disabled. Contact SpotWalla Support for more information.
403 02 The SWAPI service was not invoked using HTTPS.
403 03 The device key is disabled.
403 05 You cannot delete messages not owned by the specified device key. At least one message ID isn't owned by the specified device.
403 06 Session key has expired.
404 01 API key not found. Ensure you're using the correct API key.
404 02 Device key not found.
404 03 Session key not found.

6.0 Picture Service

If your application stores pictures using a hosting site like SmugMug of Flickr, then you can add URLs to messages that refer to pictures stored on those sites. However, if your application doesn't store pictures on a hosting site, then SpotWalla's picture service allows your application to upload and add a picture to a message. Pictures uploaded in this manner are hosted by SpotWalla.com.

SpotWalla is not a picture hosting website. The intention is to provide users with a way to quickly and efficiently add pictures to their messages so those who are following along at home can see what they see. The picture service will do three things...

  1. Store and resize the original pic so the longest edge is around ~1024 pixels.
  2. Create a thumbnail with the longest edge somewhere around ~200 pixels.
  3. Update the message's Small URL with a link to the thumbnail and update the message's Large URL with a link to the large picture.

Ideally, your application will limit the size of the uploaded picture for efficiency's sake, but that's up to you. Ultimately, SpotWalla will adjust and store the pictures.

The picture service is invoked using the following URL:

https://spotwalla.com/api/<API key>/user/<session key>/device/<device key>/picture?messageId=<message-id>

Where <API key> is the key assigned to your application, <session key> is the session key assigned after user authentication, <device key> is the key assigned to a user's device and <message-id> is the ID of the message to update.

Clients can assign a request token to each picture service call by adding a token parameter to the URL. For instance:

https://spotwalla.com/api/<API key>/user/<session key>/device/<device key>/picture?messageId=<message-id>&token=<requestToken>

Where <requestToken> is an identifier the client assigns to this specific request. The SWAPI doesn't evaluate the request token. It simply returns the token to the client. Typically, clients will use the request token to assign a unique ID to each request. Depending upon your communication model with the SWAPI this could be valuable information. For instance, if all of your SWAPI calls are asynchronous, a request token will help you determine which requests succeed or fail.

Since this service modifies an existing message, the pitcure service is invoked using an HTTP PUT request. With the exception of the picture data, all the information required is specified on the URL. The picture data is sent in binary form in the request body.

If the request is successful, SpotWalla will return a message similar to...

<?xml version="1.0"?>
<api>
    <version>0.5 Beta</version>
    <description>SWAPI</description>
    <requestToken>1362274310</requestToken>
    <user>
        <devices>
            <device>
                <id>1</id>
                <serialNumber>0-7396409</serialNumber>
                <description>Gen I</description>
                <messages>
                    <message>
                        <id>8120889</id>
                        <source>BUBBLER</source>
                        <latitude>36.52829</latitude>
                        <longitude>-86.64414</longitude>
                        <nearest>Main Street & Interstate 65, Cross Plains, TN 37049, USA</nearest>
                        <messageText></messageText>
                        <messageType>T</messageType>
                        <messageTypeDescription>TRACK</messageTypeDescription>
                        <categoryCode>N</categoryCode>
                        <categoryDescription>NONE</categoryDescription>
                        <utcSeconds>1362180333</utcSeconds>
                        <elevation>220.80</elevation>
                        <speedMph>22.00</speedMph>
                        <speedKph>35.37</speedKph>
                        <speedKnots>19.12</speedKnots>
                        <bearing>205</bearing>
                        <direction>SSW</direction>
                        <urlSmall>https://spotwalla.com/pics/54981e1c0ac0d81593d99089bb3fa013-T.png</urlSmall>
                        <urlLarge>https://spotwalla.com/pics/54981e1c0ac0d81593d99089bb3fa013.png</urlLarge>
                    </message>
                </messages>
            </device>
        </devices>
    </user>
</api>

When not successful, the HTTP status code and error XML will reflect one of the errors below...

status code message
400 17 Invalid picture data.
400 18 Cannot store picture.
400 19 Cannot store thumbnail picture.
403 01 The API key is disabled. Contact SpotWalla Support for more information.
403 02 The SWAPI service was not invoked using HTTPS.
403 03 The device key is disabled.
403 04 Cannot update messages not owned by the current user and device.
403 06 Session key has expired.
404 01 API key not found. Ensure you're using the correct API key.
404 02 Device key not found.
404 03 Session key not found.
404 05 Invalid message ID.

7.0 Family Service

The family service allows your application to interact with a user's family and friends. Currently, the family service will only return a list of family and friends as well as the distance the user is from each member.

The family service is invoked using the following URL:

https://spotwalla.com/api/<API key>/user/<session key>/family?lat=<latitude>&lon=<longitude>

Where <API key> is the key assigned to your application, <session key> is the session key assigned after user authentication, <latitude> is optional and is the user's current latitude coordinate, <longitude> is option and is the user's current longitude coordinate.

Clients can assign a request token to each family service call by adding a token parameter to the URL. For instance:

https://spotwalla.com/api/<API key>/user/<session key>/family?lat=<latitude>&lon=<longitude>&token=<requestToken>

Where <requestToken> is an identifier the client assigns to this specific request. The SWAPI doesn't evaluate the request token. It simply returns the token to the client. Typically, clients will use the request token to assign a unique ID to each request. Depending upon your communication model with the SWAPI this could be valuable information. For instance, if all of your SWAPI calls are asynchronous, a request token will help you determine which requests succeed or fail.

If the request is successful, SpotWalla will return a message similar to...

<?xml version="1.0"?>
<api>
     <version>0.5 Beta</version>
     <description>SWAPI</description>
     <requestToken>136227423420</requestToken>
     <user>
         <latitude>36</latitude>   <!-- user's latitude -->
         <longitude>98</longitude> <!-- user's longitude -->
         <friends>
             <friend>
                 <id>112312323</id>                             <!-- friend ID -->
                 <displayName>Friend 1</displayName>            <!-- configured display name -->
                 <isFamily>Y</isFamily>                         <!-- Y = Family member -->
                 <isActive>Y</isActive>                         <!-- Y = Active -->
                 <confirmDate>2011-02-07 23:28:12</confirmDate> <!-- date the friendship was confirmed -->
                 <distance>119.4</distance>                     <!-- distance from user. -1 = unknown -->
                 <message>                                 <!-- friend's last location -->
                     <id>8216433453</id>                                    <!-- message ID-->
                     <source>SPOT</source>                                  <!-- the source interface -->
                     <latitude>38.78189</latitude>                          <!-- friend's latitude -->
                     <longitude>-84.7939</longitude>                        <!-- friend's longitude -->
                     <nearest></nearest>                                    <!-- nearest location -->
                     <messageText></messageText>                            <!-- text messages -->
                     <messageType>T</messageType>                           <!-- type of message -->
                     <messageTypeDescription>TRACK</messageTypeDescription> <!-- description of messageType -->
                     <categoryCode>N</categoryCode>                         <!-- message category -->
                     <categoryDescription>NONE</categoryDescription>        <!-- message category description -->
                     <utcSeconds>1363282214</utcSeconds>                    <!-- time of message -->
                     <elevation>225.63</elevation>                          <!-- location elevation -->
                     <speedMph>33.25</speedMph>                             <!-- speed in MPH -->
                     <speedKph>53.55</speedKph>                             <!-- speed in Kph -->
                     <speedKnots>28.90</speedKnots>                         <!-- speed in knots -->
                     <bearing>261</bearing>                                 <!-- friend's bearing -->
                     <direction>W</direction>                               <!-- friend's direction -->
                     <urlSmall></urlSmall>                                  <!-- small picture url -->
                     <urlLarge></urlLarge>                                  <!-- large picture url-->
                 </message>
             </friend>
             <friend>                                      <!-- friend without a known last location -->
                 <id>3012342</id>
                 <displayName>Friend 2</displayName>
                 <isFamily>N</isFamily>
                 <isActive>Y</isActive>
                 <confirmDate>2011-11-12 08:28:36</confirmDate>
                 <distance>-1</distance>             <!-- -1 = distance cannot be determined -->
             </friend>
         </friends>
     </user>
</api>

When not successful, the HTTP status code and error XML will reflect one of the errors below...

status code message
403 01 The API key is disabled. Contact SpotWalla Support for more information.
403 02 The SWAPI service was not invoked using HTTPS.
403 06 Session key has expired.
404 01 API key not found. Ensure you're using the correct API key.
404 03 Session key not found.

Appendix A - A Simple SWAPI Client Using PHP

The following PHP client demonstrates how to interact with all of the SWAPI web services and their methods.

        <?php

        $apiHost = 'https://spotwalla.com/';
        $apiKey = '9fkd9sshflsldhfkk7';
        $sessionKey = null;
        $deviceKey = null;

        $choice = '';
        do {

            print "\n\nWhat do you want to do?\n";
            print "1) Obtain a Session Key\n";
            if ( ! is_null($sessionKey)) {
                print "2) Choose One of My Devices\n";
            }
            if ( ! is_null($deviceKey)) {
                print "3) List Last Two Messages\n";
                print "4) Create a Message\n";
                print "5) Update a Message\n";
                print "6) Delete a Message\n";
                print "7) Upload a Picture\n";
            }
            print "X) Exit\n";

            print "\nChoice: ";
            $choice = trim(fgets(STDIN));

            switch($choice) {
                case '1': // obtain a session key
                    $sessionKey = authenticateUser($apiHost, $apiKey);
                    break;
                case '2':
                    $deviceKey = chooseDevice($apiHost, $apiKey, $sessionKey);
                    break;
                case '3':
                    listMessages($apiHost, $apiKey, $sessionKey, $deviceKey);
                    break;
                case '4':
                    createMessage($apiHost, $apiKey, $sessionKey, $deviceKey);
                    break;
                case '5':
                    updateMessage($apiHost, $apiKey, $sessionKey, $deviceKey);
                    break;
                case '6':
                    deleteMessage($apiHost, $apiKey, $sessionKey, $deviceKey);
                    break;
                case '7':
                    uploadPicture($apiHost, $apiKey, $sessionKey, $deviceKey);
                    break;
            } // switch
        } while (strcasecmp($choice, 'x') != 0);



        function authenticateUser($apiHost, $apiKey) {

            print "\nTo obtain a session key, you must log into SpotWalla. Follow the directions below...\n";
            print "Email   : ";
            $email = trim(fgets(STDIN));
            print "Password: ";
            $password = trim(fgets(STDIN));

            $requestBody =
                "<?xml version=\"1.0\"?>
                <api>
                    <user>
                        <email>$email</email>
                        <password>$password</password>
                    </user>
                </api>
                ";
            $token = time();
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept: application/xml"));
            curl_setopt($ch, CURLOPT_URL, "${apiHost}api/${apiKey}/user?token=${token}");
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

            $result = curl_exec($ch);
            if ($result === false) {
                print "failed\n";
                exit;
            }
            $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);


            $xml = simplexml_load_string($result);
            if ($xml === false) {
                print "*** Cannot parse response XML\n";
                return null;
            }

            if ($status <> '200') {
                print "HTTP STATUS: " . $xml->error->status . "\n";
                print "ERROR CODE : " . $xml->error->code . "\n";
                print "MESSAGE    : " . $xml->error->message . "\n";
                return null;
            }

            print 'Hello ' . $xml->user->firstName . ' ' . $xml->user->lastName . ".\n";
            print 'Your session key is ' . $xml->user->sessionKey . "\n";
            return $xml->user->sessionKey;

        } // authenticateUser



        function chooseDevice($apiHost, $apiKey, $sessionKey) {

            print "\nYour devices are listed below...\n";
            $token = time();
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept: application/xml"));
            curl_setopt($ch, CURLOPT_URL, "${apiHost}api/${apiKey}/user/${sessionKey}/device?token=${token}");
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

            $result = curl_exec($ch);
            if ($result === false) {
                print "failed\n";
                exit;
            }
            $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);

            $xml = simplexml_load_string($result);
            if ($xml === false) {
                print "*** Cannot parse response XML\n";
                return null;
            }

            if ($status <> '200') {
                print "HTTP STATUS: " . $xml->error->status . "\n";
                print "ERROR CODE : " . $xml->error->code . "\n";
                print "MESSAGE    : " . $xml->error->message . "\n";
                return null;
            }


            print "DESCRIPTION           SERIAL NUMBER       ID\n";
            print "--------------------  ------------------  ------ \n";
            foreach ($xml->user->devices->device as $d) {
                printf("%-20s  %18s  %6d\n", $d->description, $d->serialNumber, $d->id);
            }

            print "\nEnter a device ID: ";
            $choice = trim(fgets(STDIN));

            $token = time();
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept: application/xml"));
            curl_setopt($ch, CURLOPT_URL, "${apiHost}api/${apiKey}/user/${sessionKey}/device?id=${choice}&token=${token}");
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

            $result = curl_exec($ch);
            if ($result === false) {
                print "failed\n";
                exit;
            }
            $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);

            $xml = simplexml_load_string($result);
            if ($xml === false) {
                print "*** Cannot parse response XML\n";
                return null;
            }

            if ($status <> '200') {
                print "HTTP STATUS: " . $xml->error->status . "\n";
                print "ERROR CODE : " . $xml->error->code . "\n";
                print "MESSAGE    : " . $xml->error->message . "\n";
                return null;
            }

            print "You selected device '" . $xml->user->devices->device->serialNumber .
                    "' with device key " . $xml->user->devices->device->key . "\n";
            return $xml->user->devices->device->key;

        } // chooseDevice



        function listMessages($apiHost, $apiKey, $sessionKey, $deviceKey) {

            print "\nThe last 2 messages are...\n";
            $token = time();
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept: application/xml"));
            curl_setopt($ch, CURLOPT_URL, "${apiHost}api/${apiKey}/user/${sessionKey}/device/${deviceKey}/message?last=2&token=${token}");
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

            $result = curl_exec($ch);
            if ($result === false) {
                print "failed\n";
                exit;
            }
            $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);

            $xml = simplexml_load_string($result);
            if ($xml === false) {
                print "*** Cannot parse response XML\n";
                return null;
            }

            if ($status <> '200') {
                print "HTTP STATUS: " . $xml->error->status . "\n";
                print "ERROR CODE : " . $xml->error->code . "\n";
                print "MESSAGE    : " . $xml->error->message . "\n";
                return null;
            }

            print "$result";

        } // listMessages


        function createMessage($apiHost, $apiKey, $sessionKey, $deviceKey) {

            print "Latitude : ";
            $lat = trim(fgets(STDIN));
            print "Longitude: ";
            $lon = trim(fgets(STDIN));
            print "Message  : ";
            $message = htmlentities(trim(fgets(STDIN)), ENT_QUOTES);

            $now = gmmktime();
            $requestBody =
        "<?xml version=\"1.0\"?>
        <api>
            <user>
                <devices>
                    <device>
                        <messages>
                            <message>
                                <latitude>$lat</latitude>
                                <longitude>$lon</longitude>
                                <utcSeconds>$now</utcSeconds>
                                <messageType>T</messageType>
                                <messageText>$message</messageText>
                            </message>
                        </messages>
                    </device>
                </devices>
            </user>
        </api>
        ";

            $token = time();
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept: application/xml"));
            curl_setopt($ch, CURLOPT_URL, "${apiHost}api/${apiKey}/user/${sessionKey}/device/${deviceKey}/message?token=${token}");
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

            $result = curl_exec($ch);
            if ($result === false) {
                print "failed\n";
                exit;
            }
            $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);

            $xml = simplexml_load_string($result);
            if ($xml === false) {
                print "*** Cannot parse response XML\n";
                return null;
            }

            if ($status <> '200') {
                print "HTTP STATUS: " . $xml->error->status . "\n";
                print "ERROR CODE : " . $xml->error->code . "\n";
                print "MESSAGE    : " . $xml->error->message . "\n";
                return;
            }

            print "$result";

        } // createMessage


        function updateMessage($apiHost, $apiKey, $sessionKey, $deviceKey) {


            print "Msg ID     : ";
            $id = trim(fgets(STDIN));
            print "Latitude   : ";
            $lat = trim(fgets(STDIN));
            print "Longitude  : ";
            $lon = trim(fgets(STDIN));
            print "Message    : ";
            $message = htmlentities(trim(fgets(STDIN)), ENT_QUOTES);
            print "Small Pic  : ";
            $small = trim(fgets(STDIN));
            print "Large Pic  : ";
            $large = trim(fgets(STDIN));

            $now = gmmktime();
            $requestBody =
                    "<?xml version=\"1.0\"?>
                    <api>
                        <user>
                            <devices>
                                <device>
                                    <messages>
                                        <message>;
                                            <id>$id</id>\n";

            if ( ! empty($lat)) $requestBody .= "<latitude>$lat</latitude>\n";
            if ( ! empty($lon)) $requestBody .= "<longitude>$lon</longitude>\n";
            $requestBody .= "<utcSeconds>$now</utcSeconds>\n";
            if ( ! empty($message)) $requestBody .= "<messageText>$message</messageText>\n";
            if ( ! empty($small)) $requestBody .= "<urlSmall>$small</urlSmall>\n";
            if ( ! empty($large)) $requestBody .= "<urlLarge>$large</urlLarge>\n";

            $requestBody .= "
                                        </message>
                                    </messages>
                                </device>
                            </devices>
                        </user>
                    </api>
                    ";

            $fh = fopen('php://memory', 'rw');
            fwrite($fh, $requestBody);
            rewind($fh);

            $token = time();
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept: application/xml"));
            curl_setopt($ch, CURLOPT_URL, "${apiHost}api/${apiKey}/user/${sessionKey}/device/${deviceKey}/message?token=${token}");
            curl_setopt($ch, CURLOPT_PUT, true);
            curl_setopt($ch, CURLOPT_INFILE, $fh);
            curl_setopt($ch, CURLOPT_INFILESIZE, strlen($requestBody));
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

            $result = curl_exec($ch);
            if ($result === false) {
                print "failed\n";
                exit;
            }
            $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            fclose($fh);

            $xml = simplexml_load_string($result);
            if ($xml === false) {
                print "*** Cannot parse response XML\n";
                return null;
            }

            if ($status <> '200') {
                print "HTTP STATUS: " . $xml->error->status . "\n";
                print "ERROR CODE : " . $xml->error->code . "\n";
                print "MESSAGE    : " . $xml->error->message . "\n";
                return;
            }

            print "$result";

        } // updateMessage


        function deleteMessage($apiHost, $apiKey, $sessionKey, $deviceKey) {

            print "Msg ID   : ";
            $id = trim(fgets(STDIN));

            $requestBody =
        "<?xml version=\"1.0\"?>
        <api>
            <user>
                <devices>
                    <device>
                        <messages>
                            <message>
                                <id>$id</id>
                            </message>
                        </messages>
                    </device>
                </devices>
            </user>
        </api>
        ";

            $token = time();
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept: application/xml"));
            curl_setopt($ch, CURLOPT_URL, "${apiHost}api/${apiKey}/user/${sessionKey}/device/${deviceKey}/message?token=${token}");
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
            curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

            $result = curl_exec($ch);
            if ($result === false) {
                print "failed\n";
                exit;
            }
            $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);

            $xml = simplexml_load_string($result);
            if ($xml === false) {
                print "*** Cannot parse response XML\n";
                return null;
            }

            if ($status <> '200') {
                print "HTTP STATUS: " . $xml->error->status . "\n";
                print "ERROR CODE : " . $xml->error->code . "\n";
                print "MESSAGE    : " . $xml->error->message . "\n";
                return;
            }

            print "$result";

        } // deleteMessage


    function uploadPicture($apiHost, $apiKey, $sessionKey, $deviceKey)    {

        print "Msg ID     : ";
        $id = trim(fgets(STDIN));
        print "Filename   : ";
        $filename = trim(fgets(STDIN));

        $now = gmmktime();
        $size = filesize($filename);
        print "size=$size, file=$filename\n";

        $fh = fopen($filename, 'r');

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept: application/xml"));
        curl_setopt($ch, CURLOPT_URL, "${apiHost}api/$apiKey/user/$sessionKey/device/$deviceKey/picture?messageId=${id}&token=${now}");
        curl_setopt($ch, CURLOPT_PUT, true);
        curl_setopt($ch, CURLOPT_INFILE, $fh);
        curl_setopt($ch, CURLOPT_INFILESIZE, $size);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);

        $result = curl_exec($ch);
        if ($result === false) {
            print "failed\n";
            exit;
        }
        $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        fclose($fh);

        $xml = simplexml_load_string($result);
        if ($xml === false) {
            print "*** Cannot parse response XML\n";

            return null;
        }

        if ($status <> '200') {
            print "HTTP STATUS: " . $xml->error->status . "\n";
            print "ERROR CODE : " . $xml->error->code . "\n";
            print "MESSAGE    : " . $xml->error->message . "\n";

            return;
        }

        print "$result";

    } // updatePicture

        ?>