Getting Call Status with Sinch API - python

After placing a call with Sinch API using a 'ttsCallout' method, I'm trying to get the status for that call. The calls goes through, I'm receiving its 'callId'. But when it comes to requesting my call's status, I receive 200 OK as a HTTP Response and empty ('null') content.
First, I though something is wrong with my code and the way I form Authorization headers (I use Python, its requests library and basic auth), but then I tried Sinch API explorer (https://www.sinch.com/dashboard/#/api) and it shows the same output to me (see the attached screenshot). Have to notice that this code worked about a month ago, and I was able to get call status.
Also, here is the code I use to communicate to Sinch API.
class CallNotification(Notification):
def __init__(self, data):
self.id = ""
self.call = self.data['call']
self.api_url = self.call['api_url']
self.auth = ("application:" + self.call['auth']['key'], self.call['auth']['secret'])
self.status = {'http': "new", 'result': "none", 'reason': "none"}
def send(self):
request_url = self.api_url + "/callouts"
request = requests.post(request_url,
auth=self.auth,
json={
'method': "ttsCallout",
'ttsCallout': {
'cli': "private",
'destination': {
'type': "number",
'endpoint': self.call['to']
},
'domain': "pstn",
'custom': "customData",
'locale': "en-US",
'text': self.call['message']
}
},
headers={'content-type': 'application/json'})
self.id = json.loads(request.content)['callId']
self.status['http'] = request.reason
return self.status['http']
def getstatus(self):
if not self.status['http'] == "new":
request_url = self.api_url + "/calls/id/" + self.id
request = requests.get(request_url,
auth=self.auth,
headers={'Content-type': 'application/json'})
try:
self.status['result'] = json.loads(request.content)['result']
except TypeError:
self.status['result'] = "Sent/Unknown"
return self.status['result']
Am I doing something wrong? What do I do to get status for a placed call?

Related

Python: POST request to API failed

I am trying to send a POST request to Walmart API to request reports. But it is returning me 'Report request failed.' message with json. What am I doing wrong? I don't really have that much experience with API calls in python. Here is my code.
I have a class called "Walmart" to interact with the Walmart Marketplace API. It has methods to authenticate with the API, send requests and handle responses.
class Walmart(object):
def __init__(self, client_id, client_secret):
"""To get client_id and client_secret for your Walmart Marketplace
visit: https://developer.walmart.com/#/generateKey
"""
self.client_id = client_id
self.client_secret = client_secret
self.token = None
self.token_expires_in = None
self.base_url = "https://marketplace.walmartapis.com/v3"
session = requests.Session()
session.headers.update({
"WM_SVC.NAME": "Walmart Marketplace",
"WM_QOS.CORRELATION_ID": uuid.uuid4().hex,
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json",
})
session.auth = HTTPBasicAuth(self.client_id, self.client_secret)
self.session = session
# Get the token required for API requests
self.authenticate()
def authenticate(self):
data = self.send_request(
"POST", "{}/token".format(self.base_url),
body={
"grant_type": "client_credentials",
},
)
self.token = data["access_token"]
self.token_expires_in = data["expires_in"]
self.session.headers["WM_SEC.ACCESS_TOKEN"] = self.token
#property
def report(self):
return Report(connection=self)
def send_request(
self, method, url, params=None, body=None, json=None,
request_headers=None
):
# A unique ID which identifies each API call and used to track
# and debug issues; use a random generated GUID for this ID
headers = {
"WM_QOS.CORRELATION_ID": uuid.uuid4().hex,
"WM_SVC.NAME": "Walmart Marketplace",
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json",
}
if request_headers:
headers.update(request_headers)
response = None
if method == "GET":
response = self.session.get(url, params=params, headers=headers)
elif method == "PUT":
response = self.session.put(
url, params=params, headers=headers, data=body
)
elif method == "POST":
request_params = {
"params": params,
"headers": headers,
}
if json is not None:
request_params["json"] = json
else:
request_params["data"] = body
response = self.session.post(url, **request_params)
if response is not None:
try:
response.raise_for_status()
except requests.exceptions.HTTPError:
if response.status_code == 401:
raise WalmartAuthenticationError((
"Invalid client_id or client_secret. Please verify "
"your credentials from https://developer.walmart."
"com/#/generateKey"
))
elif response.status_code == 400:
data = response.json()
if "error" in data and data["error"][0]["code"] == \
"INVALID_TOKEN.GMP_GATEWAY_API":
# Refresh the token as the current token has expired
self.authenticate()
return self.send_request(
method, url, params, body, request_headers
)
raise
try:
return response.json()
except ValueError:
# In case of reports, there is no JSON response, so return the
# content instead which contains the actual report
return response.content
And here goes authentication and the request itself. I think I am doing it wrong with the send_request method, should I do it in a different way?
api_key = '<key>'
api_secret='<secret>'
wm = Walmart(api_key, api_secret)
wm.authenticate()
url = "https://marketplace.walmartapis.com/v3/reports/reportRequests"
headers = {
"WM_QOS.CORRELATION_ID": uuid.uuid4().hex,
"WM_SVC.NAME": "Walmart Marketplace",
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json",
}
data= {
"reportType": "ITEM_PERFORMANCE",
"reportVersion": "v1",
}
method="POST"
response_dict = wm.send_request(method, url, request_headers=headers, params=data)
if 'status_code' in response_dict and response_dict['status_code'] == 200:
response_json = response_dict.get('json')
request_id = response_json.get('requestId')
print(f'Report request submitted. Request ID: {request_id}')
else:
print('Report request failed.')
if 'json' in response_dict:
print(response_dict['json'])
else:
print(response_dict)
The response that I got was in the following form.
Report request failed.
{'requestId': '46a864e8-80e8-4019-86f0-d7a1575349a4', 'requestStatus': 'RECEIVED', 'requestSubmissionDate': '2023-02-15T18:55:03Z', 'reportType': 'ITEM_PERFORMANCE', 'reportVersion': 'v1'}
Any help is appreciated
You can try to print the response to see his contents, and there may be some additional info that will help you to fix your code. Also, you can try to debug your code line by line using this https://pypi.org/project/ipdb/
The response you get seems to be a successful response, as the property requestStatus is RECEIVED, and not ERROR (which is a possible value according to the API docs you linked).
So, the issue is probably with your response checks.
Based on your checks for response:
if 'status_code' in response_dict and response_dict['status_code'] == 200:
response_json = response_dict.get('json')
request_id = response_json.get('requestId')
print(f'Report request submitted. Request ID: {request_id}')
else:
print('Report request failed.')
if 'json' in response_dict:
print(response_dict['json'])
else:
print(response_dict)
either 'status_code' in response_dict or response_dict['status_code'] == 200 is false, what makes the else block to be executed. I recommend you to print(response_dict) before the if-else block, to see the whole content and see which of those 2 conditions is false and handle it accordingly.
I think that the issue is that the object you get from wm.send_request() does not contain status_code, since you get the content of the response (when you return response.json()) and not the session.Response object from the requests lib (see the docs).

How to create reports with Python SDK Api

I am trying to create reports with Python on dailymotion but I have error,According to my received error, renponse is empty. I don't get it. I guess, My user coudln't login to dailymotion. Please check error.
{'data': {'askPartnerReportFile': None}, 'errors': [{'message': 'Not authorized to access `askPartnerReportFile` field.', 'path': ['askPartnerReportFile'], 'locations': [{'line': 3, 'column': 9}], **'type': 'not_authorized**'}]}
Traceback (most recent call last):
File "get_reports.py", line 143, in <module>
product='CONTENT',
File "get_reports.py", line 65, in create_report_request
return response.json()['data']['askPartnerReportFile']['reportFile']['reportToken'];
TypeError: 'NoneType' object is not subscriptable
Here is my code;
`
def get_access_token(app_key, app_secret, username, password):
'''
Authenticate on the API in order to get an access token
'''
response = requests.post('https://graphql.api.dailymotion.com/oauth/token', data={
'client_id': app_key,
'client_secret': app_secret,
'username': username,
'password': password,
'grant_type': 'password',
'version': '2'
})
if response.status_code != 200 or not 'access_token' in response.json():
raise Exception('Invalid authentication response')
return response.json()['access_token']
def create_report_request(access_token, dimensions, metrics, start_date, end_date, product, filters = None):
'''
Creating a report request
'''
reportRequest = """
mutation ($input: AskPartnerReportFileInput!) {
askPartnerReportFile(input: $input) {
reportFile {
reportToken
}
}
}
"""
response = requests.post(
'https://graphql.api.dailymotion.com',
json={
'query': reportRequest,
'variables': {
'input': {
'metrics': metrics,
'dimensions': dimensions,
'filters': filters,
'startDate': start_date,
'endDate': end_date,
'product': product,
}
}
},
headers={'Authorization': 'Bearer ' + access_token}
)
print(response.status_code)
if response.status_code != 200 or not 'data' in response.json():
raise Exception('Invalid response')
print(response.json())
return response.json()['data']['askPartnerReportFile']['reportFile']['reportToken'];
def check_report_status(access_token, report_token):
'''
Checking the status of the reporting request
'''
report_request_status_check = """
query PartnerGetReportFile ($reportToken: String!) {
partner {
reportFile(reportToken: $reportToken) {
status
downloadLinks {
edges {
node {
link
}
}
}
}
}
}
"""
response = requests.post(
'https://graphql.api.dailymotion.com',
json={
'query': report_request_status_check,
'variables': {
'reportToken': report_token
}
},
headers={'Authorization': 'Bearer ' + access_token}
)
if response.status_code != 200 or not 'data' in response.json():
raise Exception('Invalid response')
status = response.json()['data']['partner']['reportFile']['status'];
if (status == 'FINISHED'):
download_links = []
for url in map(lambda edge: edge['node']['link'], response.json()['data']['partner']['reportFile']['downloadLinks']['edges']):
download_links.append(url)
return download_links
else:
return None
def download_report(download_links, base_path=None):
'''
Downloading the report files
'''
cpt = 1
if not base_path:
base_path = os.getcwd()
for url in download_links:
r = requests.get(url)
filename = 'report_{}.csv'.format(cpt)
file_path = os.path.join(base_path, filename)
open(file_path, 'wb').write(r.content)
print('Report file {} downloaded: {}'.format(cpt, file_path))
cpt += 1
print('Generating access token...')
access_token = get_access_token(
app_key='******',
app_secret='*******',
username='*****',
password='*****'
)
print('Creating report request...')
report_token = create_report_request(
access_token=access_token,
dimensions=('DAY', 'VIDEO_TITLE'),
metrics=('VIEWS'),
filters={'videoOwnerChannelSlug': 'B******'},
start_date='2022-11-23',
end_date='2022-11-24',
product='CONTENT',
)
download_links = None
while not download_links:
print('Checking report status...')
# Checks every 15secs the report status
time.sleep(15)
download_links = check_report_status(
access_token=access_token,
report_token=report_token
)
download_report(download_links=download_links)
`
I tried to get data dailymotion api.
Thanks
This feature requires a specific API access, which is missing on your API Key, that's why you get the message Not authorized to access askPartnerReportFile field.
As it's a feature restricted to verified-partners, you should reach out to your content manager to ask him this kind of access, or you can try to contact our support

Create a subscription returns error Notification endpoint must respond with 200 OK to validation request

I've been trying to create a subscription to a user's outlook mail inbox using Microsoft Graph.
I've defined all the necessary grants/rights on Azure AD. (Mail.Read, Mail.ReadWrite)
My create_subscription method is defined below:
def create_subscription(
self,
change_type: str,
notification_url: str,
resource: str,
expiration_datetime: datetime,
client_state: str = None,
**kwargs,
) -> Response:
if isinstance(expiration_datetime, datetime):
expiration_datetime = format_time(expiration_datetime, is_webhook=True)
data = {
"changeType": change_type,
"notificationUrl": notification_url,
"resource": resource,
"expirationDateTime": expiration_datetime,
"clientState": client_state,
}
data.update(kwargs)
response = self._client._post(self._client.base_url + "subscriptions", json=data)
return response
The _post call redirects it to the _post() function:
def _post(self, url, **kwargs):
return self._request("POST", url, **kwargs)
def _request(self, method, url, headers=None, **kwargs) -> Response:
_headers = {
"Accept": "application/json",
}
_headers["Authorization"] = "Bearer " + self.token["access_token"]
if headers:
_headers.update(headers)
if "Content-Type" not in _headers:
_headers["Content-Type"] = "application/json"
return self._parse(requests.request(method, url, headers=_headers, **kwargs))
When I call the create_subscription function:
client.webhooks.create_subscription( "created",
"https://****-**-***-**-***.in.ngrok.io/notification/listen",
"/me/mailfolders('inbox')/messages",
"2022-10-28T10:00:00.0000000Z", "SecretClientState" )
It throws the following error:
microsoftgraph.exceptions.BadRequest:
{
'error': {
'code': 'InvalidRequest',
'message': 'Subscription validation request failed. Notification endpoint must respond with 200 OK to validation request.',
'innerError': {
'date': '2022-10-25T05:30:53',
'request-id': '53763195-88e8-441f-b3e0-1520587f6ba1',
'client-request-id': '53763195-88e8-441f-b3e0-1520587f6ba1'
}
}
}
How would I be required to go about validating the subscription; because as per my understanding, when the subscription is created, my notification URL should respond with a '200 OK' status_code, along with the value of the validationtoken query string parameter as a plain-text response.
Would really appreciate it if someone could guide me through the entire process. Thanks!

Unable to verify webhooks from PayPal in Python

I am trying to verify webhooks for subscriptions in paypal using django python. I am receiving the webhooks but when i send them to get verified i get this error: {'name': 'VALIDATION_ERROR', 'message': 'Invalid request - see details', 'debug_id': 'ccc873865982', 'details': [{'field': '/', 'location': 'body', 'issue': 'MALFORMED_REQUEST_JSON'}], 'links': []}. I have checked what the status code is for the response which gives a 400 response. By looking at the API Docs i see that invalid request + 400 response is either a validation error (which is to do with the Json format, so most likely a syntax error) or an authorization error (which says i need to change the scope). I think it is the validation error because the error points to the body.
Here is the relevant code:
header_params = {
"Accept": "application/json",
"Accept-Language": "en_US",
}
param = {
"grant_type": "client_credentials",
}
cid = settings.PAYPAL_CLIENT_ID
secret = settings.PAYPAL_CLIENT_SECRET
token_i = requests.post('https://api-m.sandbox.paypal.com/v1/oauth2/token', auth=(cid, secret), headers=header_params, data=param).json()
token = token_i["access_token"]
bearer_token = "Bearer x".replace('x', token)
headers = {
"Content-Type": "application/json",
"Authorization": bearer_token,
}
print(request.body)
webhook_event = request.body.decode("utf-8")
data = {
"transmission_id": request.headers["PAYPAL-TRANSMISSION-ID"],
"transmission_time": request.headers["PAYPAL-TRANSMISSION-TIME"],
"cert_url": request.headers["PAYPAL-CERT-URL"],
"auth_algo": request.headers["PAYPAL-AUTH-ALGO"],
"transmission_sig": request.headers["PAYPAL-TRANSMISSION-SIG"],
"webhook_id": "3AJ143072C221060T",
"webhook_event": webhook_event,
}
print(json.dumps(data))
response = requests.post('https://api-m.sandbox.paypal.com/v1/notifications/verify-webhook-signature', headers=headers, json=json.dumps(data)).json()
print('worked')
print(response)
if response["verification_status"] == "SUCCESS":
print('success')
Here is the print of the print(json.dumps(data)) (i removed some ids):
{
"transmission_id": "id_is_here",
"transmission_time": "2021-07-04T23:37:29Z",
"cert_url": "https://api.sandbox.paypal.com/v1/notifications/certs/CERT-360caa42-fca2a594-7a8abba8",
"auth_algo": "auth_algo",
"transmission_sig": "EODOx5y8kIDycYiBYcIgByiBzHyEfu1/NS2nsumOIksVuw/2vJwHj2FcuHYxIa4n/s+s25xkeqk0CXPiSuqtNUGv4pvFtpwbCVAOCU+Msn304+wBgyb7G24rwUPwrof/5jHYQxqKKX5RzxTrff4oPnisKBDUUXV4s2+KO3h2RYAhrXtwTSPt7cK5ZbGZ6SmfpYJ8qDnYFh4PIesLeflSPQ4vHQrFbgr3NiW63sZruGFJc0hTWWc8L3BhzDuUfiSrxBJLAtrqReC8R0HSV8D+Ywmdeipep54yZeJZXfbmUUGvSYbmVMsVggyzZnltyl1hP5xUd3iIi2jdNWYpLESZzA==",
"webhook_id": "Webhook_id_is_here",
"webhook_event": "{\"id\":\"id_here\",\"event_version\":\"1.0\",\"create_time\":\"2021-07-04T23:37:26.733Z\",\"resource_type\":\"subscription\",\"resource_version\":\"2.0\",\"event_type\":\"BILLING.SUBSCRIPTION.CREATED\",\"summary\":\"Subscription created\",\"resource\":{\"start_time\":\"2021-07-04T23:37:26Z\",\"quantity\":\"1\",\"create_time\":\"2021-07-04T23:37:26Z\",\"custom_id\":\"custom_id_here\",\"links\":[{\"href\":\"https://www.sandbox.paypal.com/webapps/billing/subscriptions?ba_token=BA-2UF06918UT180770Y\",\"rel\":\"approve\",\"method\":\"GET\"},{\"href\":\"https://api.sandbox.paypal.com/v1/billing/subscriptions/I-4S15814RUE18\",\"rel\":\"edit\",\"method\":\"PATCH\"},{\"href\":\"https://api.sandbox.paypal.com/v1/billing/subscriptions/I-4S15814RUE18\",\"rel\":\"self\",\"method\":\"GET\"}],\"id\":\"sub_id_here_\",\"plan_overridden\":false,\"plan_id\":\"P-0DA33732CG980003EMDQJ6BA\",\"status\":\"APPROVAL_PENDING\"},\"links\":[{\"href\":\"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-91E32247D9338170B-4RF07261WK370823W\",\"rel\":\"self\",\"method\":\"GET\"},{\"href\":\"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/id_here/resend\",\"rel\":\"resend\",\"method\":\"POST\"}]}"
}
Your data for the key webhook_event is double encoded as JSON.
You have to decode it with
webhook_event = json.loads(webhook_event)
or not encode it in the first place.

Is there a way to use the Python API for Trello to invite members to a board?

When reviewing the abilities of the Python API for Trello and considering its functionalities,
I was searching for a function that allows to add a member to a board - w./o. success.
What I have tried to use is the following:
trello = TrelloAPI(myAPIKey, myToken)
boardID = myBoardID
fields = {"fullName": "Robo Member",
"email" : myMail}
trello.boards.get_membersInvited(board_id = boardID,
fields = fields)
This is how the method implementation looks like:
def get_membersInvited(self, board_id, fields=None):
resp = requests.get("https://trello.com/1/boards/%s/membersInvited" %
(board_id), params=dict(key=self._apikey, token=self._token,
fields=fields), data=None)
resp.raise_for_status()
return json.loads(resp.content)
I end up receiving 404 Client Error URL not found.
Do you have any suggestions on what to adjust?
Maybe, I used the wrong field names (email and fullName)?
Here is a solution for .NET
Found a remedy by myself. Source --> Trello API Board Put Member
Here my own solution:
def invite_new_member(self, fullName, email, boardID):
url = self.baseURL + "boards/" + boardID + "/members"
querystring = {"email": email, "key": apikey,
"token": token}
payload = "{\"fullName\":\"" + fullName + "\"}"
headers = {
'type': "normal",
'content-type': "application/json" }
response = requests.request("PUT", url, data=payload, headers=headers,
params=querystring)

Categories