We are implementing server to server notifications for Android in-app purchases.
For each of the user-generated events (purchase, cancellation, etc.), we receive and parse real-time developer notifications, according to Google Play's rtdn reference.
After parsing each notification, we submit the subscription to the play store for verification, according to Google Play Developer API purchases.subscriptions.
The JSON responses we expect back should correspond to the action that the user has taken. For example, after the SUBSCRIPTION_PURCHASED notification was received, the verification response looks like this:
{
"startTimeMillis": "1615196368232",
"expiryTimeMillis": "1615196783756",
"autoRenewing": true,
"priceCurrencyCode": "EUR",
"priceAmountMicros": "3990000",
"countryCode": "DE",
"developerPayload": "",
"paymentState": 1,
"orderId": "GPA.3391-4718-6063-47314",
"purchaseType": 0,
"acknowledgementState": 1,
"kind": "androidpublisher#subscriptionPurchase"
}
Now, the headaches start when the user cancels their subscription (via the Play Store app), thus generating a SUBSCRIPTION_CANCELED notification. The verification response looks like this:
{
"startTimeMillis": "1615196368232",
"expiryTimeMillis": "1615196664327",
"autoRenewing": false,
"priceCurrencyCode": "EUR",
"priceAmountMicros": "3990000",
"countryCode": "DE",
"developerPayload": "",
"cancelReason": 0,
"userCancellationTimeMillis": "1615196648401",
"orderId": "GPA.3391-4718-6063-47314",
"purchaseType": 0,
"acknowledgementState": 1,
"kind": "androidpublisher#subscriptionPurchase"
}
There are some new fields present, defining the cancellation:
"cancelReason": integer,
"userCancellationTimeMillis": string,
This is great and works as expected. However, there are still some cancellation fields missing. Namely, the SubscriptionCancelSurveyResult, defined as:
"cancelSurveyResult": {
"cancelSurveyReason": integer,
"userInputCancelReason": string
}
The documentation mentions for both userInputCancelReason and userCancellationTimeMillis:
Only present if cancelReason is 0.
cancelReason is already 0, as it can be seen in the screenshot attached. However, only userCancellationTimeMillis is present. Why is there no cancelSurveyResult and no userInputCancelReason?
You app can look at the cancelReason in the subscription resource returned from the Google Play Developer API to learn why the subscription was cancelled (e.g. the customer cancelled or had billing issues). If the subscription was cancelled by the user, your app can look at the cancelSurveyResult field to learn why the user cancelled the subscription.
Source: https://developer.android.com/google/play/billing/subscriptions#cancel
Related
I have a incoming webhook that I sent a messageCard with several actioncards. I know how to post the data and value back to my server endpoint. I need to get the username of the user who pushed the button to submit the httppost. Here is the actioncard part of the code. It works. I just need to also know who submitted it, the MS Teams username.
{
"#type": "ActionCard",
"name": "Skip",
"inputs": [{
"#type": "TextInput",
"id": "skip",
"isMultiline": True,
"title": "Add a skip reason here"
}],
"actions": [{
"#type": "HttpPOST",
"name": "skip",
"target": "",
"body":"{"action":"skip","body":"{{skip.value}}}"}"
}]
}
Currently UPN is not sent part of the JSON body/payload, however it can be retrieved by decoding JWT token in Authorization header part of sender verification:
Service can validate the JWT and then extract claims and get the UPN as per below:
Security requirements for actionable messages - Outlook Developer | Microsoft Docs.
Also if you go through the Connector documentation, you’ll see that the ‘sub’ parameter contains the Azure AD object ID. You can then call Get users Graph API to get the user details from AAD Id.
I am trying to get the bot_id value for a bot when it has no conversation history.
According to the documentation:
the bot_id fields appear in bot_message message event subtypes and in
the response of methods like conversations.history.
This makes sense and works.
But is it possible to get this bot_id value, when a bot has no conversation history?
For example, say the channel between Slackbot and my bot has no conversation history. The response of a conversations.history request to this channel is the following, which does not include the bot_id value.
{
"ok": true,
"channel": {
"id": "DC6N8Q1BK",
"created": 1534129098,
"is_im": true,
"is_org_shared": false,
"user": "USLACKBOT",
"last_read": "0000000000.000000",
"latest": null,
"unread_count": 0,
"unread_count_display": 0,
"is_open": true,
"priority": 0
}
}
Any other way to get the bot_id value?
If there is a bot user, you can get it from the normal userlist with users.list. But that will not include other apps.
Then there is the unofficial API method bots.list. That will give you a list of all bots, but its not officially supported and you will need a legacy token to use as with many undocumented methods.
I would like to add an all-day event to my Google Classroom Course as an assignment with the Classroom API found here: Method: courses.courseWork.create documentation
Here is the json request I've been using in their API explorer:
{
"title": "Lesson 1.1",
"workType": "assignment",
"state": "published",
"description": "This is a test assignment.",
"dueDate": {
"year": 2017,
"month": 9,
"day": 2
},
"dueTime": {
"hours": null,
"minutes": null
}
}
I've tried many variations, but it always posts the assignment due at 8:00 PM by default, never an allDay or all-day event. Removing the dueTime isn't allowed per the documentation. Yet, when I manually create a lesson it's an optional field. I inspected the post data and couldn't find out how this is happening.
It doesn't appear to mention how to create an all-day event in the Google Classroom API documentation and the Google Calendar API docs didn't give me any usable hints.
Any ideas?
Is the botId that I receive in the webhook only bot scope or is it unique across all the bots found?
Is it permanent or can it be changed?
By botId I mean the id in recipient.id and replyToId that you fill in send message request to endpoint https://smba.trafficmanager.net/apis/v3/conversations/{{skype.idRecipient}}/activities:
{
"text": "God help us!",
"type": "message",
"from": {
"id": "{{skype.idBot}}",
"name": "bot"
},
"recipient": {
"id": "{{skype.idRecipient}}",
"name": "user"
},
"replyToId": "{{skype.idBot}}"
}
The ID you are talking about is unique only in the current channel (Skype/Facebook/Slack...) as it is the ID of ChannelAccount.
Here are some statements from documentation:
Every bot and user has an account within each channel. The account
contains an identifier (id) and other informative bot non-structural
data, like an optional name.
Also
Channel accounts have meaning only within their associated channel
So it's not excluded that id may be repeated on another channels.
And what about permanency, it depends on the channel you use as stated in documentation again:
The stability of associations between IDs, accounts, mailboxes, and
people depends on the channel
But if you want it to be "unique across all the bots found" then you can create an id by combining AppID, ChannelID and User ID.
Also here is a quite informative guide about IDs in Bot Framework which may be helpful to you
We are fetching google calendar events through OAuth2 tokens with Google Calendar API V3 to our customers, but for some of customers' calendar getting empty response. We got empty response for the same calendar in Google OAuth Playground.
{
"nextPageToken": "CjkKK2xwamMycHJ2MDU2cGp2YFxcmY3OXRtNTg0XzIwMTQwMjEyVDA0MzAwMFoYASCAgMDEtcaFoBQaDQgAEgAY2M-X7qfLvAI=",
"kind": "calendar#events",
"defaultReminders": [
{
"minutes": 30,
"method": "popup"
}
],
"items": [],
"updated": "2014-02-14T09:32:57.943Z",
"summary": "TEST",
"etag": "\"TuPKiPtcUnaxp3U8BefUMu26Bg/LWnnxrAP6L1-mgjBDhy0rIebYaE\"",
"timeZone": "Asia/Calcutta",
"accessRole": "owner"
}
But when the same user is authenticated through AuthSub, it is fetching the events list. Is anyone having the same issue? Any help would be appreciated.
TIA,
Riyaz.A
Have you tried actually calling the API with the nextPageToken? Usually the client libraries do this auto pagination for you, but in this case you may need to manually make the call. In general, you should plan on calling next pages until nextPageToken is empty or not present.
This might just be an weirdness with the API.
We can't set pageToken to the event instance
Calendar.Events.List events = service.build().events().list(gCalId);
But when we try model Events instance, we able to set pageToken and got response too
com.google.api.services.calendar.model.Events events = service.build().events().list(gCalId).setPageToken(pageToken).execute();