Neptune’s Pride has an API that can be used to access scanning data. The API is pretty simple, but entirely undocumented. This post is an attempt to document it. I will edit the main post with details as they emerge, so if I have anything wrong, missed anything out or you have any questions let me know and I’ll work it in. However, this post will assume you have a basic understanding of APIs in general and how to work with them, so a degree of technical knowledge is assumed. The FAQ at the bottom also contain some more general information on what the API can and can’t do if you are worried about sharing your API key with someone.
Code examples in this use Python 3 and the requests library, as this is what I use. If you have code examples in different languages I’ll be happy to add them (except Python 2 because if you still use that you are bad and you should feel bad).
Many thanks particularly to AnnanFay in Discord for as a lot of what I used to get started are the various things they have pinned or posted there.
What does the API do?
The API can be used to access all of the scanning data a player has in any given game, as well as some core public information. It generates only a snapshot in time of the current state of the game when the API is called.
Certain information is available in game but NOT available in the API. Particularly, the API does not give access of any kind to messages, events, or the intelligence pages. Likewise, the API is read-only – you cannot issue orders or send any form of instructions to the game, only access the information.
The main way to use the API is to access your information for analysis or calculation in a more structured form.
API Parameters
The parameters you’ll need are the Game ID and the API Key.
The game ID is the long number at the end of your game URL:
To get the API Key, got to the options section of the game you want to connect to, scroll to the bottom, and hit “Generate key”. The key will be a short 6 character mixed upper and lower case code.
Note that you can only have one active API key. If you generate a new key, and old keys will be deactivated. This is particularly important if you are using another program that uses the key like NP2Stats – make sure you use the same key or you’ll be constantly regenerating between the two connections.
How to Call the API
To call the API you need to issue a POST request to the API end point with three parameters:
api_version : “0.1”
game_number: see above
code : see above
This will return a JSON file that contains all of your scanning data
Code Example
root = "https://np.ironhelmet.com/api"
params = {"game_number" : game_id,
"code" : api_key,
"api_version" : "0.1"}
payload = requests.post(root, params).json()
Troubleshooting API Errors
When the API has been called correctly, you will get a payload with all your scanning data (see next section). However, if there is an error in the call it returns a simple JSON:
error : [Error Message]
The error messages you may received include the following options:
Error message | Trigger |
---|---|
api_version not supported |
api_version is anything but 0.1* |
unknown error while retrieving the game |
game_number is not a valid game number** |
game not found |
game_number is a valid game number** but doesn’t correspond to a game |
code not found in game |
code doesn’t match any API key generated for this game |
*The “bad API” message will also come up in many other cases. Examples include using http instead of https or not submitted a form-encoded request. Thre may be others.
**Valid game numbers are integers between -2^63 and 2^63 - 1 inclusive but excluding 0.
Explaining the Payload
The payload will return a single JSON object, which contains a series of embedded JSON objects (in Python: dictionaries). These objects each contain a mixture of parameters and further embedded objects. The top level is a single key “scanning_data” and then within that there are several different object groups.
Basic Structure
Below is the basic structure that shows roughly the different sub-objects ( using {} ) and the types of key (using [ ]) present in the object.
scanning_data : {
[Game Details]
fleets : {[Carrier Details]}
stars : {[Star Details]}
players : {[Player Details],
tech : { {level, research progress*},
war* : {}
countdown_to_war* : {}
}
the * indicates this part will only be present for the player who owns the key.
The tables below describe the data contained within each JSON object. As objects are semi-structred, keys may not always be present. The Presence column indicates when a key may or may not be present.
Key | Description |
---|---|
all | key will always be present |
owner | Present if the entry belongs to the player who owns the API key |
visible | Present if the entry is visible to the player (stars only) |
star | Present if the entry is at a star (fleets only) |
triton | Only appears in Triton (can combine with other key tags) |
proteus | Only appears in Proteus (can combine with other key tags) |
Game Details Keys
Field | Presence | Type | Description |
---|---|---|---|
admin | all | int | If the player who owns the key is admin. -1 = public game |
fleet_price | proteus | int | Incremental price for additional carriers (25 in public games) |
fleet_speed | all | float | Normal speed of carriers (1/24 of a distance unit) |
fleets | all | object | Object containing all fleet data |
game_over | all | int | If the game is completed. 0 = live, 1 = completed |
name | all | str | Name of the Game |
now | all | int | Time stamp for current time |
paused | all | boolean | If the game is paused. False = no, True = yes |
player_uid | all | int | The Player ID for the player who owns the key |
players | all | object | Object containing all player data |
production_counter | all | int | Current tick within this production cycle |
production_rate | all | int | Number of ticks per production cycle |
productions | all | int | Number of productions that have occurred so far |
stars | all | object | Object containing all stars data |
stars_for_victory | all | int | Number of stars required to win the game |
start_time | all | int | Time stamp for when the game started |
started | all | boolean | Whether the game has started. True = yes, False = No |
tick | all | int | Current tick, counted from the start of the game |
tick_fragment | all | float | Percentage of current tick that has been completed |
tick_rate | all | int | Number of minutes per tick |
total_stars | all | int | Total number of stars in the game |
trade_cost | all | int | Cost per level to trade technologies |
trade_scanned | all | int | Flag if trading is restricted to scanned players. 0 = no, 1 = yes |
turn_based | all | int | Flag if the game is turn based. 0 = no, 1 = yes |
turn_based_time_out | all | int | Deadline for turn submission, in a turn based game |
war | all | int | Unknown |
Fleets Keys
Field | Presence | Type | Description |
---|---|---|---|
exp | proteus | int | Fleet experience level |
l | all | int | Looping, 1 = looped, 0 = not looped |
lx | all | str | X coordinate for the fleet’s location at the previous tick |
ly | all | str | y coordinate for the fleet’s location at the previous tick |
n | all | str | Name of the Carrier |
o | all | list | List of orders. See below |
ouid | star | int | Unique ID for the carrier’s current star |
puid | all | int | Player ID of the owner |
sp | proteus | float | Speed the fleet is moving at (in decimal) |
st | all | int | Number of ships (strength) |
uid | all | int | Unique ID for the carrier. Matches the object ID |
w | triton | int | Flag for the fleet is travelling at warp. 0 = no, 1 = yes |
x | all | str | X coordinate for fleet’s current location |
y | all | str | Y coordinate for the fleet’s current location |
Carrier orders are presented as a list of lists. Each order is an ordered a list of 4 parameters with no key. The meaning by position is as follows:
Position | Description |
---|---|
0 | Delay value in ticks for the order |
1 | Unique ID for the star in the order |
2 | Order type ID (see below) |
3 | Number of ships in the order (e.g. Drop 20) |
The order type is expressed as an integer with the following lookup:
Value | Order |
---|---|
0 | Do Nothing |
1 | Collect All |
2 | Drop All |
3 | Collect |
4 | Drop |
5 | Collect All But |
6 | Drop All But |
7 | Garrison Star |
Stars Keys
Field | Presence | Type | Description |
---|---|---|---|
c | triton owned | float | Where ships/tick is not a whole number, the amount currently produced |
e | visible | int | Current level of economy |
exp | proteus owned | int | Unclear |
ga | visible | int | The presence of a warpgate. 0= no gate, 1 = gate |
i | visible | int | Current level of industry |
n | all | str | The current name of the star |
nr | visible | int | Natural resources of the star |
puid | all | int | Player ID of the player who owns the star |
r | triton visible | int | Resource level of the star (including terraforming bonus) |
s | visible | int | Current level of science |
st | visible | int | Number of ships on the star |
uid | all | int | Unique ID for the star (matches to the key in the parent object) |
v | all | str | Flag for if the star is visible. 0 = no, 1 = yes |
x | all | str | X coordinate of the star |
y | all | str | Y coordinate of the star |
Players Keys
Field | Presence | Type | Description |
---|---|---|---|
ai | all | int | If the player is currently AI. 0 = no, 1 = yes |
alias | all | str | The Player’s alias / display name (not true alias) |
avatar | all | int | Unique ID for the player avatar |
cash | owner | int | Current funds available to the player |
color | proteus | int | Current player colour (can change in Proteus) |
conceded | all | int | If the player has exited the game. 0 = no, 1 = conceded, 2 = inactive, 3 = total wipe out |
countdown_to_war | owner | object | An object containing all player IDs and the number of ticks until war starts, if a permanent alliance has ended |
fleet_price | proteus | int | Cost to purchase the next carrier |
huid | all | int | Unique ID for the player’s home star |
karma_to_give | all | int | The amount of renown the player has not yet given in the game |
ledger | proteus | object | Dictionary of player ID (string) to ledger balance (int) |
missed_turns | all | int | Number of turns the player has missed |
race | proteus | object | 2 element list representing technology strength/weakness |
ready | all | int | If the player’s current turn is ready |
regard | all | int | The AI’s opinion of the player. Note that this may be present for non-AI players. |
researching | owner | str | The technology currently being researched |
researching_next | owner | str | The technology being researched next |
stars_abandoned | owner | int | Number of stars abandoned this production round (note: can’t be higher than 1, resets to 0 at prod) |
ses | proteus owner | int | Unknown |
shape | proteus | int | Current player shape (can change in Proteus) |
tech | all | object | Object containing player’s technology information |
total_economy | all | int | Total economy the player has |
total_fleets | all | int | Total number of carriers the player has |
total_industry | all | int | Total industry the player has |
total_science | all | int | Total science the player has |
total_stars | all | int | Total stars the player has |
total_strength | all | int | Total ships the player has |
uid | all | int | Unique ID for the player. Matches the object key |
war | owner | dict | Object containing the war status for every other player |
Tech Keys
The main object contains 7 keys: one for each technology, which holds a further JSON object that contains the information about that technology for the player. Note that not all of the keys match exactly to the technology names we see in the game.
Field | Presence | Type | Description |
---|---|---|---|
banking | all | str | Banking |
manufacturing | all | str | Manufacturing |
propulsion | all | str | Hyperspace Range |
research | all | str | Experimentation |
scanning | all | str | Scanning |
terraforming | triton | str | Terraforming |
weapons | all | str | Weapons |
Each technology has the following fields:
Field | Presence | Type | Description |
---|---|---|---|
brr | owner | int | Research cost per tech level for this technology (nb. calculation and values are different in triton/proteus) |
bv | owner | int | Used in value calculation, see below |
level | all | int | Current technology level |
research | owner | int | Current level of research progress towards this technology |
sv | owner | int | Used in value calculation, see below |
value | all | int | Current effect of the technology, see below |
The Value field for tech levels is calculated from the ‘sv’ (start value) and ‘bv’ (base value, or the value per level). ‘value’ = ‘sv + level*bv’. For many techs, this just computes the level again. For example weapon strength is the level and weapons value is the weapon strength. For scanning and range (aka propulsion) the values are multiples of 1ly = 0.125, and can be used to determine range or scanning directly against the coordinate system of the map. It is unclear why the sv and bv of experimentation are what they are. No player has been able to map them onto anything meaningful in game.
War Keys
This object contains the player ID and a numeric key representing the formal alliance/war status for every other player in the game. In any state other than “0” the players are at war. All states can be distinguished on the other player’s empire page according to the prompt there, which offers you the ability to initiate an alliance (in state “3”, moves you to “2”), cancel that request (moves you from “2” to “3”), accept an alliance (in state 1
, moves you to “0”), or declare war (in state “0”, starts the countdown to war with that player at 24 ticks which will appear in the “countdown_to_war” object. While not verified, it is believed you will be in state 0 until the countdown ends.
Value | Meaning |
---|---|
0 | Formal Alliance |
1 | Alliance Offered (no cost to accept) |
2 | Alliance Requested (paid $150) |
3 | At war |
Countdown to War Keys
This object contains a key for each player ID with a single integer value indicated the number of ticks until war begins between the owning player and the player ID. In a game without Permanent Alliance enabled, it is always 3. Unknown for permanent alliance games.
Understanding the Coordinate System
NP uses a pretty standard X/Y coordinate system to pinpoint locations, including stars, fleets, fleet orders etc. All of them use the same X/Y system. However, translating this system to what we see on the map is not that straightforward as the map shows light years and they aren’t the same.
A value of 1 in the X/Y system is equal to 8 light years (e.g. 0,0 and 1,0 are 8 light years apart). Ships in the game move at 1 LY/tick at warp speed and 0.33 LY/tick at normal speed.
Understanding Time Fields
There are two types of time field in the NP API: ticks and timestamp. Ticks are relatively obvious, and correspond directly to the ticks we see in the game. The timestamp is used in a few different places, particularly to indicate the start and current time in the game settings data. The field gives a value in milliseconds of the time since 1/1/1970.
FAQ
My connection was working but now it isn’t, why not?
If you generated a new key, any previous keys will be deactivated. This is the most likely reason.
Can I use the API to issue orders?
No
Can I read events/messages with the API?
No
What happens if I give someone my API code?
They can access all of your scanning data in any way they see fit. They cannot issue orders, or read events or messages. If you want to revoke their access, generate a new API code and the code you gave them will no longer work.
What information can you get from the API but not from the game?
There are a few pieces of information that the API provides that are not readily available in the game’s normal interace:
-
The API shows you the absolute X/Y coordinates of your stars. In most cases this is completely useless information unless you want to map the stars in an external program, but in a dark galaxy game it can give you a rough indication of which quadrant of the map you are in.
-
You can see the amount of renown points each player has still left to give. Again, not terribly useful information, but it is there.
-
You can see the precise home star of any given player (the game zooms roughly to this location when you click on the player but is not 100% precise)
Everything else is visible by other means in the game.