Home Best Practices in Building Controlled Flows
πŸ“

Best Practices in Building Controlled Flows

Winderlly
RΓ³ger Lenhart
By Winderlly and 2 others
β€’ 7 articles

Monitoring and Continuous Improvement of Controlled Flows

To ensure that flows operate correctly, it is essential to monitor the processes of ClaudIA and Controlled Flows. We have a platform called ClaudIA panel, where all interactions passing through ClaudIA are recorded. On the panel, you can view the interactions, track flows triggered by Controlled Flows, and identify opportunities for improvement, ensuring increasingly efficient and well-monitored service. ClaudIA panel Overview ClaudIA panel Overview: Main screen displaying ClaudIA's conversation history The panel functions as a central dashboard that allows auditing, analyzing, and improving customer service. It provides a detailed view of the conversation flows, helping to identify potential bottlenecks and facilitating actions for continuous optimization. Flow Tracking in the ClaudIA Panel Flow Tracking in the ClaudIA Panel: Example of a conversation showing the start of a Controlled Flow and a return marker to ClaudIA at the end of interaction. ClaudIA panel Features βœ” Complete recording of conversations: all messages exchanged between customers and ClaudIA are stored for analysis and audit. βœ” Monitoring Controlled Flow executions: whenever ClaudIA triggers a Controlled Flow, the panel displays an indication with the flow name and the messages exchanged within, allowing tracking of the customer's journey. βœ” Indication of flow end: when a flow is completed, there is a notification of returning to ClaudIA, helping to understand when the interaction reverted to AI. βœ” Audits for continuous improvement: The ClaudIA Panel enables strategic adjustments, such as refining N1 and N2 contents, creating interactive flows, and identifying failure points that impact the customer experience. βœ” Error monitoring in Controlled Flow requests: If there is a failure in API calls or integrations within a Controlled Flow, the ClaudIA Panel allows identifying these issues, enabling quick corrections to prevent impact on service. A high-level block with a log is shown at the time of failure to facilitate issue identification. Error Log Example ClaudIA Panel Log Example: indication of a failure in a Controlled Flow request The ClaudIA Panel is an essential tool to ensure efficiency, transparency, and continuous evolution of the service, providing strategic insights into the interaction between ClaudIA, Controlled Flows, and customers. The following features are available for analysis and optimization: Identifying When a Controlled Flow is Called - On the ClaudIA Panel, it is possible to see exactly when a Controlled Flow was triggered within a conversation. - The start and end of the flow are recorded, allowing clear tracking of what happened during execution. Suggested Process for Testing and Improving Controlled Flows To ensure quality and ongoing improvement of flows created in Controlled Flows, following a structured testing and enhancement process is crucial. Since Controlled Flows does not have native version control, best practices include backup, isolated testing, and validation before publishing. Building and Modularizing - Whenever possible, break complex flows into smaller, reusable parts. - Use flow calls to facilitate maintenance and avoid rework. - Ensure all conditions (if/else) are correctly set to prevent incorrect decisions. Testing Before Publishing - Before publishing any changes, duplicate the flow and run tests in an isolated environment. - Execute comprehensive simulations, verifying decision logic, sent messages, and configured integrations. - Validate response times by observing the interval between the customer's message and ClaudIA's response in the panel. This helps identify potential delays in requests, even without exact duration details. Avoid requests that may exceed the 45-second timeout. Backup and Change Control - Since there is no native versioning system, download a copy of the flow before any modification. - Publish only after all changes are validated to avoid unexpected failures. - If a downgrade is needed, use the saved version to quickly restore the previous flow. Continuous Monitoring and Improvement - Monitor flow executions on the ClaudIA Panel, checking which were triggered and if there were failures or unexpected deviations. - Analyze logs and error messages to identify optimization points. - If recurrent failures occur, adjust decision conditions and alternative flows to ensure smoother service. This structured process minimizes errors, optimizes Controlled Flow performance, and enhances the customer experience, ensuring each flow operates at its best.

Last updated on Aug 26, 2026

How to Identify and Prevent Failures in Controlled Flow's Flows and Requests

To ensure efficient and smooth service, it is essential to understand the main failure modes that can occur in Controlled Flow's flows and in communication between Controlled Flow and ClaudIA. Identifying and mitigating these failures helps improve the customer experience and prevents unwanted disruptions. Timeout and Request Cancellation Communication between ClaudIA and Controlled Flow needs to be quick and efficient to ensure seamless customer service. However, there is a time limit for executing each request within Controlled Flow. If this time is exceeded, the request is automatically canceled, interrupting the flow and preventing the customer from receiving an appropriate response. How Does Timeout Work? - When ClaudIA calls a flow in Controlled Flow, the actions within the flow must be executed within a 45-second time limit. - This limit is in place to ensure the conversation occurs in real time, with no perceptible delays for the customer. - If a request takes longer than this period, Controlled Flow cannot complete the action, resulting in operation cancellation and no response to ClaudIA. Main Causes of Timeout and Request Cancellation High Response Time APIs - When a Controlled Flow calls an external API, the response time can be very long, exceeding the allowed limit. - Some APIs are not optimized for quick queries and may take time to process and return data. - If the API does not respond within 45 seconds, the request will be automatically canceled, negatively impacting user experience. πŸ”Ή How to Avoid: Use APIs with fast response times (ideally less than 2-3 seconds). Prioritize asynchronous or cache-based APIs to avoid delays. If you need to use a slow API, consider dividing the request into smaller parts or using intermediary solutions (such as temporary data storage). Retrieval Failure - This can happen due to configuration errors, recent flow changes, or data indexing issues. - To mitigate this problem, it is essential to review and test the content attached to the flow regularly. Internal Execution Error in Controlled Flow - Controlled Flow may encounter internal failures that prevent proper flow execution. - This can occur due to incorrect configurations, poorly structured blocks, or improper use of logical conditions (IF/ELSE). - To minimize this risk, it is recommended to test each flow before publishing and review error logs in the ClaudIA Panel if needed. Integration Execution Errors - External integrations (such as API calls, Google Sheets) may return error messages or fail entirely. - When this occurs, Controlled Flow may follow an incorrect path or not respond to the customer. - To mitigate this issue, configure appropriate error handling, such as: - Returning an explanatory message to the customer. - Escalating the service to a human agent (N2). Incorrect Execution Flow - In flows that use LLMs (Language Models like GPT) to define the execution route, there may be failures in selecting the next step. - This happens when the model's interpretation leads to an unexpected path or when conditions within the flow are not well defined. - To avoid such errors: - Define clear and well-structured prompts. - Set up conditional responses for different scenarios. - Test flow variations to ensure predictability. Total Controlled Flow Failure - In extreme cases, Controlled Flow can completely fail, preventing the flow from continuing. - To prevent the customer from getting stuck in the conversation, there is a safety feature that automatically escalates the conversation to N2. - This scalability ensures that, even in a major failure scenario, customer service is not interrupted.

Last updated on Aug 29, 2026

Transform Your Google Sheets into an API

This solution turns your Google Sheets spreadsheet into a dynamic web API, allowing you (or your clients) to read, create, update, and delete data directly via HTTP requests. It's perfect for managing data for multiple clients without the need for complex servers – all running free on Google Apps Script! We'll go from basic to advanced, with detailed steps. If you follow precisely, you'll have your API up and running in 5 minutes. You can adapt it to your needs, such as managing integrations for different clients. With this API, you or your systems can: - Read all data - Search for specific records - Add new rows - Update existing rows - Delete rows All via simple HTTP requests (GET and POST). 1. The Complete API Code (Copy and Paste) Here is the ready script that you will paste into Google Apps Script. It has been tested and works perfectly: /** * Google Spreadsheet API – FINAL CORRECTED VERSION * Exact equality search (===) * Corrected method logic */ const SPREADSHEET_ID = '[SPREADSHEET_ID]'; const SHEET_NAME = '[SHEET_NAME]'; const CACHE_TTL = 10 * 60 * 1000; // 10 minutes let cache = { data: [], headers: [], lastUpdate: 0 }; // Web App entry points function doGet(e) { return handleRequest(e, 'GET'); } function doPost(e) { return handleRequest(e, 'POST'); } function handleRequest(e, httpMethod) { let payload = {}; // Read JSON body (only in POST) if (httpMethod === 'POST' && e.postData && e.postData.type === 'application/json') { try { payload = JSON.parse(e.postData.contents || '{}'); } catch (err) { return jsonResponse({ status: 'error', message: 'Invalid JSON in body' }); } } // Refresh cache if needed if (Date.now() - cache.lastUpdate > CACHE_TTL) { refreshCache(); } // Detect simulated method (_method in payload or parameter) const simulatedMethod = (payload._method || e.parameter.method || '').toUpperCase(); // ========================== // GET β†’ List all // ========================== if (httpMethod === 'GET') { return jsonResponse({ status: 'success', total: cache.data.length, data: cache.data }); } // ========================== // POST // ========================== if (httpMethod === 'POST') { // Simulate PATCH if (simulatedMethod === 'PATCH') { if (!payload.filter || !payload.updates) { return jsonResponse({ status: 'error', message: 'PATCH requires "filter" and "updates"' }); } return jsonResponse(updateRow(payload.filter.column, payload.filter.value, payload.updates)); } // Simulate DELETE if (simulatedMethod === 'DELETE') { if (!payload.filter) { return jsonResponse({ status: 'error', message: 'DELETE requires "filter"' }); } return jsonResponse(deleteRow(payload.filter.column, payload.filter.value)); } // Filter by exact match if (payload.filter && payload.filter.column && payload.filter.value !== undefined) { const col = payload.filter.column.trim(); const val = payload.filter.value.toString(); const results = cache.data.filter(row => String(row[col] || '') === val ); return jsonResponse({ status: 'success', found: results.length > 0, total: results.length, data: results }); } // Create new row (any JSON without filter or _method) if (Object.keys(payload).length > 0) { return jsonResponse(createRow(payload)); } return jsonResponse({ status: 'error', message: 'Empty or invalid body for POST' }); } return jsonResponse({ status: 'error', message: 'Unsupported HTTP method' }); } // Refresh cache function refreshCache() { const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName(SHEET_NAME); const [header, ...rows] = sheet.getDataRange().getValues(); const headers = header.map(h => String(h).trim()); const data = rows.map(row => { const obj = {}; headers.forEach((h, i) => obj[h] = row[i]); return obj; }); cache = { data, headers, lastUpdate: Date.now() }; } // Create new row function createRow(obj) { const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName(SHEET_NAME); const headers = cache.headers; const invalids = Object.keys(obj).filter(k => !headers.includes(k)); if (invalids.length > 0) { return { status: 'error', message: `Invalid fields: ${invalids.join(', ')}` }; } const newLine = headers.map(h => obj[h] !== undefined ? obj[h] : ''); sheet.appendRow(newLine); const newObj = {}; headers.forEach((h, i) => newObj[h] = newLine[i]); cache.data.push(newObj); return { status: 'success', message: 'Row created', data: newObj }; } // Update row (first match) function updateRow(column, value, updates) { const idx = cache.data.findIndex(row => String(row[column] || '') === String(value) ); if (idx === -1) return { status: 'error', message: 'Row not found' }; const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName(SHEET_NAME); const headers = cache.headers; const rowNumber = idx + 2; Object.keys(updates).forEach(key => { if (headers.includes(key)) { const col = headers.indexOf(key) + 1; sheet.getRange(rowNumber, col).setValue(updates[key]); cache.data[idx][key] = updates[key]; } }); return { status: 'success', message: 'Row updated', data: cache.data[idx] }; } // Delete row function deleteRow(column, value) { const idx = cache.data.findIndex(row => String(row[column] || '') === String(value) ); if (idx === -1) return { status: 'error', message: 'Row not found' }; const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName(SHEET_NAME); sheet.deleteRow(idx + 2); const deleted = cache.data.splice(idx, 1)[0]; return { status: 'success', message: 'Row deleted', deletedData: deleted }; } // JSON Response function jsonResponse(obj) { return ContentService .createTextOutput(JSON.stringify({ data: obj }, null, 2)) .setMimeType(ContentService.MimeType.JSON); } 2. How to Configure Your Spreadsheet Details in the Code Before pasting the code, replace two parts: 1. [SPREADSHEET_ID] β†’ The unique ID of your Google Sheets document. - Open your spreadsheet in the browser. - Check the URL: https://docs.google.com/spreadsheets/d/ABC123XYZ456/edit#gid=0 - The ID is the part between /d/ and /edit: in the example, ABC123XYZ456. - Replace [SPREADSHEET_ID] with this value (without extra quotes). 2. [SHEET_NAME] β†’ The name of the sheet (tab) you want to use. - At the bottom of your spreadsheet, see the sheet's name (default is "Sheet1" or "Planilha1"). - Exactly match the sheet name (case-sensitive). - Never include accents or special characters. - Example: if the sheet is named "Clients", put 'Clients' After replacing these two values, your code is ready to use! 3. Opening the Script Editor and Pasting the Code 1. In your spreadsheet, click the top menu: Extensions > Apps Script. 2. In the editor that opens, delete all default code (e.g., function myFunction() {}): 3. Paste the entire code from section 1 (with SPREADSHEET_ID and SHEET_NAME replaced), then click Save (the disk icon) and give your project a name: 4. Publishing as a Web App (Making Your API Public) 1. In the Apps Script editor, click Deploy > New deployment. 2. Click Select type > Web app. 3. Fill out: - Execute as: "Me" (your account) - Who has access: "Anyone" 4. Click Deploy. 5. Authorize permissions as necessary (confirmation may be needed – click "Advanced" > "Go to project" > "Allow"). 6. Copy the web app URL that appears at the end (e.g., https://script.google.com/macros/s/…/exec). This is your API! 5. How to Use the API (Practical Examples) Now that your API is published, you can use it with any HTTP request tool, such as curl (terminal), Postman, or code in any language. Always replace YOUR_URL_HERE with the URL you copied in step 4. Below, we explain each available method separately. For POST methods, always include the header Content-Type: application/json. Get All Data (GET) This method returns a complete list of all spreadsheet records as a JSON array (each object representing a row, with keys based on headers). - How to use: Access the URL directly in the browser or via GET, with no body or extra parameters. - Example with curl: curl "YOUR_URL_HERE" - Required Body: None (do not send a body). - Expected result: JSON with all data. Example (assuming 2 rows): { "data": { "status": "success", "total": 2, "data": [ { "id": "1", "name": "John Smith", "email": "[email protected]", "balance": 1500 }, { "id": "2", "name": "Maria Oliveira", "email": "[email protected]", "balance": 3200 } ] } } Filtered Return (POST) This method searches and returns only rows that exactly match the specified value in a column (exact filter, not partial). Useful for querying specific client data. - How to use: Send a POST request with body containing the filter (column and value). - Example with curl: curl -X POST "YOUR_URL_HERE" \ -H "Content-Type: application/json" \ -d '{ "filter": { "column": "id", "value": "1" } }' - Required Body (formatted): { "filter": { "column": "id", "value": "1" } } - Expected result: JSON with filtered rows (may be empty if none found). Example: { "data": { "status": "success", "found": true, "total": 1, "data": [ { "id": "1", "name": "John Smith", "email": "[email protected]", "balance": 1500 } ] } } Add a New Row (POST) This method adds a new row to the spreadsheet with the provided values. The keys in the body must match exactly the spreadsheet headers. - How to use: Send a POST request with body containing the data for the new row (no filter or _method). - Example with curl: curl -X POST "YOUR_URL_HERE" \ -H "Content-Type: application/json" \ -d '{ "id": "3", "name": "Carlos Santos", "email": "[email protected]", "balance": 5000 }' - Required Body (formatted): { "id": "3", "name": "Carlos Santos", "email": "[email protected]", "balance": 5000 } - Expected result: Confirmation of creation with added data. Example: { "data": { "status": "success", "message": "Row created", "data": { "id": "3", "name": "Carlos Santos", "email": "[email protected]", "balance": 5000 } } } Update an Existing Row (POST) This method updates values in an existing row, using a filter to identify which row to modify (updates the first match exactly). Only fields sent in "updates" are modified. - How to use: Send a POST request with _method: "PATCH", filter, and fields to update. - Example with curl: curl -X POST "YOUR_URL_HERE" \ -H "Content-Type: application/json" \ -d '{ "_method": "PATCH", "filter": { "column": "id", "value": "3" }, "updates": { "name": "Carlos Santos Updated", "balance": 6000 } }' - Required Body (formatted): { "_method": "PATCH", "filter": { "column": "id", "value": "3" }, "updates": { "name": "Carlos Santos Updated", "balance": 6000 } } - Expected result: Confirmation of update with modified row data. Example: { "data": { "status": "success", "message": "Row updated", "data": { "id": "3", "name": "Carlos Santos Updated", "email": "[email protected]", "balance": 6000 } } } Delete a Row (POST) This method deletes an existing row, using a filter to identify which to remove (deletes the first match exactly). - How to use: Send a POST request with _method: "DELETE" and the filter. - Example with curl: curl -X POST "YOUR_URL_HERE" \ -H "Content-Type: application/json" \ -d '{ "_method": "DELETE", "filter": { "column": "id", "value": "3" } }' - Required Body (formatted): { "_method": "DELETE", "filter": { "column": "id", "value": "3" } } - Expected result: Confirmation of deletion with the data of the removed row. Example: { "data": { "status": "success", "message": "Row deleted", "deletedData": { "id": "3", "name": "Carlos Santos Updated", "email": "[email protected]", "balance": 6000 } } } Done! Now you have a professional API running. If you need help, our team is here to accelerate your integrations! πŸš€

Last updated on Mar 06, 2026

How to Reduce Controlled Flow Call Errors to Increase Retention

What are Controlled Flow Call Errors and why should I analyze them? Controlled Flow Call Errors are one of the reasons why ClaudIA transfers to human agents. To verify if the focus should be on Controlled Flow Call Errors, consult the FAQ on How to monitor and increase ClaudIA retention. This guide explains how to immediately address the Controlled Flow Call Errors that most contribute to transfers, helping to reduce the volume of tickets sent to humans. ⚑ How to use this FAQ: Read everything first to understand the concepts and the step-by-step process. Then, open the dashboard to put the guidance into practice. πŸš€ Where to start the analysis? Within the dashboard, in the tab 'Transferred due to Controlled Flow call failure,' as shown in the image below, you will find tables that help identify call failures in Controlled Flow. These tables help quickly pinpoint where the biggest impacts on retention are. Main tables Table "% of Controlled Flow Call Errors by Flow" β†’ shows for each Controlled Flow, the weekly percentage of tickets that returned to N2 because the bot failed. It's important to analyze the most recent full week to identify the biggest offenders. To sort, click on the column header. Table "Tickets with Call Error by Flow" β†’ indicates which tickets are linked to Controlled Flows that experienced failures. In this table, flows can be sorted alphabetically to facilitate analysis and audits. 1. Time to act Analysis checklist - Are the integrations/APIs correct? - Are the input data/variables validated? - Are there conflicting conditions in the flow? - Does the error occur in critical high-volume flows? Practical suggestions βœ… Fix flows with the highest error percentages. βœ… Create fallback options to prevent a poor user experience.

Last updated on Aug 30, 2026

Error Validation in Controlled Flows

This article highlights the most common error types that should be validated before publishing Controlled Flows, as well as how to identify and fix them. Adopting these best practices helps ensure the flow functions cohesively, all paths are covered, and the end-user experience remains consistent. Automatic Validation in the Editor Controlled Flow validation is performed automatically after each change made in the editor, providing real-time feedback on inconsistencies and points of attention. The validation does not prevent flow publication, but it is recommended that all issues be reviewed and resolved before deploying the flow to production. Known Errors ClaudIA Block Missing in Branches Each branch of the flow must have at least one ClaudIA block before the path ends. ClaudIA needs this information to identify when the flow has ended and to take necessary actions (continue support, resolve N1, escalate to N2, etc.). Image illustrating ClaudIA block in flow branches Text Missing Next to ClaudIA Block The ClaudIA block exists but has no associated text. The text block can be positioned before or after the ClaudIA block, provided there is no Input block placed between them. Image illustrating missing text next to ClaudIA block Incomplete Conditions Indicates when conditional blocks (IF, ELSE) are not properly filled. It is important that all outputs of the condition are connected to some block, so the flow can proceed without errors. Image illustrating incomplete condition blocks Broken Links Indicates that a link block points to a flow that no longer exists or has not yet been published. This warning can be ignored during flow construction, but it is crucial to resolve it at the time of publishing. Image illustrating broken link warning Missing Text Between Input Blocks Occurs when there are sequences of connected text input blocks without any message text between them. To prevent errors in integration with ClaudIA, a message must always be sent before any information collection. Image illustrating missing message between input blocks Conclusion Ensuring that all Controlled Flows are validated before publication is essential to guarantee a smooth user experience, reduce operational errors, and maintain the integrity of Claudia's logic. With the validations and best practices described here, your team can build more robust, predictable, and maintainable flows.

Last updated on Jun 24, 2026