<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://projectpokemon.org/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Eefi</id>
	<title>ProjectPokemon Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://projectpokemon.org/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Eefi"/>
	<link rel="alternate" type="text/html" href="https://projectpokemon.org/wiki/Special:Contributions/Eefi"/>
	<updated>2026-04-20T19:26:25Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.40.0</generator>
	<entry>
		<id>https://projectpokemon.org/wiki/index.php?title=GTS_protocol&amp;diff=3793</id>
		<title>GTS protocol</title>
		<link rel="alternate" type="text/html" href="https://projectpokemon.org/wiki/index.php?title=GTS_protocol&amp;diff=3793"/>
		<updated>2010-11-13T12:14:40Z</updated>

		<summary type="html">&lt;p&gt;Eefi: /* Protocol */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following is &#039;&#039;&#039;wild conjecture&#039;&#039;&#039; based on LordLandon&#039;s [http://projectpokemon.org/forums/showthread.php?780-GTC-website-research&amp;amp;p=67086&amp;amp;viewfull=1#post67086 sendpkm.py].&lt;br /&gt;
&lt;br /&gt;
Communication with the GTS is done over regular HTTP with http://gamestats2.gs.nintendowifi.net/.  The same protocol is used for all five Gen IV games.&lt;br /&gt;
&lt;br /&gt;
==HTTP headers==&lt;br /&gt;
&lt;br /&gt;
The games don&#039;t seem to care about these at all.  The GTS sends back a bunch of boilerplate response headers, but the game happily accepts a response with only a Content-Length.&lt;br /&gt;
&lt;br /&gt;
==Protocol==&lt;br /&gt;
&lt;br /&gt;
All requests to the server are GET requests of the form &amp;lt;code&amp;gt;&amp;lt;var&amp;gt;page&amp;lt;/var&amp;gt;.asp?pid=&amp;lt;var&amp;gt;pid&amp;lt;/var&amp;gt;&amp;amp;amp;hash=&amp;lt;var&amp;gt;hash&amp;lt;/var&amp;gt;&amp;amp;amp;data=&amp;lt;var&amp;gt;data&amp;lt;/var&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
However devices prior to the DSi also send requests without the hash (followed by a requests with hash) to which you should also return proper values or else the DS will assume communication broke off.&lt;br /&gt;
&lt;br /&gt;
===pid===&lt;br /&gt;
&lt;br /&gt;
The pid is an unsigned 32-bit integer that appears to uniquely identify a game cartridge. Although this has not been confirmed entirely:&lt;br /&gt;
Your PID is generated when you get your friendcode for the first time and is set to: friendcode &amp;amp; 0x7fffffff&lt;br /&gt;
When you change the device and are forced to change your friendcode with it, your PID doesn&#039;t change but you get a new friendcode (at this point there&#039;s no friendcode-&amp;gt;pid mapping anymore).&lt;br /&gt;
&lt;br /&gt;
For the mathematically inclined: Eevee&#039;s Platinum pid is 192615460 (0x0b7b1424) and his Pal Pad code is 0904 2026 4621.&lt;br /&gt;
&lt;br /&gt;
===Challenge/response===&lt;br /&gt;
&lt;br /&gt;
(4th Gen)&lt;br /&gt;
&lt;br /&gt;
Before each &amp;quot;real&amp;quot; request, the game sends a request of the form &amp;lt;code&amp;gt;&amp;lt;var&amp;gt;page&amp;lt;/var&amp;gt;.asp?pid=&amp;lt;var&amp;gt;pid&amp;lt;/var&amp;gt;&amp;lt;/code&amp;gt; and the server responds with a 32-byte challenge token. The game computes &amp;lt;code&amp;gt;sha1(&amp;quot;sAdeqWo3voLeC5r16DYv&amp;quot; + token)&amp;lt;/code&amp;gt; and uses that as the &amp;lt;var&amp;gt;hash&amp;lt;/var&amp;gt; value which it sends to the server. The &amp;lt;var&amp;gt;data&amp;lt;/var&amp;gt; parameter is encrypted, as explained further down.&lt;br /&gt;
&lt;br /&gt;
(5th gen)&lt;br /&gt;
&lt;br /&gt;
The process is mostly the same, except that the response hash is &amp;lt;code&amp;gt;sha1(&amp;quot;HZEdGCzcGGLvguqUEKQN&amp;quot; + token)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
That is, each request looks like the following:&lt;br /&gt;
&lt;br /&gt;
# Game requests &amp;lt;code&amp;gt;GET /pokemondpds/&amp;lt;var&amp;gt;page&amp;lt;/var&amp;gt;.asp?pid=&amp;lt;var&amp;gt;pid&amp;lt;/var&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
# Server responds with &amp;lt;var&amp;gt;token&amp;lt;/var&amp;gt;&lt;br /&gt;
# Game requests &amp;lt;code&amp;gt;GET /pokemondpds/&amp;lt;var&amp;gt;page&amp;lt;/var&amp;gt;.asp?pid=&amp;lt;var&amp;gt;pid&amp;lt;/var&amp;gt;&amp;amp;amp;hash=&amp;lt;var&amp;gt;sha1(...)&amp;lt;/var&amp;gt;&amp;amp;amp;data=&amp;lt;var&amp;gt;data&amp;lt;/var&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
# Server responds with payload&lt;br /&gt;
&lt;br /&gt;
The exact details of the game&#039;s requests are not currently known, but we are working on it!&lt;br /&gt;
&lt;br /&gt;
===Checksum===&lt;br /&gt;
&lt;br /&gt;
A 32-bit checksum of the data is used as the key for the encryption. The checksum is simply the sum of every byte of the data.&lt;br /&gt;
&lt;br /&gt;
The first 4 bytes of the sent data are the checksum, &amp;lt;code&amp;gt;xor&amp;lt;/code&amp;gt;ed with &amp;lt;code&amp;gt;0x4a3b2c1d&amp;lt;/code&amp;gt;, and sent in network byte order (big-endian).&lt;br /&gt;
&lt;br /&gt;
===Encryption===&lt;br /&gt;
&lt;br /&gt;
The data sent to the server is encrypted with a [http://en.wikipedia.org/wiki/Stream_cipher stream cipher], and [http://en.wikipedia.org/wiki/Base64#URL_applications urlsafe-base64]-encoded.&lt;br /&gt;
&lt;br /&gt;
This encryption algorithm, like others used in the game, uses a [http://en.wikipedia.org/wiki/Linear_congruential_generator Linear Congruential Generator] (not a very strong choice). The multiplicative constant is &amp;lt;code&amp;gt;0x45&amp;lt;/code&amp;gt;, and the additive constant is &amp;lt;code&amp;gt;0x1111&amp;lt;/code&amp;gt;. It appears that the game uses a signed dword to store the seed, which doesn&#039;t really matter; it shouldn&#039;t affect anything. (It means that the modulus is effectively &amp;lt;code&amp;gt;0x80000000&amp;lt;/code&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
 GRNG[n+1] = (GRNG[n] * 0x45 + 0x1111) &amp;amp; 0x7fffffff&lt;br /&gt;
&lt;br /&gt;
The GRNG is seeded with the &amp;lt;var&amp;gt;checksum&amp;lt;/var&amp;gt;, like so:&lt;br /&gt;
&lt;br /&gt;
 GRNG[0] = &amp;lt;var&amp;gt;checksum&amp;lt;/var&amp;gt; | (&amp;lt;var&amp;gt;checksum&amp;lt;/var&amp;gt; &amp;lt;&amp;lt; 16)&lt;br /&gt;
&lt;br /&gt;
The keystream is composed of the lower byte of the high word of successive GRNG values.&lt;br /&gt;
&lt;br /&gt;
 keystream[n] = (GRNG[n] &amp;gt;&amp;gt; 16) &amp;amp; 0xff&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Xor&amp;lt;/code&amp;gt; the keystream with the plaintext to get the ciphertext. &amp;lt;code&amp;gt;Xor&amp;lt;/code&amp;gt; the keystream with the ciphertext to get the plaintext.&lt;br /&gt;
&lt;br /&gt;
==Conversation==&lt;br /&gt;
&lt;br /&gt;
The first request the game makes is to &amp;lt;code&amp;gt;/pokemondpds/worldexchange/info.asp&amp;lt;/code&amp;gt;. The server responds with 0x0001.&lt;br /&gt;
&lt;br /&gt;
Platinum, Heart Gold, and Soul Silver will then make a request to &amp;lt;code&amp;gt;/pokemondpds/common/setProfile.asp&amp;lt;/code&amp;gt;.  The server responds with eight NULs (0x00000000 0x00000000).&lt;br /&gt;
&lt;br /&gt;
After the above step(s) or &#039;&#039;&#039;performing any of the tasks below&#039;&#039;&#039; other than searching, the game makes a request to &amp;lt;code&amp;gt;/pokemondpds/worldexchange/result.asp&amp;lt;/code&amp;gt;.  If the game has had a Pokémon sent to it via a trade, the server responds with the entire encrypted [[Pokemon NDS Structure|Pokémon save struct]].  Otherwise, if there is a Pokémon deposited in the GTS, it responds with 0x0004; if not, it responds with 0x0005.&lt;br /&gt;
&lt;br /&gt;
===Receiving a traded Pokémon===&lt;br /&gt;
&lt;br /&gt;
If the game receives a Pokémon from a successful trade as a response from &amp;lt;code&amp;gt;result.asp&amp;lt;/code&amp;gt;, it next requests &amp;lt;code&amp;gt;/pokemondpds/worldexchange/delete.asp&amp;lt;/code&amp;gt;.  The server responds with 0x0001.&lt;br /&gt;
&lt;br /&gt;
====A note on sendpkm.py====&lt;br /&gt;
&lt;br /&gt;
After doing the above, some Platinum, Heart Gold, and Soul Silver games will report a communication error and dump the player back to the title screen.  The Pokémon is still successfully received.  At least one person with HG/SS has received a Pokémon from a fake server without getting the error, and Diamond/Pearl have never been reported to have the problem.&lt;br /&gt;
&lt;br /&gt;
===Depositing a Pokémon===&lt;br /&gt;
&lt;br /&gt;
Pokémon are offered on the GTS by requesting &amp;lt;code&amp;gt;/pokemondpds/worldexchange/post.asp&amp;lt;/code&amp;gt;.  The sent data is 300 bytes long, and includes the Pokémon struct. If the Pokémon is rejected by the server, the response is 0x000c; otherwise, if the deposit is successful, 0x0001.&lt;br /&gt;
&lt;br /&gt;
The game then saves. After the save is complete, it issues a request to &amp;lt;code&amp;gt;/pokemondpds/worldexchange/post_finish.asp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Retrieving the deposited Pokémon===&lt;br /&gt;
&lt;br /&gt;
Checking on the deposited Pokémon is apparently done by &amp;lt;code&amp;gt;/pokemondpds/worldexchange/get.asp&amp;lt;/code&amp;gt;.  The response appears to be a [[Pokemon NDS Structure|Pokémon save struct]].&lt;br /&gt;
&lt;br /&gt;
Retrieving the deposited Pokémon is done by &amp;lt;code&amp;gt;/pokemondpds/worldexchange/return.asp&amp;lt;/code&amp;gt;.  The response is merely 0x0001; the actual Pokémon data is taken from the &amp;lt;code&amp;gt;get.asp&amp;lt;/code&amp;gt; request.&lt;br /&gt;
&lt;br /&gt;
===Searching===&lt;br /&gt;
&lt;br /&gt;
Searching is done through &amp;lt;code&amp;gt;/pokemondpds/worldexchange/search.asp&amp;lt;/code&amp;gt;.  The sent data is either 15 or 16 bytes long.&lt;br /&gt;
&lt;br /&gt;
The server responds with a full 292-byte Pokémon struct for each result.  If there are &amp;lt;var&amp;gt;n&amp;lt;/var&amp;gt; results, the response will be 292 * &amp;lt;var&amp;gt;n&amp;lt;/var&amp;gt; bytes long.  If there are no results, the server will give an empty response (0 bytes).&lt;br /&gt;
&lt;br /&gt;
==Pokémon struct==&lt;br /&gt;
&lt;br /&gt;
The Pokémon data for the GTS is 292 bytes—56 bytes larger than a party Pokémon struct. The extra 56 bytes are GTS-specific data, such as the player&#039;s name &amp;amp; country, and what Pokémon they are requesting.&lt;br /&gt;
&lt;br /&gt;
They are as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0x00-0x01 Current Pokémon&lt;br /&gt;
0x02      Gender          1=male; 2=female; 3=either/neither&lt;br /&gt;
0x03      Level&lt;br /&gt;
0x04-0x05 Requested Pokémon&lt;br /&gt;
0x06      Gender&lt;br /&gt;
0x07      Min level&lt;br /&gt;
0x08      Max level&lt;br /&gt;
0x09      always 0?&lt;br /&gt;
0x0A      Trainer Gender  0=male; 1=female&lt;br /&gt;
0x0B      always 0?&lt;br /&gt;
0x0C-0x13 Timestamp - Deposited time&lt;br /&gt;
0x14-0x1B Timestamp - Time traded away?&lt;br /&gt;
0x1c-0x1F pid - also 0x4c in the sav&lt;br /&gt;
0x20-0x2F Trainer Name&lt;br /&gt;
0x30-0x31 Trainer ID&lt;br /&gt;
0x32      Country&lt;br /&gt;
0x33      City&lt;br /&gt;
0x34      Trainer Sprite&lt;br /&gt;
0x35      Exchanged flag&lt;br /&gt;
0x36      Version         0x0A=Diamond; 0x0B=Pearl; ...&lt;br /&gt;
0x37      Language        1=jp; 2=en; 3=fr; ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The timestamps are set by the server, and are always PST (UTC-8). Timestamp format:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0x00-0x01 Year&lt;br /&gt;
0x02      Month&lt;br /&gt;
0x03      Day&lt;br /&gt;
0x04      Hour&lt;br /&gt;
0x05      Minute&lt;br /&gt;
0x06      Second&lt;br /&gt;
0x07      always 0?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Eefi</name></author>
	</entry>
</feed>