Using send API of gupshup to reply to a user within 24 hrs shows an User not opted-in error - gupshup

I have my own bot running locally and have made it publicly accessible using ngrok
Trying to use the sandbox environment of gupshup to communicate with my bot.
Have hooked my bot using webhook (link your bot)
Have also created a BOT and configured the webhook as a callback POST to my ngrok server.
However when i try replying to a user supplied whats app message after say about 10 min using the Delayed response strategy i.e. by passing the contextobj and message via the send API (http://api.gupshup.io/sm/api/bot/{botname}/msg), I get an error stating "User Not Opted In".
Why isnt the user considered as an Active User since the messaging was initiated by the user and the send API is only replying to that message with 24 hrs ?
How do i simply give a delayed response to the user within 24hrs without forcing the user to opt-in ?

We do this all the time, however we are using the endpoint documented here:
https://www.gupshup.io/developer/docs/bot-platform/guide/whatsapp-api-documentation#OutboundMessage

You have to take the consent of user once before sending messages.
Also while using sandbox the user needs to opt in but for verified user it will be relaxed.
But still you will need to take consent of user at any place (your site, your terms and conditions or anywhere) before sending him anything for the record purposes so that they cannot claim that you are spamming them without consent.

Related

Check status after verification - Twilio Verify

I have a web app with following 3-step flow using Twilio Verify for email verification:
Creating verification code with Verify
Checking verification code with Verify
Create user account in my web api
After a successful Twilio Verify verification code check (step 2), I need to be able to do another Twilio Verfy call to ensure that the email was verified before a user account is actually created in my web api (step 3). But since the SID is deleted after successful email verification, I get following answer for a GET request to:
https://verify.twilio.com/v2/Services/{ServiceSid}/Verifications/{Sid}
{
"code": 20404,
"message": "The requested resource /Services/VAxxx/Verifications/VExxx was not found",
"more_info": "https://www.twilio.com/docs/errors/20404",
"status": 404
}
Now, for the Frontend, it's easy: I move to the final account creation step only if the email was verified successfully.
But, for a true stateless Backend, after accepting the Frontend request I first need to double-check with Twilio if the email was actually already verified.
True stateless in the sense that I do not want to store in a DB if an email was already verified or not. (This is already done by Twilio)
How can I do that? I didn't find the right API in the Twilio documetaion.
Twilio developer evangelist here.
I understand that you would like to get the information that appears available in the logs, however that is not available through the API. Once a verification has succeeded (or timed out after 10 minutes, or reached the maximum number of incorrect attempts) it is deleted and you can no longer access it through the API. I assume this is to prevent replay attacks, but I’m not on that team, so don’t know all the reasons behind it.
The result of this is that you cannot call on the verification check more than once from your code.
You will have to store the state within your own system because the API will not store that state for you. Much like during login with 2FA you would need to store the state that a password had been successfully entered.

How to get the Slack DM channel ID of the Slack App

I have created a simple Slack App app where the only purpose is to send a message to a channel. I understand that there is the conversations.list API to list all public channels to get the correct ID.
However, as a first step, I just want to send the message to the app channel itself. If I use the D... ID it works as expected. No invite by the channel is needed. But how do I get this ID? conversations.list only returns publich channels, but no the app channel itself.
In Slack, there is no such thing as an app's channel. There is a DM channel between every user and your app/bot. In these terms, to send a DM message from your app/bot to the user, you need to know ID of this user and specify it as a channel argument of the postMessage API request.
The ability to pass a Slack user ID as channel is somewhat unique to chat.postMessage. If you try this with other API methods which expect a channel ID only (conversations.info), you'll get "error": "channel_not_found". The docs state:
Begin a conversation in a user's App Home
Start a conversation with users in your App Home.
With the chat:write scope enabled, call chat.postMessage and pass a user's ID (U0G9QF9C6) as the value of channel to post to that user's App Home channel. You can use their direct message channel ID (as found with im.open, for instance) instead.
Source: https://api.slack.com/methods/chat.postMessage#app_home
Note: The above behavior assumes you're using the bot token. If you provide the user token instead, you'll make the user DM themselves.
Now, if you *do* need to get a user's App Home channel ID for use outside of chat.postMessage, keep reading... Here are three ways to do it, each with their own shortcomings:
1. chat.postMessage
Well, it's worth mentioning that if you are going to use chat.postMessage, it returns the resolved channel ID in its response: "channel": "D01234ABCDE". You can save this for later use.
2. conversations.open
The API method im.open referenced in the docs above has been renamed to conversations.open, which can be used to obtain the user's App Home channel ID:
Use the user token, and set users to the app bot ID, or
Use the bot token, and set users to the user ID.
Though, I've observed some weirdness with conversations.open, which may or may not be a dealbreaker for you:
It requires stronger OAuth permission scopes than ones required to initiate a private DM with a user than chat.postMessage (a bot token with chat:write is insufficient), and
It behaves strangely with respect to the "open state" of a conversation. For example...
I tested this method with a user token.
The user for that token already had a DM channel with the app! (Doesn't that mean the conversation is already open?)
Strangely, the first response had is_opened: false (and subsequent responses had is_opened: true).
3. app_home_opened
The event app_home_opened fires when the user opens your App Home. If you handle this event, you can save the channel in the event payload on your server and use it later, obviating the need to later call conversations.open.
Since the event only occurs if and when the user opens your app's App Home, this approach is more of an optimization than a standalone solution.
4. A better way...?
Due to the drawbacks outlines above, if anyone knows a better way of getting the App Home channel ID for a Slack user, please, comment on this answer!
You can get the channel ID of the app channel through the GUI if you:
navigate to a message in the channel
go to the more actions men
select copy link
The channel ID will be the string following archives/ eg:
{myorg}.slack.com/archives/{channel_ID}
Using this approach would work for any channel in the slack app, though it's unlikely to be the best approach since it's manual vs something more programmatic.

User shown opted in but messages failing due to 'not opted in'

I want to send Whatsapp transactional messages to users and for which I am opting in them via Gupshup's WhatsApp API. This is the API that I am using:
When I go to Opt In users screen, I am able to find users who have opted in via this API. Refer below image for it:
The issue is when I try to send messages to these users (opt-in via Upload), messages failed citing the reason that user is not opted in. Refer below image for it:
Users who have opted-in via API seem to have two different status at the same time and I am not able to find out why. Do you know what may be causing this strange issue?
If you are using sandbox, the you have to send PROXY appname, through your whatsapp.
But once when your app is live, user do not need to send this message, and you will be able to use the workflow you defined above.
Hope it helps!

How should Slack bot tokens be stored?

I'm building my first Slack bot and I've got the basics mostly working... sending API requests, receiving commands and events, etc. But the part I'm left a bit confused about is what I'm supposed to do with the "Bot User OAuth Access Token".
The token appears to be shared across teams/workspaces, but it is returned to be during authentication of individual users with a call to /oauth.v2.access. Currently I'm storing the returned credentials payload in a table that has three columns:
My app's internal user ID
The Slack user ID embedded in the payload as authed_user.id
The entire JSON payload itself (jsonb in postgres if you're curious)
This allows me to initiate new API calls for actions that take place in my app (find by internal user ID) and also for interactions within Slack (find by Slack user ID).
What has left me a bit puzzled is what the convention is for when a user interacts with my bot that hasn't added my app. This can happen when a person ("Jose") adds my app and then their colleague ("Mary") discovers it in Slack and views the home screen, sends it a message, etc.
In order to take some action, such as prompt for the user to install my app, I need a token. Of course I have a token for Jose but not for Mary. I also have Jose's team ID stored in my table and Mary's team ID as part of the incoming event. So technically I could do something like this to get a working token to interact with Mary:
select credential_json from slack_credentials
where credential_json->>'type' = 'bot' and credential_json->'team'->>'id' = :marysTeamId
... which would pull out the bot token I captured when Jose added the app. This works, but it feels very wrong. I suppose if I just stored bot tokens in a separate table that looked like this:
The Slack team ID embedded in the payload as team.id
A subset of the JSON payload (ex: access_token, scope, bot_user_id, etc but not authed_user)
Then it wouldn't feel so yucky. But the docs + API ergonomics don't suggest this is a common approach either. So I'm curious what others do. If I don't hear anything back, I suppose my plan is to break out the bot tokens into a team-centric table.
Thanks!
The basic concept of Slack apps is that they are installed per workspace, not per user.
So while it's true that the app's token is derived from the user who installed your app to a new workspace, most the apps function are available to all users of the workspace.
e.g. slash commands will work for every user in every channel
e.g. posts of your app will be visible to all users of the related channel.
Therefore the best approach for storing tokens usually is with a primary key of Slack Team ID, Slack User ID.
And just to clarify. You do not need a token to prompt a user to install you app. Every app can be installed from webpage hosted by you (with the "Add to Slack button") or directly from the App Directory.

Facebook OpenGraph API: Can I Silently Send a Request from One User to Another?

How do I send a facebook app requests from one mobile user to another using the Graph API?
I have looked at facebooks documentation but the only options I have found are to A) send an app to user message from the app (which I can't get working) or B) to use the request dialog, which doesn't seem to let me send a request to a single user.
FB has instructions for how to build a custom "Multi-Friend Selector" but apparently not for mobile.
I have tried using HTTP POSTing to
https://graph.facebook.com/%s?access_token= ...
with POST data set to
message='Test Message'
but I get
WWW-Authenticate: OAuth "Facebook Platform" "invalid_request" "(#2) Failed to create any app request"
I have also tried in the Graph API Explorer but I get the same thing.
I don't want to send these messages to users that have installed the app and I don't mind the user having to provide confirmation for the FBFrictionlessRecipientCache. Also, my app is in Sandbox mode, but I only need to send the requests to the other developers.
I am looking for anything that will let me do multi-friend selectors or ask for lives, or get help from a friend, like I see in several mobile games these days.
You can use presentRequestsDialogModallyWithSession from FBWebDialogs.
You must specify a "to" parameter to identify the recipient, and you must use the FBFrictionlessRecipientCache.
The "to" parameter identifies the recipient. It stops the select user dialog from appearing.
The first time you send the request to each recipient the user will have to grant permission. After that, the FBFrictionlessRecipientCache will allow the request to be sent relatively silently (a dialog pops up briefly and goes away by itself).

Resources