cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
7168
Views
46
Helpful
13
Replies

UCCX CallBack Script

Matthew Martin
Level 5
Level 5

Hello All,

I'm working on a CallBack option for customer's who don't want to wait on hold. Basically, holding their place in the queue for the next available agent. I'm using the example found at the link below. But, have a few questions regarding the example.

https://www.cisco.com/c/en/us/support/docs/contact-center/unified-contact-center-express/214522-configure-custom-script-for-callback-fea.html 

I'm sort of ignoring the Leave a Message portion, as we already have something like that setup to send a caller to voicemail.

After the caller is Queued and the caller presses the 1 key, I send the caller to the portion of the script for the Call Back steps. Right now, I am able to successfully prompt the user for a call back number, which I then capture and read back to the caller to confirm. If the number is good, then a Terminate step.

Then, what I believe you're supposed to do is run a Place Call step to a new Script/Application containing a simple icd script with a Select Resource step. The Place Call step also has a Get Digit String (*under the Successful branch of Place Call) which waits for an Agent's input (*with a press one option to be connected).

This Place Call step hits the Unsuccessful branch. The example from the URL above just says to have the 2nd script's trigger to be a part of a different Call Control Group then the original script the caller was queued in. But, does that Call Control Group need to be a "outbound" Group Type for this to work? I don't appear to have that option when creating a new Call Control Group, so I assume we're not licensed for this. But, I did read something about Direct Preview Outbound, which doesn't require an extra license.

I have the MIVR logs from one of these test calls if needed. This is the first time we're trying anything outbound from UCCX so I'm not sure what's required.

 

Thanks in Advance,

Matt

1 Accepted Solution

Accepted Solutions

EDIT: I edited this post like 10 times to keep tweaking it.  Sorry about that.

 

First off, you cannot save the caller's position in queue with UCCX callback.  It's unfortunate, but it's just not possible right now.

For script 2, all you really need is this:

Example: Bare Bones

Script 2

 

 

Start
Accept (--Triggering Contact--)
Select Resource (--Triggering Contact--, "YourCSQName")
  Connected
    End
  Queued
    Delay 43200 sec
End

 

 

Notice that I prevent a loop from happening in the Queued branch by using a 12 hour delay.  12 Hours being the CUCM default setting for maximum call duration, at which point CUCM will drop the call.

You cannot avoid looping in Script 1 however, because it basically needs to poll something to understand when it can move to the next step, e.g., connecting to the caller.  However, care should still be taken here, because too long of a call with too quick of a loop cycle will start failing your calls, and callers will never get a callback.

As an aide in slowing down the loop cycle, you can manipulate the prompt which plays in the Get Digit String step to be longer, repeat it self, and/or mix in a Delay Prompt (E.g., dp[5000]) to create some space between playouts.

Example: Repeating Prompt 10 Times

Script 1 (cb is a Prompt variable)

 

 

contact = Place Call (to "1234")
  Successful
    Wait For Agent:
    CED = Get Digit String (contact, cb + cb + cb + cb + cb + cb + cb + cb + cb +cb)
        Timeout
            Goto Wait For Agent

 

EDIT: 2020-12-16 - Added Wait For Agent label.  Thank you Jim-J for bringing this to my attention.

Example: Adding a Delay Based on EWT Then Repeat

Script 1

 

 

contact = Place Call (to "1234")
  Successful
    Wait For Agent:
    ewt = Get Reporting Statistics (contact, Expected Wait Time)
    CED = Get Digit String (contact, dp[ewt * 1000] + cb + cb + cb + cb + cb + cb + cb + cb + cb +cb)
      Timeout
        Goto Wait For Agent

 

 

Back to Script 2 though, the way I showed it, it will statically assign the target CSQ every time.  This may or may not work for you.  It typically needs dynamic assignment in my experience.  In which case, the Contact created in Script 1, is actually the same Contact as --Triggering Contact-- in Script 2.  This is convenient, because it allows you to Set Enterprise Call Info for the Contact in Script 1, while you can then Get Enterprise Call Info in Script 2.  E.g. Pass the target CSQ name from one script to the other.

Just be careful about creating a race condition here.  That is when Script 2 thinks it's able to read the value of the CSQ too soon, but Script 1 hasn't finished writing it yet.  So, you can either just delay a little at the start of Script 2, just after Accept, or you can write a small polling interval loop, checking if the CSQ has been set yet.

Example: Delay Based Approach

Script 1

 

 

contact = Place Call (to "1234")
  Successful
    Set Enterprise Call Info (contact) Variables Used:csq
    ...

 

 

Script 2

 

 

Start
Accept (--Triggering Contact--)
Delay 5 sec
csq = Get Enterprise Call Info (--Triggering Contact--, "csq", --Scalar--, -- All --)
Select Resource (--Triggering Contact--, csq)
  Connected
    End
  Queued
    Delay 43200 sec
End

 

 

Example: Polling Based Approach

Script 1

 

 

contact = Place Call (to "1234")
  Successful
    Set Enterprise Call Info (contact) Variables Used:csq
    ...

 

 

Script 2

 

 

Start
Accept (--Triggering Contact--)
Check for CSQ:
csq = Get Enterprise Call Info (--Triggering Contact--, "csq", --Scalar--, -- All --)
If (csq == null || csq.isEmpty()) Then
  True
    Delay 5 sec
    Goto Check for CSQ
  False
Select Resource (--Triggering Contact--, csq)
  Connected
    End
  Queued
    Delay 43200 sec
End

 

 

In some cases, like even in yours, the Agent might connect to Script 1 (the pretend caller) and be at a point in the Get Digit String step where the Agent hears silence for a while.  In which case, you might employee the following strategy, though it's a trade off in that you'll loop more often.

Example: Agent Answer Detection

Script 1

 

 

contact = Place Call (to "1234")
  Successful
    Set Enterprise Call Info (contact) Variables Used:csq
    Goto Wait for Agent
  /* ...other outcomes handled here... */
Wait For Agent:
is_answered = Get Enterprise Call Info (contact, "is_answered", --Scalar--, -- All --)
If (! is_answered) Then
  True
    Delay 10 sec
    Goto Wait For Agent
  False
Interact With Agent:
/* ...do and say what you want to the Agent, you have them on the line... */

 

 

Script 2

 

 

Start
Accept (--Triggering Contact--)
Delay 5 sec
Select Resource (--Triggering Contact--, csq)
  Connected
    Set Enterprise Call Info (--Triggering Contact--) Variables used:is_answered
    End
  Queued
    Delay 43200 sec
End

 

 

 

View solution in original post

13 Replies 13

It's been a bit since I played with it, but no the CCG is just like just first CCG it doesn't have to be outbound. You're not really doing traditional outbound aka dialer. You're actually having the agent make an outbound call as if there were to pick up the phone an dial it manually.

 

david

Not only is it just like the first CCG, you do not need a second CCG. I have many Callbacks deployed in the field, none of which use a separate CCG. I have yet to read a justification for this, and I think it's just a misunderstanding. Anyway, if the Place Call is going to Unsuccessful, it's probably that the value for the CCG in the step doesn't match your actual CCG ID. This can happen especially if you downloaded a sample script where the value was already populated.

Hey, thanks for the replies.

*See screenshot below of CallBack portion from Script 1...

Ok, so I figured out the issue where the Place Call step was hitting the Unsuccessful branch. The CSS used by the CTI Route Point did not contain the Partition used by the CTI Port. So I added that Partition to the CSS and Place Call now hits Successful.

If I then take an Agent that has the Skills needed in Script 1, and make them go Ready, that Agent rings and is now at the Get Digit String step under the Label WaitForAgentCallBack. The Get Digit String step just asks the Agent to press any number to be connected to the Customer. This is now working to call the customer.

But, if I wait more then just a couple of seconds to make the Agent go Ready, the Get Digit String step times-out almost immediately when the Agent picks up. However, if as soon as the script hits Get Digit String I make the Agent go Ready, they ring and can hear the Prompt from Get Digit String except for the first couple of words, which makes me think this step is already playing a prompt before any Agent is available...

 

Lastly, I'm a little confused about the purpose of Script 2, which is the Trigger that the Place Call step is dialing. What is the purpose of Script 2? I see in the URL example from my OP, it says Script 2 should just have an Accept Step + a Select Resource step. Since Script 1 is where we're waiting for an Agent to become available, I'm not sure what to do in Script 2...

 

CallBack_Steps.png

 

Thanks Again,

Matt

"...which makes me think this step is already playing a prompt before any Agent is available..."

That's exactly how that works.  It's blindly just looping a prompt saying "press any key to continue" because there's no intelligence to know when you have the human on the line.

 

So, for callback, UCCX must call itself.  Script 1 is like the customer calling in, and Script 2 is like your queuing logic to route the call to the next available Agent.  Think of Script 1 as a person and Script 2 as a traditional script you write to handle calls.  Only, since it's a robot calling you, you don't need the pleasantries normally used like "Thank you for calling..." and "Please hold for the next available..."  I mean, who am I to say you don't need that.  Go ahead and tell it a story for all I care.  Maybe UCCX has feelings?

Hey Anthony, thanks for the reply. Very much appreciated.

Ok, I'll add GoTos within the Enter Digit String step for the Unsuccessful and Timeout branches to restart that step. That makes sense, thank you.

As for Script 2... And this might be a personal preference, but maybe there's Pros to doing it a certain way. But, in Script 1 there are already Select Resource steps that have been queued up to the caller. So if I wanted to keep those same resources available to this caller, would I just use some bogus CSQ (*or if the CSQ needs to exist to not get errors, create a CSQ that has no Agents assigned to it) in order to just use those original Agent Resources from Script 1? Assuming this would preserve the caller's spot in the Queue.

Or, if we decide we want a separate skill to answer these calls, I'm guessing I would just Dequeue the caller from those already selected resources, and then use a new CallBack_CSQ containing separate skills in Script 2.Does that sound correct?

 

Thanks Again for the reply!

-Matt

EDIT: I edited this post like 10 times to keep tweaking it.  Sorry about that.

 

First off, you cannot save the caller's position in queue with UCCX callback.  It's unfortunate, but it's just not possible right now.

For script 2, all you really need is this:

Example: Bare Bones

Script 2

 

 

Start
Accept (--Triggering Contact--)
Select Resource (--Triggering Contact--, "YourCSQName")
  Connected
    End
  Queued
    Delay 43200 sec
End

 

 

Notice that I prevent a loop from happening in the Queued branch by using a 12 hour delay.  12 Hours being the CUCM default setting for maximum call duration, at which point CUCM will drop the call.

You cannot avoid looping in Script 1 however, because it basically needs to poll something to understand when it can move to the next step, e.g., connecting to the caller.  However, care should still be taken here, because too long of a call with too quick of a loop cycle will start failing your calls, and callers will never get a callback.

As an aide in slowing down the loop cycle, you can manipulate the prompt which plays in the Get Digit String step to be longer, repeat it self, and/or mix in a Delay Prompt (E.g., dp[5000]) to create some space between playouts.

Example: Repeating Prompt 10 Times

Script 1 (cb is a Prompt variable)

 

 

contact = Place Call (to "1234")
  Successful
    Wait For Agent:
    CED = Get Digit String (contact, cb + cb + cb + cb + cb + cb + cb + cb + cb +cb)
        Timeout
            Goto Wait For Agent

 

EDIT: 2020-12-16 - Added Wait For Agent label.  Thank you Jim-J for bringing this to my attention.

Example: Adding a Delay Based on EWT Then Repeat

Script 1

 

 

contact = Place Call (to "1234")
  Successful
    Wait For Agent:
    ewt = Get Reporting Statistics (contact, Expected Wait Time)
    CED = Get Digit String (contact, dp[ewt * 1000] + cb + cb + cb + cb + cb + cb + cb + cb + cb +cb)
      Timeout
        Goto Wait For Agent

 

 

Back to Script 2 though, the way I showed it, it will statically assign the target CSQ every time.  This may or may not work for you.  It typically needs dynamic assignment in my experience.  In which case, the Contact created in Script 1, is actually the same Contact as --Triggering Contact-- in Script 2.  This is convenient, because it allows you to Set Enterprise Call Info for the Contact in Script 1, while you can then Get Enterprise Call Info in Script 2.  E.g. Pass the target CSQ name from one script to the other.

Just be careful about creating a race condition here.  That is when Script 2 thinks it's able to read the value of the CSQ too soon, but Script 1 hasn't finished writing it yet.  So, you can either just delay a little at the start of Script 2, just after Accept, or you can write a small polling interval loop, checking if the CSQ has been set yet.

Example: Delay Based Approach

Script 1

 

 

contact = Place Call (to "1234")
  Successful
    Set Enterprise Call Info (contact) Variables Used:csq
    ...

 

 

Script 2

 

 

Start
Accept (--Triggering Contact--)
Delay 5 sec
csq = Get Enterprise Call Info (--Triggering Contact--, "csq", --Scalar--, -- All --)
Select Resource (--Triggering Contact--, csq)
  Connected
    End
  Queued
    Delay 43200 sec
End

 

 

Example: Polling Based Approach

Script 1

 

 

contact = Place Call (to "1234")
  Successful
    Set Enterprise Call Info (contact) Variables Used:csq
    ...

 

 

Script 2

 

 

Start
Accept (--Triggering Contact--)
Check for CSQ:
csq = Get Enterprise Call Info (--Triggering Contact--, "csq", --Scalar--, -- All --)
If (csq == null || csq.isEmpty()) Then
  True
    Delay 5 sec
    Goto Check for CSQ
  False
Select Resource (--Triggering Contact--, csq)
  Connected
    End
  Queued
    Delay 43200 sec
End

 

 

In some cases, like even in yours, the Agent might connect to Script 1 (the pretend caller) and be at a point in the Get Digit String step where the Agent hears silence for a while.  In which case, you might employee the following strategy, though it's a trade off in that you'll loop more often.

Example: Agent Answer Detection

Script 1

 

 

contact = Place Call (to "1234")
  Successful
    Set Enterprise Call Info (contact) Variables Used:csq
    Goto Wait for Agent
  /* ...other outcomes handled here... */
Wait For Agent:
is_answered = Get Enterprise Call Info (contact, "is_answered", --Scalar--, -- All --)
If (! is_answered) Then
  True
    Delay 10 sec
    Goto Wait For Agent
  False
Interact With Agent:
/* ...do and say what you want to the Agent, you have them on the line... */

 

 

Script 2

 

 

Start
Accept (--Triggering Contact--)
Delay 5 sec
Select Resource (--Triggering Contact--, csq)
  Connected
    Set Enterprise Call Info (--Triggering Contact--) Variables used:is_answered
    End
  Queued
    Delay 43200 sec
End

 

 

 

Thanks for the very detailed explanation. Very much appreciated!

Was able to get it working. But, will use some of your tweaks about the looping to fine tune it.

Thanks Again,
Matt

You're welcome. I'm glad you were able to make improvements to your solution.

@Anthony Holloway Thanks for sharing this super detailed and helpful post!

In "Script 1 (cb is a Prompt variable)" I assume there's supposed to be a "Wait For Agent" label right after "Successful"?

You nailed it Jim! I just edited my post to reflect the label.  Thanks for the compliments too!

Hi @Anthony Holloway. Hope you are doing good. sorry to get the conversation started like this, I have been trying to get the callback script working but the callback only works internally. when it comes to 10 digit it gives me an error message with automated voice "The system is having problems" and hangs up. I have attached the screenshot of the setup. Our prefix dialing is with #. Please reply with any resolution. Thank you!!

 

 

 

VinayKumarJalalpuram5336_0-1728411782966.png

 

Anthony Holloway
Cisco Employee
Cisco Employee

@VinayKumarJalalpuram5336 

I'm pretty sure you cannot redirect to any phone number beginning with a * or #.  Check the doc excerpt here:

Screenshot 2024-10-08 at 4.01.08 PM.png

 

Source https://developer.cisco.com/docs/contact-center-express/call-redirect-step/#call-redirect-step

@Anthony Holloway Thanks for the reply. our prefix starts with #, so I added it there. before that I tried not to use the # but still gave me the same error. I was testing In jabber as it makes a call without using #. Call goes to the agent. Agent presses 1 to route the call, but it directly goes to unsuccessful and ends it giving the automated error message that the system is having problems. 

is there anything I can change? Been trying for a long time but getting the same error. Also I'm using the same CCG for both triggers