---
title: "Generar o actualizar un Informe por CUIT"
method: POST
path: "/v1/reports"
tags: ["Reports"]
---

# Generar o actualizar un Informe por CUIT

`POST /v1/reports`

## Request

- Base URL: `https://api.almanac.ar`
- URL: `https://api.almanac.ar/v1/reports`
- Auth: HTTP bearer

Genera un informe nuevo, o lo actualiza si ya existe uno previo para este CUIT en la cuenta (descuento automático: 'actualizacion' cuesta 25% de 'nuevo'). SIEMPRE corre el Motor y SIEMPRE cobra (desde 2026-08-06 este endpoint ya NO cachea por tiempo) — traer un informe ya generado sin cobrar es GET /v1/reports/{id} (o el PDF), no este POST. Para reintentos seguros ante un timeout de RED (el servidor pudo haber terminado y cobrado aunque la respuesta no haya llegado), usá el header `Idempotency-Key`. Ver GET /v1/reports/quote para conocer el costo MÁXIMO antes de llamar a este endpoint.

## Headers

- `Idempotency-Key` string, uuid: UUID que identifica esta operación de forma única, opcional (mismo patrón que Stripe). Un POST repetido con la MISMA clave para el MISMO cuit devuelve la respuesta ORIGINAL (mismo informe, mismo tipo_accion, mismo costo_unidades) sin correr el Motor ni cobrar de nuevo — reemplaza a la caché de 24h que este endpoint tenía hasta 2026-08-06. Sin este header, cada POST SIEMPRE genera y cobra, incluso para el mismo CUIT consultado segundos antes. Retención: permanente (mientras exista la fila del ledger, que no se purga) — no expira a las 24h como en Stripe. Reusar la misma clave con un CUIT distinto devuelve 409 `idempotency_key_conflict`.

## Request body

- ReportsPostBody
  - `cuit` string, required: CUIT (11 dígitos) o DNI (7-8 dígitos, se resuelve a CUIL automáticamente).

## Response `200`

Informe generado (o cobrado y devuelto por replay de Idempotency-Key / carrera concurrente).

- ReportPostResponse
  - `cuit` string, required
  - `sections` object, required
    - `identidad` ReportSection: Sección normalizada del informe. Además de los campos listados, algunas secciones traen un bloque propio: 'crediticio' → `entidades[]`, 'comex' → `comex`, 'riesgoFiscal' → `riesgoFiscal`, 'marcas' → `marcas[]`, 'concursos' → `concursos[]`. Ver NormalizedSection en lib/informes/types.ts (repo) para el detalle completo de cada bloque.
      - `title` string, required
      - `fields` ReportSectionField[], required
        - `label` string, required
        - `value` string, nullable, required
        - `fuente_dataset_id` string, required
        - `snapshot_date` string, required
      - `source` string, required
      - `snapshot_date` string, required
      - `status` 'ok' | 'parcial' | 'no_disponible', required
      - `error_reason` string
    - `crediticio` ReportSection: Sección normalizada del informe. Además de los campos listados, algunas secciones traen un bloque propio: 'crediticio' → `entidades[]`, 'comex' → `comex`, 'riesgoFiscal' → `riesgoFiscal`, 'marcas' → `marcas[]`, 'concursos' → `concursos[]`. Ver NormalizedSection en lib/informes/types.ts (repo) para el detalle completo de cada bloque.
      - `title` string, required
      - `fields` ReportSectionField[], required
        - `label` string, required
        - `value` string, nullable, required
        - `fuente_dataset_id` string, required
        - `snapshot_date` string, required
      - `source` string, required
      - `snapshot_date` string, required
      - `status` 'ok' | 'parcial' | 'no_disponible', required
      - `error_reason` string
    - `cheques` ReportSection: Sección normalizada del informe. Además de los campos listados, algunas secciones traen un bloque propio: 'crediticio' → `entidades[]`, 'comex' → `comex`, 'riesgoFiscal' → `riesgoFiscal`, 'marcas' → `marcas[]`, 'concursos' → `concursos[]`. Ver NormalizedSection en lib/informes/types.ts (repo) para el detalle completo de cada bloque.
      - `title` string, required
      - `fields` ReportSectionField[], required
        - `label` string, required
        - `value` string, nullable, required
        - `fuente_dataset_id` string, required
        - `snapshot_date` string, required
      - `source` string, required
      - `snapshot_date` string, required
      - `status` 'ok' | 'parcial' | 'no_disponible', required
      - `error_reason` string
    - `screening` ReportSection: Sección normalizada del informe. Además de los campos listados, algunas secciones traen un bloque propio: 'crediticio' → `entidades[]`, 'comex' → `comex`, 'riesgoFiscal' → `riesgoFiscal`, 'marcas' → `marcas[]`, 'concursos' → `concursos[]`. Ver NormalizedSection en lib/informes/types.ts (repo) para el detalle completo de cada bloque.
      - `title` string, required
      - `fields` ReportSectionField[], required
        - `label` string, required
        - `value` string, nullable, required
        - `fuente_dataset_id` string, required
        - `snapshot_date` string, required
      - `source` string, required
      - `snapshot_date` string, required
      - `status` 'ok' | 'parcial' | 'no_disponible', required
      - `error_reason` string
    - `comex` ReportSection: Sección normalizada del informe. Además de los campos listados, algunas secciones traen un bloque propio: 'crediticio' → `entidades[]`, 'comex' → `comex`, 'riesgoFiscal' → `riesgoFiscal`, 'marcas' → `marcas[]`, 'concursos' → `concursos[]`. Ver NormalizedSection en lib/informes/types.ts (repo) para el detalle completo de cada bloque.
      - `title` string, required
      - `fields` ReportSectionField[], required
        - `label` string, required
        - `value` string, nullable, required
        - `fuente_dataset_id` string, required
        - `snapshot_date` string, required
      - `source` string, required
      - `snapshot_date` string, required
      - `status` 'ok' | 'parcial' | 'no_disponible', required
      - `error_reason` string
    - `riesgoFiscal` ReportSection: Sección normalizada del informe. Además de los campos listados, algunas secciones traen un bloque propio: 'crediticio' → `entidades[]`, 'comex' → `comex`, 'riesgoFiscal' → `riesgoFiscal`, 'marcas' → `marcas[]`, 'concursos' → `concursos[]`. Ver NormalizedSection en lib/informes/types.ts (repo) para el detalle completo de cada bloque.
      - `title` string, required
      - `fields` ReportSectionField[], required
        - `label` string, required
        - `value` string, nullable, required
        - `fuente_dataset_id` string, required
        - `snapshot_date` string, required
      - `source` string, required
      - `snapshot_date` string, required
      - `status` 'ok' | 'parcial' | 'no_disponible', required
      - `error_reason` string
    - `marcas` ReportSection: Sección normalizada del informe. Además de los campos listados, algunas secciones traen un bloque propio: 'crediticio' → `entidades[]`, 'comex' → `comex`, 'riesgoFiscal' → `riesgoFiscal`, 'marcas' → `marcas[]`, 'concursos' → `concursos[]`. Ver NormalizedSection en lib/informes/types.ts (repo) para el detalle completo de cada bloque.
      - `title` string, required
      - `fields` ReportSectionField[], required
        - `label` string, required
        - `value` string, nullable, required
        - `fuente_dataset_id` string, required
        - `snapshot_date` string, required
      - `source` string, required
      - `snapshot_date` string, required
      - `status` 'ok' | 'parcial' | 'no_disponible', required
      - `error_reason` string
    - `concursos` ReportSection: Sección normalizada del informe. Además de los campos listados, algunas secciones traen un bloque propio: 'crediticio' → `entidades[]`, 'comex' → `comex`, 'riesgoFiscal' → `riesgoFiscal`, 'marcas' → `marcas[]`, 'concursos' → `concursos[]`. Ver NormalizedSection en lib/informes/types.ts (repo) para el detalle completo de cada bloque.
      - `title` string, required
      - `fields` ReportSectionField[], required
        - `label` string, required
        - `value` string, nullable, required
        - `fuente_dataset_id` string, required
        - `snapshot_date` string, required
      - `source` string, required
      - `snapshot_date` string, required
      - `status` 'ok' | 'parcial' | 'no_disponible', required
      - `error_reason` string
  - `status` 'ok' | 'parcial' | 'no_resuelto', required: 'ok': todas las secciones resolvieron con dato real. 'parcial': al menos una sección tiene dato real, pero no todas. 'no_resuelto': ninguna fuente entregó nada — no se cobra.
  - `generated_at` string, required
  - `informe_id` string, nullable, required
  - `cache_hit` boolean: true si esta respuesta REUTILIZA un informe ya persistido y cobrado, sin correr el Motor ni cobrar de nuevo — dos casos: (a) replay de la MISMA Idempotency-Key (ver el header en POST /v1/reports), o (b) esta request perdió una carrera de generación CONCURRENTE contra otra para el mismo CUIT+cuenta y recibió el resultado de la ganadora. Desde 2026-08-06 este endpoint YA NO cachea por tiempo: sin Idempotency-Key, un POST repetido para el mismo CUIT SIEMPRE corre el Motor y SIEMPRE cobra, aunque el último informe tenga segundos de antigüedad.
  - `tipo_accion` 'nuevo' | 'actualizacion' | 'null', nullable: Qué acción representa la consulta, en lenguaje de cliente — nunca 'créditos'. 'nuevo': primer informe de este CUIT para la cuenta (200 unidades). 'actualizacion': ya existía un informe previo (50 unidades) — se cobra siempre, cambie o no cambie el contenido respecto del informe anterior.
  - `costo_unidades` integer

## Other responses

- `400`: cuit_requerido | cuit_invalido | body_invalido | idempotency_key_invalido — body ausente/no-JSON, CUIT/CUIL con dígito verificador incorrecto, o el header Idempotency-Key no es un UUID.
- `401`: Sin sesión ni API key.
- `402`: Saldo insuficiente (sólo con el modelo de saldo habilitado).
- `403`: Cuenta suspendida, origen no confiable (CSRF, sólo sesión), o canal API no habilitado en el plan.
- `409`: generacion_en_curso (deduplicación de generaciones concurrentes para el mismo CUIT+cuenta, mig 0661 — NO_APLICADA todavía, sin efecto en prod hasta que se aplique) | idempotency_key_conflict (la misma Idempotency-Key ya se usó con un CUIT distinto en esta cuenta — mig 0664).
- `429`: rate_limited (usuario o IP). El tope diario de producto se eliminó (migración 0663, 2026-08-06).
- `500`: Error inesperado, o el informe se generó pero no se pudo persistir (informe_no_persistido — no se cobró nada).

---

[API](https://skmtc.dev/almanac/apis/almanac-api.md) · [All operations](https://skmtc.dev/almanac/apis/almanac-api/llms.txt) · [OpenAPI document](https://skmtc.dev/almanac/apis/almanac-api/revisions/f1b8ffd54263?raw)
