> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getnexor.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK de JavaScript

> Usa @getnexorai/sdk v0.1.44 desde un servidor Node.js o monta su widget avanzado en el navegador con una clave pública de Chat web.

`@getnexorai/sdk` ofrece dos superficies separadas:

* un cliente JavaScript de servidor para 16 operaciones REST públicas;
* un widget avanzado de Chat web para el navegador.

Esta referencia está fijada a `@getnexorai/sdk` v0.1.44. No presenta el paquete como un wrapper de toda la API REST.

<Warning>
  Mantén separados los dos tipos de clave. El código de servidor usa una clave REST secreta cargada desde una variable de entorno. El navegador solo puede usar la clave de Chat web visible en el navegador y no secreta que comienza con `nxr_pub_`.
</Warning>

## Instala para usar en servidor

El SDK requiere Node.js 18 o posterior.

```bash theme={null}
npm install @getnexorai/sdk@0.1.44
```

El paquete expone el singleton por defecto y exports con nombre desde la raíz. También expone tipos y helpers de chat mediante `@getnexorai/sdk/chat`.

## Inicio rápido en servidor

Define `NEXOR_API_KEY` en el gestor de secretos de tu servidor. No la subas al repositorio.

```js theme={null}
import nexor from "@getnexorai/sdk";

if (!process.env.NEXOR_API_KEY) {
  throw new Error("NEXOR_API_KEY is required");
}

nexor.init({ apiKey: process.env.NEXOR_API_KEY });

const result = await nexor.createLead({
  first_name: "Ada",
  last_name: "Lovelace",
  email: "ada@example.com",
  workflow_id: "your-workflow-uuid",
});

console.log(result.lead.id);
```

`createLead` y `createLeadsBulk` siempre envían `skip_first_message: true`. Crear un lead con estos helpers no significa, por sí solo, que el Agente envíe de inmediato el primer mensaje normal de su cadencia.

Para inyección de dependencias o código de servidor multi-tenant, crea clientes independientes en vez de cambiar el singleton:

```js theme={null}
import { NexorClient } from "@getnexorai/sdk";

const client = new NexorClient({ apiKey: process.env.NEXOR_API_KEY });
const { workflows } = await client.listWorkflows();
```

## Métodos REST

Los 16 métodos siguientes están disponibles en el export por defecto ya inicializado y en `NexorClient`.

| Método                                        | Propósito                                                                            |
| --------------------------------------------- | ------------------------------------------------------------------------------------ |
| `createLead(input, options?)`                 | Crea un lead y, de forma opcional, lo asigna a un Agente                             |
| `createLeadsBulk(inputs, options?)`           | Crea hasta 1.000 leads en una solicitud                                              |
| `updateLead(leadId, updates, options?)`       | Actualiza un lead; la API hace un merge superficial de `metadata`                    |
| `getLead(leadId, options?)`                   | Consulta un lead, sus variables capturadas, engagement y ejecución activa del Agente |
| `getLeadHistory(leadId, params?, options?)`   | Recorre mensajes, transcripciones y actividad con paginación                         |
| `isLeadPaused(leadId, params?, options?)`     | Revisa si la toma de control humana pausó la automatización                          |
| `stopAutomation(leadId, input, options?)`     | Pausa la automatización para una ejecución específica del Agente                     |
| `resumeAutomation(leadId, input, options?)`   | Devuelve el control al Agente y puede reanudar la cadencia                           |
| `syncLeadTags(input, options?)`               | Reemplaza el conjunto completo de tags de un lead, identificado por ID o correo      |
| `listLeadMeetings(leadId, params?, options?)` | Lista las reuniones de un lead y permite filtrar por status                          |
| `listWorkflows(options?)`                     | Lista los Agentes activos de la cuenta                                               |
| `listCampaigns(options?)`                     | Lista las campañas de la cuenta                                                      |
| `listTemplates(params?, options?)`            | Lista templates de WhatsApp aprobados con filtros opcionales                         |
| `sendMessage(input, options?)`                | Envía un mensaje de WhatsApp o correo, o inicia una llamada                          |
| `createMeeting(input, options?)`              | Registra una reunión agendada para un lead existente buscado por correo              |
| `createMeetingNotes(input, options?)`         | Adjunta una transcripción, resumen y acciones a una reunión                          |

Usa la [referencia de la API REST](/docs/es/api/introduction) para los endpoints que el SDK no envuelve.

## Comportamiento HTTP

| Ajuste                 | Valor por defecto o comportamiento                             |
| ---------------------- | -------------------------------------------------------------- |
| URL base               | `https://api.getnexor.ai`                                      |
| Autenticación          | `X-API-Key`                                                    |
| Timeout                | 30 segundos                                                    |
| Reintentos automáticos | 2 reintentos para HTTP 429, HTTP 5xx, fallas de red y timeouts |
| Control por solicitud  | `signal`, `timeoutMs`, `maxRetries` e `idempotencyKey`         |

Usa `maxRetries: 0` para una operación no idempotente cuando repetirla pueda duplicar un efecto. Pasar `idempotencyKey` agrega el header `Idempotency-Key`; no garantiza por sí solo que todos los endpoints dedupliquen la solicitud.

```js theme={null}
await nexor.sendMessage(
  {
    lead_id: "lead-uuid",
    workflow_id: "workflow-uuid",
    channel: "email",
    subject: "Bienvenida",
    content: "Gracias por contactarnos.",
  },
  {
    maxRetries: 0,
    timeoutMs: 15_000,
    idempotencyKey: crypto.randomUUID(),
  },
);
```

## Maneja errores

El SDK expone `NexorError`, `NexorAPIError`, `NexorAuthError`, `NexorValidationError` y `NexorNetworkError`.

```js theme={null}
import {
  NexorAPIError,
  NexorAuthError,
  NexorNetworkError,
  NexorValidationError,
} from "@getnexorai/sdk";

try {
  await nexor.getLead("lead-uuid");
} catch (error) {
  if (error instanceof NexorAuthError) {
    // La clave falta, no es válida o no tiene permiso para esta solicitud.
  } else if (error instanceof NexorValidationError) {
    // Revisa los campos de la solicitud antes de volver a intentar.
  } else if (error instanceof NexorNetworkError) {
    // La solicitud agotó los reintentos por red o timeout.
  } else if (error instanceof NexorAPIError) {
    console.error(error.status, error.code, error.requestId);
  } else {
    throw error;
  }
}
```

El paquete v0.1.44 envía actualmente `nexor-sdk-js/0.1.0` en su `User-Agent` de Node.js. No uses ese valor para determinar la versión instalada del paquete.

## Widget en el navegador

Para la mayoría de los sitios, usa el [loader alojado de Chat web](/docs/es/guides/channels/web-chat). No requiere npm y su fragmento viene directamente de la sección **Instalación** del Agente.

Usa el widget del SDK cuando necesites control programático mediante `initChat`, callbacks o configuración en runtime. El build IIFE expone un global llamado `Nexor`.

```html theme={null}
<script src="https://unpkg.com/@getnexorai/sdk@0.1.44/dist/nexor.iife.js"></script>
<script>
  Nexor.init({ apiKey: "nxr_pub_YOUR_PUBLIC_KEY" });

  const chat = Nexor.initChat({
    workflowId: "your-workflow-uuid",
    capture: { mode: "skip" },
  });

  chat.open();
</script>
```

<Warning>
  Nunca pongas una clave REST `nxr_live_` en HTML, un bundle para navegador, una captura o un repositorio público. Una clave para navegador debe comenzar con `nxr_pub_`. Configura los dominios previstos en los ajustes de Chat web del Agente; esa lista se aplica al transporte normal del widget, no como garantía de autorización para todos los flujos opcionales del SDK.
</Warning>

### Callbacks y handle del widget

Pasa callbacks a `initChat` cuando la página contenedora necesite eventos del ciclo de vida o de la conversación.

| Callback                    | Cuándo se ejecuta                                                  |
| --------------------------- | ------------------------------------------------------------------ |
| `onOpen()`                  | Se abre el panel del widget                                        |
| `onClose()`                 | Se cierra el panel del widget                                      |
| `onMessage({ role, text })` | Se agrega un mensaje con rol `user` o `bot`                        |
| `onLeadCaptured(leadId)`    | El widget recibe el ID persistido del lead                         |
| `onError(error)`            | La configuración, captura o ejecución de un turno informa un error |

`initChat` devuelve un handle con estos métodos:

| Método           | Efecto                                                           |
| ---------------- | ---------------------------------------------------------------- |
| `open()`         | Abre el panel                                                    |
| `close()`        | Cierra el panel                                                  |
| `toggle()`       | Cambia el estado abierto o cerrado                               |
| `send(text)`     | Encola un mensaje mediante la misma ruta con debounce del editor |
| `update(patch)`  | Cambia `clientPrompt` u `openingMessage` sin volver a montar     |
| `destroy()`      | Detiene timers, quita listeners y elimina el DOM del widget      |
| `getSessionId()` | Devuelve el ID generado de la sesión actual                      |

<Note>
  `send(text)` resuelve cuando el mensaje queda encolado, no cuando Nexor devuelve o muestra la respuesta. Usa `onMessage` para observar el mensaje posterior del bot y `onError` para observar un turno fallido.
</Note>

```js theme={null}
const chat = Nexor.initChat({
  workflowId: "your-workflow-uuid",
  onOpen: () => console.log("abierto"),
  onClose: () => console.log("cerrado"),
  onMessage: ({ role, text }) => console.log(role, text),
  onLeadCaptured: (leadId) => console.log("lead", leadId),
  onError: (error) => console.error(error),
});

chat.open();
await chat.send("Hola"); // Queda en cola; la respuesta puede seguir en curso.
```

### Flujo de solicitudes del widget

El flujo de red actual del widget no usa la ruta antigua `/api/public/chat` que aparecía en notas anteriores del SDK.

| Cuándo                                                                                                       | Ruta                               |
| ------------------------------------------------------------------------------------------------------------ | ---------------------------------- |
| Configuración inicial, top-level                                                                             | `GET /api/public/chat/config`      |
| Configuración inicial, alternativa embebida                                                                  | `GET /api/widget/v1/config`        |
| Intento de proof of work antes de persistir al visitante o enviar un turno                                   | `GET /api/widget/v1/pow-challenge` |
| Cada turno del chat                                                                                          | `POST /api/widget/v1/turn`         |
| Consulta de recuperación de respuestas después de actividad en el chat                                       | `GET /api/widget/v1/pending`       |
| Persistencia del formulario de captura cuando se activa `capture.createLeadOnSubmit` o el consentimiento SMS | `POST /api/widget/v1/visitor`      |
| Intento de solicitud de contacto del SDK v0.1.44 cuando se configura `requestContact`                        | `POST /api/public/leads`           |
| Diagnóstico best effort                                                                                      | `POST /api/widget/v1/telemetry`    |

<Warning>
  En el SDK v0.1.44, `requestContact` intenta llamar `POST /api/public/leads`. No actives este flujo opcional en un sitio público no confiable hasta que Nexor complete el refuerzo del backend para solicitudes de contacto. Los dominios permitidos cubren el transporte normal del widget; no garantizan la autorización de `requestContact`. Usa el formulario de captura, que persiste los datos del visitante mediante `POST /api/widget/v1/visitor`, o crea el lead desde una integración de servidor confiable.
</Warning>

Las dos rutas de configuración son alternativas: `initChat` elige la ruta pública en top-level y la ruta del widget dentro de un iframe. Antes de persistir al visitante o enviar un turno, solicita un challenge nuevo de proof of work y, cuando está disponible y se puede resolver, adjunta el resultado. Las rutas de configuración, proof of work, turnos, pendientes, visitantes y telemetría forman el transporte normal del widget y tienen controles específicos por solicitud y sesión. Usa el widget en vez de llamarlas directamente. La fila de `requestContact` queda fuera de esa garantía.

## Reproduce el smoke offline del navegador

El smoke del repositorio vuelve a compilar `dist/nexor.iife.js` desde el checkout fijado del SDK, registra su digest SHA-256 y lo evalúa en una página JSDOM vacía. Reemplaza `fetch` por un mock cerrado que rechaza cualquier origen o ruta no reconocida. Luego valida el export global, el DOM montado, la solicitud de configuración top-level, proof of work cuando está disponible, `POST /api/widget/v1/turn`, telemetría y la respuesta mostrada. También revisa, sin ejecutar los flujos condicionales, que ambas páginas incluyan las rutas de configuración embebida, bandeja de pendientes, persistencia de visitantes y solicitud pública de contacto, y que la ruta no soportada de `requestContact` incluya la advertencia requerida.

Prepara una vez el worktree fijado del SDK y después ejecuta el smoke sin credenciales de Nexor ni llamadas de red:

```bash theme={null}
git -C /absolute/path/to/nexor-sdk checkout e11035d723e2b86f74b8a15f05289c6ebc36187d
npm --prefix /absolute/path/to/nexor-sdk ci --ignore-scripts
npm run sdk:smoke -- /absolute/path/to/nexor-sdk
```

El último comando vuelve a compilar el bundle fijado y falla si cambian el checkout, el digest del bundle, el prefijo de la clave de navegador, las rutas, proof of work, la respuesta o los snippets documentados.
