{"id":48940547,"url":"https://github.com/green-api/whatsapp-chatbot-js-v2","last_synced_at":"2026-04-17T13:31:59.737Z","repository":{"id":319391378,"uuid":"922905947","full_name":"green-api/whatsapp-chatbot-js-v2","owner":"green-api","description":"The WhatsApp chat bot v2 based on the new JavaScript library","archived":false,"fork":false,"pushed_at":"2025-10-18T01:13:47.000Z","size":144,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-10-19T01:03:30.923Z","etag":null,"topics":["bot","bot-framework","botapi","whatsapp","whatsapp-api","whatsapp-bot","whatsapp-bot-api","whatsapp-chat"],"latest_commit_sha":null,"homepage":"https://green-api.com/en","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/green-api.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-01-27T09:55:34.000Z","updated_at":"2025-10-18T01:13:50.000Z","dependencies_parsed_at":"2025-10-19T01:03:37.182Z","dependency_job_id":"fbac2bae-285e-4148-bd54-9c06b2ae57bd","html_url":"https://github.com/green-api/whatsapp-chatbot-js-v2","commit_stats":null,"previous_names":["green-api/whatsapp-chatbot-js-v2"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/green-api/whatsapp-chatbot-js-v2","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/green-api%2Fwhatsapp-chatbot-js-v2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/green-api%2Fwhatsapp-chatbot-js-v2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/green-api%2Fwhatsapp-chatbot-js-v2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/green-api%2Fwhatsapp-chatbot-js-v2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/green-api","download_url":"https://codeload.github.com/green-api/whatsapp-chatbot-js-v2/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/green-api%2Fwhatsapp-chatbot-js-v2/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31931285,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-17T12:37:54.787Z","status":"ssl_error","status_checked_at":"2026-04-17T12:37:25.095Z","response_time":62,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bot","bot-framework","botapi","whatsapp","whatsapp-api","whatsapp-bot","whatsapp-bot-api","whatsapp-chat"],"created_at":"2026-04-17T13:31:55.801Z","updated_at":"2026-04-17T13:31:59.731Z","avatar_url":"https://github.com/green-api.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WhatsApp Bot Library\n\nA modern, state-based WhatsApp bot library for Node.js built on top of GREEN-API.\n\n## Support Links\n\n[![Support](https://img.shields.io/badge/support@green--api.com-D14836?style=for-the-badge\u0026logo=gmail\u0026logoColor=white)](mailto:support@green-api.com)\n[![Support](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge\u0026logo=telegram\u0026logoColor=white)](https://t.me/greenapi_support_eng_bot)\n[![Support](https://img.shields.io/badge/WhatsApp-25D366?style=for-the-badge\u0026logo=whatsapp\u0026logoColor=white)](https://wa.me/77273122366)\n\n## Guides \u0026 News\n\n[![Guides](https://img.shields.io/badge/YouTube-%23FF0000.svg?style=for-the-badge\u0026logo=YouTube\u0026logoColor=white)](https://www.youtube.com/@greenapi-en)\n[![News](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge\u0026logo=telegram\u0026logoColor=white)](https://t.me/green_api)\n[![News](https://img.shields.io/badge/WhatsApp-25D366?style=for-the-badge\u0026logo=whatsapp\u0026logoColor=white)](https://whatsapp.com/channel/0029VaLj6J4LNSa2B5Jx6s3h)\n\n[![NPM Version](https://img.shields.io/npm/v/@green-api/whatsapp-chatbot-js-v2)](https://www.npmjs.com/package/@green-api/whatsapp-chatbot-js-v2)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n## Features\n\n- State-based conversation flow\n- Built-in session management\n- Flexible message handling\n- Navigation support\n- Custom storage extensibility\n- TypeScript support\n- Automatic instance settings configuration\n\n## Installation\n\n```bash\nnpm install @green-api/whatsapp-chatbot-js-v2\n```\n\n## Quick Start\n\n```typescript\nimport { WhatsAppBot, State } from '@green-api/whatsapp-chatbot-js-v2';\n\n// Initialize the bot\nconst bot = new WhatsAppBot({\n\tidInstance: \"your-instance-id\",\n\tapiTokenInstance: \"your-token\",\n\tdefaultState: \"menu\"\n});\n\n// Define states\nconst menuState: State = {\n\tname: \"menu\",\n\tasync onEnter(message) {\n\t\tawait bot.sendText(\n\t\t\tmessage.chatId,\n\t\t\t\"Welcome! Choose an option:\\n1. Help\\n2. About\"\n\t\t);\n\t},\n\tasync onMessage(message) {\n\t\tif (message.text === \"1\") {\n\t\t\treturn \"help\";\n\t\t}\n\t\treturn null; // Continue to global handlers\n\t}\n};\n\n// Add states and start the bot\nbot.addState(menuState);\nbot.start();\n```\n\n## Core Components\n\n### Bot Configuration\n\nComplete configuration options for the WhatsAppBot:\n\n```typescript\ninterface BotConfig\u003cT = any\u003e {\n\t/** Green API instance ID */\n\tidInstance: string;\n\n\t/** Green API instance token */\n\tapiTokenInstance: string;\n\n\t/** Initial state name for new sessions. Default: \"root\" */\n\tdefaultState?: string;\n\n\t/** Session timeout in seconds. Default: 300 (5 minutes) */\n\tsessionTimeout?: number;\n\n\t/** Function to generate session timeout message based on session data */\n\tgetSessionTimeoutMessage?: (session: SessionData\u003cT\u003e) =\u003e string;\n\n\t/** Command(s) to trigger back navigation. Default: \"back\" */\n\tbackCommands?: string | string[];\n\n\t/** Custom storage adapter for session management. Default: MemoryStorage */\n\tstorage?: StorageAdapter\u003cT\u003e;\n\n\t/** Custom settings for the GREEN-API instance */\n\tsettings?: {\n\t\twebhookUrl?: string;\n\t\twebhookUrlToken?: string;\n\t\toutgoingWebhook?: \"yes\" | \"no\";\n\t\tstateWebhook?: \"yes\" | \"no\";\n\t\tincomingWebhook?: \"yes\" | \"no\";\n\t\toutgoingAPIMessageWebhook?: \"yes\" | \"no\";\n\t\toutgoingMessageWebhook?: \"yes\" | \"no\";\n\t\tpollMessageWebhook?: \"yes\" | \"no\";\n\t\tmarkIncomingMessagesReaded?: \"yes\" | \"no\";\n\t};\n\n\t/** Whether to clear webhook queue on bot startup. Default: false */\n\tclearWebhookQueueOnStart?: boolean;\n\n\t/** Controls message processing order. When true, global handlers run before state handlers (onMessage).\n\t * When false (default), state handlers run first. */\n\thandlersFirst?: boolean;\n}\n```\n\n### WhatsAppBot\n\nMain class for creating and managing your bot:\n\n```typescript\nconst bot = new WhatsAppBot\u003cCustomSessionData\u003e({\n\t// Required parameters\n\tidInstance: \"your-instance-id\",\n\tapiTokenInstance: \"your-token\",\n\n\t// Optional parameters\n\tdefaultState: \"menu\",\n\tsessionTimeout: 30, // 30 seconds\n\tgetSessionTimeoutMessage: (session) =\u003e {\n\t\t// Custom logic to return timeout message\n\t\treturn \"Your session has expired. Starting over.\";\n\t},\n\tbackCommands: [\"back\", \"return\", \"menu\"],\n\tstorage: new CustomStorage(),\n\tclearWebhookQueueOnStart: true,\n\n\t// GREEN-API instance settings\n\tsettings: {\n\t\twebhookUrl: \"\",\n\t\twebhookUrlToken: \"\",\n\t\toutgoingWebhook: \"no\",\n\t\tstateWebhook: \"no\",\n\t\tincomingWebhook: \"yes\",\n\t\toutgoingAPIMessageWebhook: \"no\",\n\t\toutgoingMessageWebhook: \"no\",\n\t\tpollMessageWebhook: \"yes\",\n\t\tmarkIncomingMessagesReaded: \"yes\"\n\t}\n});\n```\n\n### States\n\nStates define the conversation flow:\n\n```typescript\ninterface State\u003cT = any\u003e {\n\tname: string;\n\tonEnter?: (message, stateData?) =\u003e Promise\u003cvoid | string | StateTransition\u003e;\n\tonMessage: (message, stateData?) =\u003e Promise\u003cvoid | string | StateTransition | null\u003e;\n\tonLeave?: (message, stateData?) =\u003e Promise\u003cvoid\u003e;\n}\n```\n\nState handler return values:\n\n- `null`: Continue to global handlers\n- `undefined`: Stop processing\n- `string`: Transition to that state\n- `StateTransition`: Transition with data\n\n### Message Handlers\n\nGlobal message handlers for specific patterns:\n\n```typescript\n// Exact text match\nbot.onText(\"help\", async (message) =\u003e {\n\tawait bot.sendText(message.chatId, \"Help message\");\n});\n\n// Regular expression\nbot.onRegex(/^order:\\s*(\\d+)$/, async (message) =\u003e {\n\tconst [, orderId] = message.text.match(/^order:\\s*(\\d+)$/);\n\tawait bot.sendText(message.chatId, `Order ${orderId} info...`);\n});\n\n// Message type\nbot.onType(\"image\", async (message) =\u003e {\n\tawait bot.sendText(message.chatId, \"Image received!\");\n});\n```\n\n### Storage\n\nBuilt-in memory storage with custom adapter support:\n\n```typescript\ninterface StorageAdapter\u003cT = any\u003e {\n\t/** Optional event emitter for session-related events like expiration */\n\tevents?: StorageEventEmitter\u003cT\u003e;\n\n\t/** Retrieves session data for a chat */\n\tget(chatId: string): Promise\u003cSessionData\u003cT\u003e | null\u003e;\n\n\t/** Stores session data for a chat */\n\tset(chatId: string, data: SessionData\u003cT\u003e): Promise\u003cvoid\u003e;\n\n\t/** Optional method to receive session timeout value for cleanup processes */\n\tsetSessionTimeout?(timeoutMs: number): void;\n}\n```\n\nExample custom storage:\n\n```typescript\nclass CustomStorage implements StorageAdapter {\n\tasync get(chatId: string) {\n\t\treturn await db.sessions.findOne({chatId});\n\t}\n\n\tasync set(chatId: string, data: SessionData) {\n\t\tawait db.sessions.upsert({chatId, ...data});\n\t}\n}\n```\n\n# State System\n\nThe bot uses a state-based architecture where each state represents a specific point in the conversation flow. States\ncan have entry points, message handlers, and exit points.\n\n## State Functions\n\n### onEnter\n\nCalled when the bot enters a state. Useful for sending initial messages or setting up state data.\n\n```typescript\nconst menuState: State = {\n\tname: \"menu\",\n\tasync onEnter(message) {\n\t\tawait bot.sendText(message.chatId, \"Welcome to the menu!\");\n\t}\n};\n```\n\nReturn values from onEnter:\n\n- `void` - Stay in current state\n- `string` - Name of state to transition to\n- `StateTransition` - Transition with data:\n  ```typescript\n  return {\n      state: \"next_state\",\n      data: { someData: \"value\" },\n      skipOnEnter: false // Optional: skip next state's onEnter\n  };\n  ```\n\n### onMessage\n\nHandles messages received while in this state.\n\n```typescript\nconst orderState: State\u003cOrderData\u003e = {\n\tname: \"create_order\",\n\tasync onMessage(message, data = {items: []}) {\n\t\tif (message.text === \"done\") {\n\t\t\treturn \"confirm_order\";\n\t\t}\n\n\t\t// Add item to order\n\t\tdata.items.push(message.text);\n\t\treturn {\n\t\t\tstate: \"create_order\", // Stay in same state\n\t\t\tdata: data // Update state data\n\t\t};\n\t}\n};\n```\n\nReturn values from onMessage:\n\n- `null` - Continue to global handlers (like back command)\n- `undefined` - Stop processing\n- `string` - Name of state to transition to\n- `StateTransition` - Transition with data\n\n### onLeave\n\nCalled when leaving a state. Use for cleanup or final processing.\n\n```typescript\nconst paymentState: State = {\n\tname: \"payment\",\n\tasync onLeave(message, data) {\n\t\tawait savePaymentAttempt(data);\n\t}\n};\n```\n\n## Session Management\n\nSessions maintain conversation state and custom data between messages.\n\n### Session Data Structure\n\n```typescript\ninterface SessionData\u003cT = any\u003e {\n\tlastActivity: number;     // Timestamp of last activity\n\tcurrentState?: string;    // Current state name\n\tstateData?: T;           // Custom state data\n\tnavigationPath?: string[]; // History of states\n\tpreviousState?: string;   // Last state (for back navigation)\n}\n```\n\n### State Data\n\nCustom data persists between messages in the same state:\n\n```typescript\ninterface OrderData {\n\torderId: string;\n\titems: string[];\n\ttotal: number;\n}\n\nconst bot = new WhatsAppBot\u003cOrderData\u003e();\n\nconst orderState: State\u003cOrderData\u003e = {\n\tname: \"order\",\n\tasync onMessage(message, data = {items: [], total: 0}) {\n\t\t// data is typed as OrderData\n\t\tdata.items.push(message.text);\n\t\treturn {state: \"order\", data};\n\t}\n};\n```\n\n### Session Timeout\n\nSessions expire after inactivity (default 300 seconds / 5 minutes). You can customize both the timeout duration and the\nmessage sent when a session times out:\n\n```typescript\nconst bot = new WhatsAppBot({\n\t// Set timeout to 30 seconds\n\tsessionTimeout: 30,\n\n\t// Custom timeout message\n\tgetSessionTimeoutMessage: (session) =\u003e {\n\t\t// You can access session data to customize the message\n\t\tconst userName = session.stateData?.userName || \"User\";\n\t\treturn `Hello ${userName}, your session has expired. Starting a new conversation.`;\n\t}\n});\n```\n\nThe built-in memory storage checks for expired sessions every 10 seconds and automatically removes them. If you\nimplement your own storage adapter, you'll need to implement your own cleanup mechanism.\n\n### Session Timeout Events\n\nStorage adapters can optionally emit events when sessions expire. This feature enables the bot to send timeout\nnotifications:\n\n```typescript\nimport { EventEmitter } from 'events';\n\nclass DatabaseStorage implements StorageAdapter {\n\tpublic events = new StorageEventEmitter();\n\n\tconstructor(timeoutSeconds: number) {\n\t\t// Set up cleanup that emits events\n\t\tsetInterval(() =\u003e {\n\t\t\t// Find expired sessions\n\t\t\tconst expiredSessions = // ... your logic\n\n\t\t\tfor (const session of expiredSessions) {\n\t\t\t\tthis.events.emit('sessionExpired', session.chatId, session);\n\t\t\t\t// Delete session\n\t\t\t}\n\t\t}, 10000);\n\t}\n}\n```\n\nThe events field is optional - if you don't need timeout notifications, you can omit it from your storage\nimplementation. The timeout message is defined in the getSessionTimeoutMessage function.\n\n## Message Handling Flow\n\nThe bot offers two message processing flows, controlled by the `handlersFirst` configuration option:\n\n#### Default Flow (handlersFirst: false)\n\n1. Bot receives message\n2. Current state's `onMessage` handler processes message\n3. Based on return value:\n    - If `null`: Global handlers process message (onText, onType, onRegex)\n    - If `undefined`: Stop processing\n    - If state name/transition: Enter new state\n\n#### Handlers-First Flow (handlersFirst: true)\n\n1. Bot receives message\n2. Global handlers (onText, onRegex, onType) process message\n    - If a handler returns `true`, continue to state processing\n    - If a handler returns anything else, stop processing\n3. If previous global handler returned `true`, current state's `onMessage` handler processes it\n\n### Handler Return Values\n\nWhen using the handlers-first approach (`handlersFirst: true`), global message handlers support an additional return\nvalue:\n\n- undefined: Message was handled, stop processing (default)\n- true: Message was partially handled, continue to state processing\n- anything else: Treat as undefined (stop processing)\n\n## Message Handling Priority (if handlersFirst: false)\n\nMessages are processed in a specific priority order:\n\n1. **State Handler (First)**\n    - The current state's `onMessage` handler gets the first chance to process every message\n    - Based on its return value:\n        - `null`: Continue to global handlers\n        - `undefined`: Stop processing\n        - `string`: Transition to that state and stop\n        - `StateTransition`: Transition with data and stop\n\n2. **Global Handlers (Only if state handler returns null)**\n   Messages that aren't fully handled by the state (returned `null`) continue to global handlers in this order:\n\n   a. **Text Handlers**\n    - Exact text matches (case-insensitive)\n    - First matching handler processes the message and stops further handling\n\n   b. **Regex Handlers**\n    - Regular expression pattern matches\n    - First matching pattern processes the message and stops further handling\n\n   c. **Type Handlers**\n    - Specific type handlers run first\n    - Generic (\"*\") handlers run last as fallback\n    - First matching handler processes the message and stops further handling\n\nThis means that if your state's `onMessage` handler returns `undefined` (the default return value), global handlers will\nnever run. Make sure to return `null` if you want to allow global handlers to process the message.\n\n### Examples of using handlersFirst\n\n#### Configuring the Flow Order\n\n```typescript\nconst bot = new WhatsAppBot({\n\tidInstance: \"your-instance-id\",\n\tapiTokenInstance: \"your-token\",\n\tdefaultState: \"menu\",\n\thandlersFirst: true // Process global handlers before state handlers\n});\n```\n\n#### Handlers with Different Return Values\n\n```typescript\n// Handler that fully processes the message (stops further processing)\nbot.onText(\"/help\", async (message) =\u003e {\n\tawait bot.sendText(message.chatId, \"Here's the help information...\");\n\t// No explicit return - defaults to undefined (stop processing)\n});\n\n// Handler that partially processes the message and continues to state handler\nbot.onType(\"location\", async (message) =\u003e {\n\tawait bot.sendText(message.chatId, \"I've received your location...\");\n\treturn true; // Continue to state processing for additional handling\n});\n```\n\n## Global Handlers\n\n### Text Handlers\n\nMatch exact text (case-insensitive):\n\n```typescript\nbot.onText(\"menu\", async (message) =\u003e {\n\tawait bot.sendText(message.chatId, \"Main menu\");\n});\n```\n\n### Regex Handlers\n\nMatch text patterns:\n\n```typescript\nbot.onRegex(/order:\\s*(\\d+)/, async (message) =\u003e {\n\tconst [, orderId] = message.text.match(/order:\\s*(\\d+)/);\n\tawait bot.sendText(message.chatId, `Order ${orderId} details...`);\n});\n```\n\n### Type Handlers\n\nHandle specific message types:\n\n```typescript\n// Handle all images\nbot.onType(\"image\", async (message) =\u003e {\n\tconst url = message.media?.url;\n\tawait processImage(url);\n});\n\n// Handle all messages (fallback)\nbot.onType(\"*\", async (message) =\u003e {\n\tconsole.log(\"Unhandled message:\", message);\n});\n```\n\n## Custom Storage\n\nDefault storage is in-memory, but you can implement custom storage:\n\n```typescript\nclass DatabaseStorage implements StorageAdapter {\n\t// Optional event support for timeout notifications\n\tpublic events?: StorageEventEmitter;\n\n\tconstructor(timeoutSeconds: number) {\n\t\t// Optional: Set up events if you want timeout notifications\n\t\tthis.events = new StorageEventEmitter();\n\t\tthis.startCleanup(timeoutSeconds);\n\t}\n\n\tprivate async startCleanup(timeoutSeconds: number) {\n\t\tsetInterval(async () =\u003e {\n\t\t\t// Your cleanup logic\n\t\t\tif (this.events) {\n\t\t\t\t// Emit events for expired sessions\n\t\t\t\tthis.events.emit('sessionExpired', chatId, session);\n\t\t\t}\n\t\t}, 10000);\n\t}\n\n\tasync get(chatId: string): Promise\u003cSessionData | null\u003e {\n\t\treturn await db.sessions.findOne({chatId});\n\t}\n\n\tasync set(chatId: string, data: SessionData): Promise\u003cvoid\u003e {\n\t\tawait db.sessions.updateOne(\n\t\t\t{chatId},\n\t\t\t{$set: data},\n\t\t\t{upsert: true}\n\t\t);\n\t}\n}\n\nconst bot = new WhatsAppBot({\n\tstorage: new DatabaseStorage()\n});\n```\n\n## State Transition Examples\n\n### Simple State Chain\n\n```typescript\nconst steps: State[] = [\n\t{\n\t\tname: \"step1\",\n\t\tasync onMessage(message) {\n\t\t\tif (message.text) return \"step2\";\n\t\t\treturn undefined;\n\t\t}\n\t},\n\t{\n\t\tname: \"step2\",\n\t\tasync onMessage(message) {\n\t\t\tif (message.text) return \"step3\";\n\t\t\treturn undefined;\n\t\t}\n\t}\n];\n```\n\n### Conditional Transitions\n\n```typescript\nconst menuState: State = {\n\tname: \"menu\",\n\tasync onMessage(message) {\n\t\tswitch (message.text) {\n\t\t\tcase \"1\":\n\t\t\t\treturn \"orders\";\n\t\t\tcase \"2\":\n\t\t\t\treturn \"settings\";\n\t\t\tdefault:\n\t\t\t\treturn null;\n\t\t}\n\t}\n};\n```\n\n### Data Passing Between States\n\n```typescript\ninterface UserData {\n\tname?: string;\n\tage?: number;\n}\n\nconst nameState: State\u003cUserData\u003e = {\n\tname: \"get_name\",\n\tasync onMessage(message, data = {}) {\n\t\treturn {\n\t\t\tstate: \"get_age\",\n\t\t\tdata: {...data, name: message.text}\n\t\t};\n\t}\n};\n\nconst ageState: State\u003cUserData\u003e = {\n\tname: \"get_age\",\n\tasync onMessage(message, data = {}) {\n\t\tconst age = parseInt(message.text);\n\t\treturn {\n\t\t\tstate: \"confirm\",\n\t\t\tdata: {...data, age}\n\t\t};\n\t}\n};\n```\n\n## Advanced Features\n\n### Custom State Data\n\nAdd type-safe custom data to your states:\n\n```typescript\ninterface OrderData {\n\torderId?: string;\n\titems: string[];\n\ttotal: number;\n}\n\nconst bot = new WhatsAppBot\u003cOrderData\u003e({...});\n\nconst orderState: State\u003cOrderData\u003e = {\n\tname: \"create_order\",\n\tasync onMessage(message, data = {items: [], total: 0}) {\n\t\t// Type-safe access to custom data\n\t\tdata.items.push(message.text);\n\t\treturn {\n\t\t\tstate: \"confirm_order\",\n\t\t\tdata: data\n\t\t};\n\t}\n};\n```\n\n### File Handling\n\nSend different types of files:\n\n```typescript\nawait bot.sendFile(chatId, {\n\turl: \"https://example.com/image.jpg\",\n\ttype: \"image\",\n\tcaption: \"Check this out!\"\n});\n```\n\n## Best Practices\n\n1. **State Organization**\n    - Keep states focused and single-purpose\n    - Use clear naming conventions\n    - Handle edge cases and errors\n\n2. **Error Handling**\n    - Implement global error handlers\n    - Log errors appropriately\n    - Provide user-friendly error messages\n\n3. **Session Management**\n    - Clean up old sessions regularly\n    - Implement proper timeout handling\n\n## Examples\n\n### Support Ticket Bot\n\nSee `examples/tickets.ts` for a complete example of a support ticket system demonstrating state\nmanagement, file handling, and complex conversation flows.\n\n### Custom Storage Implementation\n\nCheck `examples/custom-storage/` for an example of implementing a custom storage provider\nwith a simple bot implementation.\n\n### Demo chatbot example\n\nCheck out [our demo chatbot](https://github.com/green-api/whatsapp-demo-chatbot-js-v2) to see a big scale\nimplementation, based on GREEN-API\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgreen-api%2Fwhatsapp-chatbot-js-v2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgreen-api%2Fwhatsapp-chatbot-js-v2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgreen-api%2Fwhatsapp-chatbot-js-v2/lists"}