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

# Validación

> Esquemas Zod para validar entradas y salidas de tus funciones: tipos, coerción en GET, formato de errores y comportamiento de output.

## Validación de entrada

Cuando defines un esquema `input`, cada petición se valida antes de ejecutar el handler. Si la validación falla, el handler **no se ejecuta** y se retorna un `400`:

```json theme={null}
{
  "error": "Validation failed",
  "details": [
    {
      "path": ["email"],
      "message": "Invalid email",
      "code": "invalid_string"
    }
  ]
}
```

### Ejemplo con esquema completo

```typescript index.ts theme={null}
import { define, z } from "@jelou/functions";

export default define({
  name: "crear-ticket",
  description: "Crea un ticket de soporte desde WhatsApp",
  input: z.object({
    nombre: z.string().min(1).describe("Nombre del cliente"),
    email: z.string().email().describe("Email de contacto"),
    asunto: z.string().max(200).describe("Asunto del ticket"),
    prioridad: z.enum(["baja", "media", "alta"]).default("media"),
  }),
  output: z.object({
    ticketId: z.string(),
    estado: z.string(),
  }),
  handler: async (input, ctx) => {
    ctx.log("Creando ticket", { cliente: input.nombre, prioridad: input.prioridad });
    return { ticketId: "TKT-2024-0042", estado: "abierto" };
  },
});
```

### Tipos soportados

Puedes usar cualquier tipo de Zod dentro de `z.object()`:

```typescript theme={null}
input: z.object({
  nombre: z.string().min(1),
  edad: z.number().int().positive(),
  email: z.string().email(),
  activo: z.boolean().default(true),
  rol: z.enum(["admin", "usuario", "invitado"]),
  tags: z.array(z.string()).optional(),
  metadata: z.record(z.string(), z.unknown()).optional(),
})
```

### Coerción en peticiones GET

Para peticiones GET, los query parameters son strings. Usa `z.coerce` para convertir tipos automáticamente:

```typescript index.ts theme={null}
import { define, z } from "@jelou/functions";

export default define({
  name: "buscar-pedidos",
  description: "Busca pedidos por estado",
  input: z.object({
    q: z.string(),
    limit: z.coerce.number().default(10),
    pagina: z.coerce.number().default(1),
    activo: z.coerce.boolean().default(true),
  }),
  handler: async (input, ctx) => {
    ctx.log("Buscando", { q: input.q, limit: input.limit });
    return { resultados: [], total: 0 };
  },
});
```

```bash theme={null}
curl "https://buscar-pedidos.fn.jelou.ai/?q=pendiente&limit=5&pagina=2"
```

### Anotaciones `.describe()`

Usa `.describe()` en cada campo para documentar los parámetros. Estas descripciones aparecen automáticamente en el esquema MCP, lo que ayuda a los agentes IA a entender cómo usar tu función:

```typescript theme={null}
input: z.object({
  telefono: z.string().min(10).describe("Número de teléfono con código de país, ej: 593987654321"),
  incluirHistorial: z.boolean().default(false).describe("Si incluir el historial de conversaciones"),
})
```

## Validación de salida

Cuando defines un esquema `output`, el valor retornado por el handler se valida **después** de la ejecución. Si no coincide:

* Se registra una advertencia en los logs
* La respuesta se envía normalmente con status `200`

<Note>
  La validación de output nunca bloquea la respuesta. Es una herramienta de desarrollo para detectar inconsistencias.
</Note>

```typescript theme={null}
output: z.object({
  nombre: z.string(),
  saldo: z.number(),
})
```

Si el handler retorna `{ nombre: "María", saldo: "150" }` (saldo como string), verás una advertencia en los logs pero el cliente recibe la respuesta sin cambios.

## Formato de errores de validación

Cada error en el array `details` contiene:

| Campo     | Tipo       | Descripción                                                                      |
| --------- | ---------- | -------------------------------------------------------------------------------- |
| `path`    | `string[]` | Ruta al campo con error, ej: `["email"]` o `["direccion", "ciudad"]`             |
| `message` | `string`   | Mensaje legible del error                                                        |
| `code`    | `string`   | Código de error de Zod (ej: `invalid_string`, `too_small`, `invalid_enum_value`) |

```json theme={null}
{
  "error": "Validation failed",
  "details": [
    {
      "path": ["nombre"],
      "message": "String must contain at least 1 character(s)",
      "code": "too_small"
    },
    {
      "path": ["prioridad"],
      "message": "Invalid enum value. Expected 'baja' | 'media' | 'alta', received 'urgente'",
      "code": "invalid_enum_value"
    }
  ]
}
```
