Telegram Bot gets "Bad Request: message text is empty" - telegram-bot

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();
}

Related

Request body missing from POST requests made using Postman scripting

I am trying to run a pre-request script for authenticating all my requests to the Spotify API. It works via the Postman GUI, but when I try to make the request via scripting, it fails because there is no body. Here is my code
const postRequest = {
url: pm.environment.get("spotifyAuthApi"),
method: "POST",
header: {
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "*/*",
"Content-Length": 29,
"Authorization": "Basic " + btoa(pm.environment.get("client_id") + pm.environment.get("client_secret"))
},
body: {
grant_type: "client_credentials",
}
}
I get a
error: "unsupported_grant_type"
error_description: "grant_type parameter is missing"
And when I examine the request via the postman console, there is no request body, even though the request was built exactly like my fetch token request that does the same thing successfully in postman, only via the GUI instead of via a pre-request script. I have searched far and wide about this issue and tried multiple variations of the body object but to no avail. Either the body object doesn't generate my desired field, or it doesn't get created at all.
Mode might be missing in the body object. Try this:
body: {
mode: 'raw',
raw: JSON.stringify({ grant_type: 'client_credentials' })
}
More details might be found in Postman docs for RequestBody.
If you're using urlencoded, the body of the request would be structured like this:
body: {
mode: 'urlencoded',
urlencoded: [
{ key: 'grant_type', value: 'client_credentials'}
]
}

Bandcamp api: What POST info do you send, when querying the my_bands endpoint?

https://bandcamp.com/developer/account#my_bands
It doesnt say what youre sposta send, as POST, and if you send without a POST or empty array, you get a 'must be POST' error. Their support isnt helping.
I have been able to use their other endpoints, so I know I've got the auth correct.
I send an empty payload to https://bandcamp.com/api/account/1/my_bands, like:
var parameters = {
headers: { Authorization: 'Bearer '+access_token },
method: 'post',
payload: '',
muteHttpExceptions: true // we want to handle exceptions gracefully
};

Curl command works, but httparty request gives 403

I have a curl command that makes a POST request, and returns with the correct response:
curl --data 'apiKey=someKey&apiSecureKey=someSecureKey&apiFunctionName=update&apiFunctionParams={"id”:”777”,”user_password":"password","invalid_login_attempts":"0","active_flag":"1"}' https://api-server.com/api-path/file.php
Also, when using Postman, the request works if I check the "form-data" button and paste the same four parameters that are in the curl command above into the body of the Postman request. If I check the "x-www-form-urlencoded" button in Postman, I get a 403 response (see below), so that makes me think it is a header issue.
I need to duplicate this request using httparty. Here is my attempt:
options = {
body: {
apiKey: 'someKey',
apiSecureKey: 'someSecureKey',
apiFunctionName: 'update',
apiFunctionParams: '{"id”:”777”,”user_password":"password","invalid_login_attempts":"0","active_flag":"1"}',
}
}
response = HTTParty.post("https://api-server.com/api-path/file.php", options)
This request gives me a 403 repsonse code:
{"success":false,"response":"403","responseDesc":"Forbidden. Request is missing an API permission code.","params":{"id":"777","user_password":"password","invalid_login_attempts":"0","active_flag":"1"}}
If I try to add a header, such as:
options = {
headers: {'Content-Type' => 'multipart/form-data'},
body: {
apiKey: '20a030e47a28',
apiSecureKey: '3a4e409e0c9f0e72e697fc288a88d751',
apiFunctionName: 'update',
apiFunctionParams: '{"id":"603","user_password":"password","invalid_login_attempts":"0","active_flag":"1"}',
}
response = HTTParty.post("https://beta.fxptouch.com/classes/interface/user_profile.php", options)
I get a nil response.

POST command to WebCeo API

Trying to connect to this WebCEO API.
function getProjects() {
var payload = {
"key": "CUSTOMER_KEY",
"method": "get_projects"
};
payload = JSON.stringify(payload);
var url = "https://online.webceo.com/api/";
var options = {
"method": 'POST',
"contentType" : "application/json",
"payload": payload
};
var response = UrlFetchApp.fetch(url, options);
}
Receiving "Request failed for https://online.webceo.com/api/ returned code 404".
Any hint on what else I need to include / change?
Body must contain the following:
json={"key": "YOUR_API_KEY", "method": "get_projects"}
Well, https://online.webceo.com/api/ does return a 404 when you just try to access it. Did you manage to get that page to not return a 404 error from another client?
Doing so will probably tell you what you're missing here.
However, I'd suspect their API might be having issues.
That's true, you don't make a GET request. You have to send parameters in the body of a POST request. Below is an example in CURL for a situation when you need to get the list of projects:
curl -X POST -d 'json={"key": "YOUR_API_KEY", "method": "get_projects" }' https://online.webceo.com/api/

Using Pastebin API in Node.js

I've been trying to post a paste to Pastebin in Node.js, but it appears that I'm doing it wrong.
I'm getting a Bad API request, invalid api_option, however I'm clearly setting the api_option to paste like the documentation asks for.
var http = require('http');
var qs = require('qs');
var query = qs.stringify({
api_option: 'paste',
api_dev_key: 'xxxxxxxxxxxx',
api_paste_code: 'Awesome paste content',
api_paste_name: 'Awesome paste name',
api_paste_private: 1,
api_paste_expire_date: '1D'
});
var req = http.request({
host: 'pastebin.com',
port: 80,
path: '/api/api_post.php',
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
'Content-Length': query.length
}
}, function(res) {
var data = '';
res.on('data', function(chunk) {
data += chunk;
});
res.on('end', function() {
console.log(data);
});
});
req.write(query);
req.end();
console.log(query) confirms that the string is well encoded and that api_option is there and set to paste.
Now, I've been searching forever on possible causes. I also tried setting the encoding on the write req.write(query, 'utf8') because the Pastebin API mentions that the POST must be UTF-8 encoded. I rewrote the thing over and over and re-consulted the Node HTTP documentation many times.
I'm pretty sure I completely missed something here, because I don't see how this could fail. Does anyone have an idea of what I have done wrong?
What you're creating isn't a properly-formed multipart/form-data request; it looks more like an application/x-www-form-urlencoded request. From what I can tell about pastebin's API (I've never actually used it) the latter is what you really want, so try changing the Content-Type to it.
It does not answer directly your question but maybe it could help...
Have you try to use the request module ?
Your example would be much easier to read and you might find the problem...
mikeal/request