I'm trying to connect to the ConnectWise API using Python, but I keep running into "400 Client Error: Bad Request" errors.
When I use "https://api-na.myconnectwise.net/v4_6_version/apis/3.0/" as the url, I get an "invalid token" message, and when I use the codebase shown in my company info as opposed to "v4_6_version," I get a message that says
"code": "ConnectWiseApi", "message": "UserNotAuthenticated", "errors": null"
Has anyone run into these sorts of problems? From what I've found, it seems like this is caused by incorrect public/private keys, but I've tried with several different keys and keep getting the same message. I think it might be my url that's wrong, but I'm not sure.
Three components you need:
header called "clientid" with the value of your client ID from here
https://developer.connectwise.com/ClientID
basic authentication username = company+public key
basic authentication password = private key
I was able to get 200OK response trying to authenticate as above with Postman
Related
I have a list of dictionaries that contain album information which I'm trying to use to search within Spotify and then add to users' saved albums. I tried following the examples given in the spotipy documentation, however, I'm getting an issue when using the search function via spotipy.
SCOPE = 'user-library-modify'
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI, scope=SCOPE))
for album in newMusic:
albumName = album["Title"]
artistName = f"{album['Last Name']}+{album[' First Name']}"
getRecord = sp.search(q = f"artist:{artistName}&album:{albumName}", type='album')
print(getRecord)
I provided the redirect url when prompted after running, but this results in a 401 response for each album result as such:
{
"error": {
"status": 401,
"message": "No token provided"
}
}
I have the .cache file with the access and refresh tokens but it still says no token is provided. I thought maybe I was entering the query incorrectly, but I don't see anything wrong. This is how an example end url looks:
https://api.spotify.com/v1/search?query=artist:band+name&album:album+name&type=album&offset=0&limit=10
What am I doing wrong here? How can I get my access code recognized?
Found the issue; the query entry format was wrong. I found this answer to a past question that explains my problem: Using python to get a track from the spotify API by using search Endpoint
The artist, album, etc. do not need to be declared separately (e.g. "artist: _", "album: _"). They should just be combined together like:
https://api.spotify.com/v1/search?query=first+name+last+name+album+title&type=album&offset=0&limit=10
Weirdly, this contradicts what is in the Spotify API documentation where an example query value is given as such:
Example value:
"remaster%20track:Doxy+artist:Miles%20Davis"
https://developer.spotify.com/documentation/web-api/reference/#/operations/search
I am working on a GAE(Google App Engine) based python app and which have sendgrid python SDK(v3.2.10) integrated into it. What I am trying do is right now that whenever sendgrid pushes an event webhook of type "bounce" I want to delete that bounced email from the list of bounced emails present on sendgrid.
I have already gone through the documentation provided on the official site. First I tried to delete email address using SDK and it worked fine on localhost. But after deploying it to the live server it just doesn't do anything and falls in the exception clause.
Code snippet:
try:
send_grid_client = sendgrid.SendGridAPIClient(apikey=SENDGRID_API_KEY)
data = {"emails": [email.strip()]}
delete_response = send_grid_client.client.suppression.bounces.delete(
request_body=data)
except Exception as exception:
logging.info('Exception is: {}'.format(exception))
pass
As it did not work as expected, I am now trying to do the same using REST API.
Code snippet:
import requests
data = {"emails": [email]}
headers = {"Authorization": "Bearer {}".format(SENDGRID_API_KEY)}
delete_response = requests.delete("https://api.sendgrid.com/v3/suppression/bounces", data=json.dumps(data), headers=headers)
logging.info(delete_response)
logging.info(delete_response.status_code)
logging.info(delete_response.text)
Now, sendgrid API is continuously returning error 400 with message {"errors":[{"field":null,"message":"emails or delete_all params required"}]}. I simply could not figure out how to overcome this issue. Maybe I am missing how to pass request body in the delete function but, I could not figure it out.
I just figured out the issue.
It's the SendGrid API docs here which causes confusion as it is not mentioned clearly that they have a different way of calling the same endpoint when you want to delete a single email address or list of emails.
For a single email, it needs to be passed in the URL i.e. https://api.sendgrid.com/v3/suppression/bounces/{email_address}
For a list of emails, the list needs to be passed in the body of the delete request. i.e. it will look like this {"emails": [email_address_1, email_address_1, ...]}
As in the question above a single email was meant to be deleted and it was being passed as {"emails": [email_address_1]} in the delete request. Sendgrid API was not able to digest this info and was throwing an error. The email address was to be passed in the URL.
This issue has been resolved. But, I wonder why Sendgrid API was not able to digest this info {"emails": [email_address_1]}. Why they have a hard assumption that list will always have elements greater than one in it.
I have tried multiple approaches to this. Tried first getting the user without any user id - this returns me just my user, then tried getting user with other id's and it also retrieves data correctly. However, I can't seem to be able to set user attribute 'deleted'. i'm using this python approach.
slack_client.api_call('users.profile.set', deleted=True, user='U36D86MNK')
However I get the error message of:
{u'error': u'invalid_user', u'ok': False}
Maybe someone has already done this? It says in documentation that it's a paid service mentioning this message under a user property:
This argument may only be specified by team admins on paid teams.
But shouldn't it give me a 'paid service' response in that case then?
The users.profile.set apparently does not work for for setting each and every property of a user.
To set the deleted property there is another API method called users.admin.setInactive. Its an undocumented method and it will only work on paid teams.
Note: This requires a legacy token and doesn't work with App tokens - these are only available on paid plans and new legacy tokens can't be created anymore
in python you can do the following:
import requests
def del_slack_user(user_id): # the user_id can be found under get_slack_users()
key = 'TOKEN KEY' #replace token key with your actual token key
payload = {'token': key, 'user': user_id}
response = requests.delete('https://slack.com/api/users.admin.setInactive', params=payload)
print(response.content)
def get_slack_users():
url = 'https://slack.com/api/users.list?token=ACCESSTOKEN&pretty=1'
response = requests.get(url=url)
response_data = response.json() # turns the query into a json object to search through`
You can use Slack's SCIM API to enable and disable a user. Note that, as with the undocumented API endpoint mentioned in other answers this requires a Plus/Enterprise account.
I'm learning APIs and was testing with Instagram's API.
Currently, I have an client in sandbox mode and an access token with public_content scope. I created another instagram account that is set to private profile. This new account is a sandbox user for the client.
This is my code.
import requests
import json
parameters = {'ACCESS_TOKEN':'4831128049.31d6072.13cfcadf494344cba7d7f47f18f8ba97'} #modified fake access for question sake
response = requests.get('https://api.instagram.com/v1/{i-put-the-user-id-here}/self/media/recent?access_token='+parameters['ACCESS_TOKEN'])
json_data = response.json()
print(response.status_code)
print(json_data)
But I keep getting this.
{
'meta':{
'code':400,
'error_type':'APINotAllowedError',
'error_message':'you cannot view this resource'
}
}
Edit 1: But this works if the user is the owner of the access token, that is it works perfectly for my own account but not for other private profiles that is also a sandbox account.
Am I doing something wrong?
If this is not possible, then how are there other 3rd party apps doing it? like Flume for Mac?
You cannot get private user via API even if you are following that user, this behavior changed last year with API policy. APINotAllowedError is expected response when trying to access a private user.
I am trying to create a set on Quizlet.com, using its API found here: https://quizlet.com/api/2.0/docs/sets#add
Here is my code of a set I am trying to create:
import requests
quizkey = my_client_id
authcode = my_secret_code # I'm not sure if I need this or not
data = {"client_id":quizkey, "whitespace":1, "title":"my-api-set",
"lang_terms":"it", "lang_definitions":"en",
"terms":['uno','due'], "definitions":["one","two"]}
apiPrefix = "https://api.quizlet.com/2.0/sets"
r = requests.post(url=apiPrefix, params=data)
print r.text
The response is:
{
"http_code": 401,
"error": "invalid_scope",
"error_title": "Not Allowed",
"error_description": "You do not have sufficient permissions to perform the requested action."
}
I also tried "access_token":authcode instead of "client_id":quizkey, but this resulted in the error: "You do not have sufficient permissions to perform the requested action."
How can I fix this and not get a 401 error?
Alright so 3 and a half years later (!!) I've looked into this again and here's what I've discovered.
To add a set you need an access token - this is different to the client_id (what I call quizkey in my code), and to be quite honest I don't remember what authcode in my code is.
This token is obtained by going through the user authentication flow. To summarise it:
Send a POST request to https://quizlet.com/authorize like so:
https://quizlet.com/authorize?response_type=code&client_id=MY_CLIENT_ID&scope=read&state=RANDOM_STRING
Keep the response_type as code, replace client_id with your client_id, keep the scope as read, and state can be anything
I believe this requires human intervention because you're literally authorising your own account? Not sure of another way...
You'll receive a response back with a code
Let's call this RESPONSE_CODE for now
Send a POST request to https://api.quizlet.com/oauth/token, specifying 4 mandatory parameters:
grant_type="authorization_code" (this never changes)
code=RESPONSE_CODE
redirect_uri=https://yourredirecturi.com (this can be found at your personal API dashboard)
client ID and secret token separated by a colon and then base64-encoded (the user authentication flow link above tells you what this is if you don't want to do any of the encoding)
You'll receive the access_token from this API call
Now you can use that access_token in your call to create a set like I've done above (just replace "client_id":quizkey with "access_token":access_token)
You will need to authenticate in order to make sets. This link gives an overview:
https://quizlet.com/api/2.0/docs/making_api_calls
And this one provides details about the authentication process:
https://quizlet.com/api/2.0/docs/authorization_code_flow