Send multiple messages with telegram and webhook - telegram-bot

I set a webhook with telegram and basically use this code to send messages to telegram from my server:
header("Content-Type: application/json");
$parameters = array('chat_id' => xxx, "text" => "hi there");
$parameters["method"] = "sendMessage";
echo json_encode($parameters);
and this all works.
The problem is that I can't send two messages one after the other.
I tried echoing two times:
header("Content-Type: application/json");
$parameters = array('chat_id' => xxx, "text" => "hi there");
$parameters["method"] = "sendMessage";
echo json_encode($parameters);
$parameters["text"] = "hi everybody";
echo json_encode($parameters);
and I tried sending an array of messages:
header("Content-Type: application/json");
$parameters = array('chat_id' => xxx, "text" => array("hi there", "hi everybody"));
$parameters["method"] = "sendMessage";
echo json_encode($parameters);
both with no success.
What am I doing wrong??

I had the same issue and managed to get an answer from Telegram support. Their response:
"No, only one single method can be called when answering to a webhook request, sorry."
The workaround for me was to simply use regular API requests. You can make multiple requests from your code before (or even instead of) outputting the webhook response.
https://core.telegram.org/bots/api#making-requests

Related

Client credentials invalid error for external API authentication, when credentials are correct in Processmaker

I am trying to obtain the authentication token from the Processmaker to use the APIs. I have used the same API call which works perfectly fine in the test environment, with production urls and respective client id and client secret. But, I am getting below error, although the username and password of the account is correct.
Request:
{
"grant_type": "password",
"scope": "*",
"client_id": "xxxxxx",
"client_secret":"7777777",
"username": "username",
"password": "password"
}
Response:
{
"error": "invalid_client",
"error_description": "The client credentials are invalid"
}
I have tried below steps. But still the same error.
Create a new account without AD user account as the account used in test environment is not a domain account
Change the role of account to 'System Administrator' which is similar to the account in test
**While registering the client to use the APIs, we didn't use the Callback URL as it is optional (we did not configure it in the test environment as well)
Some help is really appreciated, as I have no clue what else to check between the environment to resolve this issue.
I am not sure if you are trying to call API from ProcessMaker to RPA or RPA to ProcessMaker.
For ProcessMaker to RPA:
Using Script: I have built a ProcessMaker script in PHP and with appropriate script configuration, you will be able to run the RPA bot from ProcessMaker.
<?php
/*
* Yo. This script is developed by Abhishek Kadam.
* This script is sufficient to run all the Microbots.
* The Script Configuration contains "release_key" which is the Process ID,
* "robot_id" which is to identify where to run the Bot, "orch_unit_id" which is the folder name
* and "orch_url" which stands for Orchestrator URL. To Run the bot, All the configurations are required.
*/
//******ASSIGNING VARIABLES*****
$client_id = $config['client_id']; // $config to get data from Script Configuration
$refresh_token = $config['refresh_token'];
$release_key = $config['release_key'];
$robot_id = $config['robot_id'];
$orch_url = $config['orch_url'];
$orch_unit_id = $config["orch_unit_id"];
//****** GET ACCESS TOKENS USING CLIENT ID AND REFRESH TOKENS******
$access_token = getAccessToken($client_id,$refresh_token);
$output_response = runBot($access_token,$release_key,$robot_id,$orch_url,$orch_unit_id);
//pass the Access token to runbot() and run the bot ez-pz!
function getAccessToken($client_id,$refresh_token){
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://account.uipath.com/oauth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS =>"{\r\n \"grant_type\": \"refresh_token\",\r\n \"client_id\": \"".$client_id."\",\r\n \"refresh_token\": \"".$refresh_token."\"\r\n}",
CURLOPT_HTTPHEADER => array(
"Content-Type: application/json"
),
));
$response = curl_exec($curl);
curl_close($curl);
$responseDecode = json_decode($response);
$accessToken= $responseDecode -> access_token; //get the access token
return $accessToken;
}
function runBot($access_token,$release_key,$robot_id,$orch_url,$orch_unit_id){
$curl = curl_init(); //Not sure if it's the right way to initialize or not but meh, it works :P
curl_setopt_array($curl, array(
CURLOPT_URL => $orch_url."/odata/Jobs/UiPath.Server.Configuration.OData.StartJobs",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS =>"{ \"startInfo\":\r\n { \"ReleaseKey\": \"".$release_key."\",\r\n \"Strategy\": \"Specific\",\r\n \"RobotIds\": [ ".$robot_id."],\r\n \"JobsCount\": 0,\r\n \"Source\": \"Manual\" \r\n } \r\n}",
// Release key and Robot ID can be concatenated and passed as an argument(once I figure out how to get arguments in PM 4 scripts)
CURLOPT_HTTPHEADER => array(
"Content-Type: application/json",
"Authorization: Bearer ".$access_token,
"X-UIPATH-OrganizationUnitId: ".$orch_unit_id
//There's another way to use the Access token. For now, I found this more helpful.
//As the document is TL;DR. https://www.php.net/manual/en/function.curl-setopt.php
),
));
$response = curl_exec($curl);
curl_close($curl);
return $response;
//echo $response; //Print Response cuz why not? ;)
}
return [$access_token];
?>
I had used the UiPath RPA tool for this without mentioning any callback URL.
Using Data Connectors: Create Data Connectors in ProcessMaker. I prefer to using the Postman application before creating DC. Refer: Postman to UiPath Bot
For RPA Bot to ProcessMaker
In ProcessMaker documentation you can see the Swagger Link for your particular instance. The Swagger Documentation for ProcessMaker was not really helpful. There are few mistakes in the documentation provided.
For ease, I did import the API collection in Postman and proceeded with creating variables: baseURL & accessToken
baseURL: Your URL (https://something.processmaker.net)
ADD /api/1.0
/api/1.0 (https://something.processmaker.net/api/1.0)
Now the URL is correct. Also while sending the request make sure Params are not empty.
Note: For Access Token, Admin --> Users --> Edit --> API Tokens --> Create new Token --> Copy Token.
In Processmaker 4, API tokens are available for individual Users.
I hope this will help you in a way. Thanks!

Telegram Bot gets "Bad Request: message text is empty"

When my Telegram bot sends sendMessage to Telegram server it gets the error message:
{"ok":false,"error_code":400,"description":"Bad Request: message text is empty"}
The problem appeared this morning, before that my bot worked a whole year without errors. GetUpdates command works well as before. I use GET HTTP method to send commads:
https://api.telegram.org/bot<MyToken>/sendMessage
with UTF-8-encoded data attached:
{"chat_id":123456789,"text":"any text"}
Has anyone encountered this?
If the issue still persists, try to modify your curl request. For me adding header
'Content-Type: application/json' and -d '{"chat_id":12309832,"text":"any text"}' fixed issue
Another way to send a message by emulating a form :
curl -s -X POST https://api.telegram.org/bot{apitoken}/sendMessage \
-F chat_id='-1234567890' -F text='test message'
Well, i wrote wrapper on C language to communicate via SSL with telegram bot api. SO now I can clearly answer questions about telegram API spec.
Problem number one
First of all if we are talking about raw queries we need to remember about specifications.
By default HTTP/HTTPS post requests should consists of:
<METHOD>[space]<PATH with only valid chars> <\r\n>
<HOST valid regexed\r\n>
<Content-type valid regexed><\r\n>
<Content-Length with length of your POST body data><\r\n>
<\r\n before body>
<body>
So, i tried to send raw queries with out Content-Length and i had error same as yours. That's the first problem.
Problem number two
By default if you trying to send non valid request with sendMessage method - telegram bot api will response with error same as yours. So, yeah, that's pretty tricky error to debug...
If you trying to send raw query, be sure that your JSON data is serialized nicely and there is no errors like shielding.
Summarizing
Request:
POST /bot<token>/sendMessage HTTP/1.1
Host: api.telegram.org:443
Connection: close
Content-Type: application/json
Content-Length: 36
{"chat_id":<integer>, "text":"test \\lol"}
Second backslash if shielding.
Code on C
sprintf(reqeustCtx.request,
"POST /bot%s/%s HTTP/1.1\r\n"
"Host: %s\r\n"
"Connection: close\r\n"
"Content-Type: application/json\r\n"
"Content-Length: %d\r\n"
"\r\n"
"%s\r\n", bot_token, bot_method,
reqeustCtx.res_addr, strlen(body), body);
BIO_puts(bio, reqeustCtx.request);
BIO_flush(bio);
memset(reqeustCtx.response, '\0', BUFFSIZE);
read_bytes = BIO_read(bio, reqeustCtx.response, BUFFSIZE);
if (read_bytes <= 0) {
printf("No response");
exit(-1);
}
cert_free(cert_store, ssl_ctx, ca_cert_bio);
// free memory //
reqeustCtx.method(reqeustCtx.res_addr, reqeustCtx.request,
reqeustCtx.current_work_dir, reqeustCtx.current_cert);
/* json response, need to parse */
return reqeustCtx.response;
I got this error too.
I used sendMessage() method only with "low-level" Node https:
const https = require('https');
const data = JSON.stringify({
chat_id: config.telegram.chatId,
text: 'some ASCII text'),
});
const options = {
hostname: 'api.telegram.org',
port: 443,
path: `/bot${config.telegram.botToken}/sendMessage`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
};
const req = https.request(options, (res) => {
let chunks = [];
res.on('data', chunk => chunks.push(chunk));
res.on('end', () => {
const resBody = Buffer.concat(chunks).toString('utf8');
if (res.statusCode === 200) {
console.log(`Message sent`);
} else {
console.error(`${res.statusCode} ${res.statusMessage} ${res.headers['content-type']}
${resBody}`)
}
});
});
req.on('error', (error) => {
reject(error)
});
req.write(data);
req.end();
And for ASCII text it was ok, however for some non-ASCII text I got:
const data = JSON.stringify({
chat_id: config.telegram.chatId,
text: 'Привет Мир!'),
});
Error:
400 Bad Request application/json
{"ok":false,"error_code":400,"description":"Bad Request: message text is empty"}
In my case content length was calculated with invalid length 'Content-Length': data.length (invalid for Telegram?...), so I comment out this header and now it works for UTF-8!
headers: {
'Content-Type': 'application/json',
//'Content-Length': data.length
}
In my case, I was using curl_setopt($this->curl, CURLOPT_POSTFIELDS, json_encode($fields)); to post this json via sendMessage method:
{
"chat_id":000000000,
"text":"Choose one of the following options: ",
"reply_to_message_id":292,
"reply_markup":{
"keyboard":[
[
"Enable",
"Disable"
]
]
}
}
The problem was that when passing fields to the curl_setopt method, I was encoding the whole php array so I solved it by just encoding the reply_markup array which was a part of my json.
Try to put "Message" object with chat_id & text to HttpEntity in your restTemplate service, like below:
public MessageDto sendMessage(Message message) {
return restTemeplate.exchange(
"https://api.telegram.org/bot{token}/sendMessage",
HttpMethod.POST,
new HttpEntity<>(message, HttpHeaders.EMPTY),
MessageDto.class
).getBody();
}

Jawbone UP API oAuth and Access Tokens

I have started digging into Jawbone's UP API today and everything seems to go fine throughout the authentication process. The problem is that, once I get an access token back, it's always the same token, it doesn't work in any of my requests, and I can't change it with the refresh_token endpoint.
oAuth setup:
$url_params = array(
'response_type' => 'code',
'client_id' => CLIENT_ID,
'scope' => array('basic_read', 'extended_read', 'move_read'),
'redirect_uri' => 'https://my-site.com/up_auth.php',
);
These are the parameters attached to the https://jawbone.com/auth/oauth2/auth URL and I get sent to Jawbone and prompted as expected. When I accept the authorization I get kicked back to my-site.com as expected with the code in the URL. I then use the code like so
$params = array(
'client_id' => CLIENT_ID,
'client_secret' => APP_SECRET,
'grant_type' => 'authorization_code',
'code' => $code,
);
And attach those parameters to https://jawbone.com/auth/oauth2/token and finally get kicked back to my server with something similar to:
{
"access_token": "REALLY_LONG_STRING",
"token_type": "Bearer",
"expires_in": 31536000,
"refresh_token": "ANOTHER_REALLY_LONG_STRING"
}
When I use access_token to try and get a response like this
$headers = array(
'Host: my-site.rhcloud.com',
'Connection: Keep-Alive',
'Accept: application/json',
"Authorization: Bearer {$_REQUEST['access_token']}",
);
$ch = curl_init('https://jawbone.com/nudge/api/v.1.1/users/#me/moves');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$o = curl_exec($ch);
curl_close($ch);
var_dump($o);
from the API, this is the response every time:
{
"meta": {
"code": 401,
"error_detail": "You must be logged in to perform that action",
"error_type": "authentication_error",
"message": "Unauthorized"
},
"data": {
}
}
The token never changes, even in a private browsing session, and even if I successfully refresh using the provided refresh_token and the proper API call - the call succeeds, but Jawbone gives me back the same token. If I test the same flow through the Jawbone API Console, the Bearer token in the request headers is different from the one I get here. Note that I get the same access_token when I attempt the same process with my wife's Jawbone credentials as well.
Finally figured out what was going on and heard back from Jawbone about it. It turns out that they have collisions on the backend if you use the same auth with two different clients.
For anyone else that runs into this problem, don't use the same login in two different contexts simultaneously as it will reset auths in weird ways.
In our case, we have test user accounts that are often shared between devs since it is sometimes hard to get real data unless you have the actual device. This was causing 'duplicate' logins that made Jawbone code freak out.
We got confirmation from a Jawbone dev who ran into the same problem when developing an internal app.....

Apple Push notification script not working

I am using this php script but its producing output Message successfully delivered but not sending notification. i have already check device id and certificates they are perfect and working fine with another script.
<?php
// Put your device token here (without spaces):
$deviceToken = 'fbf04bf4ace2f1e823016082da3a798cf3ab666ae99a395b65e364eb4c6d6d4a';
// Put your private key's passphrase here:
$passphrase = '123';
// Put your alert message here:
$message = 'A push notification has been sent!';
////////////////////////////////////////////////////////////////////////////////
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'key.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
// Open a connection to the APNS server
$fp = stream_socket_client('ssl://gateway.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp)
exit("Failed to connect: $err $errstr" . PHP_EOL);
echo 'Connected to APNS' . PHP_EOL;
// Create the payload body
$body['aps'] = array('alert' => array('body' => $message, 'action-loc-key' => 'Look', ), 'badge' => 2, 'sound' => 'oven.caf', );
// Encode the payload as JSON
$payload = json_encode($body);
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));
echo "<pre>Result : ";
print_r($result);
if (!$result)
echo 'Message not delivered' . PHP_EOL;
else
echo 'Message successfully delivered' . PHP_EOL;
// Close the connection to the server
fclose($fp);
?>
Can any one help me to getting out of this.?
Thanks in advance
I encounter similar problem when i first start iOS push notifications
There Will be possibility that you are doing a development push rather than a production push
Change the server to ssl://gateway.sandbox.push.apple.com:2195 and use your development push notification key to give a try.
That solves my problem
I think you have to change port number
You code: ssl://gateway.push.apple.com:2195. 2195 use for sandbox and 2196 use for live.
Can you please change it and try.
Hope this work.

CapsuleCRM API ColdFusion Wrapper

Looking for a ColdFusion version of the following PHP API wrapper for CapsuleCRM:
<?php
// The data you want to send to Capsule CRM in xml format
// SEE http://capsulecrm.com/help/page/javelin_api_party
I'm understanding that this variable contains the XML string...
$myxml="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n
<person>\n
<title>Mr</title>\n
<firstName>Test12</firstName>\n
<lastName>Tester12</lastName>\n
<jobTitle>Chairman</jobTitle>\n
<organisationName>Big Company</organisationName>\n
<about>Testing</about>\n
</person>";
// The URL to connect with (note the /api/ that's needed and note it's person rather than party)
// SEE: http://capsulecrm.com/help/page/api_gettingstarted/
$capsulepage = 'https://sample.capsulecrm.com/api/person';
However, I don't know how to initiate cURL in ColdFusion.
// Initialise the session and return a cURL handle to pass to other cURL functions.
$ch = curl_init($capsulepage);
What does the 'curl_setopt_array' function do exactly? Is there a CF equivalent?
// set appropriate options NB these are the minimum necessary to achieve a post with a useful response
// ...can and should add more in a real application such as
// timeout CURLOPT_CONNECTTIMEOUT
// and useragent CURLOPT_USERAGENT
// replace 1234567890123456789 with your own API token from your user preferences page
$options = array(CURLOPT_USERPWD => '1234567890123456789:x',
CURLOPT_HTTPHEADER => array('Content-Type: text/xml'),
CURLOPT_HEADER => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $myxml
);
curl_setopt_array($ch, $options);
// Do the POST and collect the response for future printing etc then close the session
$response = curl_exec($ch);
$responseInfo = curl_getinfo($ch);
curl_close($ch);
?>
I could be wrong, but that looks like a basic http post. The equivalent in CF is cfhttp. To pass parameters/headers (ie curl_setopt_array) use cfhttpparam.