PlayJam GameStick server API documentation

This is an attempt to document the network API used by the PlayJam GameStick gaming console.

API basics

Use cases

Setup

A new PlayJam GameStick does the following requests:

FIXME verify

OOBE (Out Of Box Experience) process starts with the GameStick setup:

  1. Fetch registration code and show it on screen: POST http://l2.gamestickservices.net/api/rest/connect/stick/stick/xxx/view.json

  2. Check every 5 seconds if the online registration has been finished: also POST http://l2.gamestickservices.net/api/rest/connect/stick/stick/xxx/view.json

  3. Download game metadata: also POST http://l2.gamestickservices.net/api/rest/connect/stick/stick/xxx/view.json

Common data formats

JSON responses share some properties.

date

Dates have format dd/MM/yyyy - e.g. 23/12/2013.

time

Time since 01.01.1970 in milliseconds (unix timestamp * 1000)

JSON responses MUST be condensed to a single line.

HTTP Headers

User-Agent

The user agent may have two different values:

  • Dalvik/1.6.0 (Linux; U; Android 4.1.2; GameStick V1.0 Build/V1.03.04MX01_20130911)

  • GameStick/1.0

GameStick/1.0

Is used when the HTTP request is coming from com.playjam.EnhancedDownloadService.

The Accept-Encoding header is identity in that case.

Uncategorized

ping connection check

The connection check in com.playjam.gamestick.WifiTools.ChecksFragment#ping sends ICMP ping requests to three domains to see if the network is available:

  • connectcheck.gamestickservices.net

  • l2.gamestickservices.net

  • update.gamestickservices.net

GET http://connectcheck.gamestickservices.net/generate_204

Network availability ping via HTTP.

Firmware 2071 resolves the IP address for the hostname and sends the HTTP request directly to the IP address without providing a Host header.

At least firmware 0.0.53 sends the host name in the request.

HTTP request

Protocol

http

Host
  1. connectcheck.gamestickservices.com

  2. connectcheck.gamestickservices.net

  3. clients3.google.com

Path

generate_204

HTTP response

Success
Status code

204 No Content

Usage

  • com.playjam.gamestick.WifiTools.ChecksFragment#http()

    Only connectcheck.gamestickservices.net

  • com.playjam.gamestick.WifiService#ping()

    Tries all three servers until it finds one that responds.

GET http://db.gamestickservices.com/api/rest/joystick/bindings/xxx/view.json

Fetch controller mapping for a game.

Games had to request input maps themselves by sending the com.playjam.InputService.Remap intent with the game ID.

They could also send a keymap XML via the com.playjam.InputService.RemapXML intent, and the com.playjam.InputService would then take care of mapping the keys.

Unfortunately, InputService hard-codes the db.gamestickservices.com domain and does not use the .net one.

Games known to request the input map file:

  • Sela the Space Pirate, id 171

HTTP request

Protocol

http

Host

db.gamestickservices.com

Path

/api/rest/joystick/bindings/xxx/view.json

xxx

UUID of the game

HTTP response

Must be on a single line.

Status code

200 OK

Example

{
    "body": {
        "joyStickBindings": "<keymap>...</keymap>"
    }
}

Keymap file

<keymap>
  <!-- 4 options, repeat and mix as often as you want -->
  <key output="key" from="$intKeycode" to="$intKeycode"/>
  <key output="motion" from="$intKeycode" action="$byte">
    <axis id="$int" value="$float"/>
    <!-- multiple possible -->
  </key>
  <motion output="key"
    axis="$intFromAxis" low="$floatFromLowThreshold" high="$floatFromHighThreshold"
    to="$intToKeyCode" action="$byteToAction"
    multidown="$boolSendMultiDown"
    applyzero="$boolApplyZero" zerovalue="$floatZeroValue"
    />
  <motion output="motion"
    axis="$intFromAxis" low="$floatFromLowThreshold" high="$floatFromHighThreshold"
    applyzero="$boolApplyZero" zerovalue="$floatZeroValue"
  >
    <axis id="$int" value="$float"/>
    <!-- multiple possible -->
  </motion>
</keymap>

GET http://dev-db.gamestickservices.net/api/rest/developer/validate/xxx/yyy/view.json

Verify that the GameStick may switch to the developer firmware.

HTTP request

Protocol

http

Host

dev-db.gamestickservices.net

Path

/api/rest/developer/validate/xxx/yyy/view.json;jsessionid=zzz

/api/rest/developer/validate/xxx/yyy/view.json

OOBE does not add the jsessionid parameter

xxx

Hardware ID

Example: ac:db:da:09:18:5c

yyy

Verification code entered by the user.

7 characters long, all digits. Last digit is checksum calculated with the Damm algorithm.

zzz

Session ID

HTTP response

Standard response, with success set to true.

{"body":{"action":"","message":"","success":true}}

POST http://l2.gamestickservices.net/api/rest/connect/stick/stick/xxx/view.json

Used for several things:

  1. Network connection check

  2. Fetch registration code and session ID for this gamestick.

  3. Fetch information about games and their display in the main menu

HTTP request

When the GameStick is not registered yet, then this URL is fetched every 5 seconds. Once registered, it is fetched every 2 minutes.

The initial request does not contain a session ID. The hardware ID is used to associate the stick with an existing user ID and a new session ID is generated.

Method

POST

Firmware 0.0.53 uses GET.

DatabaseService.ServiceCore can be put into GET mode in Firmware 2071, in that case, GET will be used as well.

Protocol

http

Host

l2.gamestickservices.net

Firmware 0.0.53 uses db.gamestickservices.net.

Path

/api/rest/connect/stick/stick/xxx/view.json

xxx

Hardware-ID, e.g. ac:db:da:09:18:5c

;jsessionid=zzz

In GET mode, but only after the initial request.

Headers
Accept-Encoding

identity

Content-Type

application/x-www-form-urlencoded

Content-Length

0

User-Agent

GameStick/1.0 (when requested via com.playjam.EnhancedDownloadService)

If-Modified-Since

When the GameStick cache contains a previous version.

Example: If-Modified-Since: Thu, 06 Jul 2023 07:02:39 UTC

Not sent when the Cookie is sent.

POST parameters

None

Cookies
JSESSIONID

Session ID, only when available (not empty)

In POST mode only

AWSELB

When available

In POST mode only.

HTTP response

When used for connection check, the response must contain one of the following strings (no whitespace after :):

"status":"CONNECTION_IN_PROGRESS"
"status":"CONNECTED"
Not registered yet - CONNECTION_IN_PROGRESS
Status code

200 OK

{
    "sid": "dummy",
    "time": "1680109254000",
    "body": {
        "status":"CONNECTION_IN_PROGRESS",
        "registrationCode": "abcdefg"
    }
}
Registration complete - CONNECTED
Status code

200 OK

304 Not Modified - when the If-Modified-Since header value is equal or higher than the data timestamp.

body.config.apps[].genre

Not used in firmware 2071, but still available - probably for older versions.

body.config.apps[].genres

Known genres:

  • Action

  • Adventure

  • Arcade

  • Classics

  • Media

  • Platformer

  • Puzzle

  • Racing

  • Shmup

  • Shooter

body.config.apps[].images.name

Special name STICK_SCREENSHOT adds the image URLs as screenshot, otherwise as thumbnail. (firmware 2071).

Known names:

  • STICK_ICON (85x48)

  • STICK_REGISTRATION_GAME_ICON (200x200)

  • STICK_SCREENSHOT (350x160)

  • STICK_SCREENSHOT_1080 (525x240)

  • STICK_THUMBNAIL1 (350x88)

  • STICK_THUMBNAIL2 (350x160)

  • STICK_THUMBNAIL3 (350x236)

  • STICK_THUMBNAIL4 (350x400)

  • STICK_VIDEO1_SCREENSHOT (350x160)

STICK_SCREENSHOT and STICK_SCREENSHOT_1080 may have multiple URLs; the other ones only one.

body.config.global.uitranslation

Not used in firmware 2058 and 2071.

body.config.global.newfeatured.ages[].entries[].columnentries[].thumbnail

The code says this is the "tile size".

  • 6 for full-height (one game in this column) STICK_THUMBNAIL4 is used.

  • 4 for 2/3 height (two games in this column, one size 4, one size 2) STICK_THUMBNAIL3

  • 3 for 1/2 (two games in this column) STICK_THUMBNAIL2

  • 2 for 1/3 height (3 games in this column) STICK_THUMBNAIL1

{
    "sid":"dummy",
    "time":"1680109254000",

    "lastaccessed": 1385115865500,
    "x-forwarded-for": null,
    "created": 1385115865500,
    "accessCount": 0,
    "addr": "10.37.137.31",
    "remoteaddr": "135.196.28.241",

    "body": {
        "status":"CONNECTED",
        "config": {
            "apps": [
                {
                    "id": 23,
                    "minAge": 3,
                    "name": "My game title",
                    "description": "Game description FIXME format",
                    "package": "org.example.game",
                    "size": 12345,
                    "download": {
                        "version": 123,
                        "url": "http://example.org/game.apk"
                    },
                    "genre": "Racing",
                    "genres": [
                        {
                            "genre": "Racing"
                        }
                    ],
                    "popular": 1,
                    "featured": 1,
                    "isfree": true,
                    "bought": false,
                    "downloadedfree": false,
                    "multipricing": {
                        "buy": [
                            {
                                "amount": 23.42,
                                "isocurrency": "EUR"
                            }
                        ],
                        "rent": [
                        ]
                    },
                    "images": [
                        {
                            "name": "STICK_SCREENSHOT",
                            "width": 512,
                            "height": 384,
                            "urls": [
                                {
                                    "url": "http://example.org/image.jpg"
                                }
                            ]
                        }
                    ]
                }
            ],
            "global": {
                "uitranslation": {
                    "country": [
                    ],
                    "version": 0
                },
                "newfeatured": {
                    "ages": [
                        {
                            "age": 3,
                            "entries": [
                                {
                                    "columnentries": [
                                        {
                                            "gameID": 254,
                                            "thumbnail": 12,
                                            "column": 1
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            }
        }
    }
}

Usage

  • com.playjam.gamestick.WifiTools.ChecksFragment#doDatabaseConnect()

    To check if a network connection is available. Only uses l2.gamestickservices.net.

  • com.playjam.DatabaseService.apk: com.playjam.Services.Database.ConnectDownloader

GET http://l2.gamestickservices.net/api/rest/parentcontroll/change/agerating/xxx/yyy/view.json

Change the profile's minAge setting.

Only games suitable for that age are shown by the GameStick Console UI.

HTTP request

Protocol

http

Host

l2.gamestickservices.net

Path

/api/rest/parentcontroll/change/agerating/xxx/yyy/view.json;jsessionid=zzz

xxx

Age rating:

  • 3

  • 7

  • 12

  • 17

yyy

MD5-hashed user password

zzz

Session ID

HTTP response

Successful change
Status code

200 OK

{
    "body": {
        "success": true,
        "message": null,
        "action": "ChangeAgeRating"
    }
}

action and message do not seem to be needed.

Wrong password
Status code

200 OK

{
    "body": {
        "success": false
    }
}

Neither action no message seem to be needed.

GET http://l2.gamestickservices.net/api/rest/player/profile/view.json

Fetch player information.

In firmware v2071 OOBE setup will not finish when the profile is not returned properly.

HTTP request

Protocol

http

Host

l2.gamestickservices.net

Firmware 0.0.53 used db.gamestickservices.net

Path

/api/rest/player/profile/view.json;jsessionid=xxx

xxx

Session ID from the registration check api/rest/connect/stick/stick/xxx/view.json.

Empty when not registered yet.

Headers
User-Agent

Examples:

  • Dalvik/1.6.0 (Linux; U; Android 4.1.2; GameStick V1.0 Build/V1.03.04MX01_20130911)

  • GameStick/1.0

Accept-Encoding
  • gzip only when User-Agent is Dalvik/...

  • identity when User-Agent is GameStick/1.0

HTTP response

Not registered yet
Status code

200 OK

FIXME

User has been registered

Property notes:

addr

IP-Address (probably of client)

Type: string

accessCount

FIXME

Type: int

Example: 1

created

Type: int

Example: 1382005635322

lastaccessed

Type: int

Example: 1382005635738

sid

Session ID (same as in request URL)

Type: string

Example: 79C9B23DBA2682FEDFD0231A9AA28312

time

Type: string

Example: "1382005637299"

body

The actual profile data

body.accountType

Type: string

Known values:

  • MANUALY_DEFINED

  • CONSUMER

body.achievementStatus

Type: object

body.achievementStatus.lastAchievementGameName

Type: string | null

Title of the game that the player unlocked the last achievement in.

Mapping to the game data really happens via the game name, and not with a package name or UUID.

The game's logo-1 file is used in the profile overview page.

null when no achievement gotten yet.

Example: Bloo Kid

body.achievementStatus.numberOfAchievementsUnlocked

Type: int

Sum of achievements unlocked in all games

Example: 23

body.avatarLargeUrl

Type: string

Image with 400x400

body.avatarSmallUrl

Type: string

Image with 118x118px

body.action

null in all known cases.

Type: string

body.balance

Type: object

body.balance.amountOfMoneyLeft

Type: string

Examples:

  • USD 0.00

  • GBP 25.00

body.balance.transactions

Type: array

body.balance.transactions[].amount

Type: string

When buying a game. null when uploading money.

Example: GBP 2.99

body.balance.transactions[].balance

Type: string

Example: GBP 25.00

body.balance.transactions[].date

Type: string

Must contain the string " - " (space dash space). Before: date, after: description

Examples:

  • 16/10/2013 - TOP UP:PREPAID_CARD

  • 19/10/2014 - TOP UP:PAYPAL - when uploading money via PayPal

  • 12/10/2014 - Slingshot Racing - game bought

body.balance.transactions[].description

Type: string

null in all observed files

body.balance.transactions[].source

Type: string

Known values:

  • PAYPAL

  • PREPAID_CARD

  • WALLET

body.balance.transactions[].type

Type: string

Known values:

  • CREDIT_WALLET

  • GAME PRODUCT

body.currency

Three-letter currency code

Known values:

  • GBP

  • USD

body.dateJoined

Type: string

Example: 23/09/2014

body.dateOfBirth

Type: string

Example: 08/08/1984

body.email

Type: string

body.founderFlag

Type: int

The 25$ Kickstarter perk:

FOUNDER TAG: Name Check + Reserve your username before launch + Get a founder tag next to that username.

body.founderName

Type: string

body.gamertag

Type: string

Profile user name

body.location

Type: string

Two-letter uppercase country code

Known values:

  • GB

  • US

body.message

Type: string

Does not seem to be used in 2071.

body.minAge

Type: int

Example: 17

body.minAgeLabel

Type: string

Example: 17+

body.password

Password hash (probably for age change verification)

Example: 75381f9f2bd23d8b4a0dcb0ad7c364ff

body.securityLevel

Type: int

Known values:

  • 0

  • 1

body.success

Type: string

Does not seem to be used in 2071.

{
    "sid": "sessionid",
    "time": "1680109254000",
    "body": {
        "avatarLargeUrl": "http://example.org/avatar.png",
        "gamertag": "cweiske",
        "avatarSmallUrl": "http://example.org/avatar.png",
        "location": "Somewhere",
        "dateOfBirth": "23/12/1942",
        "dateJoined": "23/12/2013",
        "email": "email@example.org",
        "password": "mypassword",
        "accountType": "FIXME",
        "minAge": 17,
        "founderFlag": 1,
        "founderName": "cweiske-kickstarter",
        "minAgeLabel": "17+",
        "securityLevel": 0,
        "balance": {
            "amountOfMoneyLeft": "not much",
            "transactions": [
                {
                    "date": "23/12/2024 - buy a game",
                    "amount": "23.42"
                }
            ]
        },
        "achievementStatus": {
            "lastAchievementGameName": "Some Game",
            "numberOfAchievementsUnlocked": 23
        }
    }
}

Usage

  • com.playjam.Services.Database.ServiceCore#downloadProfile()

POST http://update.gamestickservices.net/check.php

Check if a new firmware update is available.

Three hosts are checked one after another. When update.gamestickservices.com is not available, it may take up to two minutes until the .net host is tried.

HTTP request

Protocol

http

Host

Three hosts are checked in firmware 2071:

  1. update.gamestickservices.com

  2. update.gamestickservices.net

  3. 54.215.8.117

Path

check.php

Headers
Content-Type

application/x-www-form-urlencoded

POST parameters
v

JSON-encoded hardware information (version 0.0.53):

{
    "hwid": "ac:db:da:09:18:5c",
    "major": 0,
    "minor": 0,
    "revision": 53,
    "platform": 0
}

version 2049:

{"platform":0,"revision":2049,"minor":9,"hwid":"ac:db:da:09:18:5c","major":0}

HTTP response

JSON must be one a single line; parsing will fail otherwise.

Update available
Status code

200 OK

{
    "available": true,
    "major": 0,
    "minor": 0,
    "revision": 53,
    "forced": false,
    "name": "v2.23.42",
    "description": "Update now immediately! We have new features.",
    "timestamp": 1680271986000,
    "url": "http://example.org/firmware.php?version=2071"
}
No update available
Status code

200 OK

{
    "available": false
}

Usage

  • com.playjam.gamestick.WifiTools.ChecksFragment#doUpdateConnect()

  • com.playjam.UpdateService

Update download process

Firmware updates are downloaded by a separate downloading process in com.playjam.UpdateService.

Updates are downloaded in small chunks that are combined to a single file in the end. Firmware updates are standard Android OTA .zip update files that were renamed to .img by PlayJam. (GameStick-Software-v2071.img).

The download URL given in the HTTP reponse is appended with &i= plus the chunk index number.

Two special chunk numbers exist:

-2

Returns the total size of the download (plain text long value)

-1

Returns the number of chunks (plain text, int)

-2 is fetched first, -1 second and then 0, 1 and so forth.

After download and chunk combination, the file is verified by standard Android mechanism android.os.RecoverySystem.verifyPackage().

Information about the new firmware is written to /data/GameStickCache/update.info.

Chunks

Generating chunk files:

  1. The firmware update file must be split into files of 102400 bytes.

  2. Each part must be XORed with 91 (hex 5b, binary 1011011).

  3. The binary SHA1 sum of the XORed part file must pre prepended before the data

Having a single chunk file only should work, too.

GET http://www.playjam.com/bundles/system/meta.json

Fetch link to the URL of the latest Companion App configuration file.

Used by the companion app.

HTTP request

Protocol

http

Host

www.playjam.com

Path

/bundles/system/meta.json

HTTP response

Property notes:

timestamp

Type: long. Optional.

0 to disable Companion App bundle file download.

bundleURL

Path to .zip file with configuration data.

Example:

{
    "timestamp": 0,
    "bundleURL": null
}

Usage

  • com.playjam.companionapp.service.CAServerService#fetchSystemBundle()

Achievements

GET http://l2.gamestickservices.net/api/rest/game/xxx/achievements/view.json

Fetch achievements for a single game.

Accessed from the GameStick profile view when selecting a game.

HTTP request

Protocol

http

Host

l2.gamestickservices.net

Path

/api/rest/game/xxx/achievements/view.json;jsessionid=zzz

xxx

UUID of the game

zzz

Session ID

HTTP response

Must be on a single line.

Used achievement properties seem to be id, achievementName, description, fileUrl and isCurrentUserOwner.

Images have an aspect ratio of 7:4, around 177x101px.

Grayscale .png images are not supported; they must be full-colored ones.

Status code

200 OK

Example

{
  "body": {
    "success": true,
    "gameId": "0cfc156cdca036835aa5414bafb610b8",
    "gameList": [
      {
        "id": 460,
        "achievementType": null,
        "achievementName": "Happy end",
        "description": "Beat the game",
        "xpValue": 1,
        "fileName": null,
        "fileUrl": "http://gamestick.cweiske.de/archive/gamestick_de.eiswuxe.blookid/achievements/resized/achievement_5.png",
        "isCurrentUserOwner": 1
      },
      {
        "id": 461,
        "achievementType": null,
        "achievementName": "Triple hit",
        "description": "Jump on three enemies without touching ground",
        "xpValue": 1,
        "fileName": null,
        "fileUrl": "http://gamestick.cweiske.de/archive/gamestick_de.eiswuxe.blookid/achievements/resized/achievement_6.png",
        "isCurrentUserOwner": 0
      }
    ]
  }
}

GET http://l2.gamestickservices.net/api/rest/user/achievement/summary/view.json

Get an achievement summary with statistics of games and their achievement numbers.

HTTP request

Protocol

http

Host

l2.gamestickservices.net

Path

/api/rest/user/achievement/summary/view.json;jsessionid=zzz

zzz

Session ID

Example:

GET http://l2.gamestickservices.net/api/rest/user/achievement/summary/view.json;jsessionid=sacdbda09185c

HTTP response

Status code

200 OK

Example:

{
    "body": {
        "success": true,
        "gameAchievementSummary": [
            {
                "gameId": 23,
                "gameName": "Bloo Kid",
                "lastAchievementImageUrl": "http://gamestick.cweiske.de/archive/gamestick_de.eiswuxe.blookid/logo-2.png",
                "lastAchievementName": "Reach the sky",
                "gameIdentifcation": "0cfc156cdca036835aa5414bafb610b8",
                "totalNumberofAchievements": 42,
                "numberOfPlayerUnlockedAchievements": 23
            }
        ]
    }
}

Property notes:

body.gameAchievementSummary.gameId

Probably body.config.apps[].id from POST http://l2.gamestickservices.net/api/rest/connect/stick/stick/xxx/view.json.

Type: int

body.gameAchievementSummary.gameName

Title of the game

Type: string

body.gameAchievementSummary.gameIdentifcation

Proably UUID of the game release.

Yes, there is a typo in that property name.

Type: string

Example: 0cfc156cdca036835aa5414bafb610b8

body.gameAchievementSummary.lastAchievementImageUrl

FIXME: Seems not to be used.

Best size: FIXME

Type: string

body.gameAchievementSummary.totalNumberofAchievements

Number of possible achievements in the game

Yes, the "o" in "of" is inconsistently lowercase.

Type: int

body.gameAchievementSummary.numberOfPlayerUnlockedAchievements

How many the player unlocked

Type: int

GET http://l2.gamestickservices.net/api/rest/user/achievement/xxx/set-complete/view.json

When some achievement has been reached/completed in a game.

Achievements had to be registered at PlayJam.

HTTP request

Protocol

http

Host

l2.gamestickservices.net

Path

/api/rest/user/achievement/xxx/set-complete/view.json;jsessionid=zzz

xxx

Global achievement ID.

Example: 461

zzz

Session ID

Example:

GET http://l2.gamestickservices.net/api/rest/user/achievement/461/set-complete/view.json;jsessionid=sacdbda09185c

HTTP response

Successful registration
Status code

200 OK

FIXME: Verify if this is correct

{
    "body": {
        "success": true
    }
}

GET http://l2.gamestickservices.net/api/rest/user/game/xxx/achievement/list/view.json

Fetch all achievements for a single game including the info if the user has unlocked them.

Used by games to check which achievements have already been unlocked by the user.

Known usage:

  • When "Bloo Kid" starts

HTTP request

Protocol

http

Host

l2.gamestickservices.net

Path

/api/rest/user/game/xxx/achievement/list/view.json;jsessionid=zzz

xxx

UUID of the game

zzz

Session ID

HTTP response

The response must be on one single line!

At least "Bloo Kid" only cares about the ID. The other properties must exist (JSON parsing fails otherwise), but their values are not used.

The id values are known by the server and had to be registered in the PlayJam Publishing Portal.

isCurrentUserOwner must be an integer, not a boolean.

Status code

200 OK

Example

{
    "body": {
        "success": true,
        "achievements": [
            {
                "id":461,
                "achievementType": "FIXME",
                "achievementName": "FIXME",
                "description": "FIXME",
                "xpValue": 1,
                "fileName": "FIXME",
                "fileUrl": "FIXME",
                "isCurrentUserOwner": 1
            }
        ]
    }
}

"Boulder Dash" does not want the success property but requires body to be an array listing the achievements - which contradicts the requirements by Bloo Kid and the GameStick console API:

{
    "body": [
        {
            "id":461,
            "achievementType": "FIXME",
            "achievementName": "FIXME",
            "description": "FIXME",
            "xpValue": 1,
            "fileName": "FIXME",
            "fileUrl": "FIXME",
            "isCurrentUserOwner": 1
        }
    ]
}

Known achievement IDs:

461

Bloo Kid: Triple Hit

All known IDs are listed in the game data files.

Analytics

GET http://l2.gamestickservices.net/api/rest/analytics/application-event/analytics/event/view.json

Send user behavior data to the server (tracking).

Known to be used in firmware versions:

  • 2058

HTTP request

Protocol

http

Host

l2.gamestickservices.net

Path

/api/rest/analytics/application-event/analytics/event/view.json;jsessionid=zzz?Map=yyy

zzz

Session ID from the registration check api/rest/connect/stick/stick/xxx/view.json.

yyy

Actual tracking data:

{"NAVIGATE":"Games Featured Menu","NAVIGATE":"Media All Menu","NAVIGATE":"Profile"}

Looks like JSON, but has duplicate keys.

Known keys:

  • NAVIGATE

HTTP response

Headers
Content-Type

application/json

All data in the response must be on one line.

{"body":{"success":true}}

If the response is not successful, or the response cannot be parsed into a JSON object from one line of response data, the tracking data are sent again some minutes later.

Usage

Analytics intents are sent by the console application.

Response gets parsed in com.playjam.gamestick.databaseinterfaceservice.DatabaseInterfaceService#ParseResponse()

GET http://l2.gamestickservices.net/api/rest/game/downloadedfreegame/xxx/true/view.json

When a game has been downloaded free of charge.

HTTP request

Method

GET

Protocol

http

Host

l2.gamestickservices.net

Path

/api/rest/game/downloadedfreegame/xxx/true/view.json;jsessionid=zzz

xxx

Game ID, e.g. d8a7bea559a34ba2a71b97f99de54884

zzz

Session ID

Headers
User-Agent

Dalvik/1.6.0 (Linux; U; Android 4.1.2; GameStick V1.0 Build/V1.03.04MX01_20130911)

Connection

Keep-Alive

Accept-Encoding

gzip

HTTP response

FIXME

GET http://l2.gamestickservices.net/api/rest/game/xxx/event/end-game/view.json

Notify the server that a game has been stopped/ended.

HTTP request

Protocol

http

Host

l2.gamestickservices.net

Path

/api/rest/game/xxx/event/end-game/view.json;jsessionid=zzz

xxx

UUID of the game

zzz

Session ID

HTTP response

Must be on a single line.

Status code

200 OK

Example

{"body":{"success":true,"message":"event saved","action":"end-game"}}

GET http://l2.gamestickservices.net/api/rest/game/xxx/event/start-game/view.json

Notify the server that a game has been started.

HTTP request

Protocol

http

Host

l2.gamestickservices.net

Path

/api/rest/game/xxx/event/start-game/view.json;jsessionid=zzz

xxx

UUID of the game

zzz

Session ID

HTTP response

Must be on a single line.

Status code

200 OK

Example

{"body":{"success":true,"message":"event saved","action":"start-game"}}

Leaderboards

GET http://l2.gamestickservices.net/api/rest/game/xxx/leadrboard/top50/view.json

Fetch the first 50 entries in the game's high score list.

HTTP request

Protocol

http

Host

l2.gamestickservices.net

Path
/api/rest/game/xxx/leadrboard/top50/view.json;jsessionid=zzz

The missing e is intentional.

xxx

UUID of the game

yyy

Score/points (integer)

zzz

Session ID

HTTP response

Must be on a single line.

FIXME: Unclear what values are expected in avatarId.

Status code

200 OK

Example

{
  "body": {
    "success": true,
    "leaderBoard": [
      {
        "position": 1,
        "score": 42,
        "userPlayTag": "cweiske-dev",
        "avatarId": 11
      },
      {
        "position": 2,
        "score": 23,
        "userPlayTag": "anotheruser",
        "avatarId": 11
      }
    ]
  }
}

Real response rescued from a GameStick:

{
  "sid": "2F1034E2CBC647E510D2554D4B253583",
  "body": {
    "success": true,
    "message": null,
    "action": "getTop50",
    "leaderBoard": [
      {
        "userPlayTag": "Chris",
        "avatarId": 49,
        "score": 39825,
        "position": 1,
        "extendDetail": null
      },
      {
        "userPlayTag": "LiveTest3",
        "avatarId": 36,
        "score": 21275,
        "position": 2,
        "extendDetail": null
      },
      {
        "userPlayTag": "MP1Tim",
        "avatarId": 35,
        "score": 18275,
        "position": 3,
        "extendDetail": null
      },
      {
        "userPlayTag": "mumoh",
        "avatarId": 59,
        "score": 9075,
        "position": 4,
        "extendDetail": null
      },
      {
        "userPlayTag": "DeathStalker13",
        "avatarId": 35,
        "score": 8100,
        "position": 5,
        "extendDetail": null
      },
      {
        "userPlayTag": "fagger1uk",
        "avatarId": 41,
        "score": 7900,
        "position": 6,
        "extendDetail": null
      },
      {
        "userPlayTag": "JoeMCooper",
        "avatarId": 46,
        "score": 5975,
        "position": 7,
        "extendDetail": null
      },
      {
        "userPlayTag": "dchand0571",
        "avatarId": 41,
        "score": 5450,
        "position": 8,
        "extendDetail": null
      },
      {
        "userPlayTag": "liveVega",
        "avatarId": 55,
        "score": 5125,
        "position": 9,
        "extendDetail": null
      },
      {
        "userPlayTag": "liveOli",
        "avatarId": 55,
        "score": 4975,
        "position": 10,
        "extendDetail": null
      },
      {
        "userPlayTag": "pacman130",
        "avatarId": 37,
        "score": 4725,
        "position": 11,
        "extendDetail": null
      },
      {
        "userPlayTag": "hometest10",
        "avatarId": 42,
        "score": 4525,
        "position": 12,
        "extendDetail": null
      },
      {
        "userPlayTag": "Danyel",
        "avatarId": 48,
        "score": 2675,
        "position": 13,
        "extendDetail": null
      },
      {
        "userPlayTag": "hometest6",
        "avatarId": 39,
        "score": 2225,
        "position": 14,
        "extendDetail": null
      },
      {
        "userPlayTag": "hometest1",
        "avatarId": 35,
        "score": 2075,
        "position": 15,
        "extendDetail": null
      }
    ]
  },
  "time": "1402341994155",
  "lastaccessed": 1402341982363,
  "x-forwarded-for": null,
  "created": 1402340389289,
  "accessCount": 32,
  "addr": "10.37.137.31",
  "remoteaddr": "109.151.188.110"
}

GET http://l2.gamestickservices.net/api/rest/game/xxx/save-score/yyy/extend/view.json

Store points in the game-specific leaderboard

HTTP request

Protocol

http

Host

l2.gamestickservices.net

Path

/api/rest/game/xxx/save-score/yyy/extend/view.json;jsessionid=zzz

xxx

UUID of the game

yyy

Score/points (integer)

zzz

Session ID

HTTP response

Must be on a single line.

Status code

200 OK

Example

{
    "body": {
        "success": true
    }
}

Real response rescued from a GameStick:

{
  "sid": "29D6CBE636DB8E10653FFD2EA27B7582",
  "body": {
    "success": true,
    "message": null,
    "action": "save-score"
  },
  "time": "1417290599050",
  "lastaccessed": 1417290563332,
  "x-forwarded-for": null,
  "created": 1417271831966,
  "accessCount": 366,
  "addr": "10.37.137.31",
  "remoteaddr": "50.10.244.222"
}

Payments

GET http://l2.gamestickservices.net/api/rest/wallet/payment/game/xxx/init-transaction/do/view.json

When clicking "buy" in the game details screen.

Known to be used in firmware versions:

  • 2058

HTTP request

Protocol

http

Host

l2.gamestickservices.net

Path

/api/rest/wallet/payment/game/xxx/init-transaction/do/view.json;jsessionid=zzz

xxx

Game ID.

Empty in firmware 2051.

zzz

Session ID from the registration check api/rest/connect/stick/stick/xxx/view.json.

HTTP response

Everything must be on one single line!

FIXME

Dummy example:

{
    "body": {
        "pageUrl": "xxx",
        "url": "yyy"
    }
}

Only one of pageUrl and url is needed, depends on request (if internal request name is webview_displaywebpage or webview_displayactivewebpage -> url, otherwise pageUrl).

This here should use pageUrl.

Usage

  • com.playjam.gamestick.DatabaseInterfaceService.apk: com.playjam.gamestick.databaseinterfaceservice.DatabaseInterfaceService#ParsePurchaseItemResponse()

GET http://l2.gamestickservices.net/api/rest/wallet/payment/topupwallet/init-transaction/do/view.json

Start adding credits to the wallet in the player profile ("Add credit").

The GameStick shows the webpage URL pageUrl in a window.

FIXME: Somehow the webpage must signal that adding credits worked.

HTTP request

Protocol

http

Host

l2.gamestickservices.net

Path

/api/rest/wallet/payment/topupwallet/init-transaction/do/view.json;jsessionid=zzz

zzz

Session ID

HTTP response

Status code

200 OK

{
    "body":{
        "success": true,
        "pageUrl": "http://example.org"
    }
}

Savegames

GET http://l2.gamestickservices.net/api/rest/game/xxx/save-state/view.json

Store the current game progress on the server (savegame).

HTTP request

Protocol

http

Host

l2.gamestickservices.net

Path

/api/rest/game/xxx/save-state/view.json;jsessionid=zzz

xxx

UUID of the game

zzz

Session ID

Query parameters

?data=Rm9vIDIzIDQyCg%3D%3D

mydata

base64-encoded binary save state data (URL-encoded of course)

HTTP response

Status code

200 OK

Example

{"body":{"success":true}}

GET http://l2.gamestickservices.net/api/rest/game/xxx/state/view.json

Load the current game progress from the server (savegame).

HTTP request

Protocol

http

Host

l2.gamestickservices.net

Path

/api/rest/game/xxx/state/view.json;jsessionid=zzz

xxx

UUID of the game

zzz

Session ID

HTTP response

Status code

200 OK

Example

{
    "body": {
        "success": true,
        "gameState": "Rm9vIDIzIDQyCg=="
    }
}

About

This documentation has been written by Christian Weiske, cweiske+ouya@cweiske.de.

Last update: 2024-12-06T18:33:39+01:00

License

It is licensed under the GNU Free Documentation License.

Source code

The documentation sources are available at https://git.cweiske.de/playjam-gamestick-api-docs.git and mirrored at https://codeberg.org/cweiske/playjam-gamestick-api-docs

Home page

A rendered version of this documentation is available at http://cweiske.de/gamestick-api-docs.htm

Building

You need to install rst2html5 before:

$ pip install rst2html5-tools

Rendering the docs is done via a build script:

$ ./build.sh