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
1{2"states": [3{4"transitions": [5{6"event": "incomingMessage",7"next": "send_message_1"8},9{10"event": "incomingCall",11"next": "say_play_1"12},13{14"event": "incomingRequest",15"next": "call_user_1"16}17],18"type": "trigger",19"name": "Trigger",20"properties": {21"offset": {22"y": 0,23"x": 024}25}26},27{28"transitions": [29{30"event": "audioComplete"31}32],33"type": "say-play",34"name": "say_play_1",35"properties": {36"say": "Hello world!",37"loop": 1,38"offset": {39"y": 210,40"x": 13041}42}43},44{45"transitions": [46{47"event": "sent"48},49{50"event": "failed"51}52],53"type": "send-message",54"name": "send_message_1",55"properties": {56"body": "Hello world!",57"from": "{{flow.channel.address}}",58"service": "{{trigger.message.InstanceSid}}",59"to": "{{contact.channel.address}}",60"offset": {61"y": 210,62"x": -24063},64"channel": "{{trigger.message.ChannelSid}}"65}66},67{68"transitions": [69{70"event": "answered",71"next": "say_play_1"72},73{74"event": "busy"75},76{77"event": "noAnswer"78},79{80"event": "failed"81}82],83"type": "make-outgoing-call-v2",84"name": "call_user_1",85"properties": {86"trim": "true",87"machine_detection_silence_timeout": "5000",88"from": "{{flow.channel.address}}",89"recording_status_callback": "",90"record": false,91"machine_detection_speech_threshold": "2400",92"to": "{{contact.channel.address}}",93"detect_answering_machine": false,94"sip_auth_username": "",95"machine_detection": "Enable",96"send_digits": "",97"machine_detection_timeout": "30",98"timeout": 60,99"offset": {100"y": 210,101"x": 490102},103"machine_detection_speech_end_threshold": "1200",104"sip_auth_password": "",105"recording_channels": "mono"106}107}108],109"initial_state": "Trigger",110"flags": {111"allow_concurrent_calls": true112},113"description": "A New Flow"114}
Blank Flow with no widgets attached to the Trigger
1{2"states": [3{4"transitions": [5{6"event": "incomingMessage",7"next": null8},9{10"event": "incomingCall",11"next": null12},13{14"event": "incomingRequest",15"next": null16}17],18"type": "trigger",19"name": "Trigger",20"properties": {21"offset": {22"y": 0,23"x": 024}25}26}27],28"initial_state": "Trigger",29"flags": {30"allow_concurrent_calls": true31},32"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:
1{2"states": [3// ADD WIDGET SNIPPETS HERE4],5"initial_state": "Trigger",6"flags": {7"allow_concurrent_calls": true8},9"description": "A New Flow"10}11
Snippet of JSON to add a TwiML redirect
1{2"transitions": [3{4"event": "return"5"next": null6},7{8"event": "timeout"9"next": null10},11{12"event": "fail"13"next": null14}15],16"type": "add-twiml-redirect",17"name": "redirect_1",18"properties": {19"url": "https://funny-name-1234.twil.io/",20"method": "POST",21"timeout": "14400",22"offset": {23"y": 0,24"x": 025}26}27}
Snippet of JSON to capture payments
1{2"transitions": [3{4"event": "success"5"next": null6},7{8"event": "maxFailedAttempts"9"next": null10},11{12"event": "providerError"13"next": null14},15{16"event": "payInterrupted"17"next": null18},19{20"event": "hangup"21"next": null22},23{24"event": "validationError"25"next": null26}27],28"type": "capture-payments",29"name": "pay_1",30"properties": {31"payment_token_type": "reusable",32"currency": "usd",33"postal_code": "true",34"timeout": 5,35"offset": {36"y": 0,37"x": 038},39"valid_card_types": [],40"security_code": true,41"max_attempts": 242}43}
Snippet of JSON to connect the caller to another number
1{2"transitions": [3{4"event": "callCompleted"5"next": null6},7{8"event": "hangup"9"next": null10}11],12"type": "connect-call-to",13"name": "connect_call_1",14"properties": {15"noun": "number",16"to": "+14155551212",17"caller_id": "{{contact.channel.address}}",18"record": true,19"timeout": 30,20"offset": {21"y": 0,22"x": 023}24}25}
Snippet of JSON to enqueue the call
1{2"transitions": [3{4"event": "callComplete"5"next": null6},7{8"event": "failedToEnqueue"9"next": null10},11{12"event": "callFailure"13"next": null14}15],16"type": "enqueue-call",17"name": "enqueue_1",18"properties": {19"workflow_sid": "WW1111111111111111111111",20"offset": {21"y": 0,22"x": 023}24}25}
Snippet of JSON to fork the audio stream to another endpoint
1{2"transitions": [3{4"event": "next",5"next": null6}7],8"type": "fork-stream",9"name": "stream_1",10"properties": {11"stream_action": "start",12"stream_name": "stream",13"stream_transport_type": "websocket",14"stream_track": "inbound_track",15"offset": {16"y": 0,17"x": 018},19"stream_url": "wss://funny-name-1234.twil.io/"20}21}
Snippet of JSON to gather digits or speech input
1{2"transitions": [3{4"event": "keypress",5"next": null6},7{8"event": "speech"9"next": null10},11{12"event": "timeout",13"next": null14}15],16"type": "gather-input-on-call",17"name": "gather_1",18"properties": {19"stop_gather": true,20"gather_language": "en",21"say": "Please press any key to continue.",22"loop": 1,23"timeout": 5,24"offset": {25"y": 0,26"x": 027},28"finish_on_key": "#"29}30}
Snippet of JSON to make an HTTP request to another API
1{2"transitions": [3{4"event": "success",5"next": null6},7{8"event": "failed",9"next": null10}11],12"type": "make-http-request",13"name": "http_1",14"properties": {15"url": "https://funny-name-1234.twil.io/",16"parameters": [17{18"key": "count",19"value": "{{flow.variables.count}}"20}21],22"method": "POST",23"content_type": "application/x-www-form-urlencoded;charset=utf-8",24"offset": {25"y": 0,26"x": 027}28}29}
Snippet of JSON to initiate an outbound call
1{2"transitions": [3{4"event": "answered",5"next": null6},7{8"event": "busy",9"next": null10},11{12"event": "noAnswer",13"next": null14},15{16"event": "failed",17"next": null18}19],20"type": "make-outgoing-call-v2",21"name": "call_user_1",22"properties": {23"trim": "true",24"machine_detection_silence_timeout": "5000",25"from": "{{flow.channel.address}}",26"recording_status_callback": "",27"record": false,28"machine_detection_speech_threshold": "2400",29"to": "{{contact.channel.address}}",30"detect_answering_machine": false,31"sip_auth_username": "",32"machine_detection": "Enable",33"send_digits": "",34"machine_detection_timeout": "30",35"timeout": 60,36"offset": {37"y": 0,38"x": 039},40"machine_detection_speech_end_threshold": "1200",41"sip_auth_password": "",42"recording_channels": "mono"43}44}
Snippet of JSON to record an inbound call
1{2"transitions": [3{4"event": "success",5"next": null6},7{8"event": "failed",9"next": null10}11],12"type": "record-call",13"name": "call_recording_1",14"properties": {15"trim": "do-not-trim",16"offset": {17"y": 0,18"x": 019},20"recording_status_callback_events": "completed",21"recording_status_callback_method": "POST",22"record_call": true,23"recording_channels": "dual"24}25}
Snippet of JSON to record voicemail from the caller
1{2"transitions": [3{4"event": "recordingComplete",5"next": null6},7{8"event": "noAudio",9"next": null10},11{12"event": "hangup",13"next": null14}15],16"type": "record-voicemail",17"name": "record_voicemail_1",18"properties": {19"max_length": 3600,20"timeout": 5,21"offset": {22"y": 0,23"x": 024}25}26}
Snippet of JSON to run a Twilio Function
1{2"transitions": [3{4"event": "success",5"next": null6},7{8"event": "fail"9}10],11"type": "run-function",12"name": "function_1",13"properties": {14"url": "https://funny-name-1234.twil.io/",15"parameters": [16{17"key": "foo",18"value": "bar"19}20],21"offset": {22"y": 0,23"x": 024}25}26}
Snippet of JSON to say a message to the caller
1{2"transitions": [3{4"event": "audioComplete",5"next": null6}7],8"type": "say-play",9"name": "say_play_1",10"properties": {11"say": "This call is being recorded for quality assurance.",12"loop": 1,13"offset": {14"y": 0,15"x": 016}17}18}
Snippet of JSON to send a text message and wait for a reply
1{2"transitions": [3{4"event": "incomingMessage",5"next": null6},7{8"event": "timeout",9"next": null10},11{12"event": "deliveryFailure",13"next": null14}15],16"type": "send-and-wait-for-reply",17"name": "send_and_reply_1",18"properties": {19"body": "Hello. Please reply.",20"from": "{{flow.channel.address}}",21"service": "{{trigger.message.InstanceSid}}",22"timeout": 3600,23"offset": {24"y": 0,25"x": 026},27"channel": "{{trigger.message.ChannelSid}}"28}29}
Snippet of JSON to send a text message
1{2"transitions": [3{4"event": "sent",5"next": null6},7{8"event": "failed",9"next": null10}11],12"type": "send-message",13"name": "send_message_1",14"properties": {15"body": "Hello world!",16"from": "{{flow.channel.address}}",17"service": "{{trigger.message.InstanceSid}}",18"to": "{{contact.channel.address}}",19"offset": {20"y": 0,21"x": 022},23"channel": "{{trigger.message.ChannelSid}}"24}25}
Snippet of JSON to route the contact to a Flex agent
1{2"transitions": [3{4"event": "callComplete",5"next": null6},7{8"event": "failedToEnqueue",9"next": null10},11{12"event": "callFailure",13"next": null14}15],16"type": "send-to-flex",17"name": "send_to_flex_1",18"properties": {19"workflow": "WW11111111111111111111111111111111",20"channel": "TC11111111111111111111111111111111",21"offset": {22"y": 0,23"x": 024}25}26}
Snippet of JSON to set Execution-level variables
1{2"transitions": [3{4"event": "next",5"next": null6}7],8"type": "set-variables",9"name": "set_variables_1",10"properties": {11"variables": [12{13"index": "0",14"key": "count",15"value": "{% if flow.variables.count %}\n {{flow.variables.count | plus: 1}}\n{% else %}\n 1\n{% endif %}"16}17],18"offset": {19"y": 0,20"x": 021}22}23}
Snippet of JSON to add branching logic
1{2"transitions": [3{4"event": "noMatch",5"next": null6},7{8"conditions": [9{10"type": "equal_to",11"friendly_name": "If value equal_to 1",12"arguments": [13"{{widgets.gather_1.Digits}}"14],15"value": "1"16}17],18"event": "match",19"next": null20},21{22"conditions": [23{24"type": "equal_to",25"friendly_name": "If value equal_to 2",26"arguments": [27"{{widgets.gather_1.Digits}}"28],29"value": "2"30}31],32"event": "match",33"next": null34}35],36"type": "split-based-on",37"name": "split_1",38"properties": {39"input": "{{widgets.gather_1.Digits}}",40"offset": {41"y": 0,42"x": 043}44}45}