MtGox/API/HTTP: Difference between revisions
(18 intermediate revisions by 9 users not shown) | |||
Line 3: | Line 3: | ||
* [[MtGox/API/HTTP/v0|Version 0]] | * [[MtGox/API/HTTP/v0|Version 0]] | ||
* [[MtGox/API/HTTP/v1|Version 1]] | * [[MtGox/API/HTTP/v1|Version 1]] | ||
* [[MtGox/API/HTTP/v2|Version 2]] | |||
== Summary == | == Summary == | ||
All HTTP API requests are sent to URLs beginning with <nowiki>https://mtgox.com/api/*</nowiki>. It allows placing orders, performing withdrawls, deposits, and other things. All responses are in [http://json.org/ JSON] format. | '''The URL mtgox.com was changed to data.mtgox.com on March 19th 2013. https://bitcointalk.org/index.php?topic=150786.0''' | ||
All HTTP API requests are sent to URLs beginning with <nowiki>https://data.mtgox.com/api/*</nowiki>. It allows placing orders, performing withdrawls, deposits, and other things. All responses are in [http://json.org/ JSON] format. | |||
There is a [https://rubygems.org/gems/mtgox Ruby gem], [https://rubygems.org/gems/guten-mtgox guten-mtgox] and a [[Finance::MtGox|Perl module]] available for interacting with the HTTP API. | There is a [https://rubygems.org/gems/mtgox Ruby gem], [https://rubygems.org/gems/guten-mtgox guten-mtgox] and a [[Finance::MtGox|Perl module]] available for interacting with the HTTP API. | ||
Line 18: | Line 21: | ||
USD, AUD, CAD, CHF, CNY, DKK, EUR, GBP, HKD, JPY, NZD, PLN, RUB, SEK, SGD, THB | USD, AUD, CAD, CHF, CNY, DKK, EUR, GBP, HKD, JPY, NZD, PLN, RUB, SEK, SGD, THB | ||
== tonce and nonce == | |||
Each request to the private http API ( v0, v1 , or v2 ) needs to have a nonce or a tonce | |||
Please have a look at http://en.wikipedia.org/wiki/Cryptographic_nonce for explanations of what is a nonce . | |||
See also http://en.wikipedia.org/wiki/System_time and http://en.wikipedia.org/wiki/Unix_time | |||
The tonce is a variant of the nonce. | |||
A few facts about nonce and tonce : | |||
* The value of the nonce must always increase, if you use a very high value during your tests, you could have to generate new api keys to be allowed to get back to lower values | |||
* The value of the tonce is based on the current timestamp in microseconds ( example : 1368892862123456 ) . It needs to be current microtime with +/- 10secs, and needs to be unique | |||
* Your computer's time needs to be exact if you want to use the tonce parameter | |||
* For the tonce you will use the time in microseconds , besed on http://en.wikipedia.org/wiki/Unix_time | |||
* As long as your tonce value is unique and is within +/-10secs of now, it doesn't need to be incremental | |||
* depending of which you want to use, you will add the "tonce=" or "nonce=" parameter to your api request | |||
== Authentication == | == Authentication == | ||
Line 28: | Line 55: | ||
* json data | * json data | ||
api key looks like that: 12345678-abcd-1234-abcd-50286e649d5c | |||
it's actually hexadecimal, it should be converted to binary | |||
hash should then be appended (binary too) and then encode everything in base64 | |||
'''Warning : the API is no more accepting authentication by login/pass ( since 2012 march 1 ) , you _need_ to use an API key.''' | '''Warning : the API is no more accepting authentication by login/pass ( since 2012 march 1 ) , you _need_ to use an API key.''' | ||
=== perl === | |||
'''IMPORTANT! This is a simplified perl module simply returning user info not a full API, it is shown simply for illustrative purposes for those wishing to developing there own modules from scratch.. or bots.. or other''' | |||
'''IMPORTANT! This requires you compiled perl libwww with https support''' | |||
<source lang="perl"> | |||
#!/usr/bin/perl | |||
use strict; | |||
use warnings; | |||
use Time::HiRes qw(gettimeofday); | |||
use MIME::Base64; | |||
use Digest::SHA qw(hmac_sha512); | |||
use JSON; | |||
use LWP::UserAgent; | |||
use Data::Dumper; | |||
my $lwp = LWP::UserAgent->new; | |||
$lwp->agent("perl $]"); | |||
my $json = JSON->new->allow_nonref; | |||
my $secret = '_MTGOX API SECRET GET YOURS AT https://classic.mtgox.com/support/tradeAPI'; | |||
my $key = '_MTGOX API KEY GET YOURS AT https://classic.mtgox.com/support/tradeAPI'; | |||
## user code | |||
my $request = genReq('/1/generic/private/info'); | |||
my $res = $lwp->request($request); | |||
# Check the outcome of the response | |||
if ($res->is_success) { | |||
print Dumper($json->decode( $res->content ))."\n"; | |||
} | |||
else { print $res->status_line, "\n"; } | |||
exit 0; | |||
## sub routines and helpers | |||
sub genReq { | |||
my ($uri) = shift; | |||
my $req = HTTP::Request->new(POST => 'https://mtgox.com/api/'.$uri); | |||
$req->content_type('application/x-www-form-urlencoded'); | |||
$req->content("nonce=".microtime()); | |||
$req->header('Rest-Key' => $key); | |||
$req->header('Rest-Sign' => signReq($req->content(),$secret)); | |||
return $req; | |||
}; | |||
sub signReq { | |||
my ($content,$secret) = @_; | |||
return encode_base64(hmac_sha512($content,decode_base64($secret))); | |||
} | |||
sub microtime { return sprintf "%d%06d", gettimeofday; } | |||
</source> | |||
=== PHP === | === PHP === | ||
<source lang="php"> | <source lang="php"> | ||
Line 48: | Line 145: | ||
// generate the POST data string | // generate the POST data string | ||
$post_data = http_build_query($req, '', '&'); | $post_data = http_build_query($req, '', '&'); | ||
$prefix = ''; | |||
if (substr($path, 0, 2) == '2/') { | |||
$prefix = substr($path, 2)."\0"; | |||
} | |||
// generate the extra headers | // generate the extra headers | ||
$headers = array( | $headers = array( | ||
'Rest-Key: '.$key, | 'Rest-Key: '.$key, | ||
'Rest-Sign: '.base64_encode(hash_hmac('sha512', $post_data, base64_decode($secret), true)), | 'Rest-Sign: '.base64_encode(hash_hmac('sha512', $prefix.$post_data, base64_decode($secret), true)), | ||
); | ); | ||
Line 86: | Line 188: | ||
=== Python === | === Python === | ||
<source lang="python"> | |||
from urllib import urlencode | |||
import urllib2 | |||
import time | |||
from hashlib import sha512 | |||
from hmac import HMAC | |||
import base64 | |||
import json | |||
def get_nonce(): | |||
return int(time.time()*100000) | |||
def sign_data(secret, data): | |||
return base64.b64encode(str(HMAC(secret, data, sha512).digest())) | |||
class requester: | |||
def __init__(self, auth_key, auth_secret): | |||
self.auth_key = auth_key | |||
self.auth_secret = base64.b64decode(auth_secret) | |||
def build_query(self, req={}): | |||
req["nonce"] = get_nonce() | |||
post_data = urlencode(req) | |||
headers = {} | |||
headers["User-Agent"] = "GoxApi" | |||
headers["Rest-Key"] = self.auth_key | |||
headers["Rest-Sign"] = sign_data(self.auth_secret, post_data) | |||
return (post_data, headers) | |||
def perform(self, path, args): | |||
data, headers = self.build_query(args) | |||
req = urllib2.Request("https://mtgox.com/api/0/"+path, data, headers) | |||
res = urllib2.urlopen(req, data) | |||
return json.load(res) | |||
</source> | |||
=== Node.js === | === Node.js === | ||
Generic [[Node.js Example]] trading library (supports MtGox and Bitfloor): https://github.com/bitfloor/trader.nodejs | Generic [[Node.js Example]] trading library (supports MtGox and Bitfloor): https://github.com/bitfloor/trader.nodejs | ||
=== Java === | === Java === | ||
basic [[Java Example]] on https://gist.github.com/2396722 | basic [[Java Example]] on https://gist.github.com/2396722 hoping for many java forks and pull requests on github | ||
hoping for many java forks and pull requests on github | |||
XChange API : https://github.com/timmolter/XChange | |||
mtgox-java: A Java API (based on Spring & Maven) for the MtGox bitcoin exchange WebSocket & HTTP services. | |||
http://grantsparks.github.com/mtgox-java/ | |||
mtgox-api-v2-java: A Java lib for the v2 of the API https://github.com/adv0r/mtgox-api-v2-java | |||
====Java:==== | |||
=== Javascript Firefox addon === | === Javascript Firefox addon === | ||
Line 103: | Line 244: | ||
* [[MtGox|Mt. Gox]] | * [[MtGox|Mt. Gox]] | ||
* [http://bitcointalk.org/index.php?topic=164404.0 MtGox API version 2: Unofficial Documentation] |
Latest revision as of 16:06, 18 May 2013
Two versions of the HTTP API are currently available, see the following pages for details on the methods available for each:
Summary
The URL mtgox.com was changed to data.mtgox.com on March 19th 2013. https://bitcointalk.org/index.php?topic=150786.0
All HTTP API requests are sent to URLs beginning with https://data.mtgox.com/api/*. It allows placing orders, performing withdrawls, deposits, and other things. All responses are in JSON format.
There is a Ruby gem, guten-mtgox and a Perl module available for interacting with the HTTP API.
Cache
All API methods are cached for 10 seconds. Do not request results more often than that, you might be blocked by the anti-DDoS filters.
Currency Symbols
List of the currency symbols available with the API:
USD, AUD, CAD, CHF, CNY, DKK, EUR, GBP, HKD, JPY, NZD, PLN, RUB, SEK, SGD, THB
tonce and nonce
Each request to the private http API ( v0, v1 , or v2 ) needs to have a nonce or a tonce
Please have a look at http://en.wikipedia.org/wiki/Cryptographic_nonce for explanations of what is a nonce .
See also http://en.wikipedia.org/wiki/System_time and http://en.wikipedia.org/wiki/Unix_time
The tonce is a variant of the nonce.
A few facts about nonce and tonce :
- The value of the nonce must always increase, if you use a very high value during your tests, you could have to generate new api keys to be allowed to get back to lower values
- The value of the tonce is based on the current timestamp in microseconds ( example : 1368892862123456 ) . It needs to be current microtime with +/- 10secs, and needs to be unique
- Your computer's time needs to be exact if you want to use the tonce parameter
- For the tonce you will use the time in microseconds , besed on http://en.wikipedia.org/wiki/Unix_time
- As long as your tonce value is unique and is within +/-10secs of now, it doesn't need to be incremental
- depending of which you want to use, you will add the "tonce=" or "nonce=" parameter to your api request
Authentication
Authentication is performed by signing each request using HMAC-SHA512. The request must contain an extra value "nonce" which must be an always incrementing numeric value. A reference implementation is provided here:
basically the base64 string should contain:
- the binary representation of the api key id
- binary hmac-sha512 signature
- json data
api key looks like that: 12345678-abcd-1234-abcd-50286e649d5c
it's actually hexadecimal, it should be converted to binary
hash should then be appended (binary too) and then encode everything in base64
Warning : the API is no more accepting authentication by login/pass ( since 2012 march 1 ) , you _need_ to use an API key.
perl
IMPORTANT! This is a simplified perl module simply returning user info not a full API, it is shown simply for illustrative purposes for those wishing to developing there own modules from scratch.. or bots.. or other
IMPORTANT! This requires you compiled perl libwww with https support
#!/usr/bin/perl
use strict;
use warnings;
use Time::HiRes qw(gettimeofday);
use MIME::Base64;
use Digest::SHA qw(hmac_sha512);
use JSON;
use LWP::UserAgent;
use Data::Dumper;
my $lwp = LWP::UserAgent->new;
$lwp->agent("perl $]");
my $json = JSON->new->allow_nonref;
my $secret = '_MTGOX API SECRET GET YOURS AT https://classic.mtgox.com/support/tradeAPI';
my $key = '_MTGOX API KEY GET YOURS AT https://classic.mtgox.com/support/tradeAPI';
## user code
my $request = genReq('/1/generic/private/info');
my $res = $lwp->request($request);
# Check the outcome of the response
if ($res->is_success) {
print Dumper($json->decode( $res->content ))."\n";
}
else { print $res->status_line, "\n"; }
exit 0;
## sub routines and helpers
sub genReq {
my ($uri) = shift;
my $req = HTTP::Request->new(POST => 'https://mtgox.com/api/'.$uri);
$req->content_type('application/x-www-form-urlencoded');
$req->content("nonce=".microtime());
$req->header('Rest-Key' => $key);
$req->header('Rest-Sign' => signReq($req->content(),$secret));
return $req;
};
sub signReq {
my ($content,$secret) = @_;
return encode_base64(hmac_sha512($content,decode_base64($secret)));
}
sub microtime { return sprintf "%d%06d", gettimeofday; }
PHP
<?php
function mtgox_query($path, array $req = array()) {
// API settings
$key = '';
$secret = '';
// generate a nonce as microtime, with as-string handling to avoid problems with 32bits systems
$mt = explode(' ', microtime());
$req['nonce'] = $mt[1].substr($mt[0], 2, 6);
// generate the POST data string
$post_data = http_build_query($req, '', '&');
$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)),
);
// our curl handle (initialize if required)
static $ch = null;
if (is_null($ch)) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MtGox PHP client; '.php_uname('s').'; PHP/'.phpversion().')');
}
curl_setopt($ch, CURLOPT_URL, 'https://mtgox.com/api/'.$path);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
// run the query
$res = curl_exec($ch);
if ($res === false) throw new Exception('Could not get reply: '.curl_error($ch));
$dec = json_decode($res, true);
if (!$dec) throw new Exception('Invalid data received, please make sure connection is working and requested API exists');
return $dec;
}
// example 1: get infos about the account, plus the list of rights we have access to
var_dump(mtgox_query('0/info.php'));
// old api (get funds)
var_dump(mtgox_query('0/getFunds.php'));
// trade example
// var_dump(mtgox_query('0/buyBTC.php', array('amount' => 1, 'price' => 15)));
Python
from urllib import urlencode
import urllib2
import time
from hashlib import sha512
from hmac import HMAC
import base64
import json
def get_nonce():
return int(time.time()*100000)
def sign_data(secret, data):
return base64.b64encode(str(HMAC(secret, data, sha512).digest()))
class requester:
def __init__(self, auth_key, auth_secret):
self.auth_key = auth_key
self.auth_secret = base64.b64decode(auth_secret)
def build_query(self, req={}):
req["nonce"] = get_nonce()
post_data = urlencode(req)
headers = {}
headers["User-Agent"] = "GoxApi"
headers["Rest-Key"] = self.auth_key
headers["Rest-Sign"] = sign_data(self.auth_secret, post_data)
return (post_data, headers)
def perform(self, path, args):
data, headers = self.build_query(args)
req = urllib2.Request("https://mtgox.com/api/0/"+path, data, headers)
res = urllib2.urlopen(req, data)
return json.load(res)
Node.js
Generic Node.js Example trading library (supports MtGox and Bitfloor): https://github.com/bitfloor/trader.nodejs
Java
basic Java Example on https://gist.github.com/2396722 hoping for many java forks and pull requests on github
XChange API : https://github.com/timmolter/XChange
mtgox-java: A Java API (based on Spring & Maven) for the MtGox bitcoin exchange WebSocket & HTTP services. http://grantsparks.github.com/mtgox-java/
mtgox-api-v2-java: A Java lib for the v2 of the API https://github.com/adv0r/mtgox-api-v2-java
Java:
Javascript Firefox addon
- [1] firefox ticker addon