Input: {"body":{"messages":[{"content":"Extract the following information from the input:\n{ \n/** The name of the feature */\nfeature?: string\n; \n/** The parent feature */\nparent?: string | null\n; \n/** The description of the feature */\ndescription?: string\n }\n====\n\n• Extract all things that looks like a Botpress feature in the provided input. You must extract a minimum of one element.\n• You may have multiple elements, or zero elements in the input.\n• You must extract each element separately.\n• Each element must be a JSON object with exactly the format: ■json_start■{ \"feature\": ..., \"parent\": ..., \"description\": ... }■json_end■\n• If there are no elements to extract, respond with ■ZERO_ELEMENTS■.\n• When you are done extracting all elements, type \"■NO_MORE_ELEMENT■\" to finish.\n• For example, if you have zero elements, the output should look like this: ■ZERO_ELEMENTS■■NO_MORE_ELEMENT■\n• For example, if you have two elements, the output should look like this: ■json_start■{ ... }■json_end■■json_start■{ ... }■json_end■■NO_MORE_ELEMENT■\n• You may ignore any fields that are not present in the input. All keys are optional.","role":"system"},{"content":"Here's an example to help you understand the format:\n\n<|start_schema|>\nArray<{ name: string, age: number }>\n<|end_schema|>\n\n<|start_instructions|>\nExtract all people\n<|end_instructions|>\n\n<|start_input|>\nThe story goes as follow.\nOnce upon a time, there was a person named Alice who was 30 years old.\nThen, there was a person named Bob who was 25 years old.\nThe end.\n<|end_input|>","role":"user","type":"text"},{"content":"■json_start■\n{\n  \"name\": \"Alice\",\n  \"age\": 30\n}\n■json_end■\n■json_start■\n{\n  \"name\": \"Bob\",\n  \"age\": 25\n}\n■json_end■■NO_MORE_ELEMENT■","role":"assistant","type":"text"},{"content":"Here's an example to help you understand the format:\n\n<|start_schema|>\n{ \n/** The name of the feature */\nfeature?: string\n; \n/** The parent feature */\nparent?: string | null\n; \n/** The description of the feature */\ndescription?: string\n }\n<|end_schema|>\n\n<|start_instructions|>\nExtract all things that looks like a Botpress feature in the provided input. You must extract a minimum of one element.\n<|end_instructions|>\n\n<|start_input|>\ndocs/webflow)  \n   * [Wix](/docs/wix)  \n   * [Wordpress](/docs/wordpress)\n* [Webchat v1 (deprecated)](/docs/web-chat-v1old)  \n   * [Controlling Web Chat using JavaScript](/docs/controlling-web-chat-using-javascript)  \n   * [Styling your webchat](/docs/chatbot-button)  \n         * [Chatbot Button](/docs/chatbot-button)  \n         * [Chat Header](/docs/chat-header)  \n         * [User Input Area](/docs/user-input-area)  \n         * [Show Bot Info](/docs/show-bot-info)  \n   * [Embedding Webchat](/docs/react-app)  \n         * [React App](/docs/react-app)  \n         * [React Native App](/docs/react-native-app)  \n         * [Web Chat Iframe](/docs/web-chat-iframe)  \n         * [Full Screen Chatbot](/docs/full-screen-chatbot)\n* [Webchat v2](/docs/embedded-webchat)  \n   * [Embedded Webchat](/docs/embedded-webchat)  \n         * [Custom CSS Reference](/docs/custom-css-reference)  \n   * [React Components](/docs/react-js)  \n   * [Webchat Client](/docs/webchat-client)\n## Botpress APIs\n* [Files API](/docs/files-api)\n* [Chat API](/docs/chat-api)\n## Appendix\n* [Safety](/docs/safety)  \n   * [Preventing Abuse](/docs/preventing-abuse)  \n   * [Brand Safety Framework](/docs/brand-safety-framework)\n* [Exporting Data](/docs/exporting-data)  \n   * [Raw Conversations](/docs/exporting-raw-conversations-with-the-botpress-api)  \n   * [Conversation History](/docs/getting-the-conversation-history-from-within-your-bot)  \n   * [Streaming Analytics](/docs/streaming-analytics-from-within-your-bot-with-hooks)  \n   * [Compiled Bot Analytics](/docs/exporting-compiled-bot-analytics-with-the-botpress-api)\nPowered by\n# Integrations\nDisplays integrations currently installed on your bot.\n[ Suggest Edits](/edit/integrations-1)\nThis tab lists integrations that are currently installed on your bot.\nFrom this menu, you can uninstall existing integrations, or navigate to the Botpress Hub to search for new ones.\n> ## ���\n>\n> Configure integrations from the Studio\n>\n> Integration configuration has been moved to the Studio.\n>\n> To set up integrations you've installed, or to install new integrations, you can navigate to the integrations menu found directly in the Studio.\nUpdated about 1 month ago\n---[Jump to Content](#content)\n[![Botpress](https://files.readme.io/c8cb63b6d586cd66085b4c960570959a424c7050c5ffeb0aeaf31711e2e1b2ac-small-BPLOGO_new_dark_1.png)](https://botpress.com)\n[Guides](/docs)[API Reference](/reference)[Changelog](/changelog)\n---\n[![Botpress](https://files.readme.io/c8cb63b6d586cd66085b4c960570959a424c7050c5ffeb0aeaf31711e2e1b2ac-small-BPLOGO_new_dark_1.png)](https://botpress.com)\nGuides\nMoon (Dark Mode)Sun (Light Mode)\n[Guides](/docs)[API Reference](/reference)[Changelog](/changelog)\nConnect a live agent platform with Botpress\nSearch\n## Home\n* [Botpress Documentation](/docs/home)\n## Getting Started\n* [Build](/docs/build)\n* [Deploy](/docs/deploy)\n* [Monitor](/docs/monitor)\n## DASHBOARD\n* [Workspace](/docs/workspace)  \n   * [Home](/docs/home-1)  \n   * [Members](/docs/members)  \n   * [Audits](/docs/audits)  \n   * [Your integrations](/docs/your-integrations)  \n   * [Usage](/docs/usage-2)  \n   * [Settings](/docs/settings)  \n   * [Profile Setting](/docs/user-profile)\n* [Bot](/docs/bot)  \n   * [Overview](/docs/overview-1)  \n   * [Integrations](/docs/integrations-1)  \n   * [Webchat](/docs/webchat-1)  \n   * [Logs](/docs/logs)  \n   * [Conversations](/docs/conversations)  \n   * [Analytics](/docs/analytics-1)  \n   * [Events](/docs/events-2)  \n   * [Issues](/docs/issues)  \n   * [Configuration variables](/docs/configuration-variables-1)\n## STUDIO\n* [Interface](/docs/interface)  \n   * [Nodes](/docs/nodes)  \n   * [Home](/docs/home-2)  \n   * [Flows](/docs/studio-interface-flows)  \n   * [Knowledge Base](/docs/knowledge-base)  \n   * [Tables](/docs/tables)  \n   * [Agents](/docs/agents)  \n         * [Summary Agent](/docs/summary-agent)  \n         * [Personality Agent](/docs/personality-agent)  \n         * [Policy Agent](/docs/policy-agent)  \n         * [Translator Agent](/docs/translator-agent)  \n         * [Knowledge Agent](/docs/knowledge-agent)  \n         * [HITL Agent](/docs/hitl-agent)  \n         * [Vision Agent](/docs/vision-agent)  \n         * [Analytics Agent](/docs/analytics-agent)  \n   * [Library](/docs/library)  \n   * [Hooks](/docs/hooks)  \n   * [Integrations](/docs/integrations-3)  \n   * [Schemas](/docs/schemas)  \n   * [Card Hub](/docs/card-hub)  \n   * [Versions](/docs/versions-1)  \n   * [Chatbot Settings](/docs/chatbot-settings-1)  \n   * [Find](/docs/find)  \n   * [Variables](/docs/variables)  \n   * [Card Tray](/docs/card-tray)  \n   * [Debugger, Logs & JSON](/docs/debugger-logs-json)  \n   * [Emulator](/docs/emulator)  \n   * [Keyboard Shortcuts](/docs/keyboard-shortcuts)  \n   * [Commands](/docs/studio-commands)  \n   * [Studio Preferences](/docs/studio-preferences)  \n   * [Import & Export](/docs/import-export-bots)\n* [Cards](/docs/cards)  \n   * [Send Messages](/docs/send-messages)  \n   * [Execute](/docs/execute)  \n   * [Webchat](/docs/webchat-2)  \n   * [Flow Logic](/docs/flow-logic)  \n   * [AI](/docs/ai)  \n        \n* [Webchat](/docs/webchat-2)  \n   * [Flow Logic](/docs/flow-logic)  \n   * [AI](/docs/ai)  \n         * [AI Task](/docs/ai-task-1)  \n         * [AI Transition](/docs/ai-transition)  \n         * [AI Generate Text](/docs/ai-generate-text)  \n   * [Capture Information](/docs/capture-information)  \n   * [Events](/docs/events-3)  \n   * [Agents](/docs/agents-2)  \n   * [Utilities](/docs/utilities)\n## integrations\n* [Usage](/docs/using-integrations)  \n   * [Asana](/docs/asana-integration)  \n   * [HITL](/docs/hitl-1)  \n   * [Instagram](/docs/instagram)  \n   * [Intercom](/docs/intercom)  \n   * [Line](/docs/line)  \n   * [Messenger](/docs/messenger)  \n   * [Microsoft Teams](/docs/microsoft-teams)  \n   * [Notion](/docs/notion)  \n   * [Slack](/docs/slack)  \n   * [Sunshine Conversations](/docs/sunshine-conversations)  \n   * [Telegram](/docs/telegram)  \n   * [Trello](/docs/trello)  \n   * [Twilio](/docs/twilio)  \n   * [Viber](/docs/viber)  \n   * [Vonage](/docs/vonage)  \n   * [Webhook](/docs/webhook)  \n   * [WhatsApp](/docs/whatsapp)  \n         * [Manual Configuration](/docs/manual-configuration)  \n   * [Zapier](/docs/zapier)  \n   * [Zendesk](/docs/zendesk)\n* [Building](/docs/building-integrations)  \n   * [Getting Started](/docs/getting-started-1)  \n         * [Getting Started](/docs/getting-started-1)  \n         * [Adding Messaging Channel Capabilities](/docs/adding-messaging-channel-capabilities)  \n         * [Adding Actions & Triggers to Botpress Studio](/docs/adding-actions-triggers-to-botpress-studio)  \n         * [Publish your integration on Botpress Hub](/docs/publish-your-integration-on-botpress-hub)  \n   * [Use Your Own LLM](/docs/llm-interfaces)  \n   * [Connect a live agent platform with Botpress](/docs/hitl)  \n   * [Moving Parts](/docs/moving-parts)  \n   * [CLI](/docs/cli)  \n   * [SDK](/docs/sdk)  \n   * [Key Concepts](/docs/key-concepts)  \n         * [Architecture](/docs/architecture)\n/docs/sdk)  \n   * [Key Concepts](/docs/key-concepts)  \n         * [Architecture](/docs/architecture)  \n         * [Tags](/docs/tags)  \n         * [Channels](/docs/channels)  \n         * [Configuration](/docs/configuration)  \n         * [User](/docs/user)  \n         * [Conversations](/docs/conversations-1)  \n         * [Messages](/docs/messages)  \n         * [Event](/docs/event)  \n         * [States](/docs/states-1)  \n         * [Actions](/docs/actions)  \n         * [Definitions](/docs/definitions)  \n         * [Secrets](/docs/secrets)  \n         * [ZUI - Zod schema UI components in Botpress \\[BETA\\]](/docs/zui-zod-schema-ui-components-in-botpress)  \n   * [How to](/docs/states)  \n         * [States](/docs/states)  \n         * [Register & Unregister](/docs/register-unregister)  \n         * [Integrations Actions](/docs/integrations)  \n         * [Integration Events](/docs/integration-events)  \n         * [Handler](/docs/handler)  \n         * [Logging](/docs/logging)  \n         * [Building a Custom Integration](/docs/building-a-custom-integration)\n## Webchat\n* [Webchat](/docs/webchat)  \n   * [Webflow](/docs/webflow)  \n   * [Wix](/docs/wix)  \n   * [Wordpress](/docs/wordpress)\n* [Webchat v1 (deprecated)](/docs/web-chat-v1old)  \n   * [Controlling Web Chat using JavaScript](/docs/controlling-web-chat-using-javascript)  \n   * [Styling your webchat](/docs/chatbot-button)  \n         * [Chatbot Button](/docs/chatbot-button)  \n         * [Chat Header](/docs/chat-header)  \n         * [User Input Area](/docs/user-input-area)  \n         * [Show Bot Info](/docs/show-bot-info)  \n   * [Embedding Webchat](/docs/react-app)  \n         * [React App](/docs/react-app)  \n         * [React Native App](/docs/react-native-app)  \n         * [Web Chat Iframe](/docs/web-chat-iframe)  \n         * [Full Screen Chatbot](/docs/full-screen-chatbot)\n* [Webchat v2](/docs/embedded-webchat)  \n   * [Embedded Webchat](/docs/embedded-webchat)  \n         * [Custom CSS Reference](/docs/custom-css-reference)  \n   * [React Components](/docs/react-js)  \n   * [Webchat Client](/docs/webchat-client)\n## Botpress APIs\n* [Files API](/docs/files-api)\n* [Chat API](/docs/chat-api)\n## Appendix\n* [Safety](/docs/safety)  \n   * [Preventing Abuse](/docs/preventing-abuse)  \n   * [Brand Safety Framework](/docs/brand-safety-framework)\n* [Exporting Data](/docs/exporting-data)  \n   * [Raw Conversations](/docs/exporting-raw-conversations-with-the-botpress-api)  \n   * [Conversation History](/docs/getting-the-conversation-history-from-within-your-bot)  \n   * [Streaming Analytics](/docs/streaming-analytics-from-within-your-bot-with-hooks)  \n   * [Compiled Bot Analytics](/docs/exporting-compiled-bot-analytics-with-the-botpress-api)\nPowered by\n# Connect a live agent platform with Botpress\n[ Suggest Edits](/edit/hitl)\nThis documentation will guide you through setting up and implementing a Human-In-The-Loop (HITL) integration with Botpress. By following these steps, you'll be able to connect your platform to Botpress, enabling seamless interaction between your end-users and live agents.\nHow HITL Works in Botpress\n[](#how-hitl-works-in-botpress)\nIn Botpress, the Human-In-The-Loop (HITL) functionality is powered by the HITL Agent. This agent consumes integrations that correctly implement the HITL interface, turning agent hand-off on and off.\n![](https://files.readme.io/a11417252c75c4771500955f4b4e6faff70b921c56efb9e292128189c2a57928-Screenshot_2024-09-16_at_10.45.05_AM.png)\nHere is an overview of the HITL workflow in Botpress:\n* **When a conversation is escalated to a live agent:**\n1. A user is created on both Botpress and the third-party live chat platform. The link between the two users can be done on both sides, but we recommend doing it on Botpress's end using user [tags](#tags).\n2. A conversation is initiated on Botpress, and a corresponding ticket is created on the agent handoff platform. The link between the two conversations can be done on both sides, but we recommend doing it on Botpress's end using conversation [tags](#tags).\n* **When the end user sends a message to a live agent:** The message is forwarded to the agent handoff platform through the \"hitl\" channel.\n* **When the live agent sends a message to the end user:** The agent handoff platform calls the integration webhook, which then forwards the message to the end user.\nThis guide will teach you how to make your integration compatible with the HITL agent.\nConfiguring the Integration Definition\n[](#configuring-the-integration-definition)\nAfter completing the steps in our [Quickstart Guide](https://botpress.com/docs/getting-started-1), the next step is to enhance your integration definition to support HITL.\nThe following code snippet accomplishes the following:\n1. Extends the HITL interface, making this integration compatible with HITL in Botpress.\n2. Adds a HITL channel, which will be used to route messages between the end user and the live agent.\n3. Enhances conversation and user tags with additional information, ensuring proper matching of users and conversations between Botpress and your platform.\nintegration.definition.ts\n`import { z, IntegrationDefinition, interfaces } from \"@botpress/sdk\";\nexport default new IntegrationDefinition({\nname: \"My HITL Integration\",\nversion: \"0.0.1\",\nreadme: \"hub.md\",\nicon: \"icon.svg\",\nchannels: {\nhitl: {\ntitle: \"My HITL\",\nmessages: {},\nconversation: {\ntags: {\nticketId: {\n// This is the ticket ID from your platform. It ensures that conversations are correctly matched between Botpress and your platform.\ntitle: \"Ticket ID\",\n},\nadditionalData: {\ntitle: \"You can pass additional data in the tags object.\",\n},\n},\n},\n},\n},\nactions: {},\nuser: {\ntags: {\n// This is the user ID from the live agent platform. It ensures that users are correctly matched between Botpress and live agent platform.\nagentHandoffPlatformUserId: {\ntitle: \"Live Agent Platform User ID\",\n},\n},\n},\n// Extend the HITL interface to implement HITL in your integration.\n}).extend(interfaces.hitl, () => ({}));\n`\nTags\n[](#tags)\nTags in this integration are customizable fields that can store any information relevant to a conversation or user. You can think of them as metadata. These tags are crucial for maintaining context and linking data between Botpress and your platform. While the examples provided focus on using IDs to match conversations and users, you can customize the tags to include any additional data that suits your needs.\nImplementing the HITL Logic\n[](#implementing-the-hitl-logic)\nNow, let’s walk through the process of implementing the integration step by step. Start by adding the following code to `index.ts` to initialize the integration:\nindex.ts\n`import * as sdk from \"@botpress/sdk\";\nimport * as bp from \".botpress\";\nexport default new bp.Integration({});\n`\n1\\. Add Register & Unregister Methods\n[](#1-add-register--unregister-methods)\nThese methods are part of the integration's lifecycle.\n* **register:** This method is executed every time the integration configuration is saved. We use it to set a webhook that will be triggered when a live agent sends a message. If you manually set the webhook on the third-party platform, this step can be skipped.\n* **unregister:** This method is executed when the integration is uninstalled. We use it to remove the Botpress webhook from the third-party platform. If the webhook was set manually, this step can be skipped.\nindex.ts\n`import * as sdk from \"@botpress/sdk\";\nimport * as bp from \".botpress\";\nimport AgentHandoffPlatformClient from \"./agent-handoff-client\"\nexport default new bp.Integration({\nregister: async ({ webhookUrl }) => {\n// Set the webhook to be triggered when a live agent responds\nAgentHandoffPlatformClient.setWebhook(webhookUrl);\n},\nunregister: async ({ webhookUrl }) => {\n// Remove the webhook when the integration is uninstalled\nAgentHandoffPlatformClient.deleteWebhook(webhookUrl);\n}\n});\n`\nThe webhookUrl provided in the parameters points is unique to an bot integration installation. It's refreshed when an integration is installed/re-installed. There are three webhooks that you should implement in the handler method: handling agent messages, assign a conversation to an agent, and stopping HITL. If you can set up webhooks programmatically, this is the right place to do it.\n2\\. Implement Actions\n[](#2-implement-actions)\nWhen extending the HITL interface, you need to implement a set of predefined methods, similar to how you implement methods when working with interfaces in TypeScript. Once these methods are correctly implemented, the integration can be used by the HITL Agent. These actions are automatically called by the HITL Agent and do not need to be triggered manually. You can rely on IntelliSense to guide you on the exact parameters provided to each action.\nHere are the actions you need to implement:\n* **createUser:** Creates a user in both Botpress and the third-party platform and maps them together. Then, the action returns the user ID of the created Botpress user. The mapping between the two users can be done on both sides, but we recommend doing it on Botpress's end using conversation [tags](#tags).\n* **startHitl:** Creates a conversation in Botpress and a corresponding conversation (often called a ticket) on the third-party platform and maps them together. This action must return the ID of the created Botpress conversation. The mapping between the two conversations can be done on both sides, but we recommend doing it on Botpress's end using conversation [tags](#tags).\n* **stopHitl:** Deletes a conversation on the third-party platform.\nHere’s how you can implement these actions:\nindex.ts\n`// import a library to interact with the agent handoff platform\nimport AgentHandoffPlatformClient from \"./agent-handoff-client\"\nexport default new bp.Integration({\n//...\n// Previously added code\nactions: {\n//...\n// create a user in both platforms\ncreateUser: async ({ client: botpressClient }) => {\n// Create a user on the agent handoff platform\nconst userOnAgentPlatform = AgentHandoffPlatformClient.createUser();\n// Create a user on Botpress\nconst { user: botpressUser } = await botpressClient.getOrCreateUser({\ntags: {\n// Link the Botpress user with the user on the agent handoff platform\nagentHandoffPlatformUserId: userOnAgentPlatform.id,\n},\n});\nreturn {\nuserId: botpressUser.id, // always return the newly created botpress user id\n};\n},\n// create a conversation in both platforms\nstartHitl: async ({ client: botpressClient, input }) => {\nconst { user } = await botpressClient.getUser({\n// Retrieve the user ID created in the createUser action\nid: input.userId,\n});\n// These properties are provided from the \"Escalate to a Human\" action in the Studio\nconst { title, description } = input;\n// Create a ticket on the agent handoff platform\nconst ticket = AgentHandoffPlatformClient.createTicket({\nticketTitle: title,\nticketDescription: description,\n});\n// Create a conversation in Botpress\nconst { conversation } = await botpressClient.getOrCreateConversation({\nchannel: \"hitl\",\ntags: {\n// Link the ticket with the Botpress conversation\nticketId: ticket.id,\n},\n});\nreturn {\nconversationId: conversation.id, // always return the newly created botpress conversation id\n};\n},\n// close the conversation in the agent handoff platform\nstopHitl: async ({ client: botpressClient, input }) => {\nconst { conversation } = await botpressClient.getConversation({\nid: input.conversationId,\n});\nconst ticketId = conversation.tags.ticketId;\n// Close the ticket on the agent handoff platform\nAgentHandoffPlatformClient.closeTicket({ ticketId });\nreturn {};\n},\n//...\n},\n});\n`\n3\\. Send Messages from End User to Live Agent\n[](#3-send-messages-from-end-user-to-live-agent)\nTo enable communication between the end user and the live agent, you'll need to add a special HITL channel that interacts with the third-party API.\nJavaScript\n`// index.ts\n//...\nexport default new bp.Integration({\n// Previously implemented code\nchannels: {\nhitl: {\nmessages: {\n// Send a message from the end user to the live agent\ntext: async ({ client, conversation,  ...props }: bp.AnyMessageProps) => {\nconst { text: userMessage } = props.payload;\nconst externalUserId = payload.userId ? (await client.getUser({ id: payload.userId })).tags.externalId : \"BOT\";\n// Retrieve the ticket ID that was set in the startHitl action\nconst ticketId = conversation.tags.ticketId;\n// Use the agent handoff platform's API to send the message\nAgentHandoffPlatformClient.sendMessage(ticketId, externalUserId, userMessage);\n},\n//...  you can add more message types if you want to support them\n},\n},\n},\n});\n`\nWe suggest starting with the text message type and adding more as needed.\n> ## ���\n>\n> Watch out!\n>\n> `payload.userId` is the user id of the chat-user as seen from the HITL conversation. `user.id` is the id of the bot. If you want the agent to know who he's talking to, you must use `payload.userId`.\n4\\. Send Messages from Live Agent to End User\n[](#4-send-messages-from-live-agent-to-end-user)\nWhen a live agent responds, the live-agent platform needs to send a request to the integration's webhook URL. Upon receiving this request, a special **handler** method is triggered. Let's implement this method to forward the message to the end user.\nindex.ts\n`// ...\nexport default new bp.Integration({\n// ...previously implemented logic\nhandler: async ({ req, client: botpressClient, ctx, logger }) => {\nconst liveAgentEvent = JSON.parse(req.body);\n// Fetch the Botpress user based on the user ID from the third-party platform\nconst { user } = await botpressClient.getOrCreateUser({\ntags: {\nagentHandoffPlatformUserId: liveAgentEvent.userId,\n},\n});\n// Fetch a conversation in Botpress associated with the ticket ID\nconst { conversation } = await botpressClient.getOrCreateConversation({\nchannel: 'hitl',\ntags: {\nticketId: liveAgentEvent.ticketId,\n},\n});\nswitch (liveAgentEvent.eventType) {\ncase 'newMessage':\n// Send the received message from the live agent to the end user\nawait botpressClient.createMessage({\ntype: 'text',\nuserId: user.id,\nconversationId: conversation.id,\npayload: { text: liveAgentEvent.message },\n});\nbreak;\n}\n},\n});\n`\nIn the above example, we don't check the route, or method, but we can do that with the `req` parameter of the handler, which returns an express.js-like request object. You can add `if` conditions to route different actions you'd like, such as assigning agents, or releasing the user back to the bot.\n> ## ���\n>\n> Why do I keep seeing getOrCreate?\n>\n> We don't actually want to create users or conversations at this point. Its simply a matter of the `get` methods not supporting finding by tags, while the `getOrCreate` methods do.\n5\\. Inform Bot When HITL Started and Stopped\n[](#5-inform-bot-when-hitl-started-and-stopped)\nWe need to emit two events to inform the bot about the status of the Human-In-The-Loop (HITL) process:\n**hitlAssigned**: Tells the bot that the conversation has been successfully escalated to a live agent.\n**hitlStopped**: Tells the bot that the conversation with the live agent has ended.\nindex.ts\n`// index.ts\n// ...\nexport default new bp.Integration({\n// ...previously implemented logic\nhandler: async ({ req, client: botpressClient, ctx, logger }) => {\nconst liveAgentEvent = JSON.parse(req.body);\nswitch (liveAgentEvent.eventType) {\ncase 'newMessage':\n// ...\nbreak;\ncase 'ticketAssigned':\n// Emit an event to inform the bot that HITL has been assigned\nawait botpressClient.createEvent({\ntype: 'hitlAssigned',\npayload: {\nconversationId: conversation.id,\nuserId: user.id,\n},\n});\nbreak;\ncase 'ticketSolved':\n// Emit an event to inform the bot that HITL has been stopped\nawait botpressClient.createEvent({\ntype: 'hitlStopped',\npayload: {\nconversationId: conversation.id,\n},\n});\nbreak;\n}\n},\n});\n`\nFull Example\n[](#full-example)\n`// index.ts\nimport * as sdk from \"@botpress/sdk\";\nimport * as bp from \".botpress\";\n// Replace with your actual platform client library\nimport AgentHandoffPlatformClient from \"./agent-handoff-client\";\n// Initialize the integration\nexport default new bp.Integration({\n// Register method to set the webhook when configuration is saved\nregister: async ({ webhookUrl }) => {\n// Set the webhook to be triggered when a live agent responds\nAgentHandoffPlatformClient.setWebhook(webhookUrl);\n},\n// Unregister method to remove the webhook when integration is uninstalled\nunregister: async ({ webhookUrl }) => {\n// Remove the webhook when the integration is uninstalled\nAgentHandoffPlatformClient.deleteWebhook(webhookUrl);\n},\n// Define the HITL actions\nactions: {\n// Create a user on both Botpress and the agent handoff platform\ncreateUser: async ({ client: botpressClient }) => {\n// Create a user on the agent handoff platform\nconst userOnAgentPlatform = AgentHandoffPlatformClient.createUser();\n// Create a user on Botpress\nconst { user: botpressUser } = await botpressClient.getOrCreateUser({\ntags: {\n// Link the Botpress user with the user on the agent handoff platform\nagentHandoffPlatformUserId: userOnAgentPlatform.id,\n},\n});\nreturn {\nuserId: botpressUser.id,\n};\n},\n// Start a HITL session by creating a conversation on both platforms\nstartHitl: async ({ client: botpressClient, input }) => {\nconst { user } = await botpressClient.getUser({\n// Retrieve the user ID created in the createUser action\nid: input.userId,\n});\n// These properties are provided from the \"Escalate to a Human\" action in the Studio\nconst { title, description } = input;\n// Create a ticket on the agent handoff platform\nconst ticket = AgentHandoffPlatformClient.createTicket({\nticketTitle: title,\nticketDescription: description,\n});\n// Create a conversation in Botpress\nconst { conversation } = await botpressClient.getOrCreateConversation({\nchannel: \"hitl\",\ntags: {\n// Link the ticket with the Botpress conversation\nticketId: ticket.id,\n},\n});\nreturn {\nconversationId: conversation.id,\n};\n},\n// Stop a HITL session by closing the conversation on the agent handoff platform\nstopHitl: async ({ client: botpressClient, input }) => {\nconst { conversation } = await botpressClient.getConversation({\nid: input.conversationId,\n});\nconst ticketId = conversation.tags.ticketId;\n// Close the ticket on the agent handoff platform\nAgentHandoffPlatformClient.closeTicket({ ticketId });\nreturn {};\n},\n},\n// Define the HITL channel to send messages from the end user to the live agent\nchannels: {\nhitl: {\nmessages: {\n// Send a message from the end user to the live agent\ntext: async ({ client, payload }) => {\nconst { text: userMessage, conversation, userId } = payload;\n// Retrieve the ticket ID that was set in the startHitl action\nconst ticketId = conversation.tags.ticketId;\n// Use the agent handoff platform's API to send the message\nAgentHandoffPlatformClient.sendMessage(ticketId, userId, userMessage);\n},\n},\n},\n},\n// Handler to process messages sent from the live agent to the end user\nhandler: async ({ req, client: botpressClient }) => {\nconst liveAgentEvent = JSON.parse(req.body);\n// Fetch the Botpress user based on the user ID from the agent handoff platform\nconst { user } = await botpressClient.getOrCreateUser({\ntags: {\nagentHandoffPlatformUserId: liveAgentEvent.userId,\n},\n});\n// Retrieve or create a conversation in Botpress associated with the ticket ID\nconst { conversation } = await botpressClient.getOrCreateConversation({\nchannel: \"hitl\",\ntags: {\nticketId: liveAgentEvent.ticketId,\n},\n});\nswitch (liveAgentEvent.eventType) {\ncase \"newMessage\":\n// Send the received message from the live agent to the end user\nawait botpressClient.createMessage({\ntype: \"text\",\nuserId: user.id,\nconversationId: conversation.id,\npayload: { text: liveAgentEvent.message },\n});\nbreak;\ncase \"ticketAssigned\":\n// Emit an event to inform the bot that HITL has been assigned\nawait botpressClient.createEvent({\ntype: \"hitlAssigned\",\npayload: {\nconversationId: conversation.id,\nuserId: user.id,\n},\n});\nbreak;\ncase \"ticketSolved\":\n// Emit an event to inform the bot that HITL has been stopped\nawait botpressClient.createEvent({\ntype: \"hitlStopped\",\npayload: {\nconversationId: conversation.id,\n},\n});\nbreak;\n}\n},\n});\n`\nProduction Example\n[](#production-example)\nFor a production-grade implementation, you can refer to the Zendesk integration maintained by the Botpress team. Check it out [here](https://github.com/botpress/botpress/tree/master/integrations/zendesk).\nHaving difficulties with HITL Interfaces?\n[](#having-difficulties-with-hitl-interfaces)\nContact us at [\\[email protected\\]](/cdn-cgi/l/email-protection#2941405d4504414c4559694b465d595b4c5a5a074a4644) with as much details as possible about your company and your use case.\nUpdated 17 days ago\n---\n* [Table of Contents](#)\n* * [How HITL Works in Botpress](#how-hitl-works-in-botpress)  \n   * [Configuring the Integration Definition](#configuring-the-integration-definition)  \n         * [Tags](#tags)  \n   * [Implementing the HITL Logic](#implementing-the-hitl-logic)  \n         * [1\\. Add Register & Unregister Methods](#1-add-register--unregister-methods)  \n         * [2\\. Implement Actions](#2-implement-actions)  \n         * [3\\. Send Messages from End User to Live Agent](#3-send-messages-from-end-user-to-live-agent)  \n         * [4\\. Send Messages from Live Agent to End User](#4-send-messages-from-live-agent-to-end-user)  \n         * [5\\. Inform Bot When HITL Started and Stopped](#5-inform-bot-when-hitl-started-and-stopped)  \n   * [Full Example](#full-example)  \n   * [Production Example](#production-example)  \n   * [Having difficulties with HITL Interfaces?](#having-difficulties-with-hitl-interfaces)[Jump to Content](#content)\n[![Botpress](https://files.readme.io/c8cb63b6d586cd66085b4c960570959a424c7050c5ffeb0aeaf31711e2e1b2ac-small-BPLOGO_new_dark_1.png)](https://botpress.com)\n[Guides](/docs)[API Reference](/reference)[Changelog](/changelog)\n---\n[![Botpress](https://files.readme.io/c8cb63b6d586cd66085b4c960570959a424c7050c5ffeb0aeaf31711e2e1b2ac-small-BPLOGO_new_dark_1.png)](https://botpress.com)\nGuides\nMoon (Dark Mode)Sun (Light Mode)\n[Guides](/docs)[API Reference](/reference)[Changelog](/changelog)\nRaw Conversations\nSearch\n## Home\n* [Botpress Documentation](/docs/home)\n## Getting Started\n* [Build](/docs/build)\n* [Deploy](/docs/deploy)\n* [Monitor](/docs/monitor)\n## DASHBOARD\n* [Workspace](/docs/workspace)  \n   * [Home](/docs/home-1)  \n   * [Members](/docs/members)  \n   * [Audits](/docs/audits)  \n   * [Your integrations](/docs/your-integrations)  \n   * [Usage](/docs/usage-2)  \n   * [Settings](/docs/settings)  \n   * [Profile Setting](/docs/user-profile)\n* [Bot](/docs/bot)  \n   * [Overview](/docs/overview-1)  \n   * [Integrations](/docs/integrations-1)  \n   * [Webchat](/docs/webchat-1)  \n   * [Logs](/docs/logs)  \n   * [Conversations](/docs/conversations)  \n   * [Analytics](/docs/analytics-1)  \n   * [Events](/docs/events-2)  \n   * [Issues](/docs/issues)  \n   * [Configuration variables](/docs/configuration-variables-1)\n## STUDIO\n* [Interface](/docs/interface)  \n   * [Nodes](/docs/nodes)  \n   * [Home](/docs/home-2)  \n   * [Flows](/docs/studio-interface-flows)  \n   * [Knowledge Base](/docs/knowledge-base)  \n   * [Tables](/docs/tables)  \n   * [Agents](/docs/agents)  \n         * [Summary Agent](/docs/summary-agent)  \n         * [Personality Agent](/docs/personality-agent)  \n         * [Policy Agent](/docs/policy-agent)  \n         * [Translator Agent](/docs/translator-agent)  \n         * [Knowledge Agent](/docs/knowledge-agent)  \n         * [HITL Agent](/docs/hitl-agent)  \n         * [Vision Agent](/docs/vision-agent)  \n         * [Analytics Agent](/docs/analytics-agent)  \n   * [Library](/docs/library)  \n   * [Hooks](/docs/hooks)  \n   * [Integrations](/docs/integrations-3)  \n   * [Schemas](/docs/schemas)  \n   * [Card Hub](/docs/card-hub)  \n   * [Versions](/docs/versions-1)  \n   * [Chatbot Settings](/docs/chatbot-settings-1)  \n   * [Find](/docs/find)  \n   * [Variables](/docs/variables)  \n   * [Card Tray](/docs/card-tray)  \n   * [Debugger, Logs & JSON](/docs/debugger-logs-json)  \n   * [Emulator](/docs/emulator)  \n   * [Keyboard Shortcuts](/docs/keyboard-shortcuts)  \n   * [Commands](/docs/studio-commands)  \n   * [Studio Preferences](/docs/studio-preferences)  \n   * [Import & Export](/docs/import-export-bots)\n* [Cards](/docs/cards)  \n   * [Send Messages](/docs/send-messages)  \n   * [Execute](/docs/execute)  \n   * [Webchat](/docs/webchat-2)  \n   * [Flow Logic](/docs/flow-logic)  \n   * [AI](/docs/ai)  \n        \n* [Webchat](/docs/webchat-2)  \n   * [Flow Logic](/docs/flow-logic)  \n   * [AI](/docs/ai)  \n         * [AI Task](/docs/ai-task-1)  \n         * [AI Transition](/docs/ai-transition)  \n         * [AI Generate Text](/docs/ai-generate-text)  \n   * [Capture Information](/docs/capture-information)  \n   * [Events](/docs/events-3)  \n   * [Agents](/docs/agents-2)  \n   * [Utilities](/docs/utilities)\n## integrations\n* [Usage](/docs/using-integrations)  \n   * [Asana](/docs/asana-integration)  \n   * [HITL](/docs/hitl-1)  \n   * [Instagram](/docs/instagram)  \n   * [Intercom](/docs/intercom)  \n   * [Line](/docs/line)  \n   * [Messenger](/docs/messenger)  \n   * [Microsoft Teams](/docs/microsoft-teams)  \n   * [Notion](/docs/notion)  \n   * [Slack](/docs/slack)  \n   * [Sunshine Conversations](/docs/sunshine-conversations)  \n   * [Telegram](/docs/telegram)  \n   * [Trello](/docs/trello)  \n   * [Twilio](/docs/twilio)  \n   * [Viber](/docs/viber)  \n   * [Vonage](/docs/vonage)  \n   * [Webhook](/docs/webhook)  \n   * [WhatsApp](/docs/whatsapp)  \n         * [Manual Configuration](/docs/manual-configuration)  \n   * [Zapier](/docs/zapier)  \n   * [Zendesk](/docs/zendesk)\n* [Building](/docs/building-integrations)  \n   * [Getting Started](/docs/getting-started-1)  \n         * [Getting Started](/docs/getting-started-1)  \n         * [Adding Messaging Channel Capabilities](/docs/adding-messaging-channel-capabilities)  \n         * [Adding Actions & Triggers to Botpress Studio](/docs/adding-actions-triggers-to-botpress-studio)  \n         * [Publish your integration on Botpress Hub](/docs/publish-your-integration-on-botpress-hub)  \n   * [Use Your Own LLM](/docs/llm-interfaces)  \n   * [Connect a live agent platform with Botpress](/docs/hitl)  \n   * [Moving Parts](/docs/moving-parts)  \n   * [CLI](/docs/cli)  \n   * [SDK](/docs/sdk)  \n   * [Key Concepts](/docs/key-concepts)  \n         * [Architecture](/docs/architecture)\n/docs/sdk)  \n   * [Key Concepts](/docs/key-concepts)  \n         * [Architecture](/docs/architecture)  \n         * [Tags](/docs/tags)  \n         * [Channels](/docs/channels)  \n         * [Configuration](/docs/configuration)  \n         * [User](/docs/user)  \n         * [Conversations](/docs/conversations-1)  \n         * [Messages](/docs/messages)  \n         * [Event](/docs/event)  \n         * [States](/docs/states-1)  \n         * [Actions](/docs/actions)  \n         * [Definitions](/docs/definitions)  \n         * [Secrets](/docs/secrets)  \n         * [ZUI - Zod schema UI components in Botpress \\[BETA\\]](/docs/zui-zod-schema-ui-components-in-botpress)  \n   * [How to](/docs/states)  \n         * [States](/docs/states)  \n         * [Register & Unregister](/docs/register-unregister)  \n         * [Integrations Actions](/docs/integrations)  \n         * [Integration Events](/docs/integration-events)  \n         * [Handler](/docs/handler)  \n         * [Logging](/docs/logging)  \n         * [Building a Custom Integration](/docs/building-a-custom-integration)\n## Webchat\n* [Webchat](/docs/webchat)  \n   * [Webflow](/docs/webflow)  \n   * [Wix](/docs/wix)  \n   * [Wordpress](/docs/wordpress)\n* [Webchat v1 (deprecated)](/docs/web-chat-v1old)  \n   * [Controlling Web Chat using JavaScript](/docs/controlling-web-chat-using-javascript)  \n   * [Styling your webchat](/docs/chatbot-button)  \n         * [Chatbot Button](/docs/chatbot-button)  \n         * [Chat Header](/docs/chat-header)  \n         * [User Input Area](/docs/user-input-area)  \n         * [Show Bot Info](/docs/show-bot-info)  \n   * [Embedding Webchat](/docs/react-app)  \n         * [React App](/docs/react-app)  \n         * [React Native App](/docs/react-native-app)  \n         * [Web Chat Iframe](/docs/web-chat-iframe)  \n         * [Full Screen Chatbot](/docs/full-screen-chatbot)\n* [Webchat v2](/docs/embedded-webchat)  \n   * [Embedded Webchat](/docs/embedded-webchat)  \n         * [Custom CSS Reference](/docs/custom-css-reference)  \n   * [React Components](/docs/react-js)  \n   * [Webchat Client](/docs/webchat-client)\n## Botpress APIs\n* [Files API](/docs/files-api)\n* [Chat API](/docs/chat-api)\n## Appendix\n* [Safety](/docs/safety)  \n   * [Preventing Abuse](/docs/preventing-abuse)  \n   * [Brand Safety Framework](/docs/brand-safety-framework)\n* [Exporting Data](/docs/exporting-data)  \n   * [Raw Conversations](/docs/exporting-raw-conversations-with-the-botpress-api)  \n   * [Conversation History](/docs/getting-the-conversation-history-from-within-your-bot)  \n   * [Streaming Analytics](/docs/streaming-analytics-from-within-your-bot-with-hooks)  \n   * [Compiled Bot Analytics](/docs/exporting-compiled-bot-analytics-with-the-botpress-api)\nPowered by\n# Raw Conversations\n[ Suggest Edits](/edit/exporting-raw-conversations-with-the-botpress-api)\nThe Botpress API allows you to access your bot's conversations from an external service. This is very useful if you need to manage or analyze the conversations somehow. In this tutorial we give steps to use the API for this purpose and steps to format the response data. Let's get started!\n> ## ���\n>\n> Note\n>\n> Access the API documentation to verify the schema/structure of the [Conversations](https://botpress.com/docs/api-documentation/#schema%5Fconversation) and the [Messages](https://botpress.com/docs/api-documentation/#schema%5Fmessage) and see if the data is useful for your use case.\n> ## ���\n>\n> Note\n>\n> You can find your personal access token in your [Admin Dashboard](https://app.botpress.cloud/). You can find your bot ID in the URL of your bot's dashboard, it's the letters and numbers right after `chatbots/`\n1\\. Getting the Conversations list from the API\n[](#1-getting-the-conversations-list-from-the-api)\nUsing Axios\n[](#using-axios)\nSend a `GET` request to `https://api.botpress.cloud/v1/chat/conversations` adding the following headers: `Authorization: Bearer <your-personal-access-token>` and `x-bot-id: <your-bot-id>`.\nThis is how the request would look like using Axios in a Javascript application (e.g in a Execute Code in Botpress):\nCoffeeScript\n`` const requestConfig = {\nheaders: {\n// Authorization header with a Bearer token for authentication.\nAuthorization: `Bearer ${process.env.BOTPRESS_PERSONAL_ACCESS_TOKEN}`,\n// The unique identifier of the bot for which we want to retrieve conversations.\n'x-bot-id': process.env.BOTPRESS_BOT_ID,\n},\n}\n// An empty array to store all retrieved conversations.\nconst allConversations = []\n// Send an HTTP GET request to the specified API endpoint to get conversations.\nconst getConversations = await axios.get(\n`https://api.botpress.cloud/v1/chat/conversations?nextToken=${paginationToken}`,\nrequestConfig\n)\n// Add the retrieved conversations to the list.\nallConversations.push(...getConversations.data.conversations)\n``\nUsing the Botpress Client library\n[](#using-the-botpress-client-library)\nThe same logic to get conversations but using the [Botpress Client library](https://www.npmjs.com/package/@botpress/client) in a Node.js application:\nJavaScript\n`import { Client } from '@botpress/client'\nconst client = new Client({\ntoken: process.env.BOTPRESS_ACCESS_TOKEN,\nbotId: process.env.BOTPRESS_BOT_ID,\n})\nconst allConversations = []\nconst getConversations = await client.listConversations({\nnextToken: paginationToken,\n})\nallConversations.push(getConversations.conversations)\n`\n> ## ���\n>\n> Info\n>\n> The API returns a maximum of 20 conversations per request. You will need to use the `nextToken` property to fetch the next batch of conversations. The `nextToken` property is returned in the `meta` object of the response.\n2\\. Getting all Conversations from the API\n[](#2-getting-all-conversations-from-the-api)\nNow that you know the methods of getting the first conversations from the API, let's see how to get them. You can get them gradually or all at once, but you need to use the pagination token regardless.\nGetting conversations gradually\n[](#getting-conversations-gradually)\nCreate a function that will fetch the next batch of conversations when called. You could use a button to trigger it or trigger it automatically with infinite scroll. Pass the `nextToken` property retrieved from the first request as a parameter to the function, then update it on subsequent calls. More about pagination [here](https://botpress.com/docs/api-documentation/#pagination).\nJavaScript\n`` async function loadConversations(paginationToken) {\nconst getConversations = await axios.get(\n`https://api.botpress.cloud/v1/chat/conversations?nextToken=${paginationToken}`,\n{\n...requestConfig,\n}\n)\nreturn getConversations.data\n// The returned value will be an object: `{ conversations: [...], meta: { nextToken: \"string\" } }`\n}\n``\nGetting all conversations\n[](#getting-all-conversations)\nUse a loop to fetch all conversations at once using the above logic. This is not recommended for bots with a large number of conversations as it may take a long time to complete and may cause timeouts. The use of a library like\n[p-retry](https://www.npmjs.com/package/p-retry) to retry requests automatically is recommended.\nJavaScript\n`` const allConversations = []\nlet paginationToken\ndo {\n// Send an HTTP GET request to the specified API endpoint to get conversations.\nconst getConversations = await axios.get(\n`https://api.botpress.cloud/v1/chat/conversations?nextToken=${paginationToken}`,\nrequestConfig\n)\n// Add the retrieved conversations to the list.\nallConversations.push(...getConversations.data.conversations)\n// Retrieve the token for the next set of conversations, if available.\npaginationToken = getConversations.data.meta.nextToken\n// As long as paginationToken has a value, this function will execute again\n} while (paginationToken)\n``\n3\\. Getting the Messages list\n[](#3-getting-the-messages-list)\nOnce you have gone through the list of conversations and found out the id of the desired conversation to export, you can then use the API to list the actual messages.\nIn the example below we are using the [Botpress Client library](https://www.npmjs.com/package/@botpress/client) and assume the client is set up already:\nJavaScript\n`const conversationId = 'the desired conversation id here'\nconst allMessages = []\nconst getMessages = await client.listMessages({\nconversationId,\nnextToken: paginationToken,\n})\nallMessages.push(getMessages.messages)\n`\nYou might create a loader function or a finite loop as shown above to get all the messages.\nThis is how the `allMessages` array is gonna look like:\nJSON\n`[\n{\n\"id\": \"503dda87-3e54-40b6-8167-55d685a85345\",\n\"createdAt\": \"2023-10-24T20:20:44.812Z\",\n\"conversationId\": \"ec669jj8-e465-482d-8fbe-cb348bf81212\",\n\"payload\": {\n\"text\": \"Pick one or many from the list\",\n\"options\": [\n{\n\"label\": \"First option\",\n\"value\": \"First option\"\n},\n{\n\"label\": \"Second option\",\n\"value\": \"Second option\"\n}\n]\n},\n\"tags\": {},\n\"userId\": \"efc0f8e8-7e51-4458-8907-ea1e43eb8852\",\n\"type\": \"choice\",\n\"direction\": \"outgoing\"\n},\n{\n\"id\": \"41bb8564-e7ab-4113-c3d8-5fdhh27e4c34\",\n\"createdAt\": \"2023-10-24T20:20:49.201Z\",\n\"conversationId\": \"ec66ffb8-e465-482d-8fbe-csd348b81212\",\n\"payload\": {\n\"type\": \"quick_reply\",\n\"text\": \"First option\",\n\"payload\": \"First option\"\n},\n\"tags\": {\n\"webchat:id\": \"cc70c21b-4g24-4f5c-8f52-43a900b7b047\"\n},\n\"userId\": \"f96da97d-4215-447f-86e2-b9e33232e6d3\",\n\"type\": \"quick_reply\",\n\"direction\": \"incoming\"\n},\n{\n\"id\": \"c6ee8bd6-c862-54d2-97cb-998f555d4251\",\n\"createdAt\": \"2023-10-24T20:20:49.795Z\",\n\"conversationId\": \"ec669dd8-e465-482d-8fty-cb3348581212\",\n\"payload\": {\n\"imageUrl\": \"https://s3.us-east-1.amazonaws.com/cloud-studio-botsbca2d219-2316w6llinepa/f4b77ea0-d597-4d3f-988d-9c66f127d542/media/2360a7bb-162b-4ed1-8551-7000fdb0f7ef.png\"\n},\n\"tags\": {},\n\"userId\": \"efb454t5-7e51-4458-8007-ea1e43eb8852\",\n\"type\": \"image\",\n\"direction\": \"outgoing\"\n}\n]\n`\n> ## ���\n>\n> Note\n>\n> In this example the bot sends a Multiple Choice card, then the user answers by clicking one of the options, and then the bot sends an Image card. Notice how the message payload changes according to the message type, so be mindful of that when reading the `payload` property.\n4\\. Formatting the Messages list\n[](#4-formatting-the-messages-list)\nNow that you have the list of messages of a conversation it's time to format it so it becomes readable. We are going to use a custom function for that:\n`` function formatMessage(message) {\nlet messageText = ''\nif (message.direction === 'incoming') {\nmessageText += 'User: '\n} else {\nmessageText += 'Bot: '\n}\nif (message.type === 'text' || message.type === 'quick_reply') {\nmessageText += message.payload.text\n} else if (message.type === 'choice') {\nmessageText += `${message.payload.text}: ${message.payload.options.map((option) => option.label).join(' / ')}`\n} else {\nmessageText += `Media message of type ${message.type}`\n}\nmessageText += `\\n at ${new Date(message.createdAt).toLocaleString()}`\nreturn messageText\n}\nconst history = allMessages.map((message) => formatMessage(message)).join('\\n\\n')\n``\nThe `history` string will end up looking like this:\nText\n`Bot: Pick one or many from the list: First Option / Second Option\nat 24/10/2023, 5:20:44 PM\nUser: First Option\nat 24/10/2023, 5:21:00 PM\nBot: Media message of type image\nat 24/10/2023, 5:21:09 PM\n`\n> ## ���\n>\n> Note\n>\n> You can customize the `formatMessage` function to have different formatting or to return more information of the messages. Now use the `history` variable however you like - send it via email, add it to a Google Sheets document, send it to Botpress to do further processing, etc.\nUpdated about 1 month ago\n---\n* [Table of Contents](#)\n* * [1\\. Getting the Conversations list from the API](#1-getting-the-conversations-list-from-the-api)  \n         * [Using Axios](#using-axios)  \n         * [Using the Botpress Client library](#using-the-botpress-client-library)  \n   * [2\\. Getting all Conversations from the API](#2-getting-all-conversations-from-the-api)  \n         * [Getting conversations gradually](#getting-conversations-gradually)  \n         * [Getting all conversations](#getting-all-conversations)  \n   * [3\\. Getting the Messages list](#3-getting-the-messages-list)  \n   * [4\\. Formatting the Messages list](#4-formatting-the-messages-list)[Jump to Content](#content)\n[![Botpress](https://files.readme.io/c8cb63b6d586cd66085b4c960570959a424c7050c5ffeb0aeaf31711e2e1b2ac-small-BPLOGO_new_dark_1.png)](https://botpress.com)\n[Guides](/docs)[API Reference](/reference)[Changelog](/changelog)\n---\n[![Botpress](https://files.readme.io/c8cb63b6d586cd66085b4c960570959a424c7050c5ffeb0aeaf31711e2e1b2ac-small-BPLOGO_new_dark_1.png)](https://botpress.com)\nGuides\nMoon (Dark Mode)Sun (Light Mode)\n[Guides](/docs)[API Reference](/reference)[Changelog](/changelog)\nFiles API\nSearch\n## Home\n* [Botpress Documentation](/docs/home)\n## Getting Started\n* [Build](/docs/build)\n* [Deploy](/docs/deploy)\n* [Monitor](/docs/monitor)\n## DASHBOARD\n* [Workspace](/docs/workspace)  \n   * [Home](/docs/home-1)  \n   * [Members](/docs/members)  \n   * [Audits](/docs/audits)  \n   * [Your integrations](/docs/your-integrations)  \n   * [Usage](/docs/usage-2)  \n   * [Settings](/docs/settings)  \n   * [Profile Setting](/docs/user-profile)\n* [Bot](/docs/bot)  \n   * [Overview](/docs/overview-1)  \n   * [Integrations](/docs/integrations-1)  \n   * [Webchat](/docs/webchat-1)  \n   * [Logs](/docs/logs)  \n   * [Conversations](/docs/conversations)  \n   * [Analytics](/docs/analytics-1)  \n   * [Events](/docs/events-2)  \n   * [Issues](/docs/issues)  \n   * [Configuration variables](/docs/configuration-variables-1)\n## STUDIO\n* [Interface](/docs/interface)  \n   * [Nodes](/docs/nodes)  \n   * [Home](/docs/home-2)  \n   * [Flows](/docs/studio-interface-flows)  \n   * [Knowledge Base](/docs/knowledge-base)  \n   * [Tables](/docs/tables)  \n   * [Agents](/docs/agents)  \n         * [Summary Agent](/docs/summary-agent)  \n         * [Personality Agent](/docs/personality-agent)  \n         * [Policy Agent](/docs/policy-agent)  \n         * [Translator Agent](/docs/translator-agent)  \n         * [Knowledge Agent](/docs/knowledge-agent)  \n         * [HITL Agent](/docs/hitl-agent)  \n         * [Vision Agent](/docs/vision-agent)  \n         * [Analytics Agent](/docs/analytics-agent)  \n   * [Library](/docs/library)  \n   * [Hooks](/docs/hooks)  \n   * [Integrations](/docs/integrations-3)  \n   * [Schemas](/docs/schemas)  \n   * [Card Hub](/docs/card-hub)  \n   * [Versions](/docs/versions-1)  \n   * [Chatbot Settings](/docs/chatbot-settings-1)  \n   * [Find](/docs/find)  \n   * [Variables](/docs/variables)  \n   * [Card Tray](/docs/card-tray)  \n   * [Debugger, Logs & JSON](/docs/debugger-logs-json)  \n   * [Emulator](/docs/emulator)  \n   * [Keyboard Shortcuts](/docs/keyboard-shortcuts)  \n   * [Commands](/docs/studio-commands)  \n   * [Studio Preferences](/docs/studio-preferences)  \n   * [Import & Export](/docs/import-export-bots)\n* [Cards](/docs/cards)  \n   * [Send Messages](/docs/send-messages)  \n   * [Execute](/docs/execute)  \n   * [Webchat](/docs/webchat-2)  \n   * [Flow Logic](/docs/flow-logic)  \n   * [AI](/docs/ai)  \n        \n* [Webchat](/docs/webchat-2)  \n   * [Flow Logic](/docs/flow-logic)  \n   * [AI](/docs/ai)  \n         * [AI Task](/docs/ai-task-1)  \n         * [AI Transition](/docs/ai-transition)  \n         * [AI Generate Text](/docs/ai-generate-text)  \n   * [Capture Information](/docs/capture-information)  \n   * [Events](/docs/events-3)  \n   * [Agents](/docs/agents-2)  \n   * [Utilities](/docs/utilities)\n## integrations\n* [Usage](/docs/using-integrations)  \n   * [Asana](/docs/asana-integration)  \n   * [HITL](/docs/hitl-1)  \n   * [Instagram](/docs/instagram)  \n   * [Intercom](/docs/intercom)  \n   * [Line](/docs/line)  \n   * [Messenger](/docs/messenger)  \n   * [Microsoft Teams](/docs/microsoft-teams)  \n   * [Notion](/docs/notion)  \n   * [Slack](/docs/slack)  \n   * [Sunshine Conversations](/docs/sunshine-conversations)  \n   * [Telegram](/docs/telegram)  \n   * [Trello](/docs/trello)  \n   * [Twilio](/docs/twilio)  \n   * [Viber](/docs/viber)  \n   * [Vonage](/docs/vonage)  \n   * [Webhook](/docs/webhook)  \n   * [WhatsApp](/docs/whatsapp)  \n         * [Manual Configuration](/docs/manual-configuration)  \n   * [Zapier](/docs/zapier)  \n   * [Zendesk](/docs/zendesk)\n* [Building](/docs/building-integrations)  \n   * [Getting Started](/docs/getting-started-1)  \n         * [Getting Started](/docs/getting-started-1)  \n         * [Adding Messaging Channel Capabilities](/docs/adding-messaging-channel-capabilities)  \n         * [Adding Actions & Triggers to Botpress Studio](/docs/adding-actions-triggers-to-botpress-studio)  \n         * [Publish your integration on Botpress Hub](/docs/publish-your-integration-on-botpress-hub)  \n   * [Use Your Own LLM](/docs/llm-interfaces)  \n   * [Connect a live agent platform with Botpress](/docs/hitl)  \n   * [Moving Parts](/docs/moving-parts)  \n   * [CLI](/docs/cli)  \n   * [SDK](/docs/sdk)  \n   * [Key Concepts](/docs/key-concepts)  \n         * [Architecture](/docs/architecture)\n/docs/sdk)  \n   * [Key Concepts](/docs/key-concepts)  \n         * [Architecture](/docs/architecture)  \n         * [Tags](/docs/tags)  \n         * [Channels](/docs/channels)  \n         * [Configuration](/docs/configuration)  \n         * [User](/docs/user)  \n         * [Conversations](/docs/conversations-1)  \n         * [Messages](/docs/messages)  \n         * [Event](/docs/event)  \n         * [States](/docs/states-1)  \n         * [Actions](/docs/actions)  \n         * [Definitions](/docs/definitions)  \n         * [Secrets](/docs/secrets)  \n         * [ZUI - Zod schema UI components in Botpress \\[BETA\\]](/docs/zui-zod-schema-ui-components-in-botpress)  \n   * [How to](/docs/states)  \n         * [States](/docs/states)  \n         * [Register & Unregister](/docs/register-unregister)  \n         * [Integrations Actions](/docs/integrations)  \n         * [Integration Events](/docs/integration-events)  \n         * [Handler](/docs/handler)  \n         * [Logging](/docs/logging)  \n         * [Building a Custom Integration](/docs/building-a-custom-integration)\n## Webchat\n* [Webchat](/docs/webchat)  \n   * [Webflow](/docs/webflow)  \n   * [Wix](/docs/wix)  \n   * [Wordpress](/docs/wordpress)\n* [Webchat v1 (deprecated)](/docs/web-chat-v1old)  \n   * [Controlling Web Chat using JavaScript](/docs/controlling-web-chat-using-javascript)  \n   * [Styling your webchat](/docs/chatbot-button)  \n         * [Chatbot Button](/docs/chatbot-button)  \n         * [Chat Header](/docs/chat-header)  \n         * [User Input Area](/docs/user-input-area)  \n         * [Show Bot Info](/docs/show-bot-info)  \n   * [Embedding Webchat](/docs/react-app)  \n         * [React App](/docs/react-app)  \n         * [React Native App](/docs/react-native-app)  \n         * [Web Chat Iframe](/docs/web-chat-iframe)  \n         * [Full Screen Chatbot](/docs/full-screen-chatbot)\n* [Webchat v2](/docs/embedded-webchat)  \n   * [Embedded Webchat](/docs/embedded-webchat)  \n         * [Custom CSS Reference](/docs/custom-css-reference)  \n   * [React Components](/docs/react-js)  \n   * [Webchat Client](/docs/webchat-client)\n## Botpress APIs\n* [Files API](/docs/files-api)\n* [Chat API](/docs/chat-api)\n## Appendix\n* [Safety](/docs/safety)  \n   * [Preventing Abuse](/docs/preventing-abuse)  \n   * [Brand Safety Framework](/docs/brand-safety-framework)\n* [Exporting Data](/docs/exporting-data)  \n   * [Raw Conversations](/docs/exporting-raw-conversations-with-the-botpress-api)  \n   * [Conversation History](/docs/getting-the-conversation-history-from-within-your-bot)  \n   * [Streaming Analytics](/docs/streaming-analytics-from-within-your-bot-with-hooks)  \n   * [Compiled Bot Analytics](/docs/exporting-compiled-bot-analytics-with-the-botpress-api)\nPowered by\n# Files API\n[ Suggest Edits](/edit/files-api)\nThe Files API allows you to upload, download, and manage files and searchable documents for your bots and integrations in Botpress Cloud.\nFiles can be in any text or binary format, and documents (such as PDF, Microsoft Office, HTML, CSV, etc.) can be indexed to be used for semantic search in RAG (Retrieval Augmented Generation) implementations. Files are private by default but can be made publicly accessible through a permanent URL that's unique for each file.\nGetting Started\n[](#getting-started)\n1. Get familiarized with the [API reference](../docs/api-documentation/#files) and the different API endpoints available\n2. Review the [instructions on how to authenticate](../docs/api-documentation/#authentication) with the API.\nExamples\n[](#examples)\nCreating and uploading a file\n[](#creating-and-uploading-a-file)\nIn an Execute Card in your bot\n[](#in-an-execute-card-in-your-bot)\nThe following code snippet can be put in an Execute Card in your bot to create and upload a file that can be accessed by anyone with the file URL and that will be indexed for semantic search:\n> Note: Make sure you have enabled the \"Use the Botpress Client\" setting in your bot's settings in Botpress Studio in order to have access to the `client` global variable, otherwise it will not be accessible and you'll get an error.\nJavaScript\n`const file = await client.uploadFile({\nkey: 'optional_prefix/unique_file_name.txt', // Each file needs a unique key under your bot\ncontent: 'This is a test file',\n})\n`\nOnce the code above runs, the URL to download the file will be available in the `file.url` property.\nBy default the file URL returned will be temporary and change on each request to this endpoint, and will expire after a short period of time and thus should not be stored long-term, but if the file was created with a 'public\\_content' access policy then this URL will be permanent and can be stored long-term.\nUploading from an existing URL\n[](#uploading-from-an-existing-url)\nOr if the file is already available in a URL and you want to download and then upload it to Botpress Cloud you can pass it in the `url` parameter instead of using the `content` parameter:\nJavaScript\n`const file = await client.uploadFile({\nkey: 'unique_file_name.pdf', // Each file needs a unique key under your bot\nurl: 'https://example.com/test.pdf', // This is the external URL where the file is currently located\n})\n`\nUploading a binary file\n[](#uploading-a-binary-file)\nIf you are dealing with a binary file such as a PDF or Microsoft Office document you can also pass a `Buffer` object as the `content` parameter for the file:\nJavaScript\n`const buffer = // This must be a Buffer object containing the binary content of the file\nconst file = await client.uploadFile({\nkey: 'unique_file_name.pdf', // Each file needs a unique key under your bot\ncontent: buffer,\n})\n`\nIn a custom script using the Botpress Client\n[](#in-a-custom-script-using-the-botpress-client)\nIf you're using Javascript or TypeScript the easiest way to interact with the API is using the [Botpress Client](https://www.npmjs.com/package/@botpress/client). You can install the client package by using your favorite package manager:\nnpmpnpmText\n`npm install @botpress/client\n`\n`pnpm install @botpress/client\n`\n`yarn add @botpress/client\n`\nThe Botpress Client will handle the authentication and other details for you, you just need to provide your Botpress PAT (Personal Access Token) to the client and the ID of the bot that the client will access. If your use-case requires accessing multiple bots, you can define as many client instances as needed (one for each bot).\nYou can use the following code snippet to create and upload a file in a custom script using the Botpress Client. Note that in the example below your Botpress PAT (Personal Access Token) and bot ID must be defined in the environment variables `BOTPRESS_PAT` and `BOTPRESS_BOT_ID` respectively.\nJavaScript\n`import { Client } from '@botpress/client'\nconst client = new Client({\ntoken: process.env.BOTPRESS_PAT,\nbotId: process.env.BOTPRESS_BOT_ID,\n})\nconst file = await client.uploadFile({\nkey: 'optional_prefix/unique_file_name.txt',\ncontent: 'This is a test file',\n})\n`\nIn a custom script using an HTTP client\n[](#in-a-custom-script-using-an-http-client)\nIf you can't use the Botpress Client (e.g. you can't install the package or you're working with a different programming language) you can also use any HTTP client to make requests to the API directly.\nPlease note that when calling the API directly, an HTTP request to the Botpress API (specifying the file size beforehand) will be needed to create the empty file first, and a separate HTTP request will be needed to upload the file content to the unique upload URL provided in the response of the first request.\nAdditionally, if you need to access the file URL right away a third request to the \"Get File\" API endpoint will be needed to get the URL of the file after it has been uploaded.\nHere's an example on how to do this using the native `fetch()` function in Javascript/TypeScript, note that your Botpress PAT will need to be defined in the environment variable `BOTPRESS_PAT`:\nJavaScript\n`` const fileContent = 'Here goes the content of your file'\nconst buffer = Buffer.from(fileContent)\n// Step 1: Create the file in Botpress Cloud.\n// Please note that specifying the file size (in raw bytes, not characters) is required when calling this endpoint.\nconst result = await fetch('https://api.botpress.cloud/v1/files', {\nmethod: 'PUT',\nheaders: {\n'Content-Type': 'application/json',\nAuthorization: `Bearer ${process.env.BOTPRESS_PAT}`,\n},\nbody: JSON.stringify({\nkey: 'unique_file_name.txt',\nsize: buffer.byteLength,\n}),\n})\nconst response = await result.json()\n// Step 2: Upload the file content to the unique upload URL provided for the created file.\nawait fetch(response.file.uploadUrl, {\nmethod: 'PUT',\nbody: buffer,\n})\n// The variable below will contain the URL to download the file content uploaded above. If the file was\n// created with the 'public_content' access policy it will be a permanent URL that you can store long-term,\n// otherwise it will contain a temporary pre-signed URL that expires after a short period of time.\n// If you need to get a new URL, you can always use the `getFile` API endpoint.\nconst downloadUrl = response.file.url\n``\nAdding tags to a file\n[](#adding-tags-to-a-file)\nYou can add custom tags to a file by passing the `tags` parameter when it's created. Tags allow you to organize and classify files in any way you see fit, and can be specified as a filter when listing or searching files.\nJavaScript\n`const file = await client.uploadFile({\nkey: 'test.txt',\ncontent: 'This is a test file',\ntags: {\n// Tags are optional but are useful for filtering files by a custom criteria you choose when using the \"List Files\" or \"Search Files\" API endpoints. You can change or remove the tags below based on your needs.\ncategory: 'Sales',\nknowledgeBaseName: 'Client Questions',\n},\n})\n`\nCreating a public file\n[](#creating-a-public-file)\nBy default all files are private and can only be accessed by the bot that created them. If you need to make a file publicly accessible by anyone you can assign the `public_content` access policy to the file:\nJavaScript\n`const file = await client.uploadFile({\nkey: 'test.txt',\ncontent: 'This is a public file',\naccessPolicies: ['public_content'],\n})\n`\nIf you only want to allow all the integrations installed in the bot to access the file rather than making it fully public, you can just assign the `integrations` access policy instead:\nJavaScript\n`const file = await client.uploadFile({\nkey: 'test.txt',\ncontent: 'This is a file that can be accessed by all integrations in a bot',\naccessPolicies: ['integrations'],\n})\n<|end_input|>","role":"user","type":"text"}],"meta":{"integrationName":"zai","promptCategory":"zai:zai.extract","promptSource":"zai:zai.extract:default"},"model":"fast","signal":{},"stopSequences":["■NO_MORE_ELEMENT■"]},"method":"POST","url":"https://api.botpress.cloud/v2/cognitive/generate-text"}

Output:
■json_start■{ "feature": "Files API", "parent": "Botpress APIs" }■json_end■
■json_start■{ "feature": "Chat API", "parent": "Botpress APIs" }■json_end■
■json_start■{ "feature": "Webchat v1 (deprecated)", "parent": "Webchat" }■json_end■
■json_start■{ "feature": "Webchat v2", "parent": "Webchat" }■json_end■
■json_start■{ "feature": "Webflow", "parent": "Webchat" }■json_end■
■json_start■{ "feature": "Wix", "parent": "Webchat" }■json_end■
■■json_start■{ "feature": "Wordpress", "parent": "Webchat" }■json_end■■json_start■{ "feature": "HITL", "parent": "Integrations", "description": "Human-In-The-Loop integration" }■json_end■