Feedback Actions
Update From Call Feedback Action
Explains the Call feedback action that runs when a phone call comes in through a SIP connection. Useful for answering phone calls with a voice assistant, turning calls away, following up on missed calls, and getting digits the caller typed on the keypad.
Overview
Stubber can take phone calls through your phone system (PBX). A SIP connection logs Stubber into the PBX as an extension, like a desk phone. Any call to that extension, whether someone dials it on the PBX or the PBX routes a phone number to it, rings Stubber, and the _update_from_call feedback action is triggered on the stub.
The stub that gets the call is set on the SIP connection, in the manage platform under Notifications → SIP. The PBX login is a SIP Connection credential. A connection can also send calls from chosen numbers to a draft stub, see Testing with a draft stub.
Phone calls were called dial at first. The old names still work where a template passes them in: the answer_dial_call, reject_dial_call and collect_dial_digits tasks, the dialcalluuid param, and "channel": "dial" in Start Voice Chat. The feedback action and its data use the new names only: _update_from_call, _incoming_call_data and call_data.calluuid.
The message of the stubpost, i.e. stubpost.message, says who is calling, eg Incoming call from Joe Soap (0215550123).
All the details of the call are available in the stubpost.data._incoming_call_data data path.
Two call events are posted: incoming and missed. Once a call is answered, it reports back like any live voice call, with the _update_from_voice feedback action, including when it ends. A third event, digits, brings the keys the caller typed when the template asked for them, see Keypad digits.
This is about phone calls coming in to Stubber. To make a call from a user's own PBX extension, see the Dial notification.
call_data.event tells the events apart. The flags on stubpost.data._incoming_call_data are:
is_incoming_call is false for both missed calls and digits. To handle missed calls, check call_data.event = 'missed', not is_incoming_call = false.
Answering a call
Run Start Voice Chat with the call channel and the call's audio format, then Answer Call with the call and the new voice session. Use is_incoming_call as the condition on both:
Pass call_data.audio_format to start_voice_chat with ~~, as above. Phone calls use the G.711 audio format the phone system prefers, μ-law or A-law, and the voice call has to match it. Without it, the voice call uses μ-law, and an A-law call can't be answered.
answer_call returns once the caller hears the assistant, or with an error when answering failed:
The call must be answered within 25 seconds of the incoming event. The caller hears ringing until then. After that the call is turned away and a missed event follows.
To end an answered call, end the voice call as usual, eg with a hangup voice notification.
Rejecting a call
To not take the call, run Reject Call:
It only works while the call is ringing. The caller's phone system is told the call was declined, and no missed event follows.
Missed calls
A call that was never answered triggers _update_from_call a second time, with call_data.event set to missed and is_incoming_call set to false. Use it to follow up, eg to schedule a call back:
call_data.reason says why the call was missed:
Keypad digits
To get digits the caller types on their keypad, eg a menu choice or a customer number, run Collect Call Digits on the answered call, in the same action as the voice notification that asks the question. Once the caller is done, _update_from_call is triggered on the stub that ran the task, with call_data.event set to digits:
call_data.digits has what the caller typed, without the #, and call_data.name the name you gave the task. call_data.ended_by says how the entry ended:
Keys pressed while nothing is being collected are ignored. See Collect Call Digits for a menu followed by a customer number.
Testing with a draft stub
A SIP connection has a live stub, which gets every call, and optionally a draft stub with a list of caller numbers. Calls from those numbers go to the draft stub instead, so you can try a draft template on the real extension while everyone else still reaches the live one. Missed calls go to the same stub as the call.
call_data.route says which stub got the call: live or draft.
Only the digits of a number are compared, and they must match exactly. +27 82 123 4567 matches a caller presented as 27821234567, but not 0821234567. Enter the numbers the way your phone system presents the caller, which is the from of a call. Callers who withhold their number always go to the live stub.
Things to know
- Phone audio. Phone calls are 8 kHz telephone audio (G.711), so the assistant hears and speaks at phone quality.
- One call at a time per extension. A SIP connection takes one call at a time unless Stubber raises its limit. Other callers get a busy signal.
- One voice call per stub. A stub can only have one live voice call. To take calls on more than one extension at once, have the stub that gets the calls create a stub per call.
- Who is calling.
fromis the number or extension the phone system presents for the caller. It can be an internal extension, eg101, or a full phone number. - Keypad presses (DTMF) only reach the stub while Collect Call Digits collects them.
Data Structure
Feedback Action Data
Example data for an incoming call:
Example data for a missed call:
Example data for digits the caller typed:
Properties
is_call_event boolean
true for every call event.
is_incoming_call boolean
true for a ringing call to answer or reject, false for a missed call and for digits.
from string
The caller's number or extension, as the phone system presents it.
from_name string
The caller's name, when the phone system knows it. Otherwise null.
to string
The extension that was called, i.e. the SIP connection's extension.
call_data.event string
incoming, missed or digits.
call_data.calluuid string
The id of the call. Pass it to answer_call or reject_call.
call_data.sipconnectionuuid string
The SIP connection the call came in on.
call_data.route string
incoming and missed only. Which of the SIP connection's stubs got the call: live, or draft for a caller in the draft numbers. See Testing with a draft stub.
call_data.audio_format object
incoming and missed only. The call's audio format, audio/pcmu (μ-law) or audio/pcma (A-law) at 8000. Pass it to start_voice_chat as audio.format.
call_data.answer_deadline string
incoming only. The ISO 8601 date-time by which the call must be answered.
call_data.reason string
missed only. Why the call was missed: caller_cancelled or answer_timeout.
call_data.name string
digits only. The name given to Collect Call Digits, or null.
call_data.digits string
digits only. The digits the caller typed, without the #. An empty string when they typed nothing.
call_data.ended_by string
digits only. How the entry ended: terminator, max_digits, timeout or no_input.
Last incoming platform
Like a WhatsApp call, the incoming and missed events also set the stub's last incoming platform and caller in stubpost.data._com_platforms:
No notification platform handles call, so an auto_platform notification on the stub isn't sent after a phone call.
The voice call that follows doesn't change these: Update From Voice only adds the call's state in _com_platforms.voice.
JSONSchema
The JSONSchema of the stubpost.data._incoming_call_data is: