Pages:
Author

Topic: MtGox API version 2: Unofficial Documentation - page 9. (Read 62428 times)

sr. member
Activity: 267
Merit: 250
Woodwallets.io
I've only posted perl code.. is that what you ran?

paste your java equivalent of the following:


my $nonce = 'nonce=' . sprintf "%d", gettimeofday * 1e6;
my $hash_data = $method . chr(0) . $nonce . $args;

my $req = HTTP::Request->new(POST => 'https://data.mtgox.com/api/2/' . $method );
$req->content_type('application/x-www-form-urlencoded');
$req->content($nonce . $args);
$req->header('Rest-Key' => $key);
$req->header('Rest-Sign' => encode_base64( hmac_sha512( $hash_data, decode_base64($secret) ) ));

my $result = $lwp->request($req);


Hi Mike, thanks for your support. However, if you go back in this conversation you can follow the track of the java discussion .
sr. member
Activity: 406
Merit: 250
I've only posted perl code.. is that what you ran?

paste your java equivalent of the following:


my $nonce = 'nonce=' . sprintf "%d", gettimeofday * 1e6;
my $hash_data = $method . chr(0) . $nonce . $args;

my $req = HTTP::Request->new(POST => 'https://data.mtgox.com/api/2/' . $method );
$req->content_type('application/x-www-form-urlencoded');
$req->content($nonce . $args);
$req->header('Rest-Key' => $key);
$req->header('Rest-Sign' => encode_base64( hmac_sha512( $hash_data, decode_base64($secret) ) ));

my $result = $lwp->request($req);
sr. member
Activity: 267
Merit: 250
Woodwallets.io
works via POST for me - should paste the rest of the code in question.


I receive this error when "POSTing" it : {"result":"error","error":"Invalid request method for this API","token":"invalid_request_method"}
sr. member
Activity: 267
Merit: 250
Woodwallets.io
Spotted new difference between your code

Code:
HttpsURLConnection c = (HttpsURLConnection)query.openConnection();

and my code

Code:
HttpURLConnection connection = (HttpURLConnection)query.openConnection();


still missing_nonce_error.


Plus, I don't understand howcome it works for you without specifying the keystore file .... :\ To make your code work I had to add the keystore to it! (And yes, it works with the same api keys I'm try to use)
sr. member
Activity: 406
Merit: 250
works via POST for me - should paste the rest of the code in question.
sr. member
Activity: 267
Merit: 250
Woodwallets.io
update : the call to the ticker works only via GET
sr. member
Activity: 267
Merit: 250
Woodwallets.io
Thanks! My today's resolution is : don't go to sleep unless it works.

So, lets try to capture exceptions and errors:

Code:
            if (connection.getResponseCode() != 200) {
                 BufferedReader errBr = new BufferedReader(new InputStreamReader((connection.getErrorStream())));
               
System.err.println("Failed : HTTP error code : "
+ connection.getResponseCode() + " \n Response message:"
                                        + connection.getResponseMessage() + " \n Permission :"
                                        + connection.getPermission());
                         String output;
                         System.out.println("Error Stream: : \n"); //TODO Remove
                         while ((output = errBr.readLine()) != null) {
                            System.err.println(output);

                    }                                         
}           
             

And here we go baby :

Code:
Failed : HTTP error code : 403 
Response message:Forbidden
Permission :("java.net.SocketPermission" "data.mtgox.com:80" "connect,resolve")
Error Stream: {"result":"error","error":"Identification required to access private API","token":"login_error_missing_nonce"}



missing nonce?

sr. member
Activity: 246
Merit: 250
not sure if it's an issue with v2 but others have had probs with their nonce not being long enough, something to keep in mind - but remember if you fiddle with it, you can't make it shorter again Smiley

don't know the requirement but mine's working at 16 chars.


Yeah I noticed that recently, but testing today with a separate API key I found 13 also seems to work, so millisecond time should also be ok. I'll put it on my todo list to find the minimum length at some point Smiley
sr. member
Activity: 406
Merit: 250
not sure if it's an issue with v2 but others have had probs with their nonce not being long enough, something to keep in mind - but remember if you fiddle with it, you can't make it shorter again Smiley

don't know the requirement but mine's working at 16 chars.
sr. member
Activity: 246
Merit: 250
ah, really? :\  Huh Writing this client is driving me nuts.


This is the behaviour at the moment :
Doing nothing or specifing the request method with this line :
Code:
connection.setRequestMethod("GET");
allows me to read the ticker and gives me the 403 on my info.

Using post, on the other hand, stars giving me a HTTP 500 on the ticker! (and still 403 on the info)
Code:
connection.setRequestMethod("POST");
/code]



This is everything I was able to get so far... unfortunately not any JSON.



Code:
Failed : HTTP error code : 403 -
Server returned HTTP response code: 403 for URL: https://data.mtgox.com/api/2/money/info
Forbidden("java.net.SocketPermission" "data.mtgox.com:80" "connect,resolve")
Apr 15, 2013 6:39:36 PM io.botcoin.api.MtGox query

Your code is so close to working, which makes it that much more frustrating. It must be some small, easy to miss, error. Anyway, I quickly wrote this using my own basic API as a reference: http://pastebin.com/SmrxuJQj

I was able to get it to work, so if you compare each line hopefully you'll finally find whatever's causing the problem Smiley Also, I found a way to get the JSON even with the IOException: declare the query function as throwing java.io.Exception, then you can check the response code of the connection - if it is >= 400, use getErrorStream instead of getInputStream, hopefully this will help you debug.

Note: I added "000" to the nonce because my api uses miroseconds, and otherwise I would be rejected by the server, feel free to remove them as your nonces are milliseconds.
sr. member
Activity: 246
Merit: 250

Thank you Nitrous.  I will test it out and report back.  But by looking at the original template code from mtgox, I can see why it does not work now.  

This block of code is suppose to check if the "path" is api version 2
Code:
$prefix = '';
if (substr($path, 0, 2) == '2/') {
$prefix = substr($path, 2)."\0";
}

the check is supposed to look for the "2/" at end of the string, but in this case the $path variable is "BTCUSD/money/ticker" and does not contain the "2/".  If I am correct, the original code tried to look for the "2/" in the wrong string, it should be looking for the version in the base url
Code:
https://data.mtgox.com/api/2/
using the code
Code:
substr($path, -2, 2) == '2/'
.  So if that is fixed, then you don't need to hard code the null character into the REST sign.  

UPDATE:

Here is my fix of that block of code

Code:
$prefix = '';
$baseurl = 'https://data.mtgox.com/api/2/';
if (substr($baseurl, -2, 2) == '2/') {
$prefix = $path."\0";

}

Ok, let me know how it goes, your code is very close to working, the error you received was simply not signing the request properly, which the above should fix Smiley
member
Activity: 83
Merit: 10
Hi Nitrous,

I tried to read and follow your guide to try to pull up some data, but I am getting errors in the response when I just try to get the ticker info.  

array(3) { ["result"]=> string(5) "error" ["error"]=> string(20) "Chosen API not found" ["token"]=> string(13) "unknown_error" }

Basically, all I did was taking the example php template and put in my api key and secret (not shown here), and changed the base URL to
Code:
https://data.mtgox.com/api/2/
and changed the path to
Code:
BTCUSD/money/ticker
but the var dump says Chosen API not found.  I tested with many new api key/secret codes, but that appears not to be the source of the problem.  Any insight is appreciated.  Thank you.



Hi bittencoin,

You are correct that the API code and secret are not the problem, the problem is with this part of your code:

Code:
	$prefix = '';
if (substr($path, 0, 2) == '2/') {
$prefix = substr($path, 2)."\0";
}
 
// generate the extra headers
$headers = array(
'Rest-Key: '.$key,
'Rest-Sign: '.base64_encode(hash_hmac('sha512', $prefix.$post_data, base64_decode($secret), true)),
);
 

Your prefix is empty in a normal scenario, instead, you should change this code to the following:
Code:
	$prefix = $path;
if (substr($path, 0, 2) == '2/') {
$prefix = substr($path, 2);
}
 
// generate the extra headers
$headers = array(
'Rest-Key: '.$key,
'Rest-Sign: '.base64_encode(hash_hmac('sha512', $prefix."\0".$post_data, base64_decode($secret), true)),
);

I have made sure your prefix variable contains the path, and I've moved the null character into the rest-sign to make sure it's always included. This code worked for me after doing those fixes Smiley

Thank you Nitrous.  I will test it out and report back.  But by looking at the original template code from mtgox, I can see why it does not work now.  

This block of code is suppose to check if the "path" is api version 2
Code:
$prefix = '';
if (substr($path, 0, 2) == '2/') {
$prefix = substr($path, 2)."\0";
}

the check is supposed to look for the "2/" at end of the string, but in this case the $path variable is "BTCUSD/money/ticker" and does not contain the "2/".  If I am correct, the original code tried to look for the "2/" in the wrong string, it should be looking for the version in the base url
Code:
https://data.mtgox.com/api/2/
using the code
Code:
substr($path, -2, 2) == '2/'
.  So if that is fixed, then you don't need to hard code the null character into the REST sign.  

UPDATE:

Here is my fix of that block of code

Code:
$prefix = '';
$baseurl = 'https://data.mtgox.com/api/2/';
if (substr($baseurl, -2, 2) == '2/') {
$prefix = $path."\0";

}
sr. member
Activity: 406
Merit: 250
if only the world would settle on 1 language.  Smiley
sr. member
Activity: 267
Merit: 250
Woodwallets.io
ah, really? :\  Huh Writing this client is driving me nuts.


This is the behaviour at the moment :
Doing nothing or specifing the request method with this line :
Code:
connection.setRequestMethod("GET");
allows me to read the ticker and gives me the 403 on my info.

Using post, on the other hand, stars giving me a HTTP 500 on the ticker! (and still 403 on the info)
Code:
connection.setRequestMethod("POST");
/code]



This is everything I was able to get so far... unfortunately not any JSON.



Code:
Failed : HTTP error code : 403 -
Server returned HTTP response code: 403 for URL: https://data.mtgox.com/api/2/money/info
Forbidden("java.net.SocketPermission" "data.mtgox.com:80" "connect,resolve")
Apr 15, 2013 6:39:36 PM io.botcoin.api.MtGox query
sr. member
Activity: 246
Merit: 250
All right, I'll try to get that JSON right away. In the meantime another question: is it correct that the HTTP requests are GETs, right?

I should have spotted that! No, it's POST. I'm surprised you managed to get money/ticker working without POST but yes, you need to send the post_data by POST during the connection.
sr. member
Activity: 267
Merit: 250
Woodwallets.io
All right, I'll try to get that JSON right away. In the meantime another question: is it correct that the HTTP requests are GETs, right?
sr. member
Activity: 246
Merit: 250
Thanks, as always!

I've found out about that method by reading through the pdfs @ https://github.com/MtGox/mtgox-doc/tree/master/api , it seems quite useful.

Quote
BTCUSD/money/info isn't technically the method, the actual method is money/info, but it can be accessed with a currency context as well. money/info gives your account details, including all the currency wallets you have, so if you have an EUR wallet, it will show up, as well as your BTC wallet, and any other currencies

Are you sure? I tried removing the BTCUSD from the ticker ending with (money/ticker) and I get a http 500.


Quote
Do you know what the response is that comes with the 403 error? Your function should still generate and return the answer, right?

Actually I'm afraid that I can't get the answer as the instruction to read the http inputstream throws the IOException... I'll try to go back to the buffer example to be able to read the answer from there

With money/ticker, a currency context is required as it returns information specific to a given currency, but money/info does not require a context as it is independent of the currency - it just returns an informative overview of your entire account (all wallets inclusive), so you can call BTCUSD/money/info if you want, but it's really just redirecting to money/info.

Could you catch the exception or is the response data completely blocked from you? The JSON response should contain an error key pointing to the problem, although it can be somewhat cryptic.
sr. member
Activity: 246
Merit: 250
I also recommend making sure you join your arguments to your nonce properly using the following, and updating it wherever necessay:
Code:
my $post_data = $nonce . ($args == '' ? '' : '&' . $args);
my $hash_data = $method . chr(0) . $post_data;

I think it's ok as it is - the ? doesn't seem to be required in post data and I'm supplying the args in full:

print Dumper __request('BTCUSD/money/order/add', "&type=$type&amount_int=$amount");

I've created and cancelled orders with it anyway so seems fine.


Oh sorry, yeah if you pass it with a leading ampersand it's most definitely fine, yeah that works great then  Smiley

403 probably means failed authentication - I don't think the post data should contain the method should it? (as shown above)

mine works with just nonce + any other arguments.


The API can return 403 for quite a few different reasons (wrong API key, bad nonce, etc), but it usually hints in the JSON the specific reason for the error.
post_data_mac is the equivalent of your $hash_data
sr. member
Activity: 267
Merit: 250
Woodwallets.io
Thanks, as always!

I've found out about that method by reading through the pdfs @ https://github.com/MtGox/mtgox-doc/tree/master/api , it seems quite useful.

Quote
BTCUSD/money/info isn't technically the method, the actual method is money/info, but it can be accessed with a currency context as well. money/info gives your account details, including all the currency wallets you have, so if you have an EUR wallet, it will show up, as well as your BTC wallet, and any other currencies

Are you sure? I tried removing the BTCUSD from the ticker ending with (money/ticker) and I get a http 500.


Quote
Do you know what the response is that comes with the 403 error? Your function should still generate and return the answer, right?

Actually I'm afraid that I can't get the answer as the instruction to read the http inputstream throws the IOException... I'll try to go back to the buffer example to be able to read the answer from there
sr. member
Activity: 406
Merit: 250
I also recommend making sure you join your arguments to your nonce properly using the following, and updating it wherever necessay:
Code:
my $post_data = $nonce . ($args == '' ? '' : '&' . $args);
my $hash_data = $method . chr(0) . $post_data;

I think it's ok as it is - the ? doesn't seem to be required in post data and I'm supplying the args in full:

print Dumper __request('BTCUSD/money/order/add', "&type=$type&amount_int=$amount");

I've created and cancelled orders with it anyway so seems fine.
Pages:
Jump to: