This is an attempt to document the network API used by the PlayJam GameStick gaming console.
JSON responses share some properties.
date
dd/MM/yyyy
- e.g. 23/12/2013.time
ping
connection checkThe 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
connectcheck.gamestickservices.com
connectcheck.gamestickservices.net
clients3.google.com
generate_204
204 No Content
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://dev-db.gamestickservices.net/api/rest/developer/validate/xxx/yyy/view.json
Verify that the GameStick may switch to the developer firmware.
http
dev-db.gamestickservices.net
/api/rest/developer/validate//yyy/view.json;jsessionid=zzz
xxx
Hardware ID
Example: ac:db:da:09:18:5c
yyy
zzz
FIXME
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:
http
l2.gamestickservices.net
/api/rest/analytics/application-event/analytics/event/view.json;jsessionid=xxx?Map=yyy
xxx
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
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.
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.
GET
http
l2.gamestickservices.net
/api/rest/game/downloadedfreegame/xxx/true/view.json;jsessionid=yyy
xxx
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
FIXME
POST http://l2.gamestickservices.net/api/rest/connect/stick/stick/xxx/view.json
Used for several things:
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.
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.
http
l2.gamestickservices.net
Firmware 0.0.53 uses db.gamestickservices.net
.
/api/rest/connect/stick/stick/xxx/view.json
xxx
ac:db:da:09:18:5c
;jsessionid=yyy
JSESSIONID
Session ID, only when available (not empty)
In POST mode only
AWSELB
When available
In POST mode only.
When used for connection check, the response must contain one of the following strings (no whitespace after :
):
"status":"CONNECTION_IN_PROGRESS" "status":"CONNECTED"
CONNECTION_IN_PROGRESS
200 OK
{ "sid": "dummy", "time": "1680109254000", "body": { "status":"CONNECTION_IN_PROGRESS", "registrationCode": "abcdefg" } }
CONNECTED
200 OK
body.config.apps[].genre
body.config.apps[].genres
Known genres:
body.config.apps[].images.name
Special name STICK_SCREENSHOT
adds the image URLs as screenshot, otherwise as thumbnail. (firmware 2071).
Known names:
STICK_THUMBNAIL1
(width 350, height 88)STICK_THUMBNAIL2
(width 350, height 160)STICK_THUMBNAIL3
(width 350, height 236)STICK_THUMBNAIL4
(width 350, height 400)STICK_VIDEO1_SCREENSHOT
(width 350, height 160)STICK_REGISTRATION_GAME_ICON
(200x200px)STICK_SCREENSHOT
(width 350, height 160)body.config.global.uitranslation
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 } ] } ] } ] } } } } }
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
l2.gamestickservices.net
/api/rest/parentcontroll/change/agerating/xxx/yyy/view.json;jsessionid=zzz
xxx
Age rating:
yyy
zzz
200 OK
{ "body": { "success": true, "message": null, "action": "ChangeAgeRating" } }
action
and message
do not seem to be needed.
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
l2.gamestickservices.net
Firmware 0.0.53 used db.gamestickservices.net
/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.
200 OK
FIXME
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
body.achievementStatus.numberOfAchievementsUnlocked
body.avatarLargeUrl
body.avatarSmallUrl
body.action
FIXME
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
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
Example: 16/10/2013 - TOP UP:PREPAID_CARD
body.balance.transactions[].description
body.balance.transactions[].source
Type: string
Known values:
PREPAID_CARD
body.balance.transactions[].type
Type: string
Known values:
CREDIT_WALLET
body.currency
Three-letter currency code
Known values: - GBP
- USD
body.dateJoined
body.dateOfBirth
body.email
body.founderFlag
body.founderName
body.gamertag
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 } } }
com.playjam.Services.Database.ServiceCore#downloadProfile()
GET http://l2.gamestickservices.net/api/rest/user/game/xxx/achievement/list/view.json
Fetch achievements.
Known usage:
http
l2.gamestickservices.net
/api/rest/user/game/xxx/achievement/list/view.json;jsessionid=yyy
xxx
yyy
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
seem to be registered on the server.
200 OK
{ "body": { "success": true, "message": null, "action": "ChangeAgeRating" } }
Known achievement IDs:
461
GET http://l2.gamestickservices.net/api/rest/wallet/payment/game//init-transaction/do/view.json
When clicking "buy" in the game details screen.
Known to be used in firmware versions:
http
l2.gamestickservices.net
/api/rest/wallet/payment/game/xxx/init-transaction/do/view.json;jsessionid=yyy
xxx
Game ID.
Empty in firmware 2051.
yyy
api/rest/connect/stick/stick/xxx/view.json
.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.
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
l2.gamestickservices.net
/api/rest/wallet/payment/topupwallet/init-transaction/do/view.json;jsessionid=xxx
zzz
200 OK
{ "body":{ "success": true, "pageUrl": "http://example.org" } }
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
Three hosts are checked in firmware 2071:
update.gamestickservices.com
update.gamestickservices.net
54.215.8.117
check.php
Content-Type
application/x-www-form-urlencoded
v
JSON-encoded hardware information:
{ "hwid": "ac:db:da:09:18:5c", "major": 0, "minor": 0, "revision": 53, "platform": 0 }
JSON must be one a single line; parsing will fail otherwise.
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" }
200 OK
{ "available": false }
com.playjam.gamestick.WifiTools.ChecksFragment#doUpdateConnect()
com.playjam.UpdateService
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
long
value)-1
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
.
Generating chunk files:
5b
, binary 1011011
).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
www.playjam.com
/bundles/system/meta.json
Property notes:
timestamp
Type: long. Optional.
0
to disable Companion App bundle file download.
bundleURL
.zip
file with configuration data.Example:
{ "timestamp": 0, "bundleURL": null }
com.playjam.companionapp.service.CAServerService#fetchSystemBundle()
This documentation has been written by Christian Weiske, cweiske+ouya@cweiske.de.
Last update: 2023-06-18T08:47:09+02:00
It is licensed under the GNU Free Documentation License.
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
A rendered version of this documentation is available at http://cweiske.de/gamestick-api-docs.htm
You need to install rst2html5
before:
$ pip install rst2html5-tools
Rendering the docs is done via a build script:
$ ./build.sh