Skip to contentSkip to navigationSkip to topbar
Rate this page:
On this page

Studio Flow Definition


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(link takes you to an external page) 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.


Standalone Definitions

standalone-definitions page anchor

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 Definition

simple-flow-definition page anchor

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
}


Rate this page: