Flows API Reference
Read and build Chatfuel flows through the Public API: flows and groups, blocks and connections, message and action components, keyword rules and test chats.
Last updated on
A flow is a scripted conversation made of blocks connected to each other; each block holds components such as a WhatsApp message, a list, a condition or a JSON API call. Through the Public API you can read flows, create and organize them, add and connect blocks, configure every component, manage keyword rules and triggers, and run test chats. Reading flows and running test chats works for Agent virtual users; every change needs Editor.
How to read flows
type Bot {
# Agent.
flowGroups: [FlowGroup!]! # { id name flows { id name } }
flowsWithoutGroup: [RegularFlow!]!
defaultReplyFlows: [DefaultReplyFlow!]!
flow(flowID: FlowID!): Flow!
}query FlowStructure($botID: BotID!, $flowID: FlowID!) {
bot(id: $botID) {
flow(flowID: $flowID) {
id
name
platform
startingPointBlock { id }
blocks {
id
name
positionX
positionY
blockElements { id errors { __typename } }
}
connections { __typename }
}
}
}Block and BlockElement are interfaces with one type per kind of block and component. Use inline fragments for the types you work with.
How to create and organize flows
All mutations on this page change flows and need Editor.
type Mutation {
createFlow(botID: BotID!, platform: Platform!): Bot!
updateFlowName(flowID: FlowID!, name: String!): Flow!
deleteFlow(flowID: FlowID!): Bot!
createFlowGroup(botID: BotID!): Bot!
updateFlowGroupName(id: FlowGroupID!, name: String!): FlowGroup!
deleteFlowGroup(flowGroupId: FlowGroupID!): Bot!
moveFlowToGroup(flowID: FlowID!, groupID: FlowGroupID!): Bot!
removeFlowFromGroup(flowID: FlowID!): Bot!
sortFlowGroups(botID: BotID!, flowGroupIds: [FlowGroupID!]!): Bot!
sortFlowsInGroup(groupID: FlowGroupID!, flowIds: [FlowID!]!): FlowGroup!
sortUngroupedFlows(botID: BotID!, flowIds: [FlowID!]!): Bot!
}How to work with blocks and connections
type Mutation {
updateBlockName(flowID: FlowID!, blockID: BlockID!, name: String!): Block!
updateBlockPosition(flowID: FlowID!, blockID: BlockID!, positionX: Int!, positionY: Int!): Block!
updateBlockPositionBulk(flowID: FlowID!, update: [BlockPositionBulkUpdate!]!): Flow!
deleteBlock(flowID: FlowID!, blockID: BlockID!): Flow!
blockSetStartingPoint(flowID: FlowID!, blockID: BlockID!): Flow!
blockEnableEntryPoint(flowID: FlowID!, blockID: BlockID!): Flow!
blockDisableEntryPoint(flowID: FlowID!, blockID: BlockID!): Flow!
sortBlockElements(blockID: BlockID!, elementIDs: [BlockElementID!]!): Block!
blockElementDelete(botID: BotID!, elementID: BlockElementID!): Flow!
# Block → block, or a component's output handle (a button, a condition branch) → block.
blockToBlockConnectionCreateOrUpdate(flowID: FlowID!, request: BlockToBlockConnectionCreateRequest!): Flow!
blockToBlockConnectionDelete(flowID: FlowID!, sourceBlockID: BlockID!): Flow!
componentToBlockConnectionCreateOrUpdate(flowID: FlowID!, request: ComponentToBlockConnectionCreateRequest!): Flow!
componentToBlockConnectionDelete(flowID: FlowID!, sourceBlockElementID: BlockElementID!, sourceHandleID: ComponentHandleID!): Flow!
}Positions are canvas coordinates in pixels, the same as in the dashboard flow editor.
How to add components
Each component kind has a family of mutations named after it. Most families have three ways to create a component:
<family>CreateWithBlock(flowID, positionX, positionY)creates a new block with the component at the given position.<family>CreateWithBlockAndConnection(flowID, request, positionX, positionY)also connects it to an existing block or handle given inrequest: { sourceBlockID, sourceBlockElementID, sourceHandleID }.<family>CreateInBlock(blockID)adds the component to an existing block.
Setters then take the component's blockElementID. A WhatsApp text message, for example:
type Mutation {
whatsAppTextCreateWithBlock(flowID: FlowID!, positionX: Int!, positionY: Int!): Flow!
whatsAppTextCreateWithBlockAndConnection(flowID: FlowID!, request: UndefinedTargetBlockConnectionCreateRequest!, positionX: Int!, positionY: Int!): Flow!
whatsAppTextCreateInBlock(blockID: BlockID!): ContentBlock!
whatsAppTextSetText(blockElementID: BlockElementID!, text: String!): ContentBlock!
whatsAppTextSetWaitForReplies(blockElementID: BlockElementID!, waitForReplies: Boolean!): ContentBlock!
whatsAppTextSetSaveContactReplyToAttribute(blockElementID: BlockElementID!, saveContactReply: Boolean!, attribute: AttributeName): ContentBlock!
}The component families and their mutations, after the family prefix:
whatsAppText,whatsAppImage,whatsAppVideo,whatsAppAudio,whatsAppDocument: the three create mutations,SetTextorSetImageFile/SetVideoFile/SetAudioFile/SetDocumentFile,SetCaption(image, video, document),SetWaitForReplies,SetSaveContactReplyToAttribute.whatsAppTextAndButtons:CreateWithBlock,CreateWithBlockAndConnection,SetHeaderText,SetBodyText,SetFooterText,SetButtonTitle,AddNewContinueFlowButton,DeleteButton,MoveButton,WaitForReplies,SetSaveContactReplyToAttribute.whatsAppTextAndURL:CreateWithBlock,CreateWithBlockAndConnection,SetHeaderText,SetBodyText,SetFooterText,SetButtonTitle,SetButtonURL,WaitForReplies,SetSaveContactReplyToAttribute.whatsAppList:CreateWithBlock,CreateWithBlockAndConnection,SetBodyText,SetButtonTitle,AddRow,DeleteRow,ReorderRows,SetRowTitle,SetRowDescription,WaitForReplies,SetSaveContactReplyToAttribute.whatsAppTemplate:CreateWithBlock,CreateWithBlockAndConnection,SetTemplate,DeleteTemplate,SetHeaderTextParamValue,SetBodyTextParamValue,SetFooterTextParamValue,SetHeaderImageFile,SetHeaderVideoFile,SetHeaderDocumentFile,SetURLButtonTextParamValue,SetCopyCodeButtonCodeValue,SetWaitForReplies,SetSaveContactReplyToAttribute.whatsAppScheduledMessage:CreateWithBlock,CreateWithBlockAndWATemplate,UpdateSegment,SetFirstSendTime,SetRepeatType,SetRepeatEveryNDays,SetOnCertainDates,SetWeekdays.whatsAppOneTimeNotification:CreateWithBlock,CreateWithBlockAndWATemplate,UpdateSegment,Send.widgetTextAndButtons: the three create mutations,SetText,AddNewContinueFlowButton,AddNewOpenURLButton,AddNewPhoneButton,SetButtonTitle,SetButtonURL,SetButtonPhone,DeleteButton,MoveButton,SetWaitForReplies,SetSaveContactReplyToAttribute.widgetImage: the three create mutations,SetImageFile,SetWaitForReplies,SetSaveContactReplyToAttribute.whatsAppSwitchToChatWithHumanAgent,facebookSwitchToChatWithHumanAgent,instagramSwitchToChatWithHumanAgent,tiktokSwitchToChatWithHumanAgent,widgetSwitchToChatWithHumanAgent: the three create mutations.aiAgent:CreateWithBlockandCreateWithBlockAndConnectionwith atemplateIDfrom theaiAgentTemplates(locale:)query,UpdateAdditionalInstructions,CreateRule,DeleteRule,UpdateRuleTitle,UpdateRulePrompt. A custom AI agent usesaiAgentCustomUpdatePrompt,aiAgentCustomCreateRule,aiAgentCustomDeleteRule,aiAgentCustomUpdateRuleTitleandaiAgentCustomUpdateRulePrompt.sendJson(the JSON API action): the three create mutations,UpdateHTTPMethod,UpdateURL,AddHeader,UpdateHeaderTitle,UpdateHeaderValue,DeleteHeader,AddURLParam,UpdateURLParamTitle,UpdateURLParamValue,DeleteURLParam,UpdatePayloadType,UpdateCustomRequestPayload,EnableResponseParsingRules,DisableResponseParsingRules,ResponseAddParsingRule,UpdateResponseParsingRuleJSONPath,UpdateResponseParsingRuleAttributeName,DeleteResponseParsingRule,TestRequest.albatoIntegration: the three create mutations with atemplateID,UpdateSelectedEvent,UpdateEventFieldValue,AddEventCustomField,RemoveEventCustomField,UpdateEventCustomFieldName,UpdateEventCustomFieldValue.setCondition: the three create mutations,UpdateSegment.setContactProperty: the three create mutations,SetAttribute,SetValue.clearContactProperty: the three create mutations,SetAttribute.summarizeChat: the three create mutations,AddEntry,UpdateEntry,DeleteEntry.redirectToFlow:CreateWithBlock,CreateWithBlockAndConnection,SetTargetFlow,RemoveTargetFlow.triggeredMessage:CreateWithBlock,CreateWithBlockAndWATemplate,SetSegment.
How to integrate with JSON API explains what each sendJson setting does.
Keyword rules and triggers
Keyword rules send a contact to a flow or reply with a message when their text matches. Reading them with bot.keywordRules(first, after) and changing them both need Editor.
type Mutation {
keywordRuleCreate(botID: BotID!): KeywordRule!
# matchType: similarTo, contains or matches
keywordRuleUpdateMatchType(botID: BotID!, keywordRuleID: KeywordRuleID!, matchType: KeywordRuleMatchType!): KeywordRule!
keywordRuleUpdateKeywords(botID: BotID!, keywordRuleID: KeywordRuleID!, keywords: [String!]!): KeywordRule!
# actionType: switchToFlow, sendMessage or doNothing, set per platform
keywordRuleUpdateActionType(botID: BotID!, keywordRuleID: KeywordRuleID!, platform: Platform!, actionType: KeywordRuleActionType!): KeywordRule!
keywordRuleDelete(botID: BotID!, keywordRuleID: KeywordRuleID!): Bot!
# Triggers of triggered messages. An enabled trigger can't be changed (EnabledTriggerIsImmutable).
# conditionType: LastMessageFromContact or ContactAttributeChanged
triggerSetConditionType(id: TriggerID!, conditionType: TriggerConditionType!): Trigger!
triggerSetAttributeFilter(id: TriggerID!, attrCondition: AttrFilterInput!): Trigger!
triggerDeleteAttributeFilter(id: TriggerID!): Trigger!
triggerSetDelay(id: TriggerID!, delay: TriggerDelayInput!): Trigger!
}How to test a flow in a test chat
A test chat runs a flow, the whole bot or an automation in a sandbox conversation without messaging real contacts. Starting a session works for Agent:
type Mutation {
previewResponsesStartInFlow(flowID: FlowID!): PreviewResponsesFlowSession!
previewResponsesStartForBot(botID: BotID!, platform: Platform!): PreviewResponsesBotSession!
previewResponsesStartForFuelyAutomation(botID: BotID!, fuelyAutomationID: FuelyAutomationID!): PreviewResponsesFuelyAutomationSession!
}The session returns a conversationID. Play the contact's side with previewResponsesWhatsappTextSend, previewResponsesInstagramTextSend, previewResponsesFacebookTextSend, previewResponsesTikTokTextSend or previewResponsesWidgetTextSend, simulate comments with previewResponsesInstagramPostCommentSend and previewResponsesFacebookPostCommentSend, and simulate clicks with previewResponsesWhatsappContinueFlowBtnClickSend, previewResponsesWhatsappListRowClickSend, previewResponsesWhatsappTemplateQuickReplyBtnClickSend and the previewResponsesWidget*BtnClickSend mutations. All take botID and conversationID. Read the bot's answers with the messageAdded subscription described in messaging.
Common issues
"NotEnoughPermissions" when changing a flow
Agent virtual users can read flows and run test chats but not change them. Change the role to Editor.
"EnabledTriggerIsImmutable"
A triggered message can't be edited while it is on. Turn it off in the dashboard, change the trigger, and turn it on again.
A component shows errors in the flow
blockElements { errors } lists what is missing, such as an empty text or an unset template. The dashboard shows the same errors on the block; fill in the missing settings with the component's setters.