{
  "name": "ConecteAI — Chatbot Contratação WhatsApp",
  "nodes": [
    {
      "parameters": {
        "content": "## ConecteAI Chatbot Contratação (v1 webhook)\n\nGatilho: `quero contratar` (contains).\nEstado por `wa_id` (static data + session echo).\nPlanos: `GET /api/v2/providers/plans` na hora.\nSem plan_id/coupon/Origin Wipi hardcoded.\nWhatsApp Trigger presente, sem credencial.\nProva: POST `{wa_id,text}` neste webhook.",
        "height": 380,
        "width": 320,
        "color": 5
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -360,
        0
      ],
      "id": "2f6715c9-694f-4802-9f36-1467657000a2",
      "name": "Arquitetura v1"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "conecteai-chatbot-contratacao",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        0,
        0
      ],
      "id": "7f1709d3-c18d-472a-ba07-2268aed180e4",
      "name": "Webhook",
      "webhookId": "1420ee3a-b16b-4886-adee-a3714e332d62"
    },
    {
      "parameters": {
        "updates": [
          "messages"
        ]
      },
      "type": "n8n-nodes-base.whatsAppTrigger",
      "typeVersion": 1,
      "position": [
        0,
        280
      ],
      "id": "ff013903-4816-4ba4-8342-29ec2f2d2907",
      "name": "WhatsApp Trigger",
      "disabled": true
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        520
      ],
      "id": "b8048d93-42b1-4833-85a4-25cfca3ce9e8",
      "name": "Manual Trigger"
    },
    {
      "parameters": {
        "jsCode": "const item = $input.first().json || {};\nif (item.body || item.wa_id || item.text || item.entry) return [{ json: item }];\nreturn [{ json: { wa_id: 'manual', text: item.chatInput || item.text || 'quero contratar' } }];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        280,
        160
      ],
      "id": "cc48fb2e-fe78-4e14-906b-fc884bcc89f3",
      "name": "Normalize Input"
    },
    {
      "parameters": {
        "jsCode": "const helpers = this.helpers;\nconst staticData = $getWorkflowStaticData('global');\nif (!staticData.sessions) staticData.sessions = {};\n\nconst DEFAULTS = {\n  BASE: 'https://testnet-demo.conecte.ai',\n  ORIGIN: 'Salveeeeee333eeeeINTELIGENCIAARTIFAISAJOSIDJALKSDN012OIQWLJAKSNDOIALSNKD',\n  TRIGGER: 'quero contratar',\n  CHECKOUT: 'https://testnet-demo.conecte.ai',\n  COUPON: '',\n};\n\nfunction cfgFrom(item) {\n  const b = item.body || item;\n  return {\n    BASE: (b.CONECTEAI_BASE_URL || DEFAULTS.BASE).replace(/\\/$/, ''),\n    ORIGIN: b.CONECTEAI_ORIGIN || DEFAULTS.ORIGIN,\n    TRIGGER: (b.TRIGGER_KEYWORD || DEFAULTS.TRIGGER).toLowerCase(),\n    CHECKOUT: (b.CHECKOUT_BASE || DEFAULTS.CHECKOUT).replace(/\\/$/, ''),\n    COUPON: b.COUPON_ID || DEFAULTS.COUPON || '',\n  };\n}\n\nfunction parseInput(raw) {\n  const j = raw || {};\n  const body = j.body && typeof j.body === 'object' ? j.body : j;\n  let wa = body.wa_id || body.from || body.phone || body.telefone || j.wa_id || j.from || '';\n  let text = '';\n  if (typeof body.text === 'string') text = body.text;\n  else if (body.text && typeof body.text.body === 'string') text = body.text.body;\n  else if (typeof body.message === 'string') text = body.message;\n  else if (typeof body.chatInput === 'string') text = body.chatInput;\n  else if (typeof j.text === 'string') text = j.text;\n  try {\n    const msg = (j.entry || body.entry || [])[0]?.changes?.[0]?.value?.messages?.[0];\n    if (msg) {\n      wa = msg.from || wa;\n      text = msg.text?.body || msg.button?.text || msg.interactive?.button_reply?.title || msg.interactive?.list_reply?.title || msg.interactive?.list_reply?.id || text;\n    }\n  } catch (e) {}\n  wa = String(wa || '').replace(/\\D/g, '');\n  if (!wa) wa = 'synthetic';\n  text = String(text || '').trim();\n  return { wa_id: wa, text, body, echoed: body.session && typeof body.session === 'object' ? body.session : null };\n}\n\nfunction formatPhone(wa) {\n  let d = String(wa).replace(/\\D/g, '');\n  if (d.startsWith('55') && d.length >= 12) d = d.slice(2);\n  if (d.length === 11) return `(${d.slice(0, 2)}) ${d.slice(2, 7)}-${d.slice(7)}`;\n  if (d.length === 10) return `(${d.slice(0, 2)}) ${d.slice(2, 6)}-${d.slice(6)}`;\n  return d;\n}\n\nfunction validCpf(cpf) {\n  cpf = String(cpf).replace(/\\D/g, '');\n  if (cpf.length !== 11 || /^(\\d)\\1+$/.test(cpf)) return false;\n  let s = 0;\n  for (let i = 0; i < 9; i++) s += parseInt(cpf[i], 10) * (10 - i);\n  let d1 = (s * 10) % 11;\n  if (d1 === 10) d1 = 0;\n  if (d1 !== parseInt(cpf[9], 10)) return false;\n  s = 0;\n  for (let i = 0; i < 10; i++) s += parseInt(cpf[i], 10) * (11 - i);\n  let d2 = (s * 10) % 11;\n  if (d2 === 10) d2 = 0;\n  return d2 === parseInt(cpf[10], 10);\n}\n\nfunction validEmail(e) {\n  return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]{2,}$/.test(String(e || '').trim());\n}\n\nfunction isValidDate(d, m, y) {\n  d = parseInt(d, 10);\n  m = parseInt(m, 10);\n  y = parseInt(y, 10);\n  if (!d || !m || !y) return false;\n  if (y < 1900 || y > new Date().getFullYear()) return false;\n  if (m < 1 || m > 12 || d < 1 || d > 31) return false;\n  const dt = new Date(y, m - 1, d);\n  return dt.getFullYear() === y && dt.getMonth() === m - 1 && dt.getDate() === d;\n}\n\nfunction ageYears(d, m, y) {\n  const now = new Date();\n  let a = now.getFullYear() - parseInt(y, 10);\n  const mm = parseInt(m, 10);\n  const dd = parseInt(d, 10);\n  if (now.getMonth() + 1 < mm || (now.getMonth() + 1 === mm && now.getDate() < dd)) a -= 1;\n  return a;\n}\n\nfunction yes(t) {\n  return /^(sim|s|yes|1|ok|certo|confirma)$/i.test(String(t).trim());\n}\nfunction no(t) {\n  return /^(n[aã]o|nao|n|no|2)$/i.test(String(t).trim());\n}\nfunction isContratar(t) {\n  return /contratar|internet|1\\b/i.test(t);\n}\nfunction isChip(t) {\n  return /chip|outros|2\\b/i.test(t);\n}\n\nconst COPY = {\n  askName: 'Olá! Sou o assistente virtual. Para saber mais sobre nossos planos, preciso de algumas informações. 😊\\n\\nQual seu nome?',\n  menu: 'O que você procura? Estou aqui para te auxiliar no que precisar!\\n\\n1) Contratar internet\\n2) Chip / outros\\n\\nResponda com o número ou o nome da opção.',\n  askCep: 'Certo, vou pedir algumas informações.\\n\\nQual seu CEP?\\nPreciso que seja neste formato abaixo e SOMENTE números:\\nExemplo: 20010050',\n  badCep: 'CEP inválido. Digite um CEP com 8 dígitos, somente números.\\nExemplo: 20010050',\n  askNumero: 'E qual número da sua residência?',\n  confirma(s) {\n    return `Seu endereço está correto? ${s.rua}, número ${s.numero}, no bairro ${s.bairro} e na cidade ${s.cidade}. 😊\\n\\nResponda SIM ou NÃO.`;\n  },\n  oQueErrado: 'O que está errado no endereço? Diga se é rua, bairro ou cidade. Em seguida vamos coletar o CEP de novo.',\n  askComp: 'Sua casa tem complemento? (apto, bloco, casa... Se não tiver, envie \"não\")',\n  escolhePlanoHeader: 'Obrigado pelas informações! Enquanto verificamos se há viabilidade em sua residência... Bora escolher seu plano. 😊\\n\\nEscolha seu plano aqui:',\n  askCpf: 'Perfeito! Últimas informações necessárias. Qual seu CPF?\\nDigite um CPF com 11 dígitos, por gentileza.',\n  badCpf: 'CPF inválido, pode digitar novamente?\\nDigite um CPF com 11 dígitos, por gentileza.',\n  askRg: 'Qual seu RG?',\n  askDia: 'Agora, sua data de nascimento. Qual dia você nasceu?',\n  badDia: 'Dia inválido. Envie um número de 1 a 31.',\n  askMes: 'Certo... Qual mês você nasceu? Preciso que me mande o número do mês. Exemplo: Maio = 5, Outubro = 10, Março = 3 🙂',\n  badMes: 'Mês inválido. Envie o número do mês (1 a 12).',\n  askAno: 'Ok... Qual ano você nasceu?',\n  badAno: 'Ano inválido. Envie um ano com 4 dígitos, por exemplo 1980.',\n  menor: 'É necessário ter 18 anos ou mais para contratar. Confira a data e envie o dia novamente.',\n  confirmaNasc(s) {\n    const dd = String(s.dia).padStart(2, '0');\n    const mm = String(s.mes).padStart(2, '0');\n    return `Certo... Sua data de nascimento é essa? ${dd}/${mm}/${s.ano}. Preciso que me confirme se está correto, por favor.\\n\\nResponda SIM ou NÃO.`;\n  },\n  oQueNasc: 'O que está errado? Dia, mês ou ano? Vamos coletar a data de novo a partir do dia.',\n  askEmail: 'Perfeito! 😁 Para receber seu contrato, preciso de um e-mail válido, por favor.',\n  badEmail: 'E-mail inválido. Envie um e-mail válido, por favor.',\n  cta(s, url) {\n    return `Pronto, ${s.nome}! Seu contrato de internet está pronto.\\n\\nClique aqui para assinar digitalmente:\\n${url}`;\n  },\n  chip: 'Para Chip / outros assuntos, um atendente humano pode te ajudar. Se quiser contratar internet, responda *Contratar*.',\n};\n\nfunction newSession(wa) {\n  return {\n    wa_id: wa,\n    state: 'idle',\n    nome: '',\n    uuid: '',\n    phone: formatPhone(wa),\n    cep: '',\n    numero: '',\n    rua: '',\n    bairro: '',\n    cidade: '',\n    uf: '',\n    lat: '',\n    lng: '',\n    coverage: null,\n    complemento: '',\n    plans: [],\n    plan_id: '',\n    plan_nome: '',\n    cpf: '',\n    rg: '',\n    dia: '',\n    mes: '',\n    ano: '',\n    email: '',\n    checkout_url: '',\n  };\n}\n\nfunction save(wa, session) {\n  staticData.sessions[wa] = session;\n  return session;\n}\n\nfunction load(wa, echoed) {\n  if (echoed && echoed.state) return echoed;\n  if (staticData.sessions[wa]) return staticData.sessions[wa];\n  return newSession(wa);\n}\n\nfunction out(session, reply, extra) {\n  save(session.wa_id, session);\n  return {\n    json: Object.assign({\n      reply,\n      state: session.state,\n      wa_id: session.wa_id,\n      uuid: session.uuid || null,\n      checkout_url: session.checkout_url || null,\n      coverage: session.coverage,\n      session,\n    }, extra || {}),\n  };\n}\n\nasync function api(cfg, method, path, body) {\n  const opts = {\n    method,\n    url: `${cfg.BASE}${path}`,\n    headers: {\n      Origin: cfg.ORIGIN,\n      'Content-Type': 'application/json',\n      Accept: 'application/json',\n    },\n    json: true,\n  };\n  if (body !== undefined) opts.body = body;\n  return helpers.httpRequest(opts);\n}\n\nasync function postLead(cfg, session) {\n  const phones = [session.phone];\n  const digits = String(session.wa_id).replace(/\\D/g, '');\n  const local = digits.startsWith('55') ? digits.slice(2) : digits;\n  if (local.length >= 10) phones.push(formatPhone(local));\n  phones.push(digits.startsWith('55') ? `+${digits}` : `+55${digits}`);\n  let lastErr = null;\n  const seen = {};\n  for (const tel of phones) {\n    if (!tel || seen[tel]) continue;\n    seen[tel] = true;\n    const payload = {\n      subscription: {\n        nome_razao_social: session.nome,\n        telefone_celular: tel,\n        cold_lead: true,\n        pre_subscription: true,\n      },\n    };\n    if (cfg.COUPON) payload.subscription.coupon_id = cfg.COUPON;\n    try {\n      const res = await api(cfg, 'POST', '/api/v2/subscriptions', payload);\n      const id = res?.data?.id;\n      if (id) {\n        session.phone = tel;\n        session.uuid = id;\n        session.coverage = res?.data?.attributes?.coverage ?? null;\n        return;\n      }\n      lastErr = res;\n    } catch (e) {\n      lastErr = e;\n      const msg = String(e?.message || e);\n      if (!/422|telefone|phone/i.test(msg)) throw e;\n    }\n  }\n  throw new Error(`POST subscriptions falhou: ${JSON.stringify(lastErr && lastErr.message ? lastErr.message : lastErr)}`.slice(0, 400));\n}\n\nasync function lookupCep(cep) {\n  const clean = String(cep).replace(/\\D/g, '');\n  const res = await helpers.httpRequest({\n    method: 'GET',\n    url: `https://brasilapi.com.br/api/cep/v2/${clean}`,\n    json: true,\n  });\n  return res;\n}\n\nasync function putSubscription(cfg, session, fields) {\n  if (!session.uuid) throw new Error('uuid ausente');\n  const res = await api(cfg, 'PUT', `/api/v2/subscriptions/${session.uuid}`, fields);\n  session.coverage = res?.data?.attributes?.coverage ?? session.coverage;\n  return res;\n}\n\nfunction formatPrice(attrs) {\n  const reais = attrs.mensalidade_reais;\n  const cents = String(attrs.mensalidade_centavos || '00').padStart(2, '0');\n  if (reais === undefined || reais === null) return '';\n  return `R$ ${reais},${cents}`;\n}\n\nfunction formatPlans(plans) {\n  const lines = plans.slice(0, 10).map((p, i) => {\n    const a = p.attributes || {};\n    const nome = a.nome || a.titulo || p.id;\n    const price = formatPrice(a);\n    const obs = a.mensalidade_observacao ? ` (${a.mensalidade_observacao})` : '';\n    return `${i + 1}) ${nome}${price ? ` — ${price}` : ''}${obs}`;\n  });\n  return lines.join('\\n');\n}\n\nfunction pickPlan(text, plans) {\n  const t = String(text).trim();\n  const n = parseInt(t, 10);\n  if (n >= 1 && n <= plans.length) return plans[n - 1];\n  const low = t.toLowerCase();\n  return plans.find((p) => {\n    const a = p.attributes || {};\n    const nome = String(a.nome || a.titulo || '').toLowerCase();\n    return nome && (low === nome || low.includes(nome) || nome.includes(low));\n  });\n}\n\nasync function getPlans(cfg) {\n  const res = await api(cfg, 'GET', '/api/v2/providers/plans');\n  const data = Array.isArray(res?.data) ? res.data : [];\n  return data.filter((p) => p && p.id);\n}\n\nfunction buildFinalBody(session) {\n  const dd = String(session.dia).padStart(2, '0');\n  const mm = String(session.mes).padStart(2, '0');\n  const body = {\n    plan_id: session.plan_id,\n    cpf_cnpj: session.cpf,\n    rg_ie: session.rg,\n    data_nascimento: `${dd}/${mm}/${session.ano}`,\n    email: session.email,\n    cep: session.cep,\n    cidade: session.cidade,\n    bairro: session.bairro,\n    rua: session.rua,\n    numero: session.numero,\n    complemento: session.complemento,\n    coordinates: { lat: session.lat, lng: session.lng },\n  };\n  return body;\n}\n\nconst item = $input.first().json;\nconst parsed = parseInput(item);\nconst cfg = cfgFrom(parsed.body);\nconst wa = parsed.wa_id;\nconst text = parsed.text;\nlet session = load(wa, parsed.echoed);\nsession.wa_id = wa;\n\nif (text === '__reset__') {\n  session = newSession(wa);\n  return [out(session, 'Sessão limpa. Envie o gatilho para começar.', { route: 'reply' })];\n}\n\nconst hasSession = session.state && session.state !== 'idle' && session.state !== 'done';\nconst triggered = text.toLowerCase().includes(cfg.TRIGGER);\n\nif (!hasSession && !triggered && session.state !== 'start') {\n  return [out(session, null, { route: 'ignore' })];\n}\n\nif ((session.state === 'idle' || session.state === 'done') && triggered) {\n  session = newSession(wa);\n  session.state = 'start';\n  return [out(session, COPY.askName, { route: 'start' })];\n}\n\ntry {\n  switch (session.state) {\n    case 'start': {\n      if (!text || text.toLowerCase().includes(cfg.TRIGGER)) {\n        return [out(session, COPY.askName, { route: 'start' })];\n      }\n      session.nome = text.replace(/\\s+/g, ' ').trim();\n      await postLead(cfg, session);\n      session.state = 'menu';\n      return [out(session, COPY.menu, { route: 'menu' })];\n    }\n    case 'menu': {\n      if (isContratar(text)) {\n        session.state = 'cep';\n        return [out(session, COPY.askCep, { route: 'cep' })];\n      }\n      if (isChip(text)) {\n        return [out(session, COPY.chip, { route: 'menu' })];\n      }\n      return [out(session, COPY.menu, { route: 'menu' })];\n    }\n    case 'cep': {\n      const cep = text.replace(/\\D/g, '');\n      if (cep.length !== 8) {\n        return [out(session, COPY.badCep, { route: 'cep' })];\n      }\n      session.cep = cep;\n      session.state = 'numero';\n      return [out(session, COPY.askNumero, { route: 'cep' })];\n    }\n    case 'numero': {\n      const num = text.replace(/[^\\dA-Za-z\\-]/g, '');\n      if (!num) {\n        return [out(session, COPY.askNumero, { route: 'cep' })];\n      }\n      session.numero = num;\n      let cepJson;\n      try {\n        cepJson = await lookupCep(session.cep);\n      } catch (e) {\n        session.state = 'cep';\n        return [out(session, COPY.badCep, { route: 'cep', error: 'cep_not_found' })];\n      }\n      session.rua = cepJson.street || cepJson.rua || '';\n      session.bairro = cepJson.neighborhood || cepJson.bairro || '';\n      session.cidade = cepJson.city || cepJson.cidade || '';\n      session.uf = cepJson.state || '';\n      const coords = cepJson.location && cepJson.location.coordinates ? cepJson.location.coordinates : {};\n      session.lat = coords.latitude != null ? String(coords.latitude) : '';\n      session.lng = coords.longitude != null ? String(coords.longitude) : '';\n      if (!session.rua || !session.cidade) {\n        session.state = 'cep';\n        return [out(session, COPY.badCep, { route: 'cep' })];\n      }\n      const putBody = {\n        cep: session.cep,\n        cidade: session.cidade,\n        bairro: session.bairro,\n        rua: session.rua,\n        numero: session.numero,\n        coordinates: { lat: session.lat, lng: session.lng },\n      };\n      await putSubscription(cfg, session, putBody);\n      session.state = 'confirma_end';\n      return [out(session, COPY.confirma(session), { route: 'confirma_end' })];\n    }\n    case 'confirma_end': {\n      if (yes(text)) {\n        session.state = 'complemento';\n        return [out(session, COPY.askComp, { route: 'complemento' })];\n      }\n      if (no(text)) {\n        session.state = 'end_errado';\n        return [out(session, COPY.oQueErrado, { route: 'confirma_end' })];\n      }\n      return [out(session, COPY.confirma(session), { route: 'confirma_end' })];\n    }\n    case 'end_errado': {\n      session.cep = '';\n      session.numero = '';\n      session.rua = '';\n      session.bairro = '';\n      session.cidade = '';\n      session.state = 'cep';\n      return [out(session, COPY.askCep, { route: 'cep' })];\n    }\n    case 'complemento': {\n      session.complemento = no(text) ? '' : text;\n      const plans = await getPlans(cfg);\n      session.plans = plans.map((p) => ({\n        id: String(p.id),\n        nome: (p.attributes && (p.attributes.nome || p.attributes.titulo)) || String(p.id),\n        attributes: p.attributes || {},\n      }));\n      session.state = 'planos';\n      const lista = formatPlans(session.plans);\n      return [out(session, `${COPY.escolhePlanoHeader}\\n\\n${lista}`, { route: 'planos' })];\n    }\n    case 'planos': {\n      const picked = pickPlan(text, session.plans);\n      if (!picked) {\n        const lista = formatPlans(session.plans);\n        return [out(session, `Não reconheci esse plano. Escolha pelo número:\\n\\n${lista}`, { route: 'planos' })];\n      }\n      session.plan_id = String(picked.id);\n      session.plan_nome = (picked.attributes && (picked.attributes.nome || picked.attributes.titulo)) || picked.nome || session.plan_id;\n      session.state = 'cpf';\n      return [out(session, COPY.askCpf, { route: 'cpf' })];\n    }\n    case 'cpf': {\n      const cpf = text.replace(/\\D/g, '');\n      if (!validCpf(cpf)) {\n        return [out(session, COPY.badCpf, { route: 'cpf' })];\n      }\n      session.cpf = cpf;\n      session.state = 'rg';\n      return [out(session, COPY.askRg, { route: 'rg' })];\n    }\n    case 'rg': {\n      if (!text) return [out(session, COPY.askRg, { route: 'rg' })];\n      session.rg = text.replace(/\\s+/g, '');\n      session.state = 'nasc_dia';\n      return [out(session, COPY.askDia, { route: 'nasc' })];\n    }\n    case 'nasc_dia': {\n      const d = parseInt(text.replace(/\\D/g, ''), 10);\n      if (!d || d < 1 || d > 31) return [out(session, COPY.badDia, { route: 'nasc' })];\n      session.dia = d;\n      session.state = 'nasc_mes';\n      return [out(session, COPY.askMes, { route: 'nasc' })];\n    }\n    case 'nasc_mes': {\n      const m = parseInt(text.replace(/\\D/g, ''), 10);\n      if (!m || m < 1 || m > 12) return [out(session, COPY.badMes, { route: 'nasc' })];\n      session.mes = m;\n      session.state = 'nasc_ano';\n      return [out(session, COPY.askAno, { route: 'nasc' })];\n    }\n    case 'nasc_ano': {\n      const y = parseInt(text.replace(/\\D/g, ''), 10);\n      if (!y || String(y).length !== 4) return [out(session, COPY.badAno, { route: 'nasc' })];\n      if (!isValidDate(session.dia, session.mes, y)) {\n        session.state = 'nasc_dia';\n        return [out(session, `Data inválida. ${COPY.askDia}`, { route: 'nasc' })];\n      }\n      if (ageYears(session.dia, session.mes, y) < 18) {\n        session.state = 'nasc_dia';\n        return [out(session, COPY.menor, { route: 'nasc' })];\n      }\n      session.ano = y;\n      session.state = 'nasc_confirma';\n      return [out(session, COPY.confirmaNasc(session), { route: 'nasc' })];\n    }\n    case 'nasc_confirma': {\n      if (yes(text)) {\n        session.state = 'email';\n        return [out(session, COPY.askEmail, { route: 'email' })];\n      }\n      if (no(text)) {\n        session.dia = '';\n        session.mes = '';\n        session.ano = '';\n        session.state = 'nasc_dia';\n        return [out(session, COPY.oQueNasc + '\\n\\n' + COPY.askDia, { route: 'nasc' })];\n      }\n      return [out(session, COPY.confirmaNasc(session), { route: 'nasc' })];\n    }\n    case 'email': {\n      const email = text.trim();\n      if (!validEmail(email)) return [out(session, COPY.badEmail, { route: 'email' })];\n      session.email = email;\n      await putSubscription(cfg, session, buildFinalBody(session));\n      session.checkout_url = `${cfg.CHECKOUT}/plano/${session.plan_id}?auto=${session.uuid}`;\n      session.state = 'done';\n      return [out(session, COPY.cta(session, session.checkout_url), { route: 'finalizar' })];\n    }\n    default: {\n      if (triggered) {\n        session = newSession(wa);\n        session.state = 'start';\n        return [out(session, COPY.askName, { route: 'start' })];\n      }\n      return [out(session, null, { route: 'ignore' })];\n    }\n  }\n} catch (err) {\n  const msg = String(err && err.message ? err.message : err).slice(0, 280);\n  return [out(session, `Não consegui concluir este passo agora. Tente de novo ou envie o gatilho para recomeçar.\\n(${msg})`, { route: 'error', error: msg })];\n}\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        560,
        160
      ],
      "id": "ceb8d87f-8005-4a0a-b205-8bc7dd6eab3e",
      "name": "Switch Estado / Chat Engine"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.route }}",
                    "rightValue": "start",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "start"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.route }}",
                    "rightValue": "menu",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "menu"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.route }}",
                    "rightValue": "cep",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "cep"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.route }}",
                    "rightValue": "confirma_end",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "confirma_end"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.route }}",
                    "rightValue": "complemento",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "complemento"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.route }}",
                    "rightValue": "planos",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "planos"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.route }}",
                    "rightValue": "cpf",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "cpf"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.route }}",
                    "rightValue": "rg",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "rg"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.route }}",
                    "rightValue": "nasc",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "nasc"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.route }}",
                    "rightValue": "email",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "email"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.route }}",
                    "rightValue": "finalizar",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "finalizar"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.route }}",
                    "rightValue": "reply",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "reply"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.route }}",
                    "rightValue": "ignore",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "ignore"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.route }}",
                    "rightValue": "error",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "error"
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra"
        }
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.2,
      "position": [
        880,
        160
      ],
      "id": "454a9b8c-cd24-44ef-af95-16c2a70737dd",
      "name": "Switch(estado)"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ reply: $json.reply, state: $json.state, wa_id: $json.wa_id, uuid: $json.uuid, checkout_url: $json.checkout_url, coverage: $json.coverage, session: $json.session, route: $json.route }) }}",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        1200,
        160
      ],
      "id": "fa585bb7-616e-4369-ac38-05b07e5e408d",
      "name": "Respond to Webhook"
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Normalize Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "WhatsApp Trigger": {
      "main": [
        [
          {
            "node": "Normalize Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "Normalize Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Input": {
      "main": [
        [
          {
            "node": "Switch Estado / Chat Engine",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch Estado / Chat Engine": {
      "main": [
        [
          {
            "node": "Switch(estado)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch(estado)": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "availableInMCP": true
  },
  "staticData": null
}