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

# Paso JavaScript

> Ejecuta código JavaScript en sandbox: input, output, objetos disponibles y ejemplos.

El paso `code.javascript` ejecuta un script en un entorno aislado. Úsalo para transformar datos, validar, armar payloads o integrar fuentes que no cubre un HTTP simple.

## Campos del paso

| Campo       | Requerido | Descripción                                                                             |
| ----------- | --------- | --------------------------------------------------------------------------------------- |
| `actionKey` | Sí        | Debe ser `code.javascript`.                                                             |
| `code`      | Sí        | Script JavaScript. Máximo `100000` caracteres.                                          |
| `input`     | No        | Objeto de variables. Se resuelven plantillas `{{...}}` y queda disponible como `input`. |
| `timeoutMs` | No        | Límite de ejecución en milisegundos.                                                    |
| `capture`   | No        | Copia campos de `output` a `context`.                                                   |
| `debug`     | No        | Activa metadatos adicionales de depuración cuando aplica.                               |

## Contrato de ejecución

1. La API resuelve plantillas en `input`.
2. El sandbox recibe ese objeto como global `input`.
3. Tu código debe asignar `output = ...`.
4. Ese `output` es la salida del paso (y `response.body` para `capture`).

Consulta [Variables y contexto](/automatizaciones/variables-y-contexto) para armar `input` y pasar datos entre pasos.

## Pasar variables desde un paso anterior

Declara en `input` lo que necesitas del trigger, de `context` o de `steps.<n>.output`. Luego léelo como `input.*` en el script.

```json theme={null}
{
  "name": "Calcular IVA",
  "actionKey": "code.javascript",
  "input": {
    "monto": "{{steps.0.output.monto}}",
    "token": "{{context.accessToken}}"
  },
  "code": "const monto = Number(input.monto);\noutput = {\n  monto,\n  iva: Number((monto * 0.16).toFixed(2)),\n  total: Number((monto * 1.16).toFixed(2)),\n  hasToken: Boolean(input.token)\n};",
  "capture": {
    "totales": {
      "from": "response.body",
      "required": true
    }
  }
}
```

Para publicar datos al siguiente paso:

1. Asigna `output = { ... }`.
2. En el paso siguiente usa `{{steps.N.output.<campo>}}`, **o**
3. Declara `capture` y lee `{{context.<clave>}}`.

## Objetos y APIs disponibles

| Global                                       | Uso                                                                      |
| -------------------------------------------- | ------------------------------------------------------------------------ |
| `input`                                      | Variables inyectadas desde el `input` del paso.                          |
| `output`                                     | Resultado que debes asignar.                                             |
| `console`                                    | `log`, `info`, `warn`, `error`, `table` (aparecen en los logs del paso). |
| `fetch`                                      | HTTP nativo (`Headers`, `Request`, `Response` también disponibles).      |
| `axios`                                      | Cliente HTTP.                                                            |
| `DateTime`                                   | Luxon anclado a la zona de la automatización.                            |
| `DateTimeUTC`                                | Luxon en UTC.                                                            |
| `WORKFLOW_TIMEZONE`                          | Zona IANA activa (string).                                               |
| `sleep(ms)`                                  | Pausa asíncrona.                                                         |
| `Buffer`, `crypto`, `URL`, `URLSearchParams` | Utilidades Node/Web habituales.                                          |
| `_`                                          | Lodash.                                                                  |
| `z`                                          | Zod, para validar estructuras.                                           |
| `setTimeout` / `setInterval`                 | Temporizadores (se limpian al terminar).                                 |
| `mysql`                                      | Helper para MySQL.                                                       |
| `sftp`                                       | Helper para SFTP.                                                        |

### Zona horaria

* Trigger `cron`: `DateTime.now()` usa la `timezone` del trigger.
* Otros triggers (p. ej. webhook): la zona efectiva es `UTC`.

## Buen ejemplo: normalizar y validar

```json theme={null}
{
  "name": "Normalizar pago",
  "actionKey": "code.javascript",
  "input": {
    "referencia": "{{trigger.body.referencia}}",
    "monto": "{{trigger.body.monto}}"
  },
  "code": "const referencia = String(input.referencia || '').trim();\nconst monto = Number(input.monto);\nif (!referencia) throw new Error('referencia requerida');\nif (!Number.isFinite(monto) || monto <= 0) throw new Error('monto inválido');\noutput = { referencia, monto, moneda: 'MXN' };",
  "capture": {
    "pago": {
      "from": "response.body",
      "required": true
    }
  }
}
```

Script equivalente (más legible):

```javascript theme={null}
const referencia = String(input.referencia || "").trim();
const monto = Number(input.monto);

if (!referencia) {
  throw new Error("referencia requerida");
}
if (!Number.isFinite(monto) || monto <= 0) {
  throw new Error("monto inválido");
}

output = {
  referencia,
  monto,
  moneda: "MXN",
};
```

## Buen ejemplo: llamar una API con `fetch`

```javascript theme={null}
const response = await fetch("https://ejemplo.com/api/pagos", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${input.token}`,
  },
  body: JSON.stringify({
    referencia: input.referencia,
    monto: input.monto,
  }),
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

output = await response.json();
```

Pasa `token`, `referencia` y `monto` por `input` con plantillas; no los incrustes en `code`.

## Buen ejemplo: fechas con `DateTime`

```javascript theme={null}
const ahora = DateTime.now();
const vencimiento = DateTime.fromISO(input.fechaVencimiento);

output = {
  timezone: WORKFLOW_TIMEZONE,
  ahora: ahora.toISO(),
  vencido: vencimiento < ahora,
  diasRestantes: Math.floor(vencimiento.diff(ahora, "days").days),
};
```

## Malos ejemplos

### No asignar `output`

```javascript theme={null}
const total = Number(input.monto) * 1.16;
// falta: output = { total };
```

Sin `output`, el paso no deja un resultado útil para pasos siguientes ni para `capture`.

### Usar `require` o APIs de sistema

```javascript theme={null}
const fs = require("fs");
process.env.SECRET;
```

El sandbox no expone `require`, `process`, ni acceso al sistema de archivos del runner. Usa `input`, `fetch`/`axios`, `mysql` o `sftp`.

### Leer el trigger directo sin pasarlo por `input`

```javascript theme={null}
output = { referencia: trigger.body.referencia };
```

`trigger` no existe como global. Declara `"referencia": "{{trigger.body.referencia}}"` en `input` y usa `input.referencia`.

### Mutar estado “global” entre pasos

```javascript theme={null}
if (!globalThis.cache) globalThis.cache = {};
globalThis.cache.token = input.token;
output = { ok: true };
```

Cada paso corre en un proceso aislado. Comparte datos con `output` + `capture`/`context` o con el `input` del siguiente paso.

## MySQL (opcional)

```javascript theme={null}
const db = await mysql.connect({
  host: input.mysql.host,
  port: input.mysql.port || 3306,
  user: input.mysql.user,
  password: input.mysql.password,
  database: input.mysql.database,
});

try {
  const rows = await db.execute(
    "SELECT id, email FROM customers WHERE status = ? LIMIT ?",
    ["active", 10]
  );
  output = { customers: rows };
} finally {
  await db.close();
}
```

Pasa host, usuario y contraseña por `input` (idealmente desde el body del webhook o un secreto que tú controles en tu integración). No hardcodees credenciales en `code`.

## SFTP (opcional)

```javascript theme={null}
const client = await sftp.connect({
  host: input.sftp.host,
  port: input.sftp.port || 22,
  username: input.sftp.username,
  password: input.sftp.password,
});

try {
  const files = await client.list("/entradas");
  output = {
    archivos: files.filter((f) => f.isFile).map((f) => f.name),
  };
} finally {
  await client.close();
}
```

## Límites prácticos

* El script corre con `"use strict"`.
* Usa `throw new Error("...")` para fallar el paso con un mensaje claro.
* Los `console.*` se recortan si son muy grandes; no uses logs para transportar el resultado final: usa `output`.
* Prefiere pasos cortos y deterministas; deja esperas largas al paso [Esperar](/automatizaciones/paso-esperar).

## Ejemplo de solicitud completo

```bash theme={null}
curl -X POST "https://api.insuranceboosters.com/api/v1/workflows" \
  -H "Content-Type: application/json" \
  -H "x-ib-api-key: TU_API_KEY" \
  -d '{
    "name": "Normalizar pago por webhook",
    "status": "disabled",
    "trigger": { "type": "webhook" },
    "steps": [
      {
        "name": "Normalizar pago",
        "actionKey": "code.javascript",
        "input": {
          "referencia": "{{trigger.body.referencia}}",
          "monto": "{{trigger.body.monto}}"
        },
        "code": "const referencia = String(input.referencia || \"\").trim();\nconst monto = Number(input.monto);\nif (!referencia) throw new Error(\"referencia requerida\");\nif (!Number.isFinite(monto) || monto <= 0) throw new Error(\"monto inválido\");\noutput = { referencia, monto };"
      }
    ]
  }'
```
