# Automated Voice Apps Alpha Preview
Thank you for participating in RingCentral Automated Voice Apps scripting feature alpha testing! We appreciate any feedback and encourage you to ask any questions you have while creating your app.
## Alpha Preview Limitations
* The API is now available on Sandbox (platform.devtest.ringcentral.com) only.
* Preliminary manual account configuration is needed to start API usage. They are:
1. IVR app extension creation;
2. IVR app access token generation;
3. IVR app callback URIs setup.
Please contact dev.platform.team@ringcentral.com when you're ready to start to get your Sandbox account prepared for testing.
* Known issue: in call out scenario, when the call is made within RingCentral account on-call-enter event is raised before the user answers the call. Workarounds (for testing):
- use external PSTN number or
- set prompt "Press 1 to answer the call" - then on-call-enter event is raised after the callee press the key.
* Since the API is not even in "beta", the API request/response formats and the set of methods will most likely be changed in the release version based on your feedback. No backward compatibility is guaranteed at this stage.
## How It Works: Basics
To make a custom call handling possible, we support specific extension type:
ApplicationExtension. Since it's still an extension, it may receive incoming calls the same way as any other extension, e.g. User or Department (aka Call Queue):
* by calling Company Number * Extension Number of the IVR app extension (or just an extension number within the account):
+15551234567*201
* by calling DID aka Direct Number assigned to the IVR app extension:
![alt text][1]
* by calling Company/Site Number and setting the IVR App extension as Company/Site operator:
![alt text][2]
* by forwarding from some other extension with specific call handling rule or call transfer.
For RingCentral to pass the call control to your IVR app, it should expose some callback URIs which will be called by RingCentral when the call is directed to the app by any reason mentioned above. There are 3 events which your app should handle:
* *Call Enter*: raised on an incoming call to the IVR app extension;
* *Command Update*: raised on command status update (see *IVR commands* below);
* *Call Exit*: raised on the call handling by IVR app should be stopped (call ended or transferred).
Typical call flow may look as follows:
![alt text][3]
For outbound calls, Ring Out feature/API may be used. The trick here is that the customer phone number should be "the first leg" of the call, i.e. `from` number, since the IVR app should get the call control only after the callee answers the call. The call flow then looks like:
![alt text][4]
## Callback Format
### On Call Enter
On incoming call to the IVR app extension, RingCentral makes an API call(back) to the IVR app with the following payload:
POST /ivr-app-example/on-call-enter
{
"accountId": "400131801008",
"extensionId": "400137552008",
"inParty": {
"from": {
"phoneNumber": "+12127150355"
},
"id": "p-467aa7237b524387b053c5d5f06787f5",
"to": {
"phoneNumber": "+12014320001"
}
},
"partyId": "p-ec4202d7dd35401f9e6230d428493701",
"sessionId": "s-82eecd460b564de1a42b395eb845d912"
}
The parameters here mean:
* `accountId` - RingCentral **account** identifier;
* `extensionId` - **IVR app extension** identifier;
* `inParty` - call **party of the caller** (customer) with `from` and `to` phone numbers corresponding to customer's phone number and the called number respectively;
* `partyId` - **IVR app call party** identifier;
* `sessionId` - **call session** identifier.
Most of that parameters are used on IVR app side to execute *IVR Commands* (see below).
In order to proceed with call handling, the app should immediately respond with HTTP 204 No Content to the on-call-enter request. Any further commands like `Play` and `Collect` should be executed after.
### On Command Update
When the IVR app calls some *IVR command* like play or collect it should receive some update after the command is completed with an execution result. To support that, IVR app should expose on-command-update callback URI which will be used by RingCentral to send the status update payload in the following format:
http POST /ivr-app-example/on-command-update
{ "accountId" : "400131801008", "command" : "Play", "commandId" : "171888866234845407", "extensionId" : "400137552008", "partyId" : "p-467aa7237b524387b053c5d5f06787f5", "sessionId" : "s-82eecd460b564de1a42b395eb845d912", "status" : "Completed" }
where the parameters should be treated as follows:
* `accountId` - RingCentral **account** identifier;
* `command` - **command type** (now supported: `Play` or `Collect`);
* `commandId` - **command instance** identifier;
* `extensionId` - **IVR app extension** identifier;
* `partyId` - command **target party** (party of the caller) identifier;
* `sessionId` - **call session** identifier;
* `status`
- `Completed` in case of successful command execution,
- `Failed` in case of command execution failed, e.g. media resource to be played is not reachable,
- `Canceled` in case of `Play` command interrupted by cancel command,
- `Interrupted` in case of `Play` command interrupted by DTMF.
Also, command status update payload may contain parameters structure with command type specific execution result, e.g., for Collect command:
* `parameters.digits` - **DTMF command** (key pressed).
See more details in *IVR Commands* section below.
### On Call Exit
In some cases your IVR app may need to make some actions when the call ends or is transferred from IVR app, to update some data in your system, notify some other system, schedule a meeting, call back, etc. In order to support that, RingCentral makes the following request to your IVR App:
http POST /ivr-app-example/on-call-exit
{
"accountId" : "400131801008",
"extensionId" : "400137552008",
"partyId" : "p-467aa7237b524387b053c5d5f06787f5",
"sessionId" : "s-82eecd460b564de1a42b395eb845d912"
}
where the parameters are quite the same with on-call-enter callback except for there is no customer call party info here.
## IVR Commands
### Play
Play command actually **plays media resource** specified in the request. The API request format is as follows:
http POST /restapi/v1.0/account/~/telephony/sessions/s-82eecd460b564de1a42b395eb845d912/parties/p-467aa7237b524387b053c5d5f06787f5/play
{
"resources": [
{
"uri": "http://example.com/ivr-app-example/greeting.wav"
}
],
"interruptByDtmf": false,
"repeatCount": 1
}
* resources is a list of media resources to be played, now only uri option is supported (will be extended with Prompts Library support in future releases);
* interruptByDtmf - determines if the playback should be stopped or not when the caller press a key;
* repeatCount - how many times to repeat the media, 0 for infinite - by default.
What is important here: In the request URL the `partyId` (path parameter which stands between `parties` and `play`) should be specified with **caller party** identifier, not the IVR app party, since the media should be played for the customer but not for the app (unless you'd like your bot to enjoy some music just for fun).
If the request accepted successfully, the API response looks like
http HTTP 201 Created
{
"id": "171888866234845407",
"interruptByDtmf": false,
"repeatCount": 1,
"resources": [
{
"uri": "http://example.com/ivr-app-example/greeting.wav"
}
],
"status": "InProgress"
}
where the attributes have the same meaning as parameters in the request plus
* `id` - **command instance** identifier, may be used to cancel the command and match `on-command-update` callback request with certain command action.
* `status` - **command status**, always `InProgress` in this scenario, means the playback is actually started.
To cancel the playback, you may use the following API call:
http DELETE /restapi/v1.0/account/~/telephony/sessions/s-82eecd460b564de1a42b395eb845d912/parties/p-467aa7237b524387b053c5d5f06787f5/play/171888866234845407
When the playback ends (taking into account `repeatCount`), RingCentral makes `on-command-update` request to your IVR app as described in *Callback Format* section above.
### Collect
A typical IVR scenario includes entering some (digital) information by the caller using phone (real or virtual) keys like "press one for this, press two for that, ..." or "enter your access code to continue". To gather that information (which is also called [DTMF signaling](https://en.wikipedia.org/wiki/Dual-tone_multi-frequency_signaling)) the IVR app should make the following API call:
http POST /restapi/v1.0/account/~/telephony/sessions/s-82eecd460b564de1a42b395eb845d912/parties/p-467aa7237b524387b053c5d5f06787f5/collect
{
"patterns" : [ "1", "2" ],
"timeout" : 600000,
"interDigitTimeout" : 2000
}
The same approach works for the `partyId` here as for the `Play` command: the **caller party** identifier should be used.
Let's take a look at request params:
* `patters` is a list of digital patterns your IVR app expect from the customer. The pattern may consist of
- digits,
- "x" for any key;
* `timeout` - determines command termination condition: specified milliseconds passed since command start;
* `interDigitTimeout` - determines command termination condition: specified milliseconds passed since user has entered min amount of digits;
* `terminator` - determines command termination condition: hash ("#") or star ("*"") sign entered, "#" by default.
* `resetInput` - set this to `false` if you'd like to keep digits entered for previous collect command(s) as a part of a sequence (`true` by default).
When the user finishes input according to one of the command termination conditions, RingCentral makes a request to your app `on-command-update` callback URI (see *Callback Format* section above) with the payload like this:
http POST /ivr-app-example/on-command-update
{
"accountId": "400131801008",
"command": "Collect",
"extensionId": "400137547008",
"parameters": {
"digits": "1"
},
"partyId": "p-1aef4fa8a4b54266ac01d6f00b182483",
"sessionId": "s-88d87ed9412343a0a83be08debac6c48",
"status": "Completed"
}
`parameters.digits` is what your app's interested in here: it's the key sequence the user entered in case it matches any pattern you specified in the request. If it does not, the `status` param has `Not Found` value. If the user didn't enter the requested amount of digits (by the pattern with min length), `status`: `Timeout` is sent in command update callback payload.
### Transfer
In many IVR cases, the call should be transferred to one or another person/group as a result of some customer action and the context. Unlike regular VoIP calls, for the calls processed by IVR app Forward API should be used here instead of Transfer. Also, for this command IVR app `partyId` should be used, but not the customer party as for `Play` and `Collect`. Here is the request example:
http POST /restapi/v1.0/account/~/telephony/sessions/s-82eecd460b564de1a42b395eb845d912/parties/p-ec4202d7dd35401f9e6230d428493701/forward
{
"extensionNumber" : "103"
}
* `extensionNumber` here is the target extension the call should be transferred to;
* `phoneNumber` can be used instead to forward the call to some external PSTN number.
After the call is transferred, the IVR app gets `on-call-exit` callback just like for the dropped calls.
## Outbound Calls
In some cases, you may want your app to initiate the call: notify the customer of appointment, tell her/him about your brand new product, whatever. We'll support some dedicated API for that in future releases; still, it's already possible even now! (with some known limitations - see *Alpha Preview Limitations* at the beginning of that guide)
In RingCentral service, we have a [RingOut](https://support.ringcentral.com/s/article/What-is-RingOut) feature which basically connects two phone numbers. It might also be used with extension numbers - and that's what we're going to use here. To make a call from your app to some external PSTN number (of your customer), the app should make [RingOut API](https://developers.ringcentral.com/api-reference/RingOut) request as follows:
http POST /restapi/v1.0/account/~/extension/~/ring-out
{
"from" : {
"phoneNumber" : "+12056860001"
},
"to" : {
"phoneNumber" : "201"
}
}
Please pay attention to `from` and `to` values here: yes, the customer number should be set as `from` and the IVR app extension number as `to`. The reason is we want the customer to receive the call first and start the IVR app call control only after that. So for the app, the next steps are quite the same as for incoming call: it receives `on-call-enter` request and starts executing IVR commands (typically - `Play`) as described above.
## (Static) IVR Menu x Scripting
You may find it useful to combine [`IVRMenu`](https://support.ringcentral.com/s/article/6593) and `ApplicationExtension` in the same IVR tree to easily setup basic IVR scenario (greeting, transfer by DTMF) with custom call handling (by IVR App). In order to do that, assign your IVR application extension to some Key in IVR Menu extension [**Key Presses** settings](https://support.ringcentral.com/s/article/6560):
![alt text][5]
You can also use [Visual IVR Editor](https://support.ringcentral.com/s/article/7344) to do that:
![alt text][6]
Actually, IVR Menu and IVR Apps can be mixed in any combination which fits your particular use case: call can be transferred to IVR Menu from IVR App by your custom rule (implemented in your app), see *IVR Commands / Transfer a Call* above.
We appreciate any feedback, so please tell us what you think of:
* does the API fit your tasks and expectations,
* is the API easy to understand and work with,
* any IVR commands enhancements or additional commands you'd like us to support,
* any other questions, ideas, concerns, impressions, whatever you want to share with us.
The future is now; let 's move to that new communications era together. We're constantly working on new and existing API and RingCentral service feature improvements - stay tuned!
# Demo App
Our developer team also built a demo App to showcase how you might be building or getting started with your app. This codebase is open source so you use this to have an idea to how to build your own app.
Demo App: https://github.com/tylerlong/rc-ivr-scripting-demo
[1]: https://uploads-us-west-2.insided.com/ringcentral-en/attachment/272_image1.png
[2]: https://uploads-us-west-2.insided.com/ringcentral-en/attachment/273_image2.png
[3]: https://uploads-us-west-2.insided.com/ringcentral-en/attachment/274_image3.png
[4]: https://uploads-us-west-2.insided.com/ringcentral-en/attachment/301_image4.png
[5]: https://uploads-us-west-2.insided.com/ringcentral-en/attachment/275_image5.png
[6]: https://uploads-us-west-2.insided.com/ringcentral-en/attachment/302_image-6.png
Enter your E-mail address. We'll send you an e-mail with instructions to reset your password.