El objeto ctx es el segundo parámetro de todo handler. Contiene información de la empresa, bot, usuario, tipo de trigger, y da acceso a secrets, mensajería, memoria y logging.
handler : async ( input , ctx , request ) => {
ctx . log ( "Petición recibida" , {
company: ctx . company . name ,
bot: ctx . bot . channel ,
user: ctx . user . id ,
trigger: ctx . trigger . type ,
});
}
Referencia
Propiedad Tipo Descripción ctx.functionSlugstringSlug de la función ctx.company{ id, name }Empresa del request ctx.bot{ id, name, channel }Bot que originó el request ctx.user{ id, names?, roomId? }Usuario de la conversación ctx.conversation{ id?, ... }Datos de la conversación ctx.operator{ id?, ... }Operador asignado ctx.triggerTriggerInfoTipo de trigger (http, cron, event) ctx.envEnvAccessorAcceso a secrets ctx.paramsRecord<string, string>Parámetros de ruta ctx.queryRecord<string, string>Query string params ctx.jelouJelouSDKCliente de mensajería WhatsApp ctx.memoryMemorySDKMemoria de sesión key-value ctx.methodstringMétodo HTTP (GET, POST, etc.) ctx.pathstringPath del request ctx.requestIdstringUUID único del request ctx.isCronbooleantrue si es trigger cronctx.isEventbooleantrue si es trigger eventctx.isHttpbooleantrue si es request HTTPctx.skillIdstring | nullID del skill de Brain Studio ctx.executionIdstring | nullID de ejecución de Brain Studio ctx.log()(...args) => voidLogger estructurado
Identidad
handler : async ( input , ctx ) => {
// Empresa
ctx . company . id ; // 42
ctx . company . name ; // "Tienda ABC"
// Bot
ctx . bot . id ; // "bot-123"
ctx . bot . name ; // "Bot de Soporte"
ctx . bot . channel ; // "whatsapp"
// Usuario
ctx . user . id ; // 99
ctx . user . names ; // "María García" (opcional)
ctx . user . roomId ; // "room-456" (opcional)
// Conversación y operador
ctx . conversation . id ; // "conv-789" (opcional)
ctx . operator . id ; // "op-012" (opcional)
}
Los datos se hidratan automáticamente desde la plataforma según los headers del request (x-bot-id, x-user-id).
Trigger
Tres tipos de trigger determinan cómo se invocó tu función:
handler : async ( input , ctx ) => {
if ( ctx . isHttp ) {
// Petición HTTP normal
ctx . trigger ; // { type: "http" }
}
}
handler : async ( input , ctx ) => {
if ( ctx . isCron ) {
ctx . trigger . type ; // "cron"
ctx . trigger . cron ; // "0 9 * * *"
ctx . trigger . cronName ; // "recordatorio-mañana" (opcional)
}
}
handler : async ( input , ctx ) => {
if ( ctx . isEvent ) {
ctx . trigger . type ; // "event"
ctx . trigger . event ; // "pago.completado"
}
}
Usa los guards ctx.isCron, ctx.isEvent y ctx.isHttp en lugar de comparar ctx.trigger.type manualmente.
Request
export default define ({
description: "API con ruta parametrizada" ,
input: z . object ({}) ,
config: { path: "/users/:id" } ,
handler : async ( input , ctx ) => {
ctx . method ; // "GET"
ctx . path ; // "/users/42"
ctx . params . id ; // "42"
ctx . query . format // "json" (de ?format=json)
ctx . requestId ; // "a1b2c3d4-..."
return { userId: ctx . params . id };
} ,
}) ;
Environment (secrets)
handler : async ( input , ctx ) => {
// Obtener un secret
const apiKey = ctx . env . get ( "CRM_API_KEY" ); // string | undefined
// Verificar si existe
if ( ctx . env . has ( "WEBHOOK_SECRET" )) {
// ...
}
// Obtener todos (excepto internos __FN_*)
const all = ctx . env . toObject (); // Record<string, string>
}
Las variables internas con prefijo __FN_ están bloqueadas — ctx.env.get("__FN_COMPANY_ID") retorna undefined.
Mensajería (ctx.jelou)
Envía mensajes de WhatsApp directamente desde tu función:
handler : async ( input , ctx ) => {
if ( ctx . jelou . available ) {
await ctx . jelou . send ({
type: "text" ,
to: "+593987654321" ,
text: "Tu pedido está listo" ,
});
}
}
Guía de mensajería 14 tipos de mensaje, templates HSM y manejo de errores.
Memoria (ctx.memory)
Persiste datos por sesión (key-value con TTL):
handler : async ( input , ctx ) => {
if ( ctx . memory . available ) {
const paso = await ctx . memory . get ( "paso" , "inicio" );
await ctx . memory . set ( "paso" , "confirmacion" , 3600 );
}
}
Guía de memoria Primitivos, JSON, TTL, límites y patrones comunes.
Brain Studio (skillId, executionId)
Cuando tu función es invocada desde Brain Studio como herramienta MCP:
handler : async ( input , ctx ) => {
if ( ctx . skillId ) {
ctx . log ( "Invocado desde Brain Studio" , {
skillId: ctx . skillId , // "skill-abc-123"
executionId: ctx . executionId , // "exec-def-456"
});
}
}
Estos campos son null para peticiones HTTP directas y triggers cron.
Logging
ctx.log() escribe JSON estructurado con metadatos automáticos:
handler : async ( input , ctx ) => {
ctx . log ( "Procesando pedido" , { telefono: input . telefono });
// Escribe a stdout:
// {
// "requestId": "a1b2c3d4-...",
// "function": "mi-funcion",
// "company": 42,
// "timestamp": "2026-04-07T15:30:01.234Z",
// "args": ["Procesando pedido", { "telefono": "593987654321" }]
// }
}
Visualiza los logs con jelou logs mi-funcion.
Ejemplo completo
import { define , z } from "@jelou/functions" ;
export default define ({
name: "procesar-pedido" ,
description: "Procesa un pedido y notifica al cliente por WhatsApp" ,
input: z . object ({
pedidoId: z . string (),
telefono: z . string (). min ( 10 ),
}) ,
handler : async ( input , ctx ) => {
ctx . log ( "Procesando pedido" , {
pedidoId: input . pedidoId ,
company: ctx . company . id ,
bot: ctx . bot . name ,
});
// Consultar API externa con secret
const apiKey = ctx . env . get ( "ORDERS_API_KEY" );
const res = await fetch ( `https://api.example.com/orders/ ${ input . pedidoId } ` , {
headers: { Authorization: `Bearer ${ apiKey } ` },
});
const pedido = await res . json ();
// Notificar al cliente por WhatsApp
if ( ctx . jelou . available ) {
await ctx . jelou . send ({
type: "text" ,
to: input . telefono ,
text: `Tu pedido ${ pedido . id } está ${ pedido . status } .` ,
});
}
// Guardar estado en memoria
if ( ctx . memory . available ) {
await ctx . memory . set ( "ultimo_pedido" , input . pedidoId , 86400 );
}
return {
pedidoId: pedido . id ,
status: pedido . status ,
notificado: ctx . jelou . available ,
};
} ,
}) ;
Mensajería Enviar WhatsApp con ctx.jelou.
Memoria Persistir datos con ctx.memory.
Secrets Variables de entorno cifradas.
Autenticación Runtime tokens y funciones públicas.