I am writing a custom Python class to encapsulate the Poloniex trading API. However, I am running in to a problem with the request returning a "404 Error". I have been over and over the documentation and am quite sure that I am utilizing the right endpoint... What else could I be doing wrong here:
...
self.trading_api = 'https://poloniex.com/tradingapi'
self.api_key = 'My API key'
self.secret_key = bytes('My Secret Key', 'latin-1')
...
req['nonce'] = int(time.time()*1000)
data = urllib.parse.urlencode(req).encode()
sign = hmac.new(self.secret_key, data, sha512)
signature=sign.hexdigest()
headers = dict(Key=self.api_key, Sign=signature)
conn = urllib.request.Request(self.trading_api, headers=headers)
self.rate_limit()
try:
requested = urllib.request.urlopen(conn, data=data)
return requested
The A in the url must be capitalized:
self.trading_api = 'https://poloniex.com/tradingApi'
While Poloniex's documentation does not make note of this (in fact the url used was copied directly from their page), remember to capitalize it!
Related
I have looked through the FTX API documentation found here: https://docs.ftx.us/#overview
And I've looked at the example code found in this repo: https://github.com/ftexchange/ftx/tree/master/rest
I can't get or post anything that requires Authentication. I am using the API key on my account that has 'full trade permissions', and when I look at print(request.headers) the headers look like they are in the right format.
Let me know if you need any more information, my code returns
Error Code: 400 Invalid API Key
import time
import hmac
from requests import Request
ts = int(time.time() * 1000)
request = Request('GET', 'https://ftx/api/wallet/balances')
prepared = request.prepare()
signature_payload = f'{ts}{prepared.method}{prepared.path_url}'.encode()
signature = hmac.new('API SECRET'.encode(), signature_payload, 'sha256').hexdigest()
request.headers[f'FTXUS-KEY'] = API KEY'
request.headers[f'FTXUS-SIGN'] = signature
request.headers[f'FTXUS-TS'] = str(ts)
res = requests.get('https://ftx/api/wallet/balances', headers=prepared.headers)
r = res.json()
I also got this error and It was a silly mistake.
I think you have FTX.US API Key and you are hitting on 'https://ftx/api/wallet/balances'. U should hit on 'https://ftx.us/api/wallet/balances' to get this working
I'm fairly new to using web APIs and pulling data and i'm also pretty new with python. My goal is to make a stat-tracker app but I keep getting a 401 when I try and pull the data.
I've printed out the entire url just to make sure I didn't get it wrong. I copied and pasted the API key exactly so that shouldn't be a problem
api_token = 'api key in python file'
api_url_base = 'https://public-api.tracker.gg/v2/apex/standard/'
headers = {'Content-Type' : 'application/json',
'Authorization' : 'Bearer {}'.format(api_token)}
def get_player_profile():
api_url = '{}profile/psn/Daltoosh'.format(api_url_base)
response = requests.get(api_url, headers=headers)
if response.status_code == 200:
return json.loads(response.content.decode('utf-8'))
else:
return response.status_code, api_url
print(get_player_profile())
#player_profile = get_player_profile()
#if player_profile is not None:
# print("Career Stats:")
# for k, v in player_profile['profile/psn/Daltoosh'].items():
# print('{0}:{1}.format(k, v)')
#else:
# print('[!] Data Request Failed [!]')
I expected a status code of 200 but there seems to be a problem authenticating.
I'm not too well versed in the web API that you are using, but I think you might be using the API token incorrectly. I don't think that specific API requires a Bearer token, but instead a separate header called TRN-Api-Key.
So maybe write something like this:
headers = {'Content-Type' : 'application/json', 'TRN-Api-Key' : api_token}
If you look here, you should be able to read up on how to set up authentication.
I do have some tutorial code that makes use of the bit.ly API v3 for shortening an URL response. I would like to migrate this code to the v4 API but I do not understand how to set up the correct API endpoint. At least I think this is my error and the API documentation is difficult to understand and to adapt for me, as I'm a beginner.
I do have 2 files to work with:
bitlyhelper.py (this needs to be migrated to bit.ly API v4)
views.py
This is the relevant code that relates to the URL shortening.
bitlyhelper.py
import requests
#import json
TOKEN = "my_general_access_token"
ROOT_URL = "https://api-ssl.bitly.com"
SHORTEN = "/v3/shorten?access_token={}&longUrl={}"
class BitlyHelper:
def shorten_url(self, longurl):
try:
url = ROOT_URL + SHORTEN.format(TOKEN, longurl)
r = requests.get(url)
jr = r.json()
return jr['data']['url']
except Exception as e:
print (e)
views.py
from .bitlyhelper import BitlyHelper
BH = BitlyHelper()
#usr_account.route("/account/createtable", methods=["POST"])
#login_required
def account_createtable():
form = CreateTableForm(request.form)
if form.validate():
tableid = DB.add_table(form.tablenumber.data, current_user.get_id())
new_url = BH.shorten_url(config.base_url + "newrequest/" + tableid)
DB.update_table(tableid, new_url)
return redirect(url_for('account.account'))
return render_template("account.html", createtableform=form, tables=DB.get_tables(current_user.get_id()))
The code does work fine when using the v3 API.
I tried a few combinations of the API endpoint, but couldn't get it to work.
for example simply changing the version number does not work.
SHORTEN = "/v4/shorten?access_token={}&longUrl={}"
It would be great if someone could help with setting up the proper API endpoint.
Here is the API documentation: https://dev.bitly.com/v4_documentation.html
This is the relevant part I think:
import requests
header = {
"Authorization": "Bearer <TOKEN HERE>",
"Content-Type": "application/json"
}
params = {
"long_url": form.url.data
}
response = requests.post("https://api-ssl.bitly.com/v4/shorten", json=params, headers=header)
data = response.json()
if 'link' in data.keys(): short_link = data['link']
else: short_link = None
First you want to create the request header with your bearer token.
Make sure to set the content type too.
After setting your header you have to provide the url you would like to shorten for example.
The data variable contains your 201 request.
I got some help and ended up using bitlyshortener from here: https://pypi.org/project/bitlyshortener/
In this way:
from bitlyshortener import Shortener
tokens_pool = ['bitly_general_access_token'] # Use your own.
shortener = Shortener(tokens=tokens_pool, max_cache_size=128)
#usr_account.route("/account/createtable", methods=["POST"])
def account_createtable():
form = CreateTableForm(request.form)
if form.validate():
tableid = DB.add_table(form.tablenumber.data, current_user.get_id())
new_urls = [f'{config.base_url}newrequest/{tableid}']
short_url = shortener.shorten_urls(new_urls)[0]
DB.update_table(tableid, short_url)
return redirect(url_for('account.account'))
return render_template("account.html", createtableform=form, tables=DB.get_tables(current_user.get_id()))
This does work perfectly fine, and bitlyshortener even adds the s to https://my_shortlink automagically.
It makes sense that your v3 code fails against v4, based on this:
Authentication
How you authenticate to the Bitly API has changed with V4. Previously your authentication token would be provided as the access_token query parameter on each request. V4 instead requires that the token be provided as part of the Authorization header on each request.
You will want to move your token out of the args and into the header.
Using https://github.com/bitly/bitly-api-python might possibly be an option,
except that it is some years since it was last updated.
Quick question: I'm trying to use the Discord API to make a backup of all the messages on a server (or a guild, if you use the official term).
So I implemented OAuth without any problems, I have my access token and I can query some endpoints (I tried /users/#me, /users/#me/guilds). Though, most of them don't work. For example, if I query /users/#me/channels (which is supposed to be the DMs) I get a 401 Unauthorized response from the API. It's the same if I gather a guild id from /users/#me/guilds and then try to list the channels in it with /guilds/guild.id/channels.
The really weird thing is that I do have all the scopes required (I think so, I didn't take the RPC ones since I don't think it's required for what I want to do) and I can't figure it out myself... What is also weird is that on the OAuth authorization screen, I have those two things:
It kind of counterdicts itself... :(
Do you have any ideas you'd like to share ?
Thanks!
Note: I'm using Python but I don't think it's related here, since some endpoints do work with the headers and tokens I have...
Here is my "authentication code":
baseUrl = "https://discordapp.com/api"
def authorize():
scopes = [
"guilds",
"email",
"identify",
"messages.read",
"guilds.join",
"gdm.join",
"connections"
]
urlAuthorize = "{}/oauth2/authorize?client_id={}&scope={}&response_type=code".format(baseUrl, clientid, ('+'.join(scopes)))
pyperclip.copy(urlAuthorize)
code = input("Code: ")
return code
def getAccessToken(code):
url = "{}/oauth2/token".format(baseUrl)
params = {
"client_id" : clientid,
"client_secret" : clientsecret,
"redirect_uri" : "http://localhost",
"grant_type":"authorization_code",
"code" : code,
}
req = requests.post(url, params = params)
return json.loads(req.text)
And the code related to an API request:
def getHeaders():
return {
"Authorization" : "{} {}".format("Bearer", config["accessToken"]),
# "user-agent" : "DiscordBackup/0.0.1"
}
def getRequest(endpoint, asJson = True, additional = None):
url = "{}/{}".format(baseUrl, endpoint)
req = requests.get(url, headers = getHeaders())
print()
print(getHeaders())
print(url)
print(req.text)
if asJson:
return json.loads(req.text)
else:
return req.text
def getMe(): # this works
endpoint = "users/#me"
return getRequest(endpoint)
def getMyDMs(): # this gives me a code 401 Unauthorized
endpoint = "/users/#me/channels"
return getRequest(endpoint)
I came across this post when encountering this issue, and to put it bluntly, there's no way to resolve it.
The messages.read permission is for a local RPC server; https://discordapp.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes
However, local RPC servers are in private beta and you must sign up/get accepted to use this.
I wanted to create a DM exporter, but that doesn't look likely now.
I am implementing Coinbase's exchange API using custom auth in requests-python. The following code works with all the (authenticated) GET-based calls, but fails for all the authenticated POST-based calls (I haven't tried with DELETE or UPDATE verbs). I don't understand why the signature wouldn't work for both, because the payload is timestamp + method + path for GETs and timestamp + method + path + body for PUTs, so custom auth seems correct. Something is going wrong with adding the body and changing GET to POST. Thanks!
You can get your API keys for trying it out here: https://gdax.com/settings
import json, hmac, hashlib, time, requests, base64
from requests.auth import AuthBase
class CoinbaseAuth(AuthBase):
SIGNATURE_HTTP_HEADER = 'CB-ACCESS-SIGN'
TIMESTAMP_HTTP_HEADER = 'CB-ACCESS-TIMESTAMP'
KEY_HTTP_HEADER = 'CB-ACCESS-KEY'
PASSPHRASE_HTTP_HEADER = 'CB-ACCESS-PASSPHRASE'
def __init__(self, api_key, secret_key, passphrase):
self.api_key = api_key
self.secret_key = secret_key
self.passphrase = passphrase
def __call__(self, request):
#Add headers
request.headers[CoinbaseAuth.KEY_HTTP_HEADER] = self.api_key
request.headers[CoinbaseAuth.PASSPHRASE_HTTP_HEADER] = self.passphrase
timestamp = str(time.time())
request.headers[CoinbaseAuth.TIMESTAMP_HTTP_HEADER] = timestamp
#add signature
method = request.method
path = request.path_url
content = request.body
message = timestamp + method + path
if content:
message += content
hmac_key = base64.b64decode(self.secret_key)
sig = hmac.new(hmac_key, message, hashlib.sha256)
sig_b64 = sig.digest().encode("base64").rstrip("\n")
#Add signature header
request.headers[CoinbaseAuth.SIGNATURE_HTTP_HEADER] = sig_b64
return request
#Get your keys here: https://gdax.com/settings
key = 'KEY GOES HERE'
secret = 'SECRET GOES HERE'
passphrase = 'PASSPHRASE GOES HERE'
api_url = 'https://api.gdax.com:443/'
auth = CoinbaseAuth(API_KEY, API_SECRET, API_PASS)
#GETs work, shows account balances
r = requests.get(api_url + 'accounts', auth=auth)
print r.json()
#POSTs fail: {message: 'invalid signature'}
order = {}
order['size'] = 0.01
order['price'] = 100
order['side'] = 'buy'
order['product_id'] = 'BTC-USD'
r = requests.post(api_url + 'orders', data=json.dumps(order), auth=auth)
print r.json()
And the output:
GET call: 200: [{u'available': .......}]
POST call: 400: {u'message': u'invalid signature'}
EDIT: POSTing 'a' instead of valid JSON-encoded data results in the same signature error (rather than a JSON decoding error from the server), so I don't think it is the way I'm forming the data. Notably, if I omit the body -- request.post(..., data='',...) --- the server responds appropriately with {u'message': u'Missing product_id'}.
I don't know why, but if I change the data keyword argument to requests.post() to json it works:
r = requests.post(api_url + 'orders', json=order, auth=auth)
EDIT: The only thing that changes, AFAICT, is the content-type in the header is changed from text to JSON. So it is likely that or a unicode vs ASCII encoding issue. Here's the issue for the library that added this feature recently: https://github.com/kennethreitz/requests/issues/2025#issuecomment-46337236
I believe the content needs to be a json string with no spaces (this is what the node example does anyway). Maybe try this:
message += json.dumps(content).replace(' ', '')
I had the same exact problem until I looked at the public gdax API for nodeJS and found that they are using some additional headers that were not mentioned in the GDAX API docs. I added them and then it started working. See my answer to the following: GDAX API Always Returns Http 400 "Invalid Signature" Even though I do it exactly like in the API Doc