What's wrong with my twilio function? (block phone numbers and play mp3 for blocked numbers)

95 views
Skip to first unread message

Clint Gorman

unread,
Mar 21, 2023, 5:30:47 PM3/21/23
to Twilio Functions
I've got a simple twilio function that blocks calls, plays an MP3 for blocked callers and should reject the blocked calls. 

The non-blocked callers are sent through to a twilio flow.

Here's the function:

exports.handler = function(context, event, callback) {
  // List all blocked phone numbers in quotes and E.164 formatting, separated by a comma
  let numberBlock = ["+19703163016"];
 
  if (numberBlock.indexOf(event.Caller) !== -1) {
    // Play an MP3 file to the blocked number and then reject the call
    const response = new Twilio.twiml.VoiceResponse();
    response.play('https://clickfuzz.com/misc/rejected.mp3');
    response.reject();
    callback(null, response);
  } else {
    // Allow the call to proceed for non-blocked numbers
    callback(null, {});
  }
};


But this function doesn't work. I've even added the mp3 response to the else {
and I don't hear the mp3 when calling. 

Here's my twilio flow:
Screen Shot 2023-03-21 at 10.23.13 PM.png

Any ideas why I don't hear the mp3 when calling from a blocked number?

Thanks!

vre...@gmail.com

unread,
Mar 21, 2023, 5:44:12 PM3/21/23
to Twilio Functions
I just tested your Function and seems to work fine. What do the Studio logs show? Also, what is the experience since it does not work, do you go to any of the 2 branches Success/Failed?

jassen

unread,
Mar 21, 2023, 5:54:51 PM3/21/23
to vre...@gmail.com, Twilio Functions
This group doesn't get very much traffic. Like it has maybe been a few years since a message. You should try over on stackoverflow.com

I think the reason your code isn't working is because callback(null, {}); doesn't produce a "fail". You need to return like a 404 or an error response from the function to trigger a fail. Now if we were on stackoverflow you might have given me some points for this :) Good luck!

--
You received this message because you are subscribed to the Google Groups "Twilio Functions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to twilio-functio...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/twilio-functions/3e5cfaaa-70b8-4d0d-8896-23e7200a1580n%40googlegroups.com.

Richard Rosen

unread,
Mar 21, 2023, 5:58:54 PM3/21/23
to jassen, Twilio Functions, vre...@gmail.com
Why play the MP3?  You pay for the usage. Just block the call. 



--
photograph
Rich Rosen
Fastcall CEO
email: ric...@fastcall.com
phone: +13237994777
Fastcall, 8033 Sunset Blvd Los Angeles CA 90046
 Native Phone and SMS in the Salesforce AppExchange

vre...@gmail.com

unread,
Mar 21, 2023, 6:09:29 PM3/21/23
to Twilio Functions
By the way, I see what you are doing wrong.

The Function itself (in isolation), would work if you pointed the incoming webhook of your number directly to it (i.e. it returns TwiML that the incoming webhook expects).

The issue is that you have it as part of a Studio Flow, so it won't work to return directly TwiML like that in the Function.

You need to return something from the Function, for example a boolean that indicates if the number is in the blocked block or not, and then branch accordingly in the Flow.

For example your Function could be:
exports.handler = function(context, event, callback) {
// List all blocked phone numbers in quotes and E.164 formatting, separated by a comma
let numberBlock = ["+121312321"];
isBlocked = (numberBlock.indexOf(event.Caller) !== -1) ? false : true
callback(null, {isBlocked: isBlocked})
}

And then your flow capture that outcome (of course you can handle the Fail outcome if something goes wrong in the Function)
Screenshot 2023-03-21 at 22.07.01.png

Richard Rosen

unread,
Mar 21, 2023, 6:16:26 PM3/21/23
to CL, Twilio Functions, jassen, vre...@gmail.com
"bots deregister my number"

I doubt that.

If fact, the opposite may happen.  the call is answered so the bots get excited. 



photograph
Rich Rosen
Fastcall CEO
email: ric...@fastcall.com
phone: +13237994777
Fastcall, 8033 Sunset Blvd Los Angeles CA 90046
 Native Phone and SMS in the Salesforce AppExchange


On Tue, Mar 21, 2023 at 3:05 PM CL <ma...@clintgorman.com> wrote:
I want the tone to play so the bots deregister my number. 

Does a tone play when only rejected? 

Even if I remove the mp3 section, I still don’t get rejected when calling from a blocked number. I always continue to the flow. 

vre...@gmail.com

unread,
Mar 21, 2023, 6:22:01 PM3/21/23
to Twilio Functions
By the way on my previous answer just write "true : false" instead of "false : true" in the condition and should be ok

vre...@gmail.com

unread,
Mar 21, 2023, 6:25:05 PM3/21/23
to Twilio Functions
(Just to clarify - and I will stop hammering with messages - I just reversed it to be more logical i.e. if the number is in the array, then return isBlocked = true etc. Then in the Studio flow, you say "if I found isBlocked = true" then do whatever you need to do for blocked numbers)

So Cat

unread,
Mar 21, 2023, 6:50:02 PM3/21/23
to CL, Twilio Functions
Hehe just had to switch off, pretty late in Europe :)

But will try it tomorrow.

Generally why not use a Subflow for this task? You can put all this logic in a subflow and call it from different flows (subflows generally are useful for repeatable task)

On Tue, 21 Mar 2023, 22:43 CL, <ma...@clintgorman.com> wrote:
Hammer away, thank you for all the responses! It’s hard to find twilio help, you’re great. 

My idea was to put the reject with the tone mp3 in the function so I don’t need to add the additional split and say/play widgets. 

Is that possible? I’ve got a lot of flows to add this to. 

I’m not at a computer to test this, I’m on Prague time. 

Clint Gorman

unread,
Mar 22, 2023, 4:39:01 AM3/22/23
to Twilio Functions
A subflow task. I didn't know that existed! 

I'll check it out and see if it works.

vre...@gmail.com

unread,
Mar 22, 2023, 4:40:50 AM3/22/23
to Twilio Functions

Clint Gorman

unread,
Mar 22, 2023, 5:11:00 AM3/22/23
to Twilio Functions
Putting together my subflow, how do we "reject" if blocked is true?

https://www.twilio.com/docs/voice/twiml/reject

"Using <Reject> as the first verb in your response
is the only way to prevent Twilio from answering a call.
Any other response will result in an answered call and
your account will be billed."

Why I wanted to use a 'number disconnected' call tone:

My thought here was that if we send the bot to a 'number disconnected' tone, the bot will parse the tone, understand it's disconnected and remove the number from a list because it thinks the number will never work and I will only be billed for playing the tone once.

if there is no tone and the flow only "rejects" - then the bot will try back using different phone numbers (I see spam bots call my number using different numbers all the time). and I'll get billed when it connects using a number not in my block list.

Can I assume that these bots parse tones?

Or should I just reject?

I could easily test this.



vre...@gmail.com

unread,
Mar 22, 2023, 5:30:56 AM3/22/23
to Twilio Functions
On the topic of how to stop the call in case isBlocked in True:

In the Split Widget you can simply address only the "if value equals false" case. Which means that when the execution arrives at the Split Widget, if isBlocked==True then it will terminate the call. of course you can add a <Play> widget if you wish to play that MP3 before terminating the call.

I am not sure if the call bots have that logic behind them - not saying that it does not make sense

vre...@gmail.com

unread,
Mar 22, 2023, 6:03:07 AM3/22/23
to Twilio Functions
I will do some extra tests, because I think that letting the call end, will still charge an amount, as opposed to using Reject.
It might be better to use TwiML Redirect in the beginning of the Flow, check and Reject in a Function and then if needed return the call back to Studio (i.e. if the number is not blocked).

I will come back with updates.

Clint Gorman

unread,
Mar 22, 2023, 6:11:53 AM3/22/23
to Twilio Functions
Ok, got it. 

Now i'm adding a subflow, how should I exit the subflow so the non-blocked call returns success and the non-blocked call returns failed? The idea is to not add a split widget after the subflow. It should sort blocked=failed and not-blocked=completed  inside the subflow

Screen Shot 2023-03-22 at 10.54.16 AM.png



Clint Gorman

unread,
Mar 22, 2023, 6:16:33 AM3/22/23
to Twilio Functions
Ok cool! 

it would be great if either a function (best) or subflow would test the blocked callers and reject the call (twilio will not charge only if first verb is <reject>). So the actual function or subflow won't let callers through. No need for split after.

Then the non-blocked would only proceed to the parent flow. 

vre...@gmail.com

unread,
Mar 22, 2023, 6:53:14 AM3/22/23
to Twilio Functions
Ok so here are my latest tests:

The Function now looks like this:

exports.handler = async function(context, event, callback) {

console.log(event.FlowSid + event.ExecutionSid)

const twiml = new Twilio.twiml.VoiceResponse();
const numberBlock = [context.PHONE_NUMBER]; // I added the phone number as env variable to be easier to test by changing it, otherwise need to re-build the function
isBlocked = (numberBlock.indexOf(event.Caller) !== -1) ? true : false

if(isBlocked){
twiml.reject()
console.log("reject")
const client = context.getTwilioClient()
await client.studio.v2.flows(event.FlowSid)
.executions(event.ExecutionSid)
.update({status: 'ended'})
}
else{
twiml.say("returning to Studio")
const STUDIO_URL =
`https://webhooks.twilio.com/v1/Accounts/${context.ACCOUNT_SID}/Flows/${event.FlowSid}?FlowEvent=return`
twiml.redirect(STUDIO_URL)
console.log("return")
}
return callback(null, twiml)
}

Important parts:
- We pass in both FlowSid and Execution Sid (apart from the Caller). FlowSid is used in both rejection and non-rejection.
ExecutionSid is used in order to terminate the flow execution when we reject the call (otherwise the Flow will hang/keep running)

- If number is blocked we reject the call and terminate the flow execution. This uses the Execution API. Note:
---> It's async operation. So I have made the whole function "async" so I can use "await" to wait for the API to finish. You can use whatever async method you want
---> I use getTwilioClient() to initialise the client itself

- If the number is not blocked, we need to return to Studio as per this:
So we construct the URL of Studio. I prefer to do it dynamically because then you can apply this Function to any flow, without having to mess with env variables

============================================================

So now, all you need in your Studio Flow is a Twiml Redirect widget
The URL that this widget will point , is the Function URL, along with passing the parameters you need, for example:
https://xxxxxx.twil.io/blocked-nums?Caller={{trigger.call.From}}&FlowSid={{flow.flow_sid}}&ExecutionSid={{flow.sid}}

Screenshot 2023-03-22 at 10.49.23 (2).png

So the Function will hit the "Return" branch if and only if the call is not rejected.

Which means that perhaps you can avoid building a subflow, because it's again only 1 widget that you would be adding to your multiple flows (unless you want the subflow to do even more things)

vre...@gmail.com

unread,
Mar 22, 2023, 6:53:43 AM3/22/23
to Twilio Functions
With the above also, if you see the logs you will see the blocked calls have no charge i.e. it will show "0 seconds"

vre...@gmail.com

unread,
Mar 22, 2023, 6:55:12 AM3/22/23
to Twilio Functions
Ah, and if you try this, under "Dependencies" make sure to add the latest version of "twilio" library. The Studio v2 API is newer, so if you have an old library it might not recognise the "executions" endpoint
Reply all
Reply to author
Forward
Message has been deleted
Message has been deleted
Message has been deleted
0 new messages