Multiple teams, outbound CID by country/area code

Hi,
New to the community, thanks for being lenient.

We’re working to move away from our current provider (justcall.io) and into freepbx. Due to integrations etc. all our numbers are on a pjsip with twilio (currently single SIP). I can’t find a definitive answer for our needs, I’d like your advise on how to approach the configuration.

I have 3 separate teams: recruiting, service support and Client Success. Each Team has at least 2 outbound CIDS: one for Canada, one for US. As we grow, it is possible more US local numbers are added. In our current solution, the user simply toggles between assigned outbound CIDs in their softphone. In FreePBX, since this does not seem possible, I was thinking to automate the outgoing routing based on area codes.

I searched this topic and the suggestion seems to be to use the settings at extension level (there’s no user group level and trunk levels does not seem to fit the need?).

Is there a way to effectively lump all US or Canadian area codes in fewer lines when setting CID field in pattern matching? Or I should go the database or custom code approach I’ve seen suggested?

In terms of trunks, you suggest me to split them by team (i.e. 3 trunks) or by number (i.e. currently 6)?

Does this approach makes sense to you?

If it matters, additional details:

  • inbound these are 3 ring groups with voicemail for each going to a virtual extension.
  • I considered setting up a single extension per group and be done but it does not seem elegant and I would lose control in terms of knowing who does what in the PBX.
  • we only use softphones on both desktop and mobile, no physical phones.
  • A solution where the user must add a number to chose route is not viable for us, it will mess with our click to call, CRM, etc.
  • I looked into the CallerID commerical module, I do not mind paying for it. But it doesn’t seem to be able to do what we need (it’s a hard route this prefix to that caller id, but doesn’t flex by user or extension or group). Unless I’m misreading the documentation.

Some custom dialplan.that does this

Thank you!

  • First off, stupid question: how does it work exactly? :grinning: I place this on /etc/asterisk/extensions_custom.conf and edit as needed, but then is this associated to all extensions? How would I instruct the PBX to for example use the [outbound-el-cid] vs [outbound-random-cid]?

  • if this impacts all extensions, how to I use the user/extension (or best, user group) into this? I.e. recruiting team will have different settings than service team.

  • For our user case I assume I will mainly focus on [outbound-el-cid] because matching alone will not work (i.e. currently one number for all US). is there a way besides wildcards to set OR options while writing a single exten line? It seems that Canadian extensions can’t really be easily segregated by first area code digit etc. So I can for example say 4XX and catch them all.

  • Does the PBX goes in order when processing line 57 - 58 ? Meaning, can I also add a (example) line 59 that works as catch all and route the calls with a specific CID if all above exten lines to not have a match? Eg. exten => XXX,1,Set(CALLERID(number)=9205553333)

In it’s current form, this dialplan would apply to all outbound calls from all extensions. It would need to be modified for your use case which is fairly complex.

If each user is a member of one and only one group, you could repurpose the extension’s accountcode field to indicate which custom dialplan to run.

Lines 57-58 are where the area codes start with only 2 examples. You can list as many or as few area codes as you want in this section using the same format and you can add a general case of _XXX. The way things are written, the lines are not executed in order, they will match more specific cases first and the more general cases last.

Yes, a team member can only be part of a single team. Will something like this work then to incorporate accountcode?

[custom-variables]
exten => s,1,Set(RecruitingCA=12345678911)   ; Canadian CID for Recruiting
exten => s,n,Set(RecruitingUS=98765432111)   ; US CID for Recruiting
exten => s,n,Set(SupportCA=9999999999)      ; Canadian CID for Support
exten => s,n,Set(SupportUS=8888888888)      ; US CID for Support
exten => s,n,Set(CSCA=7777777777)          ; Canadian CID for CS
exten => s,n,Set(CSUS=6666666666)          ; US CID for CS

[macro-dialout-trunk-predial-hook]
exten => s,1,NoOp(Entering user defined outbound macro)
exten => s,n,GotoIf($["${OUTBOUND_GROUP_ID}" != ""]?dialout-group-${OUTBOUND_GROUP_ID}-predial-hook,s,1)

; Ontario Area Codes
exten => _437XXXXXXXX,1,GotoIf($["${ACCOUNTCODE}" = "Recruiting"]?canadian_recruiting)
exten => _647XXXXXXXX,1,GotoIf($["${ACCOUNTCODE}" = "Recruiting"]?canadian_recruiting)
exten => _905XXXXXXXX,1,GotoIf($["${ACCOUNTCODE}" = "Recruiting"]?canadian_recruiting)
exten => _249XXXXXXXX,1,GotoIf($["${ACCOUNTCODE}" = "Recruiting"]?canadian_recruiting)
exten => _343XXXXXXXX,1,GotoIf($["${ACCOUNTCODE}" = "Recruiting"]?canadian_recruiting)
exten => _416XXXXXXXX,1,GotoIf($["${ACCOUNTCODE}" = "Recruiting"]?canadian_recruiting)
exten => _519XXXXXXXX,1,GotoIf($["${ACCOUNTCODE}" = "Recruiting"]?canadian_recruiting)
exten => _705XXXXXXXX,1,GotoIf($["${ACCOUNTCODE}" = "Recruiting"]?canadian_recruiting)
exten => _365XXXXXXXX,1,GotoIf($["${ACCOUNTCODE}" = "Recruiting"]?canadian_recruiting)
exten => _548XXXXXXXX,1,GotoIf($["${ACCOUNTCODE}" = "Recruiting"]?canadian_recruiting)
exten => _613XXXXXXXX,1,GotoIf($["${ACCOUNTCODE}" = "Recruiting"]?canadian_recruiting)
exten => _807XXXXXXXX,1,GotoIf($["${ACCOUNTCODE}" = "Recruiting"]?canadian_recruiting)
exten => _226XXXXXXXX,1,GotoIf($["${ACCOUNTCODE}" = "Recruiting"]?canadian_recruiting)
exten => _289XXXXXXXX,1,GotoIf($["${ACCOUNTCODE}" = "Recruiting"]?canadian_recruiting)
;...repeat for each Ontario Area Code and Support, CS

; Prince Edward Island Area Codes
exten => _902XXXXXXX,14,GotoIf($["${ACCOUNTCODE}" = "Recruiting"]?canadian_recruiting)
exten => _782XXXXXXX,14,GotoIf($["${ACCOUNTCODE}" = "Recruiting"]?canadian_recruiting)
exten => _902XXXXXXX,15,GotoIf($["${ACCOUNTCODE}" = "Support"]?canadian_support)
exten => _782XXXXXXX,15,GotoIf($["${ACCOUNTCODE}" = "Support"]?canadian_support)
exten => _902XXXXXXX,16,GotoIf($["${ACCOUNTCODE}" = "CS"]?canadian_cs)
exten => _782XXXXXXX,16,GotoIf($["${ACCOUNTCODE}" = "CS"]?canadian_cs)
;...will add Quebec and Saskatchewan below

; Set Canadian CID for each team
exten => s,n(canadian_recruiting),Set(CALLERID(number)=${RecruitingCA})
exten => s,n(canadian_support),Set(CALLERID(number)=${SupportCA})
exten => s,n(canadian_cs),Set(CALLERID(number)=${CSCA})
exten => s,n,Goto(default_cid)


; Default to US CID if not a Canadian call
exten => s,n(default_cid),GotoIf($["${ACCOUNTCODE}" = "Recruiting"]?us_recruiting) 
exten => s,n,GotoIf($["${ACCOUNTCODE}" = "Support"]?us_support)         
exten => s,n,GotoIf($["${ACCOUNTCODE}" = "CS"]?us_cs)       


; Set US CID for each team
exten => s,n(us_recruiting),Set(CALLERID(number)=${RecruitingUS})
exten => s,n(us_support),Set(CALLERID(number)=${SupportUS})
exten => s,n(us_cs),Set(CALLERID(number)=${CSUS})

Perhaps this is shorter with a canadian number flag:

[custom-variables]
exten => s,1,Set(RecruitingCA=11234567891)   ; Canadian CID for Recruiting
exten => s,n,Set(RecruitingUS=19876543211)   ; US CID for Recruiting
exten => s,n,Set(SupportCA=19999999999)      ; Canadian CID for Support
exten => s,n,Set(SupportUS=18888888888)      ; US CID for Support
exten => s,n,Set(CSCA=17777777777)          ; Canadian CID for CS
exten => s,n,Set(CSUS=16666666666)          ; US CID for CS

[macro-dialout-trunk-predial-hook]
exten => s,1,NoOp(Entering user defined outbound macro)
exten => s,n,GotoIf($["${OUTBOUND_GROUP_ID}" != ""]?dialout-group-${OUTBOUND_GROUP_ID}-predial-hook,s,1)

; Function to Check if a Number is Canadian
exten => s,n,Set(IsCanadian=0) ; Default to not Canadian
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "204"]?set_canadian:check_next_area_code) ; Manitoba
exten => s,n(check_next_area_code),GotoIf($["${OUTNUM:0:3}" = "226"]?set_canadian:check_next_area_code) ; Ontario
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "236"]?set_canadian:check_next_area_code) ; British Columbia
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "249"]?set_canadian:check_next_area_code) ; Ontario
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "250"]?set_canadian:check_next_area_code) ; British Columbia
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "289"]?set_canadian:check_next_area_code) ; Ontario
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "306"]?set_canadian:check_next_area_code) ; Saskatchewan
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "343"]?set_canadian:check_next_area_code) ; Ontario
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "365"]?set_canadian:check_next_area_code) ; Ontario
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "367"]?set_canadian:check_next_area_code) ; Quebec
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "387"]?set_canadian:check_next_area_code) ; Alberta
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "403"]?set_canadian:check_next_area_code) ; Alberta
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "416"]?set_canadian:check_next_area_code) ; Ontario
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "418"]?set_canadian:check_next_area_code) ; Quebec
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "431"]?set_canadian:check_next_area_code) ; Manitoba
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "437"]?set_canadian:check_next_area_code) ; Ontario
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "438"]?set_canadian:check_next_area_code) ; Quebec
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "450"]?set_canadian:check_next_area_code) ; Quebec
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "506"]?set_canadian:check_next_area_code) ; New Brunswick
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "514"]?set_canadian:check_next_area_code) ; Quebec
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "519"]?set_canadian:check_next_area_code) ; Ontario
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "548"]?set_canadian:check_next_area_code) ; Ontario
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "579"]?set_canadian:check_next_area_code) ; Quebec
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "581"]?set_canadian:check_next_area_code) ; Quebec
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "587"]?set_canadian:check_next_area_code) ; Alberta
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "604"]?set_canadian:check_next_area_code) ; British Columbia
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "613"]?set_canadian:check_next_area_code) ; Ontario
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "639"]?set_canadian:check_next_area_code) ; Saskatchewan
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "647"]?set_canadian:check_next_area_code) ; Ontario
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "705"]?set_canadian:check_next_area_code) ; Ontario
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "709"]?set_canadian:check_next_area_code) ; Newfoundland and Labrador
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "778"]?set_canadian:check_next_area_code) ; British Columbia
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "780"]?set_canadian:check_next_area_code) ; Alberta
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "782"]?set_canadian:check_next_area_code) ; Prince Edward Island
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "807"]?set_canadian:check_next_area_code) ; Ontario
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "819"]?set_canadian:check_next_area_code) ; Quebec
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "825"]?set_canadian:check_next_area_code) ; British Columbia
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "867"]?set_canadian:check_next_area_code) ; Yukon, Northwest Territories, Nunavut
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "873"]?set_canadian:check_next_area_code) ; Quebec
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "902"]?set_canadian:check_next_area_code) ; Nova Scotia
exten => s,n,GotoIf($["${OUTNUM:0:3}" = "905"]?set_canadian:default_cid) ; Ontario 

exten => s,n(set_canadian),Set(IsCanadian=1)
exten => s,n,Goto(default_cid)

; Default CID logic based on team and IsCanadian flag
exten => s,n(default_cid),GotoIf($["${ACCOUNTCODE}" = "Recruiting" & ${IsCanadian} = 1]?canadian_recruiting)
exten => s,n,GotoIf($["${ACCOUNTCODE}" = "Recruiting"]?us_recruiting) 

exten => s,n,GotoIf($["${ACCOUNTCODE}" = "Support" & ${IsCanadian} = 1]?canadian_support)
exten => s,n,GotoIf($["${ACCOUNTCODE}" = "Support"]?us_support) 

exten => s,n,GotoIf($["${ACCOUNTCODE}" = "CS" & ${IsCanadian} = 1]?canadian_cs)
exten => s,n,GotoIf($["${ACCOUNTCODE}" = "CS"]?us_cs) 

; Set the final CallerID based on team and country
exten => s,n(canadian_recruiting),Set(CALLERID(number)=${RecruitingCA})
exten => s,n(us_recruiting),Set(CALLERID(number)=${RecruitingUS})
exten => s,n(canadian_support),Set(CALLERID(number)=${SupportCA})
exten => s,n(us_support),Set(CALLERID(number)=${SupportUS})
exten => s,n(canadian_cs),Set(CALLERID(number)=${CSCA})
exten => s,n(us_cs),Set(CALLERID(number)=${CSUS})

edit: fixed few lines of code