twilio / twilio-node

Node.js helper library
MIT License
1.4k stars 511 forks source link

Twilio.sendMessage, price in response data is null #45

Closed Bossa573 closed 10 years ago

Bossa573 commented 10 years ago

I used Twilio.sendMessage to send SMS:

Twilio.sendMessage({to: to, from: from, body: message   }, function(err, responseData) {
   console.log(responseData);
};

Here is the sample of the responseData: (some fields are masked)

{ sid: 'xxx',
  date_created: 'Tue, 20 May 2014 04:34:22 +0000',
  date_updated: 'Tue, 20 May 2014 04:34:22 +0000',
  date_sent: null,
  account_sid: 'xxx',
  to: 'xxx',
  from: 'xxx',
  body: 'xxx',
  status: 'queued',
  num_segments: '1',
  num_media: '0',
  direction: 'outbound-api',
  api_version: '2010-04-01',
  price: null,
  price_unit: 'USD',
  uri: '/2010-04-01/Accounts/xxx/Messages/xxx.json',
  subresource_uris: { media: '/2010-04-01/Accounts/xxx/Messages/xxx/Media.json' },
  dateCreated: Tue May 20 2014 12:34:22 GMT+0800 (HKT),
  dateUpdated: Tue May 20 2014 12:34:22 GMT+0800 (HKT),
  dateSent: null,
  accountSid: 'xxx',
  numSegments: '1',
  numMedia: '0',
  apiVersion: '2010-04-01',
  priceUnit: 'USD',
  subresourceUris: { media: '/2010-04-01/Accounts/xxx/Messages/xxx/Media.json' } }

and the field price become null

kwhinnery commented 10 years ago

Hi there - thanks for using Twilio! Hope you're liking it so far. This behavior is actually expected, but I can see how it is confusing at first blush. I'll try to explain a little bit:

In the response you get back from the Twilio API immediately after creating a new message (which is what sendMessage does), the price field will be null initially. That is because the first thing Twilio will do with your message is queue it for delivery (note the value of the status field in the response, which initially reads "queued"). So since the message has not yet been delivered, it does not yet have a price associated with it.

A few moments later, when the message is delivered, the price field for the message will be populated. If you make a REST API request with the message SID in the initial response, you can get those further details. Where Twilio is what you called your authenticated twilio.RestClient, that code would look like:

Twilio.messages('the message SID').get(function(err, message) {
    console.log('Current delivery status: ' + message.status);
    console.log('Message price, if delivered: ' + message.price);
});

Alternately, you can choose to be notified via webhook when the message has been delivered. When you send the message, you can specify a status callback URL to a server you control. This endpoint will receive an HTTP request when the message status has been changed:

Twilio.sendMessage({
    to: to, 
    from: from, 
    body: message,
    statusCallback: 'http://www.yourserver.com/status'
}, function(err, responseData) {
   console.log(responseData);
};

If you have further questions, please send a note to help@twilio.com and we'd be happy to help further. I'm happy to answer questions on GitHub, but since we usually only use Github Issues for library bugs and dev tasks, you won't get help as quickly as you might from our crack support squad.

Thanks, -Kevin

euskode commented 10 years ago

It is worth noting that Kevin's status callback reference is not entirely of relevance, given that the price itself is nowhere to be found in the webhook request's body, so one is left with no choice but to query for the price regardless of webhook, which in my opinion is excessively cumbersome.

kwhinnery commented 10 years ago

I can see how you might want/expect all the data for a given message resource (including price) to be POSTed to your status callback webhook. I can definitely pass along this feedback.

Unfortunately, you will need to use the REST API to obtain that information when a status callback webhook request is received. In this instance, the status callback is useful only as a mechanism for letting the developer know when the additional information might be available via a GET. This would be preferable to, say, polling the Twilio API on an interval to see when the message price data has been updated.

euskode commented 10 years ago

I actually have found a few instances where querying immediately after the message has been 'sent' (as per the webhook request from Twilio) still results in a null price, so I am just waiting 3 seconds and querying then. I think getting the price in the POST would be an awesome improvement, especially if you guys have that information handy at that point anyway.

Mamonaku commented 7 years ago

This thread was closed long ago, I'm not sure it makes sense to add a comment now, but just in case.

The fact that costs are nowhere to be found, unless specific request is made to twillio, is a huge impediment to apps targeting small businesses, where costs are consolidated on a per user basis. In other words, from a development standpoint, it is impossible to cap the amount spent by a user, or to provide a reliable price indication (unless cumbersome and very-very ugly code), when he sends SMS to his clients.

I understand that Twilio targets big fish, but there are also smaller businesses who'd love to enjoy the same tools to communicate with their customers.

In the US, small businesses employ 53 percent of the workforce, and 99% of employing organisations are small businesses.

Just in case.

kevinburke commented 7 years ago

@mamonaku there's a new pricing API that you can use to get a message's price ahead of time: https://www.twilio.com/docs/api/pricing

if you want, you can make requests to the pricing API for each phone number you could send from ahead of time, and store all of those prices in a map.

Bossa573 commented 7 years ago

In fact until today, from time to time we got some rare cases that Twilio sent the SMS successfully, but the Twilio never charge us, and from the log, the cost is zero.

image

We confirmed with Twilio support team multiple times (years ago) and apparently those cases due to issue on carrier side. (those SMSs are sent successfully)

We used the SMS cost returned by Twilio API to charge the customer so it had raised some issues for such behavior but eventually we solved by some workaround.

Mamonaku commented 7 years ago

Hi there, just some thoughts,

@kevinburke, I understand that this is the only way around, but to me this is highly inefficient and worst, extremely fragile code. Furthermore, with this approach, there is no way to implement a robust billing reconciliation mechanism.

@Bossa573 precisely what I mentioned above, this is the result of no proper implementation of a billing end-point. Out of curiosity, what was the work around?

@twilio Just to say that calling the pricing api on each individual sms to eventually get the total amount charged, is simply twilio pushing the consequence of some bad api design back on to their users.

There's a callback function, twilio should use it, at the very least to send a charging event so we can keep track of what was charged, and what wasn't.

Mamonaku commented 7 years ago

@kevinburke also, considering the prices and map stuff; the map is unfortunately inadequate, because prices depend on the local operator, ex Austria:

Austria AUSTRIA Outbound SMS - T-Mobile 0.09317 Austria AUSTRIA Outbound SMS - Tele2 0.0932 Austria AUSTRIA Outbound SMS - UPC 0.09317

or SG

SINGAPORE Outbound SMS - M1 0.03 SINGAPORE Outbound SMS - Other 0.03 SINGAPORE Outbound SMS - SingTel 0.05 SINGAPORE Outbound SMS - StarHub 0.03

So you have to call the sms API for ALL phone numbers. This adds 0.5 seconds computation time on the back end, at a minimum.

Why is it so difficult for twilio to send a charging event when they know the price? It's common practice in telecoms, everyone does that.

Bossa573 commented 7 years ago

@Mamonaku our situation is first we send the sms, the API response does not include the cost. At the same moment if I make another api call to get the message by SID, the cost is null.

So I try to store a document in the db, together with all the info I need and the SID, and there are 2 ways:

  1. a worker to query these documents and query Twilio API to try to retrieve the cost, if the cost is returned or from the status we know there's no further status update (e.g. the cost is null but the status is sending error), then we know we can process and delete the document.

  2. get the response from Twilio webhook (didn't try that though) and process, concept is the same.

So by either way, eventually you'll find some documents stucked in the database (that Twilio never return any price, and the status is NOT error), so you may want to do auto clean mechanism from time to time, e.g. if you find there's no update after several hours or days, then proceed to next step (your business logic, or delete the document)

kevinburke commented 7 years ago

I'm guessing there are some situations where Twilio does not charge you for the message because it could not be delivered and that's why they don't return the price up front. If they did you could end up with extra charges in the database that you didn't end up getting charged for.

I'd suggest passing a message callback that Twilio will hit when the message is delivered or fails to be.

On Thu, Apr 6, 2017 at 22:02 Bossa notifications@github.com wrote:

@Mamonaku https://github.com/Mamonaku our situation is first we send the sms, the API response does not include the cost. At the same moment if I make another api call to get the message by SID, the cost is null.

So I try to store a document in the db, together with all the info I need and the SID, and there are 2 ways:

1.

a worker to query these documents and query Twilio API to try to retrieve the cost, if the cost is returned or from the status we know there's no further status update (e.g. the cost is null but the status is sending error), then we know we can process and delete the document. 2.

get the response from Twilio webhook (didn't try that though) and process, concept is the same.

So by either way, eventually you'll find some documents stucked in the database (that Twilio never return any price, and the status is NOT error), so you may want to do auto clean mechanism from time to time, e.g. if you find there's no update after several hours or days, then proceed to next step (your business logic, or delete the document)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/twilio/twilio-node/issues/45#issuecomment-292439764, or mute the thread https://github.com/notifications/unsubscribe-auth/AAOSIyBMqzM0nIWBaaGiTZbw-kTKVOlkks5rtcOBgaJpZM4B8ZeG .

--

-- Kevin Burke 925.271.7005 | kev.inburke.com

Bossa573 commented 7 years ago

@kevinburke nope, confirmed with Twilio support with so many emails and some of those cases are indeed sent out successfully with zero cost.

From Twilio support apparently it's because for those particular SMSs, carrier didn't charge Twilio, so Twilio was unable to return a cost to me.

Anyway that's what happen back to 2014, not sure if it's the exactly same case right now.

Mamonaku commented 7 years ago

@Bossa573 I understand you were doing your best to compensate from twilio billing API, but this is very fragile code, the type of which I'm not necessarily happy to use.

also, 'get the response from Twilio webhook '=> twilio doesn't send any price info via the web hook, what I was saying is that it should do that. As a matter of fact, I called

Twilio.messages('the message SID').get(function(err, message) {
    console.log('Current delivery status: ' + message.status);
    console.log('Message price, if delivered: ' + message.price);
});

... after receiving the 'delivered' event. But even this didn't give me the price. Looks like the api has changed so you have to send a vanilla http GET request. Anyway, the cost that it returned was specific to the end operator and could not be deduced from a mapping country => price. In essence, @kevinburke suggestion while attractive, is incorrect.

Conclusion: This API is for big business looking to reach out to their customers (Airlines, Walmart etc..) because the billing information doesn't need to be consolidated or reconciled. But it requires (too?) excessive dev efforts for developers who want to target small businesses.

I'm going for FB messenger.

Bossa573 commented 7 years ago

@Mamonaku yea sure i have to say the solution is kinda hacky and seems like a temp workaround, and seems it's difficult to change on my side.

avisiboni commented 6 years ago

HI, Same issue here, i'm using the status callback to my web API but the only thing that i got is the message id and the new status, but the price never came, not in the immediately response and not in the status callback webhook

any help will appreciate Thanks.

adrianbj commented 4 years ago

In my case at least, I am seeing that at the time the delivery callback is made, the cost is still not populated in the Twilio log, but at some point (maybe minutes or hours - not sure yet), it does get populated, but of course it's a bit late then because by that point there is no callback to trigger my API request to get the cost.

I just submitted a support ticket to see if we can get some action on this, because this is really a big problem!

FYI - I know this issue is on the "node" repo, but it's not language specific.

adrianbj commented 4 years ago

Just to follow up, from the time of delivery, it took about 2-3 minutes for the cost to be shown in the log entry. Is this an issue with certain carriers, or is this normal? It would be really useful to enable a callback when the cost is available so we don't have to make a scheduled request at a later time when we think it will be available.

adrianbj commented 4 years ago

Just heard back on the support ticket and was told that it can take up to 24 hours for the price to be available and that a daily cronjob is really the only option for getting the price for messages.

redochka commented 1 year ago

becareful when you fetch the message details, you will find that the price is negative...

price=-0.00790
priceUnit=USD,

Another strange thing with their api...

Abdurrehman404 commented 3 weeks ago

Thread started in 2014 and still Twilio havn't provided us any sort of event based call backs. Initial implementation might be easy but its a cheap way to vendor lock. My app handles thousands of messages on daily basis and i still cannot get the exact cost. For every thousand messages i have to call the Twilio server just to get the cost. Definitely poor API design.