Felo API PlatformFelo API Platform

Soporte

Clasifica un ticket de soporte en un borrador de respuesta fundamentado

Enmascara el ticket, clasifica intención y prioridad con Chat, recupera los pasajes que responden desde la documentación, revisa conversaciones públicas de incidencia y deja un borrador enrutado para aprobación humana.

Tiempo20 minutosNivelIntermedioActualizado2026-10-30
Para quiénResponsables de soporteHelpdesk AgentIngenieros de soporte

Copiar el prompt

Sustituye los campos entre corchetes y pégalo en Claude Code, Codex o cualquier IA con acceso a terminal. Instala el skill de Felo, pregunta antes de gastar créditos y ejecuta el flujo.

Clasifica este ticket de soporte y redacta un borrador de respuesta para revisión humana: [pega el ticket después de quitar nombre, correo, ID de cuenta, datos de pago y cualquier información identificable].

Área de producto: [producto]. Plan o región: [solo si hace falta para responder]. Fuente documental: [URL del centro de ayuda o LiveDoc short_id].
Ruta de aprobación: [quién revisa]. Cola de escalado: [equipo o canal].

Genera:
1. Intención: una categoría y una frase de justificación.
2. Prioridad: urgente / normal / baja, con la regla aplicada.
3. Evidencia: los pasajes de documentación que responden al ticket, con título y relevancia.
4. Comprobación de incidentes: ¿los informes públicos sugieren una caída amplia? Enlace y fecha, o «sin señal pública».
5. Enrutado: borrador, pedir información al cliente o escalar, y por qué.
6. Borrador de respuesta: de dos a cuatro frases, solo con la evidencia, nombrando la fuente en la que se apoya.

Reglas:
- No incluyas nombres, correos, números de pedido, tokens ni datos de pago en llamadas API ni salidas. Trabaja solo con el ticket enmascarado.
- Responde solo con la documentación recuperada. Sin evidencia, escala en lugar de adivinar.
- No prometas reembolsos, descuentos, plazos ni cambios de cuenta; deriva esos casos al escalado.
- Los rumores públicos de caída son señales, no pruebas. Cita la publicación y la fecha.
- Antes de gastar créditos, muestra las llamadas previstas y espera mi aprobación.
- No envíes respuestas, no actualices el ticket ni actúes sobre la cuenta. Devuelve el borrador para revisión.
- Escribe el resultado en ./support-triage.md y resúmelo en el chat.

La copia también incluye los pasos de instalación y las reglas de seguridad.

Lo que obtienes

Salida de ejemplo de una ejecución. No es generación en vivo.

Ejemplo de triaje (extracto)

Triaje — ticket de ejemplo

Intención

Pregunta de facturación / renovación. El cliente pregunta por qué se renovó el plan otra vez.

Prioridad

Normal. Es una pregunta de facturación, no una caída, y el cliente no está bloqueado.

Evidencia

  • «preguntas frecuentes de facturación» — momento de renovación y reintentos de tarjeta. Relevancia: alta.
  • «Cambios de plan» — downgrade entre renovaciones. Relevancia: media.

Comprobación de incidentes

Sin reportes públicos en las últimas 48 horas.

Ruta

Borrador. La documentación cubre la pregunta.

Borrador de respuesta

Hola: tu plan se renueva el día 1 de cada mes, y una tarjeta fallida se reintenta durante tres días antes de pausar el asiento. Puedes cambiar la tarjeta en Ajustes de facturación; la preguntas frecuentes de facturación tiene los pasos. Si necesitas mover la fecha de renovación, responde y lo escalaremos al equipo de facturación.

Nota para revisión

Aprobar, editar o escalar a la cola de facturación.

Las llamadas exactas

Para desarrolladores: el mismo flujo como código, en orden de ejecución.

Mostrar las llamadas reales a la API
  1. Enmascara y clasifica

    Retira por código email, teléfono y número de pedido, y luego usa Chat para intención y prioridad.

    triage.ts
    const BASE = "https://openapi.felo.ai";
    const headers = {
      Authorization: `Bearer ${process.env.FELO_API_KEY}`,
      "Content-Type": "application/json",
    };
    
    async function felo<T>(path: string, body?: unknown): Promise<T> {
      const res = await fetch(`${BASE}${path}`, {
        method: body ? "POST" : "GET",
        headers,
        body: body ? JSON.stringify(body) : undefined,
      });
      if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
      return res.json() as Promise<T>;
    }
    
    const redact = (text: string) =>
      text
        .replace(/[\w.+-]+@[\w.-]+\.\w+/g, "[email]")
        .replace(/\b(?:acct|account|order|invoice)[-_ ]?\w+\b/gi, "[id]")
        .replace(/\b(?:\d[ -]?){13,19}\b/g, "[card]");
    
    type Ticket = {
      id: string;
      product: string;
      subject: string;
      body: string;
      plan?: string;
      sensitive?: boolean;
    };
    
    const ticket: Ticket = {
      id: "T-1042",
      product: "Acme Workspace",
      subject: "Why did my plan renew?",
      body: "I was charged again and cannot find the renewal date on my account.",
      plan: "team",
    };
    
    const summary = redact(`${ticket.subject}\n\n${ticket.body}`).slice(0, 1500);
    
    type ChatData = {
      data: {
        answer: string;
        resources: { link: string; title: string; snippet: string }[];
      };
    };
    
    const triage = await felo<ChatData>("/v2/chat", {
      query: `Classify this support question by intent and priority, and list what is missing:\n\n${summary}`,
    });
    
    console.log(triage.data.answer);

    Salida de ejemplo

    {
      "answer": "Intent: billing / renewal question. Priority: normal. Missing: the renewal date the customer expects.",
      "resources": [
        { "link": "https://example.com/billing-faq", "title": "Billing FAQ", "snippet": "…" }
      ]
    }
  2. Recupera evidencias documentales

    Busca pasajes relevantes en el LiveDoc de la base de conocimiento, guardando títulos y puntuaciones.

    triage.ts
    type Hit = { title: string; content: string; score: number };
    
    const KB = process.env.SUPPORT_LIVEDOC_ID!; // the help-center LiveDoc short_id
    
    const retrieved = await felo<{ data: Hit[] }>(
      `/v2/livedocs/${KB}/resources/retrieve`,
      { query: summary },
    );
    
    const hits = retrieved.data.filter((hit) => hit.score >= 0.7).slice(0, 4);
    
    if (hits.length === 0) {
      console.log("No grounded evidence: escalate instead of drafting");
    }

    Salida de ejemplo

    [
      {
        "title": "Billing FAQ",
        "content": "Your plan renews on the first of the month; a failed card retries for three days…",
        "score": 0.91
      }
    ]
  3. Comprueba incidencia pública

    Busca en X el producto y palabras como «caída/indisponible» en 48 horas, solo como señal pública.

    triage.ts
    type XData = {
      data: {
        tweets: {
          content: string;
          author: { username: string };
          created_at: string;
          url: string;
        }[];
      };
    };
    
    const since = Math.floor((Date.now() - 48 * 60 * 60 * 1000) / 1000);
    
    const incident = await felo<XData>("/v2/x/tweet/search", {
      query: `"${ticket.product}" (outage OR "not working" OR error)`,
      limit: 20,
      since_time: since,
    });
    
    const reports = incident.data.tweets.map((post) => ({
      text: post.content,
      handle: post.author.username,
      at: post.created_at.slice(0, 10),
      link: post.url,
    }));

    Salida de ejemplo

    [
      {
        "text": "Workspace login is failing for my whole team.",
        "handle": "example_user",
        "at": "2026-10-30",
        "link": "https://x.com/example_user/status/..."
      }
    ]
  4. Define la ruta y monta la respuesta

    Las reglas deciden la cola; empaqueta evidencias, siguiente paso y borrador.

    triage.ts
    type Route = "draft" | "ask-customer" | "escalate";
    
    function decideRoute(): { route: Route; reason: string } {
      if (hits.length === 0) {
        return { route: "escalate", reason: "no grounded evidence in the knowledge base" };
      }
      if (ticket.sensitive) {
        return { route: "escalate", reason: "an account or billing action is requested" };
      }
      if (reports.length >= 3) {
        return { route: "escalate", reason: "public reports suggest a wider issue" };
      }
      if (!ticket.plan) {
        return { route: "ask-customer", reason: "the plan is needed to answer the question" };
      }
      return { route: "draft", reason: "the documentation covers the question" };
    }
    
    const decision = decideRoute();
    
    const packet = [
      `# Triage — ${ticket.id}`,
      "",
      `Route: ${decision.route} (${decision.reason})`,
      "",
      "## Intent and priority",
      triage.data.answer,
      "",
      "## Evidence",
      ...hits.map((hit) => `- ${hit.title} (score ${hit.score})`),
      "",
      "## Public signal",
      ...(reports.length
        ? reports.map((report) => `- @${report.handle} (${report.at}): ${report.text} — ${report.link}`)
        : ["No public reports in the last 48 hours."]),
      "",
      "## Reply draft",
      "[Written by the host Agent from the evidence above — human review required]",
    ].join("\n");
    
    console.log(packet);

    Salida de ejemplo

    # Triage — T-1042
    
    Route: draft (the documentation covers the question)
    
    ## Intent and priority
    Intent: billing / renewal question. Priority: normal.
    
    ## Evidence
    - Billing FAQ (score 0.91)
  5. Registra el triaje

    Escribe el resultado en el LiveDoc para retrospectiva y auditoría.

    triage.ts
    type LiveDocData = { data: { short_id: string } };
    
    const log = await felo<LiveDocData>("/v2/livedocs", {
      name: "Support triage log",
      description: "One document resource per triaged ticket",
    });
    
    await felo(`/v2/livedocs/${log.data.short_id}/resources/doc`, {
      title: `Triage — ${ticket.id}`,
      content: packet,
    });
    
    console.log(log.data.short_id); // reuse it for the next ticket

    Salida de ejemplo

    { "short_id": "PvyKouzJirXjFdst4uKRK3" }

Qué incluye

  • Clasificación de intención y prioridad tras enmascarar
  • Evidencias documentales con puntuaciones
  • Comprobación de incidencia pública
  • Borrador de respuesta enrutado
  • LiveDoc con el registro de triaje

Qué no hace

  • No envía respuesta, no cierra el ticket ni ejecuta acciones de cuenta
  • No envíes contraseñas, datos de pago ni datos completos del cliente a la API
  • Sin resultado documental, el escalado es obligatorio
  • X es una señal pública de incidencia, no el estado del sistema de soporte
  • Las reglas de prioridad son tuyas; el modelo solo sugiere

Preguntas

¿Qué datos del ticket puedo enviar?

Solo el contexto necesario tras enmascarar: producto, descripción, plan y región. No envíes contraseñas, pago, dirección completa ni conversación privada.

¿De dónde viene la respuesta?

De los pasajes recuperados del LiveDoc de documentación. Sin resultados, el flujo escala en vez de adivinar.

¿Responde o cierra el ticket?

No. Solo genera borrador y ruta; envío y cierre los hace una persona o tu sistema.

¿Cómo se decide la prioridad?

Con tus reglas; el modelo sugiere y justifica, y la ruta confirma la prioridad final.

¿Y si la documentación no cubre?

Escalado a la cola humana, marcando «no cubierto» en el paquete de triaje.

¿Cuánto cuesta un triaje?

Chat, búsqueda y X Search se facturan por uso; las tarifas están en la página de precios y el prompt pide aprobación antes de gastar.

Flujos relacionados

Hazlo tuyo

La misma receta, adaptada a cómo entregas de verdad.

Solo clasificación

Sin respuesta: solo intención, prioridad y cola recomendada.

Conecta al sistema de tickets

Con tu webhook, escribe el paquete en el ticket sin envío automático.

Pasa a base de conocimiento

Con resultado documental, pasa al flujo de base de conocimiento para una respuesta más completa.

Las páginas de referencia detrás de esta receta y los siguientes pasos.