To represent the complex structure and requirements of a Studio Flow and its widget configurations, the Flow definition is expressed as a JSON schema. Thus, when creating or updating Flows via the REST API, the JSON sent in the Definition
parameter must pass validation against that schema.
Below are sample Flow and widget definitions you can copy and paste into your application. Alternatively, use the Studio editor in Twilio Console to automatically create valid definitions and export them from the API to save them locally or to add them to version control. Refer to the JSON schemas for full details of widgets and properties.
The following sample definitions can be used as standalone starters for your application. Include the complete JSON as the Definition
parameter in your POST to the API.
Simple Flow for handling Incoming Message, Incoming Call and REST API triggered Executions
_114{_114 "states": [_114 {_114 "transitions": [_114 {_114 "event": "incomingMessage",_114 "next": "send_message_1"_114 },_114 {_114 "event": "incomingCall",_114 "next": "say_play_1"_114 },_114 {_114 "event": "incomingRequest",_114 "next": "call_user_1"_114 }_114 ],_114 "type": "trigger",_114 "name": "Trigger",_114 "properties": {_114 "offset": {_114 "y": 0,_114 "x": 0_114 }_114 }_114 },_114 {_114 "transitions": [_114 {_114 "event": "audioComplete"_114 }_114 ],_114 "type": "say-play",_114 "name": "say_play_1",_114 "properties": {_114 "say": "Hello world!",_114 "loop": 1,_114 "offset": {_114 "y": 210,_114 "x": 130_114 }_114 }_114 },_114 {_114 "transitions": [_114 {_114 "event": "sent"_114 },_114 {_114 "event": "failed"_114 }_114 ],_114 "type": "send-message",_114 "name": "send_message_1",_114 "properties": {_114 "body": "Hello world!",_114 "from": "{{flow.channel.address}}",_114 "service": "{{trigger.message.InstanceSid}}",_114 "to": "{{contact.channel.address}}",_114 "offset": {_114 "y": 210,_114 "x": -240_114 },_114 "channel": "{{trigger.message.ChannelSid}}"_114 }_114 },_114 {_114 "transitions": [_114 {_114 "event": "answered",_114 "next": "say_play_1"_114 },_114 {_114 "event": "busy"_114 },_114 {_114 "event": "noAnswer"_114 },_114 {_114 "event": "failed"_114 }_114 ],_114 "type": "make-outgoing-call-v2",_114 "name": "call_user_1",_114 "properties": {_114 "trim": "true",_114 "machine_detection_silence_timeout": "5000",_114 "from": "{{flow.channel.address}}",_114 "recording_status_callback": "",_114 "record": false,_114 "machine_detection_speech_threshold": "2400",_114 "to": "{{contact.channel.address}}",_114 "detect_answering_machine": false,_114 "sip_auth_username": "",_114 "machine_detection": "Enable",_114 "send_digits": "",_114 "machine_detection_timeout": "30",_114 "timeout": 60,_114 "offset": {_114 "y": 210,_114 "x": 490_114 },_114 "machine_detection_speech_end_threshold": "1200",_114 "sip_auth_password": "",_114 "recording_channels": "mono"_114 }_114 }_114 ],_114 "initial_state": "Trigger",_114 "flags": {_114 "allow_concurrent_calls": true_114 },_114 "description": "A New Flow"_114}
Blank Flow with no widgets attached to the Trigger
_33{_33 "states": [_33 {_33 "transitions": [_33 {_33 "event": "incomingMessage",_33 "next": null_33 },_33 {_33 "event": "incomingCall",_33 "next": null_33 },_33 {_33 "event": "incomingRequest",_33 "next": null_33 }_33 ],_33 "type": "trigger",_33 "name": "Trigger",_33 "properties": {_33 "offset": {_33 "y": 0,_33 "x": 0_33 }_33 }_33 }_33 ],_33 "initial_state": "Trigger",_33 "flags": {_33 "allow_concurrent_calls": true_33 },_33 "description": "A New Flow"_33}
Widgets are defined as "states" that the Studio workflow engine transitions to in response to events. The following JSON snippets can be used to add individual widgets as states
to an existing Flow definition.
Add each widget snippet as a new item in the states
array:
_10{_10 "states": [_10 // ADD WIDGET SNIPPETS HERE_10 ],_10 "initial_state": "Trigger",_10 "flags": {_10 "allow_concurrent_calls": true_10 },_10 "description": "A New Flow"_10}
Snippet of JSON to add a TwiML redirect
_27{_27 "transitions": [_27 {_27 "event": "return"_27 "next": null_27 },_27 {_27 "event": "timeout"_27 "next": null_27 },_27 {_27 "event": "fail"_27 "next": null_27 }_27 ],_27 "type": "add-twiml-redirect",_27 "name": "redirect_1",_27 "properties": {_27 "url": "https://funny-name-1234.twil.io/",_27 "method": "POST",_27 "timeout": "14400",_27 "offset": {_27 "y": 0,_27 "x": 0_27 }_27 }_27}
Snippet of JSON to capture payments
_43{_43 "transitions": [_43 {_43 "event": "success"_43 "next": null_43 },_43 {_43 "event": "maxFailedAttempts"_43 "next": null_43 },_43 {_43 "event": "providerError"_43 "next": null_43 },_43 {_43 "event": "payInterrupted"_43 "next": null_43 },_43 {_43 "event": "hangup"_43 "next": null_43 },_43 {_43 "event": "validationError"_43 "next": null_43 }_43 ],_43 "type": "capture-payments",_43 "name": "pay_1",_43 "properties": {_43 "payment_token_type": "reusable",_43 "currency": "usd",_43 "postal_code": "true",_43 "timeout": 5,_43 "offset": {_43 "y": 0,_43 "x": 0_43 },_43 "valid_card_types": [],_43 "security_code": true,_43 "max_attempts": 2_43 }_43}
Snippet of JSON to connect the caller to another number
_25{_25 "transitions": [_25 {_25 "event": "callCompleted"_25 "next": null_25 },_25 {_25 "event": "hangup"_25 "next": null_25 }_25 ],_25 "type": "connect-call-to",_25 "name": "connect_call_1",_25 "properties": {_25 "noun": "number",_25 "to": "+14155551212",_25 "caller_id": "{{contact.channel.address}}",_25 "record": true,_25 "timeout": 30,_25 "offset": {_25 "y": 0,_25 "x": 0_25 }_25 }_25}
Snippet of JSON to enqueue the call
_25{_25 "transitions": [_25 {_25 "event": "callComplete"_25 "next": null_25 },_25 {_25 "event": "failedToEnqueue"_25 "next": null_25 },_25 {_25 "event": "callFailure"_25 "next": null_25 }_25 ],_25 "type": "enqueue-call",_25 "name": "enqueue_1",_25 "properties": {_25 "workflow_sid": "WW1111111111111111111111",_25 "offset": {_25 "y": 0,_25 "x": 0_25 }_25 }_25}
Snippet of JSON to fork the audio stream to another endpoint
_21{_21 "transitions": [_21 {_21 "event": "next",_21 "next": null_21 }_21 ],_21 "type": "fork-stream",_21 "name": "stream_1",_21 "properties": {_21 "stream_action": "start",_21 "stream_name": "stream",_21 "stream_transport_type": "websocket",_21 "stream_track": "inbound_track",_21 "offset": {_21 "y": 0,_21 "x": 0_21 },_21 "stream_url": "wss://funny-name-1234.twil.io/"_21 }_21}
Snippet of JSON to gather digits or speech input
_30{_30 "transitions": [_30 {_30 "event": "keypress",_30 "next": null_30 },_30 {_30 "event": "speech"_30 "next": null_30 },_30 {_30 "event": "timeout",_30 "next": null_30 }_30 ],_30 "type": "gather-input-on-call",_30 "name": "gather_1",_30 "properties": {_30 "stop_gather": true,_30 "gather_language": "en",_30 "say": "Please press any key to continue.",_30 "loop": 1,_30 "timeout": 5,_30 "offset": {_30 "y": 0,_30 "x": 0_30 },_30 "finish_on_key": "#"_30 }_30}
Snippet of JSON to make an HTTP request to another API
_29{_29 "transitions": [_29 {_29 "event": "success",_29 "next": null_29 },_29 {_29 "event": "failed",_29 "next": null_29 }_29 ],_29 "type": "make-http-request",_29 "name": "http_1",_29 "properties": {_29 "url": "https://funny-name-1234.twil.io/",_29 "parameters": [_29 {_29 "key": "count",_29 "value": "{{flow.variables.count}}"_29 }_29 ],_29 "method": "POST",_29 "content_type": "application/x-www-form-urlencoded;charset=utf-8",_29 "offset": {_29 "y": 0,_29 "x": 0_29 }_29 }_29}
Snippet of JSON to initiate an outbound call
_44{_44 "transitions": [_44 {_44 "event": "answered",_44 "next": null_44 },_44 {_44 "event": "busy",_44 "next": null_44 },_44 {_44 "event": "noAnswer",_44 "next": null_44 },_44 {_44 "event": "failed",_44 "next": null_44 }_44 ],_44 "type": "make-outgoing-call-v2",_44 "name": "call_user_1",_44 "properties": {_44 "trim": "true",_44 "machine_detection_silence_timeout": "5000",_44 "from": "{{flow.channel.address}}",_44 "recording_status_callback": "",_44 "record": false,_44 "machine_detection_speech_threshold": "2400",_44 "to": "{{contact.channel.address}}",_44 "detect_answering_machine": false,_44 "sip_auth_username": "",_44 "machine_detection": "Enable",_44 "send_digits": "",_44 "machine_detection_timeout": "30",_44 "timeout": 60,_44 "offset": {_44 "y": 0,_44 "x": 0_44 },_44 "machine_detection_speech_end_threshold": "1200",_44 "sip_auth_password": "",_44 "recording_channels": "mono"_44 }_44}
Snippet of JSON to record an inbound call
_25{_25 "transitions": [_25 {_25 "event": "success",_25 "next": null_25 },_25 {_25 "event": "failed",_25 "next": null_25 }_25 ],_25 "type": "record-call",_25 "name": "call_recording_1",_25 "properties": {_25 "trim": "do-not-trim",_25 "offset": {_25 "y": 0,_25 "x": 0_25 },_25 "recording_status_callback_events": "completed",_25 "recording_status_callback_method": "POST",_25 "record_call": true,_25 "recording_channels": "dual"_25 }_25}
Snippet of JSON to record voicemail from the caller
_26{_26 "transitions": [_26 {_26 "event": "recordingComplete",_26 "next": null_26 },_26 {_26 "event": "noAudio",_26 "next": null_26 },_26 {_26 "event": "hangup",_26 "next": null_26 }_26 ],_26 "type": "record-voicemail",_26 "name": "record_voicemail_1",_26 "properties": {_26 "max_length": 3600,_26 "timeout": 5,_26 "offset": {_26 "y": 0,_26 "x": 0_26 }_26 }_26}
Snippet of JSON to run a Twilio Function
_26{_26 "transitions": [_26 {_26 "event": "success",_26 "next": null_26 },_26 {_26 "event": "fail"_26 }_26 ],_26 "type": "run-function",_26 "name": "function_1",_26 "properties": {_26 "url": "https://funny-name-1234.twil.io/",_26 "parameters": [_26 {_26 "key": "foo",_26 "value": "bar"_26 }_26 ],_26 "offset": {_26 "y": 0,_26 "x": 0_26 }_26 }_26}
Snippet of JSON to say a message to the caller
_18{_18 "transitions": [_18 {_18 "event": "audioComplete",_18 "next": null_18 }_18 ],_18 "type": "say-play",_18 "name": "say_play_1",_18 "properties": {_18 "say": "This call is being recorded for quality assurance.",_18 "loop": 1,_18 "offset": {_18 "y": 0,_18 "x": 0_18 }_18 }_18}
Snippet of JSON to send a text message and wait for a reply
_29{_29 "transitions": [_29 {_29 "event": "incomingMessage",_29 "next": null_29 },_29 {_29 "event": "timeout",_29 "next": null_29 },_29 {_29 "event": "deliveryFailure",_29 "next": null_29 }_29 ],_29 "type": "send-and-wait-for-reply",_29 "name": "send_and_reply_1",_29 "properties": {_29 "body": "Hello. Please reply.",_29 "from": "{{flow.channel.address}}",_29 "service": "{{trigger.message.InstanceSid}}",_29 "timeout": 3600,_29 "offset": {_29 "y": 0,_29 "x": 0_29 },_29 "channel": "{{trigger.message.ChannelSid}}"_29 }_29}
Snippet of JSON to send a text message
_25{_25 "transitions": [_25 {_25 "event": "sent",_25 "next": null_25 },_25 {_25 "event": "failed",_25 "next": null_25 }_25 ],_25 "type": "send-message",_25 "name": "send_message_1",_25 "properties": {_25 "body": "Hello world!",_25 "from": "{{flow.channel.address}}",_25 "service": "{{trigger.message.InstanceSid}}",_25 "to": "{{contact.channel.address}}",_25 "offset": {_25 "y": 0,_25 "x": 0_25 },_25 "channel": "{{trigger.message.ChannelSid}}"_25 }_25}
Snippet of JSON to route the contact to a Flex agent
_26{_26 "transitions": [_26 {_26 "event": "callComplete",_26 "next": null_26 },_26 {_26 "event": "failedToEnqueue",_26 "next": null_26 },_26 {_26 "event": "callFailure",_26 "next": null_26 }_26 ],_26 "type": "send-to-flex",_26 "name": "send_to_flex_1",_26 "properties": {_26 "workflow": "WW11111111111111111111111111111111",_26 "channel": "TC11111111111111111111111111111111",_26 "offset": {_26 "y": 0,_26 "x": 0_26 }_26 }_26}
Snippet of JSON to set Execution-level variables
_23{_23 "transitions": [_23 {_23 "event": "next",_23 "next": null_23 }_23 ],_23 "type": "set-variables",_23 "name": "set_variables_1",_23 "properties": {_23 "variables": [_23 {_23 "index": "0",_23 "key": "count",_23 "value": "{% if flow.variables.count %}\n {{flow.variables.count | plus: 1}}\n{% else %}\n 1\n{% endif %}"_23 }_23 ],_23 "offset": {_23 "y": 0,_23 "x": 0_23 }_23 }_23}
Snippet of JSON to add branching logic
_45{_45 "transitions": [_45 {_45 "event": "noMatch",_45 "next": null_45 },_45 {_45 "conditions": [_45 {_45 "type": "equal_to",_45 "friendly_name": "If value equal_to 1",_45 "arguments": [_45 "{{widgets.gather_1.Digits}}"_45 ],_45 "value": "1"_45 }_45 ],_45 "event": "match",_45 "next": null_45 },_45 {_45 "conditions": [_45 {_45 "type": "equal_to",_45 "friendly_name": "If value equal_to 2",_45 "arguments": [_45 "{{widgets.gather_1.Digits}}"_45 ],_45 "value": "2"_45 }_45 ],_45 "event": "match",_45 "next": null_45 }_45 ],_45 "type": "split-based-on",_45 "name": "split_1",_45 "properties": {_45 "input": "{{widgets.gather_1.Digits}}",_45 "offset": {_45 "y": 0,_45 "x": 0_45 }_45 }_45}