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

# Auditoría

> Quién hizo qué y cuándo en tu organización: qué se registra, qué guarda cada entrada, por qué no se puede alterar y cómo consultarla o exportarla.

La **bitácora de auditoría** es el registro de las acciones importantes de tu organización: quién timbró, canceló, descargó o modificó algo, desde dónde y a qué hora. Sirve para resolver dudas internas ("¿quién canceló esta factura?"), para responder a un auditor y para detectar usos que no esperabas.

## Quién la puede ver

* En la web: **Configuración → Auditoría**. Solo la ven los usuarios con rol **owner** o **admin**; un **member** no tiene acceso.
* Por API, SDK o CLI: con una sesión de owner o admin, o con una API key que tenga el scope `read:audit-logs`.

La bitácora es de **solo lectura**: no existe forma de crear, editar ni borrar entradas desde la aplicación.

## Qué se registra

Cada acción de esta lista deja exactamente una entrada, sin importar si se hizo desde la web, la API, el SDK, la CLI o un proceso automático.

| Categoría | Acción registrada | Código (`action`) |
| - | - | - |
| CFDI | Timbrado de un CFDI | `cfdi.stamped` |
| CFDI | Intento de timbrado rechazado por el PAC | `cfdi.stamp_failed` |
| CFDI | Descarga del XML o del PDF | `cfdi.xml_downloaded`, `cfdi.pdf_downloaded` |
| CFDI | Envío de un CFDI por correo | `cfdi.emailed` |
| Cancelación | Solicitud de cancelación (con motivo y folio de sustitución) | `cancellation.requested` |
| Cancelación | Respuesta del receptor o del SAT: aceptada, rechazada o en espera | `cancellation.accepted`, `cancellation.rejected`, `cancellation.pending` |
| Certificado (CSD) | Subir, reemplazar o eliminar el certificado de sello digital | `certificate.uploaded`, `certificate.rotated`, `certificate.deleted` |
| Clientes | Crear, actualizar o eliminar un cliente | `customer.created`, `customer.updated`, `customer.deleted` |
| Productos | Crear, actualizar o eliminar un producto, o importar un CSV de productos | `product.created`, `product.updated`, `product.deleted`, `product.imported` |
| Organización | Cambios en los datos generales, los datos fiscales o el logo y los colores | `organization.updated`, `organization.legal_data_updated`, `organization.branding_updated` |
| Organización | Cerrar, reabrir o eliminar la organización | `organization.closed`, `organization.reopened`, `organization.deleted` |
| Organización | Cambio de plan | `organization.plan_changed` |
| Miembros | Invitar, cancelar una invitación, aceptarla o rechazarla | `member.invited`, `member.invite_cancelled`, `member.joined`, `member.invite_declined` |
| Miembros | Cambiar el rol de un miembro o quitarlo | `member.role_changed`, `member.removed` |
| API keys | Crear, activar, desactivar o eliminar una llave | `api_key.created`, `api_key.activated`, `api_key.deactivated`, `api_key.deleted` |
| Webhooks | Crear, actualizar o eliminar un webhook | `webhook.created`, `webhook.updated`, `webhook.deleted` |
| Apps OAuth | Crear, actualizar o eliminar una app | `oauth_app.created`, `oauth_app.updated`, `oauth_app.deleted` |
| Exportaciones | Exportar el reporte de facturas (CSV, XML o PDF) o la propia bitácora | `report.exported`, `audit_log.exported` |

En la web y en el CSV verás estas acciones con texto claro ("Timbró CFDI", "Cambió el rol de un miembro"), no con el código. El código solo aparece en la API.

Algunas notas:

* Un CFDI timbrado genera **una sola** entrada `cfdi.stamped`, aunque haya reintentos o el timbrado se confirme después de forma automática.
* `cfdi.stamp_failed` solo se registra cuando la solicitud **llegó al PAC** y fue rechazada. Los rechazos previos (datos fiscales inválidos, límite del plan, organización cerrada) no dejan entrada.
* Los intentos que fallan en el resto de las acciones no se registran, porque no cambiaron nada.
* No se registran inicios de sesión ni cambios de contraseña.

## Qué guarda cada entrada

| Campo | Qué es |
| - | - |
| Fecha y hora | Cuándo ocurrió. En la web y el CSV se muestra en hora de México (`America/Mexico_City`); la API la entrega en UTC |
| Acción y resultado | Qué se hizo y si salió bien (`success`) o falló (`failure`) |
| Actor | Quién lo hizo: una persona, una API key o el sistema (por ejemplo el reconciliador de timbrados o Stripe). Se guarda su nombre o correo tal como era en ese momento, así que sigue siendo legible aunque después se elimine la persona o la llave |
| Recurso | Sobre qué: tipo y identificador (UUID fiscal del CFDI, RFC del cliente, etc.) |
| Canal | Desde dónde: web, API, SDK, CLI, MCP, proceso automático o Stripe |
| Ambiente | Producción o sandbox, cuando aplica |
| IP y navegador | La IP que vio la API y el `User-Agent`. En acciones hechas desde la web también se guarda la IP que reporta el navegador (`clientIp`), que es informativa y no está verificada |
| ID de la solicitud | El `X-Request-Id` de la request, para cruzarlo con el [request log](https://docs.timbrix.mx/debugging.md) |
| Campos cambiados | En las actualizaciones, los **nombres** de los campos que cambiaron. No se guardan los valores anteriores ni los nuevos |
| Detalles (`metadata`) | Datos del catálogo según la acción: serie y folio, RFC del receptor, total, motivo de cancelación, serial y vigencia del CSD, etc. |

La bitácora **nunca** guarda contraseñas del CSD, API keys, secretos de webhooks, tokens ni el contenido de los XML.

De la URL de un webhook solo se guarda el dominio y el primer tramo de la ruta, por ejemplo `https://hooks.slack.com/services/…`. Nunca el usuario, la contraseña, los parámetros (`?token=...`) ni el resto de la ruta, que es donde suelen ir las credenciales.

Si una entrada no se puede guardar en el momento (por ejemplo, por una falla breve de la base de datos), tu acción sigue adelante y la entrada se reintenta sola hasta guardarse, normalmente en uno o dos minutos. En ese caso `metadata.recordedLate.occurredAt` trae la hora en que ocurrió la acción, y la fecha de la entrada es la hora en que se guardó.

## Inmutabilidad

Las entradas no se pueden modificar ni borrar. La base de datos rechaza cualquier `UPDATE`, `DELETE` o `TRUNCATE` sobre la bitácora, incluso desde la propia aplicación, y los usuarios normales no pueden insertar entradas inventadas ni leer las de otra organización.

Eliminar una organización **nunca** borra su historial de auditoría: la bitácora no depende de la organización para conservarse.

## Integridad verificada

Además de bloquear los cambios, la bitácora deja **evidencia** si alguien los logra por un camino excepcional, como un acceso directo y privilegiado a la base de datos.

Funciona como una cadena: cada entrada se sella con una huella (hash SHA-256) que se calcula a partir de su propio contenido **y de la huella de la entrada anterior** de tu organización. Si alguien cambia, borra o mete una entrada en medio, todas las huellas posteriores dejan de coincidir.

Para comprobarlo, el panel de **Configuración → Auditoría** muestra el indicador **Integridad verificada**, que recorre la cadena completa. Si encuentra un problema, indica el número de la primera entrada afectada. También puedes hacerlo por API:

```bash theme={null}
curl "https://api.timbrix.mx/audit-logs/verify" -H "X-API-Key: sk_..."
```

```json theme={null}
{ "valid": true, "checkedEntries": 1280, "firstBrokenSeq": null }
```

Si `valid` es `false`, `firstBrokenSeq` es el número (`seq`) de la primera entrada alterada, borrada o insertada. Ver [Verify Audit Log Integrity](https://docs.timbrix.mx/api-reference/audit-logs/verify.md).

## Retención

Las entradas se conservan **5 años**.

## Exportar a CSV

Desde el panel con el botón **Exportar CSV**, o por API/SDK/CLI, con los mismos filtros que el listado. El archivo trae las fechas en hora de México y las acciones con su texto en español. Cada exportación se registra a su vez en la bitácora (`audit_log.exported`).

El límite es de **50,000 filas** por archivo. Si tu filtro devuelve más, la API responde `422` con el código `AUDIT_EXPORT_TOO_LARGE`; acota el rango de fechas y vuelve a intentar.

## Consultarla por API, SDK o CLI

Necesitas una API key con el scope `read:audit-logs` (ver [Create API Key](https://docs.timbrix.mx/api-reference/api-keys/create.md)). Con una API key, la organización se toma de la llave.

### API

```bash theme={null}
# Timbrados y cancelaciones de octubre de 2026
curl "https://api.timbrix.mx/audit-logs?action=cfdi.stamped,cancellation.requested&from=2026-10-01&to=2026-10-31" \
  -H "X-API-Key: sk_..."

# CSV
curl "https://api.timbrix.mx/audit-logs/export.csv?from=2026-10-01&to=2026-10-31" \
  -H "X-API-Key: sk_..." -o bitacora-octubre.csv
```

Una fecha sola (`YYYY-MM-DD`) se interpreta en hora de México: `from` empieza a las 00:00 y `to` incluye todo ese día.

### SDK

```typescript theme={null}
import { Timbrix } from "@timbrix/sdk"

const client = new Timbrix({ apiKey: "sk_..." })
const orgId = "550e8400-e29b-41d4-a716-446655440000"

const { data, nextCursor } = await client.auditLogs.list(orgId, {
  action: ["cfdi.stamped"],
  from: "2026-10-01",
  to: "2026-10-31",
})

const csv = await client.auditLogs.exportCsv(orgId, { from: "2026-10-01" })
const { valid, firstBrokenSeq } = await client.auditLogs.verify(orgId)
```

### CLI

```bash theme={null}
timbrix audit-logs list --org <org-id> --from 2026-10-01 --to 2026-10-31 --action cfdi.stamped
timbrix audit-logs export --org <org-id> --out bitacora.csv
```

Referencia completa: [List](https://docs.timbrix.mx/api-reference/audit-logs/list.md), [Get](https://docs.timbrix.mx/api-reference/audit-logs/get.md), [Export](https://docs.timbrix.mx/api-reference/audit-logs/export.md) y [Verify](https://docs.timbrix.mx/api-reference/audit-logs/verify.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.