I have set up a read-only API key on Binance to access account information like currency balances but I can't see the JSON data. The string query I put into the URL returns the following error:
{"code":-2014,"msg":"API-key format invalid."}
The URL I am using is this: https://api.binance.com/api/v3/account?X-MBX-APIKEY=**key**&signature=**s-key**
The documentation for Binance API can be found here: https://www.binance.com/restapipub.html. What am I doing wrong ?
Binance's websocket API kinda tricky to use. Also there is no way to use a secret key.
Common usage
Send HTTP POST request with your secret API key as a X-MBX-APIKEY header to https://api.binance.com/api/v1/userDataStream
You will get listen key which should be used for websocket connection. It will be available 1 hour.
{"listenKey": "your listen key here"}
Use it when connecting to Binance's websocket
wss://stream.binance.com:9443/ws/{your listen key here}
Python example
import ssl
from websocket import create_connection
import requests
KEY = 'your-secret-key'
url = 'https://api.binance.com/api/v1/userDataStream'
listen_key = requests.post(url, headers={'X-MBX-APIKEY': KEY})['listenKey']
connection = create_connection('wss://stream.binance.com:9443/ws/{}'.format(KEY),
sslopt={'cert_reqs': ssl.CERT_NONE})
def get_listen_key_by_REST(binance_api_key):
url = 'https://api.binance.com/api/v1/userDataStream'
response = requests.post(url, headers={'X-MBX-APIKEY': binance_api_key}) # ['listenKey']
json = response.json()
return json['listenKey']
print(get_listen_key_by_REST(binance_api_key))
def get_all_orders(symbol, binance_api_key, binance_secret_key):
"""Get all account orders; active, canceled, or filled.
Args: symbol: Symbol name, e.g. `BTCUSDT`.
Returns:
"""
from datetime import datetime, timezone, timedelta
now = datetime.now(timezone.utc)
epoch = datetime(1970, 1, 1, tzinfo=timezone.utc) # use POSIX epoch
posix_timestamp_micros = (now - epoch) // timedelta(microseconds=1)
posix_timestamp_millis = posix_timestamp_micros // 1000 # or `/ 1e3` for float
import hmac, hashlib
queryString = "symbol=" + symbol + "×tamp=" + str(
posix_timestamp_millis)
signature = hmac.new(binance_secret_key.encode(), queryString.encode(), hashlib.sha256).hexdigest()
url = "https://api.binance.com/api/v3/allOrders"
url = url + f"?{queryString}&signature={signature}"
response = requests.get(url, headers={'X-MBX-APIKEY': binance_api_key})
return response.json()
You put it in the header. Following is tested working PHP example borrowed from jaggedsoft binance PHP library, it's a signed request that will return the account status.
$api_key = "cool_key";
$secret = "awesome_secret";
$opt = [
"http" => [
"method" => "GET",
"header" => "User-Agent: Mozilla/4.0 (compatible; PHP Binance API)\r\nX-MBX-APIKEY: {$api_key}\r\n"
]
];
$context = stream_context_create($opt);
$params['timestamp'] = number_format(microtime(true)*1000,0,'.','');
$query = http_build_query($params, '', '&');
$signature = hash_hmac('sha256', $query, $secret);
$endpoint = "https://api.binance.com/wapi/v3/accountStatus.html?{$query}&signature={$signature}";
$res = json_decode(file_get_contents($endpoint, false, $context), true);
X-MBX-APIKEY should be set as a field in the HTTP header, and not as a HTTP parameter. See this page for more information on HTTP header fields.
However, I tried the same with Excel and could not get it running until now.
Another open question is how to use the secret key.
This worked for me:
base_url="https://api.binance.com"
account_info="/api/v3/account"
url="${base_url}${account_info}"
apikey="your_apikey"
secret="your_secret"
queryString="timestamp=$(date +%s)" #$(python3 binance_time.py) must sync
requestBody=""
signature="$(echo -n "${queryString}${requestBody}" | openssl dgst -sha256 -hmac $secret)"
signature="$(echo $signature | cut -f2 -d" ")"
req=$(curl -H "X-MBX-APIKEY: $apikey" -X GET "$url?$queryString&signature=$signature")
echo $req
You should set the API key in the request header, not as a parameter in the request url. Please provide more information on your request procedure (language, etc.).
If you are based in USA - make sure to switch your base url to https://api.binance.us
_httpClient.DefaultRequestHeaders.Add("X-MBX-APIKEY", "apikey");
_httpClient.DefaultRequestHeaders.Add("SecretKey", "secretkey");
curl -H "X-MBX-APIKEY:your_api_key" -X POST https://api.binance.com/api/v1/userDataStream
Related
I am using a nodemcu esp8266 and the plan is to make a spotify api request to automate playing some songs, and I have a fully functional python script that does exactly that, but when I tried to convert it to upython it failed. I have now spent hours on this and have figured out that the problem is that the urequest for some reason only works on specific websites, for example if I try:
import urequests as requests
x = requests.get('https://www.spotify.com')
print(x.status_code)
i get a 302
but when I try:
import urequests as requests
x = requests.get('https://www.google.com')
print(x.status_code)
I get a 200. That problem percists with a few websites and with no valid response my urequests.put command does not return the things I need... any ideas how to fix it?
thank you in advance.
this is the code I am trying to run:
import urequests as requests
import ujson as json
refresh_token = "xxxxx"
base_64 = "xxxxx"
class Refresh:
def __init__(self):
self.refresh_token = refresh_token
self.base_64 = base_64
def refresh(self):
query = "https://accounts.spotify.com/api/token"
payload={"grant_type": "refresh_token", "refresh_token": refresh_token}
headers={'Authorization': 'Basic %s' % base_64}
data = (json.dumps(payload)).encode()
response = requests.post(query,
data=data,
headers=headers)
print(response.status_code)
print(response.reason)
a = Refresh()
a.refresh()
There are several things going on here that are going to cause your problems.
First, you're trying to send JSON data to the /api/token endpoint:
data = (json.dumps(payload)).encode()
response = requests.post(query,
data=data,
headers=headers)
...but according to the documentation, this endpoint excepts application/x-www-form-urlencoded data.
Second, while the documentation suggests you need to send a basicAuthorization header, in my experiments this evening I wasn't able to get that to work...but I was able to successfully refresh a token if I included the client id and secret in the request body.
You can see my forum post with this question here.
With that in mind, the following code seems to work on my esp8266 running micropython 1.18:
import urequests as requests
refresh_token = "..."
client_id = "..."
client_secret = "..."
class Refresh:
def __init__(self, refresh_token, client_id, client_secret):
self.refresh_token = refresh_token
self.client_id = client_id
self.client_secret = client_secret
def refresh(self):
url = "https://accounts.spotify.com/api/token"
data = "&".join(
[
"grant_type=refresh_token",
f"refresh_token={self.refresh_token}",
f"client_id={self.client_id}",
f"client_secret={self.client_secret}",
]
)
headers = {
"content-type": "application/x-www-form-urlencoded",
}
response = requests.post(url, data=data, headers=headers)
print(data)
print(response.status_code)
print(response.reason)
print(response.text)
a = Refresh(refresh_token, client_id, client_secret)
a.refresh()
I try to connect to db2 on cloud via Excel Power Query.
Based on documentation this is format of curl request:
curl -X POST https://hostname.com/dbapi/v4/sql_query_export -H 'authorization: Bearer MyToken' -H 'content-type: text/csv' -d '{"command":"select * from mytable"}'
I tried to go via GUI but this gives me error
I am pretty sure I am not doing it right, but I could not even google how to pass my parameters.
Could someone please navigate how to assembly M code for this?
I tried this according to #nfgl answer
let
body = [#"command"="select * from mytable"]
,json = Json.FromValue(body)
,wc = Web.Contents("https://hostname.com/dbapi/v4/sql_query_export", [Headers=[#"content-type"="text/csv", authorization="Bearer XXX"]])
,Source = Csv.Document(wc,[Delimiter=",", Encoding=65001, QuoteStyle=QuoteStyle.Csv])
in
Source
However cannot go around credentials ui anonymously:
When I try Web API with token:
BTW, everything works with python:
import http.client
conn = http.client.HTTPSConnection("hostname.com")
payload = "{\"command\":\"select * from mytable\"}"
headers = {
'content-type': "text/csv",
'authorization': "Bearer XXX"
}
conn.request("POST", "/dbapi/v4/sql_query_export", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
You can't do it via GUI, command JSON must be in request content, and content-type is the one you send, ie JSON, open advanced editor and do something like this
let
url = "https://showcase.api.linx.twenty57.net/UnixTime/fromunixtimestamp",
body = [#"UnixTimeStamp"= 1589772280, #"Timezone"=""],
json = Json.FromValue(body),
wc = Web.Contents(url, [Headers=[#"Content-Type"="application/json"], Content=json]),
Source = Csv.Document(wc,[Delimiter=",", Encoding=65001, QuoteStyle=QuoteStyle.Csv])
in
Source
I've set up a simple, standard environment Google App Engine project which uses Cloud Endpoints by going through the steps in the tutorial here:
https://cloud.google.com/endpoints/docs/frameworks/python/get-started-frameworks-python
This works great - I can make a curl call to the echo endpoint and get the expected result.
However, I can't successfully call the authenticated endpoint.
I'm following the steps here: https://cloud.google.com/endpoints/docs/frameworks/python/javascript-client and, while I can successfully sign in, when I send my sample authenticated request I get a 401 Unauthorized HTTP response.
From the log on the server I see :
Client ID is not allowed: <my client id>.apps.googleusercontent.com (/base/data/home/apps/m~bfg-data-analytics/20190106t144214.415219868228932029/lib/endpoints/users_id_token.py:508)
So far I've checked:
The web app is using the correct version of the cloud endpoints config.
The client ID in the endpoint config (x-google-audiences) matches the
client ID that the javascript web app is posting.
Any ideas on how to fix this?
Using the example code to set up the end point in:
https://cloud.google.com/endpoints/docs/frameworks/python/create_api
and
https://cloud.google.com/endpoints/docs/frameworks/python/service-account-authentication
And modifying the python code for generating a token from :
https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/endpoints/getting-started/clients/service_to_service_google_id_token
I've got it working.
Here's the server endpoint code:
import endpoints
from endpoints import message_types
from endpoints import messages
from endpoints import remote
class EchoRequest(messages.Message):
message = messages.StringField(1)
class EchoResponse(messages.Message):
"""A proto Message that contains a simple string field."""
message = messages.StringField(1)
ECHO_RESOURCE = endpoints.ResourceContainer(
EchoRequest,
n=messages.IntegerField(2, default=1))
#endpoints.api(
name='echo',
version='v1',
issuers={'serviceAccount': endpoints.Issuer(
'MY-PROJECT#appspot.gserviceaccount.com',
'https://www.googleapis.com/robot/v1/metadata/x509/MY-PROJECT#appspot.gserviceaccount.com')},
audiences={'serviceAccount': ['MY-PROJECT#appspot.gserviceaccount.com']})
class EchoApi(remote.Service):
# Authenticated POST API
# curl -H "Authorization: Bearer $token --request POST --header "Content-Type: applicationjson" --data '{"message":"echo"}' https://MY-PROJECT#appspot.com/_ah/api/echo/v1/echo?n=5
#endpoints.method(
# This method takes a ResourceContainer defined above.
ECHO_RESOURCE,
# This method returns an Echo message.
EchoResponse,
path='echo',
http_method='POST',
name='echo')
def echo(self, request):
print "getting current user"
user = endpoints.get_current_user()
print user
# if user == none return 401 unauthorized
if not user:
raise endpoints.UnauthorizedException
# Create an output message including the user's email
output_message = ' '.join([request.message] * request.n) + ' ' + user.email()
return EchoResponse(message=output_message)
api = endpoints.api_server([EchoApi])
And the code to generate a valid token
import base64
import json
import time
import google
import google.auth
from google.auth import jwt
def generate_token(audience, json_keyfile, client_id, service_account_email):
signer = google.auth.crypt.RSASigner.from_service_account_file(json_keyfile)
now = int(time.time())
expires = now + 3600 # One hour in seconds
payload = {
'iat': now,
'exp': expires,
'aud' : audience,
'iss': service_account_email,
'sub': client_id,
'email' : service_account_email
}
jwt = google.auth.jwt.encode(signer, payload)
return jwt
token = generate_token(
audience="MY-PROJECT#appspot.gserviceaccount.com", # must match x-google-audiences
json_keyfile="./key-file-for-service-account.json",
client_id="xxxxxxxxxxxxxxxxxxxxx", # client_id from key file
service_account_email="MY-PROJECT#appspot.gserviceaccount.com")
print token
Make an authenticated call with curl
export token=`python main.py`
curl -H "Authorization: Bearer $token" --request POST --header "Content-Type: application/json" --data '{"message":"secure"}' https://MY-PROJECT.appspot.com/_ah/api/echo/v1/echo?n=5
i would like to know can you transfert some currencies from Kraken to Poloniex using API functions ?
Didn't see anything talking about that.
Thank a lot
*
create new API key with "Withdraw funds" right on kraken
Go to account settings then click on "api" to go to settings api page, then click on "generate new key"
Fill all field and tick the box "Withdraw Funds", then validate.
add the poloniex deposit address in kraken (assuming deposit address already created)
Go to funding deposit page
then click on "withdraw" to go to funding withdraw page
Select the currency on the left side
(here we assume that you want withdraw BTC)
so you have to click on "Bitcoin (XBT)" on the left panel
Then click on "add address" then
fill both "Description" & "Bitcoin address" field.
Write down "Description" field because it will be required later when you will send API request to withdraw from Kraken to Poloniex.
Create the API request which will be sent to Kraken
Use the following code (re-use this example python library):
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import time
import requests
import urllib
import urllib2
import json
import hashlib
import httplib
import hmac
import random
import string
import base64
def _query( urlpath, req = {}, conn = None, headers = {}):
"""Low-level query handling.
Arguments:
urlpath -- API URL path sans host (string, no default)
req -- additional API request parameters (default: {})
conn -- kraken.Connection object (default: None)
headers -- HTTPS headers (default: {})
"""
uri = 'https://api.kraken.com'
url = uri + urlpath
if conn is None:
conn = Connection()
ret = conn._request(url, req, headers)
return json.loads(ret)
def query_private( method, req={}, conn = None):
#secret data
key = "123456789_my_api_key"
secret = "123456798_my_api_secret"
apiversion='0'
uri='https://api.kraken.com'
urlpath = '/' + apiversion + '/private/' + method
req['nonce'] = int(1000*time.time())
postdata = urllib.urlencode(req)
message = urlpath + hashlib.sha256(str(req['nonce']) +
postdata).digest()
signature = hmac.new(base64.b64decode(secret),
message, hashlib.sha512)
headers = {
'API-Key': key,
'API-Sign': base64.b64encode(signature.digest())
}
return _query(urlpath, req, conn, headers)
withdraw_params={
'asset': 'xbt',
'key': "Withdrawal address Description",
'amount': 0.25,
}
res=query_private('Withdraw', withdraw_params)
You'll need the withdrawFunds method from the Kraken API (https://www.kraken.com/help/api#withdraw-funds).
Using the Poloniex API, you'll need to get your deposit address using returnDepositAddresses. If you don't have a deposit address for the given cryptocurrency, use generateNewAddress.
Kraken API Documentation: https://www.kraken.com/help/api
Poloniex API Documentation: https://poloniex.com/support/api/
Whats is the python urllib equivallent of
curl -u username:password status="abcd" http://example.com/update.json
I did this:
handle = urllib2.Request(url)
authheader = "Basic %s" % base64.encodestring('%s:%s' % (username, password))
handle.add_header("Authorization", authheader)
Is there a better / simpler way?
The trick is to create a password manager, and then tell urllib about it. Usually, you won't care about the realm of the authentication, just the host/url part. For example, the following:
password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
top_level_url = "http://example.com/"
password_mgr.add_password(None, top_level_url, 'user', 'password')
handler = urllib2.HTTPBasicAuthHandler(password_mgr)
opener = urllib2.build_opener(urllib2.HTTPHandler, handler)
request = urllib2.Request(url)
Will set the user name and password to every URL starting with top_level_url. Other options are to specify a host name or more complete URL here.
A good document describing this and more is at http://www.voidspace.org.uk/python/articles/urllib2.shtml#id6.
Yes, have a look at the urllib2.HTTP*AuthHandlers.
Example from the documentation:
import urllib2
# Create an OpenerDirector with support for Basic HTTP Authentication...
auth_handler = urllib2.HTTPBasicAuthHandler()
auth_handler.add_password(realm='PDQ Application',
uri='https://mahler:8092/site-updates.py',
user='klem',
passwd='kadidd!ehopper')
opener = urllib2.build_opener(auth_handler)
# ...and install it globally so it can be used with urlopen.
urllib2.install_opener(opener)
urllib2.urlopen('http://www.example.com/login.html')