Todas las peticiones a la API de Money Manager deben ser autenticadas. El acceso se controla mediante API Keys de usuario restringidas por una matriz de Scopes (permisos de seguridad granulares).
🔑 Generar una Clave de API (API Key)
Para generar tus credenciales de integración:
- Inicia sesión en la aplicación web.
- Navega a Ajustes > Claves de API en el menú lateral.
- Haz clic en Crear clave de API.
- Configura:
- Nombre/Etiqueta: Ej. Integración n8n o Servicio Contable.
- Scopes: Marca únicamente los permisos específicos que tu integración necesita (principio de menor privilegio).
- Haz clic en Generar.
- Importante: Copia el token generado y guárdalo en un lugar seguro. No volverá a mostrarse por seguridad.
Aquí puedes ver la vista de Ajustes de Claves de API en la aplicación:

🛡️ Métodos de Autenticación HTTP
La API soporta autenticación mediante cabeceras HTTP en dos modalidades:
1. Cabecera Authorization Bearer (Recomendado)
Pasa el token como una credencial de tipo portador en la cabecera estándar Authorization.
Con API Key de integración:
Authorization: Bearer mm_live_xxxxxx...bashCon Token de sesión de Clerk (para agentes autónomos y widgets que actúan como el usuario):
Authorization: Bearer <clerk_session_jwt>bashLa API valida la sesión activa de Clerk, identifica el usuario y su espacio de trabajo activo, y hereda los permisos del usuario.
2. Cabecera Personalizada (API Keys)
Alternativamente, si tu cliente HTTP o plataforma de automatización tiene restricciones de configuración, puedes pasar la API Key en la cabecera x-api-key:
x-api-key: mm_live_xxxxxx...bashRestricciones de seguridad: Las API Keys (
mm_live_...) no tienen permisos para administrar llaves (/api/api-keys), eliminar espacios de trabajo (DELETE /api/workspace), solicitar tokens de tiempo real (/api/realtime/token) ni gestionar notificaciones push (/api/push/subscribe,/api/push/unsubscribe). Estas operaciones requieren obligatoriamente sesión autenticada de Clerk.
💬 Identidad de WhatsApp (X-Wallavi-Identity)
El agente de WhatsApp de Wallavi llama a esta API sin navegador. En cada petición manda la cabecera X-Wallavi-Identity con un JWT firmado con el número que Meta verificó. Money Manager lo verifica, busca el vínculo del número (Ajustes → WhatsApp) y arma un contexto kind: "whatsapp" con permisos acotados.
X-Wallavi-Identity: <JWT>bashSin Bearer. No se mezcla con x-api-key ni con Authorization: si llegan juntos, la respuesta es 401 WHATSAPP_IDENTITY_INVALID.
El JWT: HS256, typ JWT, firmado con WALLAVI_CHANNEL_IDENTITY_SECRET (los bytes UTF-8 de la cadena hexadecimal de 64 caracteres). Claims obligatorios: iss = wallavi, aud = origen de Money Manager (por ejemplo https://money.depot.center), sub = wa:+<número> (^wa:\+[1-9][0-9]{7,14}$), agentId, threadId, jti (UUID v4 nuevo en cada petición), iat y exp = iat + 120. Se toleran 30 s de reloj: un iat más de 30 s en el futuro (o más de 150 s en el pasado) se rechaza con reason: "iat". Los claims desconocidos se ignoran. Cada jti sirve una sola vez.
El aud en producción: es el origen de NEXT_PUBLIC_APP_URL. Si en producción esa variable falta o está vacía, toda petición de WhatsApp responde 503 WHATSAPP_NOT_CONFIGURED; nunca se cae a localhost. Fuera de producción, sin la variable, el origen es http://localhost:3000. Fuera de producción (NODE_ENV !== "production"), verifyWallaviIdentity también acepta el origen de WALLAVI_IDENTITY_DEV_AUDIENCE si está configurada.
La huella de identidad (identityKeyHash, opcional): cuando alguien registra tu número en otro teléfono, WhatsApp cambia la huella del contacto y Wallavi la manda en este claim (^[A-Za-z0-9+/=_-]{1,128}$; si no cumple, 401 con reason: "claims"). Sin el claim no se revisa nada. Si el vínculo no tiene huella, se guarda la primera que llega. Si llega otra, el vínculo se pausa, queda en la bitácora (whatsapp_link, reason: "identity_changed", sin el número ni las huellas) y la respuesta es 401 WHATSAPP_LINK_SUSPENDED. Para reactivarlo, vuelve a vincular desde Ajustes → WhatsApp: el vínculo nuevo nace sin pausa y con la huella de ese momento.
Qué puede hacer: solo estas operaciones — getAgentContext, listTransactions, listWallets, listCategories, listReports, createTransactionByName, getSpendingSummary, undoLastTransaction, updateLastTransaction, listMyWorkspaces y setWhatsappWorkspace (las cinco últimas, en Por WhatsApp) —, y solo con los permisos que su rol le da en el espacio de trabajo activo del vínculo (transactions:read, transactions:write, wallets:read, categories:read, reports:read, agent:context). Cualquier otra ruta responde 403 FORBIDDEN. Límite: 30 peticiones por minuto por teléfono.
Vincular: POST /api/whatsapp/link (operationId: linkWhatsapp) con { "code": "ABCD-EF23" } convierte el código de Ajustes en un vínculo y responde { "linked": true, "workspaceName": "…" }. Es idempotente (el mismo código otra vez, desde el mismo número, responde alreadyLinked: true) y limita a 5 intentos por minuto. Vincular o desvincular desde Ajustes (/api/me/whatsapp) solo se puede con la sesión del dueño de la cuenta.
| Código | HTTP | Cuándo |
|---|---|---|
WHATSAPP_IDENTITY_INVALID | 401 | Firma, claims, expiración o jti repetido (details.reason: reused, expired, iat, signature, claims, lifetime, sub, jti, malformed, missing, mixed_credentials). |
WHATSAPP_NOT_LINKED | 401 | El número no está vinculado; el mensaje explica cómo hacerlo. |
WHATSAPP_LINK_SUSPENDED | 401 | El vínculo está pausado por seguridad (por ejemplo, cambió la huella de identidad). Se reactiva volviendo a vincular desde Ajustes → WhatsApp. |
WHATSAPP_NOT_CONFIGURED | 503 | El servidor no tiene WALLAVI_CHANNEL_IDENTITY_SECRET, o está en producción sin NEXT_PUBLIC_APP_URL. |
WHATSAPP_CODE_INVALID · _EXPIRED · _LOCKED | 400 | El código de linkWhatsapp no sirve. |
Las acciones de WhatsApp quedan en la bitácora con userAgent = whatsapp; agent=<agentId>; thread=<threadId>; nunca con el teléfono.
📊 Matriz de Scopes (Permisos)
Al crear tu clave de API, debes asociarle uno o más de los siguientes scopes. Si intentas realizar una petición a un recurso sin el scope adecuado, la API devolverá una respuesta HTTP 403 Forbidden.
| Scope | Operaciones Permitidas |
|---|---|
* | Control total. Otorga acceso a todos los scopes actuales y futuros. |
transactions:read | Listar y consultar movimientos financieros en carteras y categorías. |
transactions:write | Registrar, editar y borrar ingresos, gastos y transferencias. |
wallets:read | Consultar la lista de carteras y sus balances correspondientes. |
wallets:write | Crear nuevas carteras y modificar saldos iniciales de las mismas. |
categories:read | Ver el catálogo de categorías y sus presupuestos límite actuales. |
categories:write | Crear o actualizar presupuestos y categorías de gasto. |
budgets:read | Consultar presupuestos y gastos del período actual. |
budgets:write | Crear, modificar y eliminar presupuestos. |
goals:read | Consultar metas de ahorro activas y su porcentaje de progreso. |
goals:write | Crear metas y registrar abonos o retiros de capital en las mismas. |
recurrent:read | Listar y consultar suscripciones y transacciones recurrentes. |
recurrent:write | Crear, actualizar y eliminar suscripciones recurrentes. |
reports:read | Consultar reportes y analítica de ingresos, exportar PDF/CSV. |
profile:read | Consultar el perfil del usuario autenticado. |
profile:write | Actualizar el perfil del usuario autenticado. |
agent:context | Consultar contexto agregado del workspace para agentes de IA. |
debts:read | Ver la lista de deudas y las proyecciones del acelerador. |
debts:write | Registrar nuevas deudas, abonos u obligaciones amortizables. |
team:manage | Administrar miembros del equipo, bitácora de auditoría, roles y permisos de acceso. |
sharing:read | Ver accesos compartidos otorgados al usuario. |
sharing:manage | Crear, modificar y revocar accesos compartidos. |
groups:read | Ver grupos de usuarios en el espacio de trabajo. |
groups:manage | Crear, modificar y eliminar grupos de usuarios. |
comments:read | Ver comentarios en transacciones y registros. |
comments:write | Crear y responder comentarios en registros. |
tags:read | Listar y consultar etiquetas activas del workspace. |
tags:write | Crear, actualizar y eliminar etiquetas. |
invoices:read | Ver facturas emitidas, clientes y datos fiscales del emisor. |
invoices:write | Crear, timbrar, cancelar facturas y registrar cobros. |
customers:read | Ver clientes de facturación registrados. |
customers:write | Crear, modificar y eliminar clientes de facturación. |
webhooks:read | Listar suscripciones de webhooks salientes. |
webhooks:write | Crear, actualizar, probar y eliminar webhooks salientes. |
uploads:write | Subir y eliminar archivos, comprobantes y adjuntos. |
🚫 Manejo de Errores de Autenticación
Si una llamada no cumple con las condiciones de seguridad, la API responderá con alguno de los siguientes códigos HTTP:
HTTP 401 Unauthorized (Token Inválido)
Ocurre si la cabecera de autenticación hace falta, el token está mal escrito o ha sido revocado.
{
"error": {
"code": "UNAUTHORIZED",
"message": "Token de autenticación ausente o inválido.",
"requestId": "583a965a-f992-40a3-b52d-3bae520d2d96"
}
}jsonHTTP 403 Forbidden (Scope Insuficiente)
Ocurre si el token es válido, pero no tiene el scope requerido para la acción (ej. intentar registrar un gasto con una API Key que solo tiene transactions:read).
{
"error": {
"code": "FORBIDDEN",
"message": "La API Key provista no tiene permisos suficientes para este recurso. Se requiere el scope 'transactions:write'.",
"requestId": "583a965a-f992-40a3-b52d-3bae520d2d96"
}
}json