La bitácora
Cada llamada deja exactamente una fila inmutable: auditoría, correlación con soporte y fuente de verdad de la facturación.
Toda ejecución de una tool, entre por REST, por MCP, desde el dashboard o disparada por el scheduler, escribe exactamente una fila en la bitácora. La tabla es append-only por doble candado (ningún rol de aplicación tiene UPDATE ni DELETE, y no existe política que los permita), así que una fila escrita no se edita nunca. Sobre ese registro se apoyan tres cosas a la vez: la auditoría, el soporte y la facturación. No hay un contador de cobro separado que pueda divergir de lo que de verdad pasó.
La anatomía de una fila
Las columnas que vas a usar, de la tabla real bitacora_execution:
| Columna | Qué guarda | Por qué importa |
|---|---|---|
request_id | El req_… de esta llamada, generado por el servidor | La llave de correlación: viaja en el meta de cada respuesta y dentro de cada error |
tool_id / connector_code | Qué se ejecutó (sii.rcv.consultar) y de qué sistema | El grano de todo análisis de uso |
connection_id | La conexión (conn_…); null en conectores sin conexión | Atribuye la llamada a una empresa concreta |
plane | action o read | Distingue una consulta barata de una sincronización real (Los dos planos) |
surface | rest, mcp_meta, mcp_native, dashboard o hosted | Por dónde entró la llamada |
actor_id / actor_type | Quién actuó: user, agent, system o connect_session | La atribución (abajo) |
credential_id | La credencial que autenticó (el id de la API key) | Separada del actor a propósito |
input_digest | sha256 del input canonicalizado y redactado | Compara inputs sin poder reconstruirlos |
result_status / error_code | ok o error, y con qué código | Las fallas también dejan fila |
latency_ms | Duración de la ejecución | El mismo valor que viaja en meta.latency_ms |
parent_request_id | En MCP, la fila del delegado apunta a la del execute que lo invocó | Reconstruye la cadena meta-tool → tool del catálogo |
meter_category / billable_units / billable | La clasificación de cobro | La facturación (abajo) |
created_at | Cuándo | Junto a un id monotónico para paginar por cursor |
Atribución: humano o agente, nunca confundidos
Una API key autentica como agente: actor_type: "agent", con el id de la clave como actor_id. Un token OAuth o una sesión del dashboard autentican como usuario. En ningún caso la acción de un agente se atribuye al humano dueño de la credencial, porque la fila diría una mentira y la bitácora existe para lo contrario. Por eso credential_id es una columna aparte: revocar una clave no reescribe la autoría de nada.
El input no se guarda: se guarda su huella
input_digest es sha256(canonicalize(redact(input))). Antes de calcular el hash, todo campo con forma de secreto (token, password, credential, api key) se reemplaza por un marcador; después, el objeto se serializa con las llaves ordenadas, para que el mismo input produzca siempre el mismo digest. El resultado permite responder «¿estas dos llamadas llevaron el mismo input?» sin poder reconstruir el input. La credencial de una conexión ni siquiera llega aquí: se resuelve server-side y jamás aparece en un resultado, en un log ni en la bitácora.
De un request_id a su fila
Toda respuesta lleva meta.request_id, y todo error lo repite dentro del envelope junto al suggested_fix. Con ese req_… encuentras la fila en el dashboard, y es el dato que soporte te va a pedir. El meta.audit_status de la respuesta cierra el círculo: recorded significa que la fila quedó escrita en línea; degraded, que el registro cayó a un respaldo durable. Una acción que ya se ejecutó con éxito nunca se convierte en un 5xx porque falló su auditoría; ese 5xx invitaría a reintentar una acción regulada ya hecha.
Qué se factura
La bitácora es la fuente de verdad de la facturación, y la columna billable la calcula la base de datos, no el código de aplicación: exige result_status = 'ok', una categoría facturable y billable_units > 0. Las consecuencias prácticas:
- Un error nunca factura.
billable_unitsqueda en 0 en toda fila fallida. meter_categoryclasifica cada llamada.action_call,read_syncyread_querycuentan contra el plan;meta(las meta-tools de MCP),internal(conectores abiertos comocoreeindicadores) yunclassifiedson overhead y no cuentan.- Los conectores abiertos dejan fila igual, con
billable_units: 0: auditar y cobrar son ejes distintos. - Lo que haces en tu propio dashboard no gasta tu cuota. Una llamada con
surface: "dashboard"o"hosted"se audita idéntica a cualquier otra y factura 0: guardar tu credencial o paginar tus propios datos no puede consumir la cuota de tu integración.
Lo que no está en la bitácora
Dos registros vecinos completan el cuadro. Las fallas de autenticación no tienen organización que las reciba (el token no resolvió a ningún tenant), así que van a security_events, que guarda el prefijo de la credencial y nunca el token completo. Y los cambios de configuración (crear una clave, deshabilitar una conexión, rotar una credencial) van a audit_control, el registro del plano de control, con su before y su after.
Dónde verla
En connect.emisso.ai/bitacora: las columnas Actor, Herramienta, Scope, Plano, Resultado, Latencia, request_id y Fecha, con filtro por API key. Cada conexión tiene además su propia pestaña de bitácora, con las ejecuciones y los cambios de configuración que la tocaron.
Próximos pasos
- Autenticación: quién puede escribir estas filas y cómo.
- Conexiones: la unidad a la que se atribuye cada llamada.
- Errores: el catálogo completo, con
suggested_fixpor código.