{
  "name": "Mawidi WhatsApp AI Agent - Complete",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "mawidi-whatsapp-agent",
        "responseMode": "responseNode",
        "options": {
          "rawBody": true
        }
      },
      "id": "webhook-trigger",
      "name": "WhatsApp Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [240, 400],
      "webhookId": "mawidi-whatsapp-main"
    },
    {
      "parameters": {
        "jsCode": "// Parse incoming WhatsApp message\nconst body = $input.first().json.body || $input.first().json;\n\n// Handle both direct webhook and WhatsApp Cloud API format\nlet customerPhone = '';\nlet customerName = '';\nlet messageText = '';\nlet messageId = '';\nlet whatsappBusinessId = '';\n\n// Check if it's WhatsApp Cloud API format\nif (body.entry && body.entry[0]?.changes) {\n  const change = body.entry[0].changes[0];\n  const value = change.value;\n  \n  if (value.messages && value.messages[0]) {\n    const msg = value.messages[0];\n    customerPhone = msg.from;\n    messageId = msg.id;\n    messageText = msg.text?.body || msg.interactive?.button_reply?.title || '';\n    whatsappBusinessId = value.metadata?.phone_number_id || '';\n    \n    // Try to get customer name from contacts\n    if (value.contacts && value.contacts[0]) {\n      customerName = value.contacts[0].profile?.name || 'Customer';\n    }\n  }\n} else {\n  // Direct webhook format (for testing)\n  customerPhone = body.from || body.customer_phone || '+966501234567';\n  customerName = body.customer_name || 'Test Customer';\n  messageText = body.message || body.text || 'Hello';\n  messageId = body.message_id || `msg_${Date.now()}`;\n  whatsappBusinessId = body.phone_number_id || 'test-phone-id';\n}\n\nreturn {\n  json: {\n    customer_phone: customerPhone,\n    customer_name: customerName,\n    message: messageText,\n    message_id: messageId,\n    whatsapp_business_id: whatsappBusinessId,\n    timestamp: new Date().toISOString(),\n    raw_body: body\n  }\n};"
      },
      "id": "parse-message",
      "name": "Parse WhatsApp Message",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [460, 400]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "check-message",
              "leftValue": "={{ $json.message }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "check-valid-message",
      "name": "Has Message?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [680, 400]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $env.MAWIDI_API_URL || 'http://host.docker.internal:9000' }}/api/n8n/context",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"auth_token\": \"{{ $env.MAWIDI_WEBHOOK_TOKEN || 'your-webhook-token' }}\",\n  \"lookup_type\": \"whatsapp_number\",\n  \"lookup_value\": \"{{ $json.whatsapp_business_id }}\",\n  \"include\": {\n    \"knowledge_base\": true,\n    \"credentials\": false,\n    \"workflow_config\": true,\n    \"recent_conversations\": true\n  }\n}",
        "options": {
          "timeout": 30000,
          "response": {
            "response": {
              "fullResponse": true
            }
          }
        }
      },
      "id": "get-context",
      "name": "Get Mawidi Context",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [900, 300],
      "credentials": {
        "httpHeaderAuth": {
          "id": "mawidi-auth",
          "name": "Mawidi Auth"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "check-success",
              "leftValue": "={{ $json.body?.success }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "check-context",
      "name": "Context Found?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [1120, 300]
    },
    {
      "parameters": {
        "jsCode": "// Prepare context for AI\nconst context = $('Get Mawidi Context').first().json.body;\nconst message = $('Parse WhatsApp Message').first().json;\n\nconst user = context.user || {};\nconst kb = context.knowledge_base || {};\nconst recent = context.recent_conversations || [];\n\n// Build FAQ context\nlet faqContext = 'No FAQ available.';\nif (kb.faq_summary && kb.faq_summary.length > 0) {\n  faqContext = kb.faq_summary\n    .slice(0, 10) // Limit to 10 FAQs\n    .map(f => `Q: ${f.question}\\nA: ${f.answer}`)\n    .join('\\n\\n');\n}\n\n// Build recent conversation context\nlet recentContext = 'No recent messages.';\nif (recent.length > 0) {\n  recentContext = recent\n    .slice(0, 5) // Last 5 conversations\n    .map(c => `[${c.platform}] ${c.last_message || 'No message'}`)\n    .join('\\n');\n}\n\n// Determine language\nconst language = user.language === 'ar' ? 'Arabic' : 'English';\n\n// Build system prompt\nconst systemPrompt = `You are an AI assistant for ${user.company_name || 'a medical clinic'}.\n\n## Your Role\nYou help customers with:\n- Booking appointments\n- Answering questions about services\n- Providing clinic information\n- General customer support\n\n## Language\nRespond in ${language}. If the customer writes in Arabic, respond in Arabic. If in English, respond in English.\n\n## Business Information\n- Business Name: ${user.company_name || 'Medical Clinic'}\n- Working Hours: ${user.working_hours || 'Sunday-Thursday 9AM-5PM'}\n\n## Custom Instructions\n${kb.custom_instructions || 'Be helpful, professional, and concise.'}\n\n## FAQ Knowledge Base\n${faqContext}\n\n## Recent Conversation History\n${recentContext}\n\n## Guidelines\n1. Be professional and friendly\n2. If you don't know something, say so\n3. For appointment bookings, collect: name, phone, preferred date/time, service needed\n4. Keep responses concise (under 200 words)\n5. Use appropriate greetings based on time of day`;\n\nreturn {\n  json: {\n    system_prompt: systemPrompt,\n    user_message: message.message,\n    customer_phone: message.customer_phone,\n    customer_name: message.customer_name,\n    user_id: user.id,\n    language: language,\n    context_available: true\n  }\n};"
      },
      "id": "prepare-context",
      "name": "Prepare AI Context",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [1340, 200]
    },
    {
      "parameters": {
        "resource": "chat",
        "model": "gpt-4o-mini",
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "={{ $json.system_prompt }}"
            },
            {
              "role": "user",
              "content": "={{ $json.user_message }}"
            }
          ]
        },
        "options": {
          "maxTokens": 500,
          "temperature": 0.7
        }
      },
      "id": "openai-chat",
      "name": "Generate AI Response",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 1.8,
      "position": [1560, 200],
      "credentials": {
        "openAiApi": {
          "id": "openai-creds",
          "name": "OpenAI Account"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $env.MAWIDI_API_URL || 'http://host.docker.internal:9000' }}/api/webhooks/n8n/conversation",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"auth_token\": \"{{ $env.MAWIDI_WEBHOOK_TOKEN || 'your-webhook-token' }}\",\n  \"user_id\": \"{{ $('Prepare AI Context').first().json.user_id }}\",\n  \"platform\": \"whatsapp\",\n  \"customer_phone\": \"{{ $('Prepare AI Context').first().json.customer_phone }}\",\n  \"customer_name\": \"{{ $('Prepare AI Context').first().json.customer_name }}\",\n  \"message\": {\n    \"role\": \"user\",\n    \"content\": \"{{ $('Prepare AI Context').first().json.user_message }}\",\n    \"timestamp\": \"{{ $now.toISO() }}\"\n  }\n}",
        "options": {
          "timeout": 10000
        }
      },
      "id": "log-user-message",
      "name": "Log User Message",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [1560, 400],
      "credentials": {
        "httpHeaderAuth": {
          "id": "mawidi-auth",
          "name": "Mawidi Auth"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $env.MAWIDI_API_URL || 'http://host.docker.internal:9000' }}/api/webhooks/n8n/conversation",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"auth_token\": \"{{ $env.MAWIDI_WEBHOOK_TOKEN || 'your-webhook-token' }}\",\n  \"user_id\": \"{{ $('Prepare AI Context').first().json.user_id }}\",\n  \"conversation_id\": \"{{ $('Log User Message').first().json.conversation_id }}\",\n  \"platform\": \"whatsapp\",\n  \"customer_phone\": \"{{ $('Prepare AI Context').first().json.customer_phone }}\",\n  \"message\": {\n    \"role\": \"agent\",\n    \"content\": \"{{ $('Generate AI Response').first().json.message.content.replace(/\\\"/g, '\\\\\"').replace(/\\n/g, '\\\\n') }}\",\n    \"timestamp\": \"{{ $now.toISO() }}\"\n  }\n}",
        "options": {
          "timeout": 10000
        }
      },
      "id": "log-agent-response",
      "name": "Log Agent Response",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [1780, 200],
      "credentials": {
        "httpHeaderAuth": {
          "id": "mawidi-auth",
          "name": "Mawidi Auth"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Prepare successful response\nconst aiResponse = $('Generate AI Response').first().json.message.content;\nconst conversationId = $('Log User Message').first().json.conversation_id;\nconst customerPhone = $('Prepare AI Context').first().json.customer_phone;\n\nreturn {\n  json: {\n    success: true,\n    response: aiResponse,\n    conversation_id: conversationId,\n    customer_phone: customerPhone,\n    timestamp: new Date().toISOString()\n  }\n};"
      },
      "id": "prepare-response",
      "name": "Prepare Response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [2000, 200]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}",
        "options": {
          "responseCode": 200,
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "application/json"
              }
            ]
          }
        }
      },
      "id": "respond-success",
      "name": "Respond Success",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [2220, 200]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ success: false, error: 'No message content provided' }) }}",
        "options": {
          "responseCode": 400,
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "application/json"
              }
            ]
          }
        }
      },
      "id": "respond-no-message",
      "name": "Respond No Message",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [900, 520]
    },
    {
      "parameters": {
        "jsCode": "// Handle case when user context is not found\nconst message = $('Parse WhatsApp Message').first().json;\n\n// Default response when no context\nconst defaultResponse = message.message.includes('مرحبا') || message.message.includes('السلام')\n  ? 'مرحباً! شكراً لتواصلك معنا. سيتم الرد عليك قريباً.'\n  : 'Hello! Thank you for contacting us. We will get back to you shortly.';\n\nreturn {\n  json: {\n    success: true,\n    response: defaultResponse,\n    customer_phone: message.customer_phone,\n    context_available: false,\n    fallback: true,\n    timestamp: new Date().toISOString()\n  }\n};"
      },
      "id": "fallback-response",
      "name": "Fallback Response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [1340, 420]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}",
        "options": {
          "responseCode": 200,
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "application/json"
              }
            ]
          }
        }
      },
      "id": "respond-fallback",
      "name": "Respond Fallback",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [1560, 520]
    },
    {
      "parameters": {
        "content": "## Mawidi WhatsApp AI Agent\n\n### Setup Instructions:\n\n1. **Create OpenAI Credentials**\n   - Go to Credentials > Add Credential > OpenAI API\n   - Name it exactly: `OpenAI Account`\n\n2. **Create HTTP Header Auth**\n   - Go to Credentials > Add Credential > Header Auth\n   - Name: `Mawidi Auth`\n   - Header Name: `Authorization`\n   - Header Value: `Bearer YOUR_MAWIDI_WEBHOOK_TOKEN`\n\n3. **Set Environment Variables** (Settings > Variables)\n   - `MAWIDI_API_URL`: Your Mawidi URL (e.g., http://localhost:9000)\n   - `MAWIDI_WEBHOOK_TOKEN`: Your user's webhook token\n\n4. **Activate the workflow**\n\n5. **Test with this curl command:**\n```bash\ncurl -X POST \"YOUR_N8N_URL/webhook/mawidi-whatsapp-agent\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"from\": \"+966501234567\", \"message\": \"Hello, I want to book an appointment\"}'\n```",
        "height": 460,
        "width": 380,
        "color": 4
      },
      "id": "sticky-note",
      "name": "Setup Instructions",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [-60, 240]
    },
    {
      "parameters": {
        "content": "## Error Handling\n\nThis branch handles:\n- Missing user context\n- Invalid phone numbers\n- API failures\n\nReturns a polite fallback message.",
        "height": 160,
        "width": 260,
        "color": 6
      },
      "id": "sticky-error",
      "name": "Error Handling Note",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [1120, 500]
    }
  ],
  "connections": {
    "WhatsApp Webhook": {
      "main": [
        [
          {
            "node": "Parse WhatsApp Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse WhatsApp Message": {
      "main": [
        [
          {
            "node": "Has Message?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Message?": {
      "main": [
        [
          {
            "node": "Get Mawidi Context",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond No Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Mawidi Context": {
      "main": [
        [
          {
            "node": "Context Found?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Context Found?": {
      "main": [
        [
          {
            "node": "Prepare AI Context",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Fallback Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare AI Context": {
      "main": [
        [
          {
            "node": "Generate AI Response",
            "type": "main",
            "index": 0
          },
          {
            "node": "Log User Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate AI Response": {
      "main": [
        [
          {
            "node": "Log Agent Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Agent Response": {
      "main": [
        [
          {
            "node": "Prepare Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Response": {
      "main": [
        [
          {
            "node": "Respond Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fallback Response": {
      "main": [
        [
          {
            "node": "Respond Fallback",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "saveDataSuccessExecution": "all",
    "saveDataErrorExecution": "all"
  },
  "staticData": null,
  "meta": {
    "templateCredsSetupCompleted": false,
    "instanceId": "mawidi-instance"
  },
  "pinData": {},
  "versionId": "2",
  "triggerCount": 0,
  "tags": [
    {
      "name": "mawidi",
      "id": "mawidi-tag"
    },
    {
      "name": "whatsapp",
      "id": "whatsapp-tag"
    },
    {
      "name": "ai-agent",
      "id": "ai-agent-tag"
    },
    {
      "name": "production-ready",
      "id": "production-tag"
    }
  ]
}
