Voximplant. Blog

Rapid callback app development

Callback scheme

One of the most popular telephony scenarios is a callback, in this scenario VoxImplant makes 2 calls (to phone number, SIP or SDK) and connects them with each other. Scenario execution can be controlled via HTTP API, developer can invoke functions remotely or make HTTP requests right from the scenario itself. Check this step-by-step tutorial to build your callback app.
First of all, you need to get a VoxImplant developer account. It’s free, just visit https://voximplant.com/sign-up/ and submit the registration form. After you get the account and activate it you can login into VoxImplant control panel at https://manage.voximplant.com/#login , it provides convenient web interface that lets developers control apps and users, write and debug scenarios, check call history and make payments, get API access info, etc. After you log in you will see the following interface:
VoxImplant Control Panel
For our callback application we will need to create VoxImplant application, scenario and application rule to connect our scenario to the application. In the end we will make HTTP-request to start the session (scenario). After the HTTP-request, if everything was done right, we will receive media_session_access_url, which will let control the session remotely using RPC mechanism. For example, if we need to stop the scenario execution we can write the following code in our VoxEngine scenario:

  1. VoxEngine.addEventListener(AppEvents.HttpRequest, handleHttpRequest);
  2. function handleHttpRequest(e) {
  3. VoxEngine.terminate();
  4. }

If you have this code in your scenario then after HTTP-request to media_session_access_url the session will be terminated. But let’s return to our callback application. First, create the app in Applications section of the control panel, let’s call it callback (full name will be callback.youraccountname.voximplant.com) and in the Scenarios section we create a new scenario with the following code:

  1. var call1, call2, data;
  2.  
  3. VoxEngine.addEventListener(AppEvents.Started, handleScenarioStart);
  4.  
  5. function handleScenarioStart(e) {
  6. // Data can be passed to scenario using customData
  7. // script_custom_data param in StartScenarios HTTP request will be available to scenario as customData
  8. // in this scenario we will pass number1:number2 string via script_custom_data
  9. data = VoxEngine.customData();
  10. data = data.split(":");
  11. // start scenario - calling number 1
  12. call1 = VoxEngine.callPSTN(data[0]);
  13. // assign event handlers
  14. call1.addEventListener(CallEvents.Connected, handleCall1Connected);
  15. call1.addEventListener(CallEvents.Failed, function(e) { VoxEngine.terminate(); });
  16. call1.addEventListener(CallEvents.Disconnected, function(e) { VoxEngine.terminate(); });
  17. }
  18.  
  19. function handleCall1Connected(e) {
  20. // first call connected successfully, play message
  21. call1.say("Hi, this call is from callback service, please wait", Language.US_ENGLISH_FEMALE);
  22. call1.addEventListener(CallEvents.PlaybackFinished, function(e1) {
  23. // after message played - calling number 2
  24. call2 = VoxEngine.callPSTN(data[1]);
  25. // assign event handlers
  26. call2.addEventListener(CallEvents.Connected, handleCall2Connected);
  27. call2.addEventListener(CallEvents.Failed, function(e2) {
  28. call1.say("Unfortunately, the connection can't be established", Language.US_ENGLISH_FEMALE);
  29. call1.addEventListener(CallEvents.PlaybackFinished, function(e3) {
  30. VoxEngine.terminate();
  31. });
  32. });
  33. call2.addEventListener(CallEvents.Disconnected, function(e2) {
  34. VoxEngine.terminate();
  35. });
  36. });
  37. }
  38.  
  39. function handleCall2Connected(e) {
  40. // connect two calls with each other - media
  41. VoxEngine.sendMediaBetween(call1, call2);
  42. // and signalling
  43. VoxEngine.easyProcess(call1, call2);
  44. }

This scenario makes calls to phone numbers we will pass using script_custom_data param of the StartScenarios in the following format – phonenumber1:phonenumber2. First, scenario calls phonenumber1 and then plays a message using Text-to-speech, then it calls phonenumber2 and connects two calls with each other. We don’t handle some events, like call failure, for example, if we can’t establish connection with phonenumber1 we just terminate the session (stop scenario execution). If we add some additional logic we can notify outer world about the issue, let’s change

call1.addEventListener(CallEvents.Failed, function(e) { VoxEngine.terminate(); });

to

call1.addEventListener(CallEvents.Failed, handleCall1Failed);

and then add handleCall1Failed description:

  1. function handleCall1Failed(e) {
  2. // failure reason available here
  3. var code = e.code,
  4. reason = e.reason;
  5. // we can send it to outer world using HTTP request
  6. Net.httpRequest("http://somewebservice", function(e1) {
  7. // HTTP request info - e1.code, e1.text, e1.data, e1.headers
  8. // terminate session
  9. VoxEngine.terminate();
  10. });
  11. }

This example shows simple HTTP-request (GET method). HTTP-request parameters (method, headers, etc.) can be customized using HttpRequestOptions.

After our scenario is ready we need to save it using some name, let’s say Callback, and go to Applications section of the Control Panel, where we can connect scenario to the application using Rule and get Rule id – it will be used for HTTP-request to launch the scenario (StartScenarios):

1. Start editing the application
2. Open Rules tab
3. Click Add rule button
4. Specify the name for the rule (let’s say Callback) and use drag’n’drop to put Callback scenario from Available to Assigned scenarios column.

VoxImplant Application Rule

Created rule will appear in the Rules list and its ID should be visible now – we will need this ID for our HTTP-request.

VoxImplant Application Rules

5. Save the app by clicking the Save button in General tab.

That’s it! Now we can make StartScenarios HTTP-request (we will need some additional params for it, including the api_key you can get in API Access section of the Control Panel):

https://api.voximplant.com/platform_api/StartScenarios/?account_id=1&api_key=eec36d6c-a0eb-46b5-a006-1c2b65343bac&rule_id=67462&script_custom_data=number1%3Anumber2

Just replace the params (account_id, api_key, rule_id, number1 and number2) with your data and, if everything was done correctly, you will see the result of the request:

  1. {
  2. "result" : 1,
  3. "media_session_access_url" : "http:\/\/1.2.3.4:12092\/request?id=93e41c6e20811b9b.1380201554.0@1.2.3.4&token=36bc7ce95edc679e32d83bb6f3ad985f"
  4. }

This media_session_access_url can be used for communication with the session (RPC). You can always check logs in Calls section of the Control Panel (arrow in the top right corner) or use our cloud debugger. The text of the scenario is available at our GitHub account:

VoxImplant Callback Scenario at GitHub

Tagged in , , , , ,

Comments

  • acheshkov

    great, i like it

  • acheshkov

    Can we start scenario from HTTP POST and get post data by VoxEngine.CustomData() ?

  • deniska

    I get the restrictions of this callback scenario. Second call to second subscriber have to be from initiator caller_id. But I can’t change the string
    call2 = VoxEngine.callPSTN(data[1]);
    to the string with caller_id
    call2 = VoxEngine.callPSTN(data[1],data[0]);
    because caller_id have to be string from registred user and I can’t add variety parameter….
    But if you call to SUBSCRIBER_B via CALLBACK service usually SUBSCRIBER_B have to see normal call from SUBSCRIBER_A, ! But in your service subscriber_B saw UNKNOWN MOSCOW NUMBER and HE may hang up the phone.

    • Alexey Aylarov

      This function can be enabled by request, since callPSTN has 2nd parameter – caller id.

      • deniska

        I know about caller_id parameter. But according to your rule it doesn’t work if caller_id is different from the static registred phones. As I understand you can switch this function on by request?

        • Alexey Aylarov

          Yes, you will need to sign the agreement to use this functionality.

          • deniska

            I understand. Thank you.

  • deniska

    I test your callback example. After split two incoming callback calls it charging independently. it charging like two outgoing calls……. Why you can split also charging for callback by some special rules to one or made one of the callback call chipper?

  • deniska

    what for we need accountcallback types here http://voximplant.com/docs/references/httpapi/AccountCallback.html ?
    So every accounts in array have its own balance and etc.
    And the question.
    1) How to add independent account via interface for every callback subscriber?
    2) Is it possible to make full functuanality commercial callback service via your site for any user with his own accounts and with possibility to add money to his account via some paidcard?
    How we will plan to devide revenue between site and owner of the script if it will be many callback subscribers?

  • creciun.work

    День добрый!
    В CallList есть возможность отправить результат работы, посредством ф-ций CallList.reportError / CallList.reportResult.

    А как можно отправлять при создании обычного звонка (коллбэка), а не из списка?
    Парсить логи не очень хочется.

    • Alexey Aylarov

      Если я правильно вас понял, то вам нужна эта функция http://voximplant.com/docs/references/appengine/Net.html#Net_httpRequest

      • creciun.work

        Насколько я понимаю эта ф-ция позволяет отправить запрос на наш сервер.
        Что тоже не самая лучшая идея (а что будет если сервер будет недоступен?)

        Хотелось бы видеть результат работы обращаясь к GetCallHistory.
        Ну или к какой-нибудь аналогичной ф-ции.

        • Alexey Aylarov
          • creciun.work

            Как вариант годится, но тогда не хватает данных для поиска конкретного звонка.

            Я сохранял в customData ID звонка в нашей БД и затем использовал для быстрого поиска конкретного звонка.
            Да, можно искать по дате или по номерам телефонов. Но опять-таки немного не то.