afourney edited this page Dec 17, 2016 · 34 revisions

NEW! Host your own app appstore in the Pebble iOS app

Additional Notes

  • See notes on Reverse Engineering the Official App Store for info on how to install apps from a webpage within the App Store Web View.

  • While the Safari Web Inspector looks like it can be turned on in the secret settings menu, it appears to be disabled in production builds?

Appstore Resources (and Backups!)

Rsync mirror backup

There is a public rsync mirror containing a fair amount of backups from above. As more content gets released, they will generally end up within the rsync backup. Running the following rsync command on a regular basis should allow for the creation of a secondary mirror. Feel free to add it to a cron to pull the latest data from the server on a regular basis. If anyone would like to share their rsync mirrors (that are pulling from the one listed below), it'd be great to have those mirrors listed as well in order to spread out the bandwidth usage a bit.

/usr/bin/rsync --bwlimit=400 -rlptv --delete --delete-delay rsync:// pebble

API info


Pebble uses an authentication URL for all apps. No apps store the username or password, just the authentication token and refresh token. The following url can be opened in a browser / webview, which will show the pebble login page:

After logging in, it redirects to:


after login. A header "Authorization: Bearer {access_token}" is used on the other calls.

See Example HTTP Requests for an example exchange.

WARNING: Don't share your bearer token. It doesn't expire, and cannot be revoked. It remains unclear if changing your password also changes the bearer token. (verify)

Account data

Returns a list of locker apps, using the same format as the store applications.


Returns the app in the locker that matches the guid.


Adds the app to the locker. The request body should be everything in the "application" key returned by the store API.


Removes the app from the locker. Note: This URL could theoretically change, you should send the DELETE request to the URL in "links" => "remove" returned by the locker API.

Timeline sync

The basic loop for the companion apps works the following way:

  1. Set nextQueryUrl to
  2. Query nextQueryUrl, and store it in a variable response.
  3. If response["mustResync"] is true, go to 1.
  4. Parse all updates in the response["updates"] array
  5. If response["nextPageURL"] exists and is a string, set nextQueryUrl = response["nextPageURL"] and go to 2.
  6. set nextQueryUrl = response["syncURL"]
  7. Wait a fixed amount of time (the official apps wait ~11 minutes)
  8. Go to 2.

When sending a request, the Timeline API will return a JSON object that consists of a list of updates to the timeline. The timeline pin/notification format is described in the Pebble documentation.

The response will contain an array of updates, response["updates"]. Each update entry is an object consisting of two keys, "type" and "data". type can be one of the following events: timeline.topic.subscribe, timeline.topic.unsubscribe,,


Some app or service has subscribed the user to a new topic. As far as I know, the companion app does not need to do anything with this information. The update data consists of two elements, "topicKey" and "subDate".


This event occurs when the user gets unsubscribed from a topic. The update data consists of one element, "topicKey". The companion app should remove all existing timeline pins with this topicKey from the watch timeline. and

These two events insert and delete pins and reminders on the timeline. In both cases, the update data consists of a full timeline pin object, as described in the Pebble documentation.

When the event is a delete event, the pin should be deleted from the watch timeline. The create event can either add a new pin to the timeline, or update an existing pin. (When updating, the UUID will be the same as one of the previous UUIDs). The "updateNotification" will only be sent if newItem.Updated > item.Updated. The createNotification will only be sent if the UUID is new.


Not sure what all the possible uses of this endpoint are, but one used by the official iOS app is to check for firmware updates. One example request is:

Which returns:

    "fw": {
        "3.x-migration": {
            "friendlyVersion": "v3.8-mig10",
            "notes": "Pebble 3.X Migration Firmware",
            "sha-256": "46b19b1b25bfc71f59229f6b4552652b75dbcece7ac47c9d2e66e279cce1c4ad",
            "timestamp": 1449968598,
            "url": ""
        "normal": {
            "friendlyVersion": "v3.12.3",
            "notes": "Fixed various timezone bugs for Classic-Series Pebble watches. Learn more at",
            "sha-256": "8b7badccf5085255f04bdef926a18a23f015c808f549252561ab607de1f4e3e6",
            "timestamp": 1479505803,
            "url": ""

The possible values for select are (possibly incomplete list): fw, health-insights, lp, linked-services, pipeline-api

An example health-insights response:

    "health-insights": {
        "url": "",
        "version": 11

For some reason, authentication is needed for this as well.

Other URLs

Not sure what it does, but it's accessed by the app. Possibly to load fonts?{id}

Returns user account information, consisting of a list of appids in the locker, flagged & liked apps and some other info.

id can be set to "me" to get the user account info of the user identified by the authentication token.{companion_platform}/{pebble_platform}.json

The initial apps installed on any new pebble.

  • companion_platform can be android or ios.
  • pebble_platform can be aplite, basalt, and possibly some other values. (chalk does not exist)

Returns a list of available language packs for the hardware.

Pebble Health


Stores a JSON object containing information about the user (SI units):

    "age": 28,
    "weight": 60,
    "gender": "male",
    "height": 1.75

gender can be male, female and other.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.