{"openapi":"3.0.0","info":{"title":"Almanac API","version":"1.0.0","description":"API comercial de Almanac — Informe por CUIT (Reports/Account) + Datasets (catálogo público y descarga de snapshots). Autenticación por API key (`Authorization: Bearer alm_<key>`, generada en https://almanac.ar/account) salvo donde se indica 'Público, sin auth'. La API le habla al cliente de INFORMES y ACTUALIZACIONES, nunca de 'créditos': las unidades son contabilidad interna. Este documento no cubre necesariamente TODA la superficie de /v1 — ver https://almanac.ar/developers para lo que exista sin contrato propio acá todavía.","contact":{"name":"Almanac","url":"https://almanac.ar/developers"}},"servers":[{"url":"https://api.almanac.ar","description":"Producción"}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"API key de Almanac (`alm_...`), generada en /account. Se envía como `Authorization: Bearer alm_<key>`."}},"schemas":{"ReportSectionField":{"type":"object","properties":{"label":{"type":"string","example":"Denominación"},"value":{"type":"string","nullable":true,"example":"ACME S.A."},"fuente_dataset_id":{"type":"string","example":"arca.padron.contribuyentes"},"snapshot_date":{"type":"string","example":"2026-08-01"}},"required":["label","value","fuente_dataset_id","snapshot_date"],"additionalProperties":false},"ReportSection":{"type":"object","properties":{"title":{"type":"string","example":"Identidad y situación fiscal"},"fields":{"type":"array","items":{"$ref":"#/components/schemas/ReportSectionField"}},"source":{"type":"string","example":"arca.padron.contribuyentes"},"snapshot_date":{"type":"string","example":"2026-08-01"},"status":{"type":"string","enum":["ok","parcial","no_disponible"]},"error_reason":{"type":"string"}},"required":["title","fields","source","snapshot_date","status"],"additionalProperties":{"nullable":true},"description":"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."},"ReportStatus":{"type":"string","enum":["ok","parcial","no_resuelto"],"description":"'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."},"TipoAccion":{"type":"string","nullable":true,"enum":["nuevo","actualizacion"],"description":"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."},"ReportResult":{"type":"object","properties":{"cuit":{"type":"string","example":"30000000007"},"sections":{"type":"object","properties":{"identidad":{"$ref":"#/components/schemas/ReportSection"},"crediticio":{"$ref":"#/components/schemas/ReportSection"},"cheques":{"$ref":"#/components/schemas/ReportSection"},"screening":{"$ref":"#/components/schemas/ReportSection"},"comex":{"$ref":"#/components/schemas/ReportSection"},"riesgoFiscal":{"$ref":"#/components/schemas/ReportSection"},"marcas":{"$ref":"#/components/schemas/ReportSection"},"concursos":{"$ref":"#/components/schemas/ReportSection"}}},"status":{"$ref":"#/components/schemas/ReportStatus"},"generated_at":{"type":"string","example":"2026-08-05T14:32:00.000Z"}},"required":["cuit","sections","status","generated_at"],"additionalProperties":false},"ReportPostResponse":{"allOf":[{"$ref":"#/components/schemas/ReportResult"},{"type":"object","properties":{"informe_id":{"type":"string","nullable":true,"example":"6e1b9e0a-8f3b-4e9a-9d1e-2b1a5b7d9c10"},"cache_hit":{"type":"boolean","description":"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":{"$ref":"#/components/schemas/TipoAccion"},"costo_unidades":{"type":"integer","minimum":0}},"required":["informe_id"],"additionalProperties":false}]},"CuitRequeridoError":{"type":"object","properties":{"error":{"type":"string","enum":["cuit_requerido"]}},"required":["error"],"additionalProperties":false},"CuitInvalidoError":{"type":"object","properties":{"error":{"type":"string","enum":["cuit_invalido"]},"message":{"type":"string"},"reason":{"type":"string","enum":["formato","tipo","digito_verificador"]}},"required":["error","reason"],"additionalProperties":false},"BodyInvalidoError":{"type":"object","properties":{"error":{"type":"string","enum":["body_invalido"]}},"required":["error"],"additionalProperties":false,"description":"400 — el body de POST /v1/reports no es JSON válido."},"IdempotencyKeyInvalidoError":{"type":"object","properties":{"error":{"type":"string","enum":["idempotency_key_invalido"]},"message":{"type":"string"}},"required":["error","message"],"additionalProperties":false,"description":"400 — el header Idempotency-Key vino, pero no es un UUID válido."},"UnauthenticatedError":{"type":"object","properties":{"error":{"type":"string","enum":["unauthenticated"]},"message":{"type":"string"}},"required":["error","message"],"additionalProperties":false},"InformeCuitPack":{"type":"object","properties":{"packSize":{"type":"integer","minimum":0,"exclusiveMinimum":true},"unidades":{"type":"integer","minimum":0,"exclusiveMinimum":true},"priceArs":{"type":"number","minimum":0},"displayLabel":{"type":"string","example":"10 informes"}},"required":["packSize","unidades","priceArs","displayLabel"],"additionalProperties":false},"SaldoInsuficienteError":{"type":"object","properties":{"error":{"type":"string","enum":["saldo_insuficiente"]},"tipo_accion":{"$ref":"#/components/schemas/TipoAccion"},"costo_unidades":{"type":"integer","minimum":0},"saldo":{"type":"object","properties":{"cupo_disponible_unidades":{"type":"integer","minimum":0},"saldo_comprado_unidades":{"type":"integer","minimum":0}},"required":["cupo_disponible_unidades","saldo_comprado_unidades"],"additionalProperties":false},"mensaje":{"type":"string"},"packs":{"type":"array","items":{"$ref":"#/components/schemas/InformeCuitPack"}}},"required":["error","tipo_accion","costo_unidades","saldo","mensaje","packs"],"additionalProperties":false,"description":"402 — sólo en el camino con saldo habilitado (INFORME_CUIT_SALDO_CONSUMO_ENABLED)."},"AccountSuspendedError":{"type":"object","properties":{"error":{"type":"string","enum":["account_suspended"]},"message":{"type":"string"}},"required":["error","message"],"additionalProperties":false},"ForbiddenCsrfError":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"]},"message":{"type":"string"}},"required":["error","message"],"additionalProperties":false},"ChannelDisabledError":{"type":"object","properties":{"error":{"type":"string","enum":["channel_disabled","internal"]},"message":{"type":"string"},"upgrade_url":{"type":"string"}},"required":["error","message","upgrade_url"],"additionalProperties":false,"description":"403 — el plan actual no tiene habilitado el canal API REST (plan_prices.api_rest_enabled, `error: 'channel_disabled'`), o no se pudo verificar el entitlement del plan (`error: 'internal'`, ver assertApiRestAccess)."},"GeneracionEnCursoError":{"type":"object","properties":{"error":{"type":"string","enum":["generacion_en_curso"]},"mensaje":{"type":"string"}},"required":["error","mensaje"],"additionalProperties":false,"description":"409 — ya hay una generación en curso para este CUIT + esta cuenta (de #1624, deduplicación de requests concurrentes). Acompañado del header `Retry-After` (segundos) — reintentar entonces. Usa `mensaje` (no `message`), igual que `informe_no_persistido` — verificado contra el body real de #1624 (dos respuestas 409, ambas con `mensaje` siempre presente)."},"IdempotencyKeyConflictError":{"type":"object","properties":{"error":{"type":"string","enum":["idempotency_key_conflict"]},"mensaje":{"type":"string"}},"required":["error","mensaje"],"additionalProperties":false,"description":"409 — la misma Idempotency-Key ya se usó antes con un CUIT DISTINTO para esta cuenta (mismo criterio que Stripe: una clave identifica UNA operación lógica). Generá una clave nueva por cada CUIT/consulta distinta. Usa `mensaje` (no `message`), mismo criterio que GeneracionEnCursoError/InformeNoPersistidoError."},"RateLimitedError":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited"]},"message":{"type":"string"}},"required":["error"],"additionalProperties":false,"description":"429 — acompañado siempre del header `Retry-After` (segundos)."},"InternalError":{"type":"object","properties":{"error":{"type":"string","enum":["internal"]},"message":{"type":"string"}},"required":["error","message"],"additionalProperties":false,"description":"500 — mensaje genérico siempre; nunca se propaga el detalle de la excepción (evita filtrar nombres de columna/tabla)."},"InformeNoPersistidoError":{"type":"object","properties":{"error":{"type":"string","enum":["informe_no_persistido"]},"mensaje":{"type":"string"}},"required":["error","mensaje"],"additionalProperties":false,"description":"500 — el Motor corrió pero el informe no se pudo persistir; no se cobró nada. Usa `mensaje` (no `message`, a diferencia del resto de los errores de este contrato) — inconsistencia real y preexistente del handler compartido (app/api/herramientas/informe-cuit/route.ts), documentada tal cual es. Renombrar el campo es un cambio de contrato aparte, fuera de esta fase."},"ReportsPostBody":{"type":"object","properties":{"cuit":{"type":"string","description":"CUIT (11 dígitos) o DNI (7-8 dígitos, se resuelve a CUIL automáticamente).","example":"30000000007"}},"required":["cuit"],"additionalProperties":false},"ReportListItem":{"type":"object","properties":{"id":{"type":"string"},"cuit":{"type":"string"},"cuit_formateado":{"type":"string","example":"30-00000000-7"},"denominacion":{"type":"string","nullable":true},"denominacion_origen":{"type":"string","nullable":true,"enum":["padron","concursos","marcas","cendeu"],"description":"De dónde se resolvió el nombre: 'padron' (ARCA), 'concursos'/'marcas' (fallback dentro del propio informe), o 'cendeu' (BCRA, último fallback, batch)."},"status":{"$ref":"#/components/schemas/ReportStatus"},"generated_at":{"type":"string"},"created_at":{"type":"string"}},"required":["id","cuit","cuit_formateado","denominacion","denominacion_origen","status","generated_at","created_at"],"additionalProperties":false},"ReportsListResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ReportListItem"},"maxItems":50},"has_more":{"type":"boolean"}},"required":["items","has_more"],"additionalProperties":false},"ErrorEnvelope":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error","message"],"additionalProperties":false},"NotFoundError":{"type":"object","properties":{"error":{"type":"string","enum":["not_found"]},"message":{"type":"string"}},"required":["error","message"],"additionalProperties":false},"TipoAccionEstimado":{"type":"string","enum":["nuevo","actualizacion"],"description":"Qué acción representa la consulta, en lenguaje de cliente — nunca 'créditos'. 'nuevo': primer informe de este CUIT para la cuenta (cuesta 200 unidades = costo_maximo_unidades). 'actualizacion': ya existía un informe previo (cuesta 50 unidades = costo_maximo_unidades, siempre — cambie o no cambie el contenido respecto del informe anterior)."},"ReportQuoteResponse":{"type":"object","properties":{"cuit":{"type":"string","example":"30000000007"},"tipo_accion_estimado":{"$ref":"#/components/schemas/TipoAccionEstimado"},"costo_maximo_unidades":{"type":"integer","minimum":0,"description":"TECHO del costo real de un POST /v1/reports subsiguiente para este CUIT, en la misma unidad que `tipo_accion_estimado` ya nombra (1 'nuevo' = 200, 1 'actualizacion' = 50). El costo real nunca puede ser MAYOR a este número, y nunca baja por contenido idéntico al último informe (pedir una actualización siempre cuesta la actualización). Puede bajar en un caso borde de concurrencia — ver comentario de cabecera de este endpoint en el repo."},"saldo":{"type":"object","properties":{"cupo_disponible_unidades":{"type":"integer","minimum":0},"saldo_comprado_unidades":{"type":"integer","minimum":0},"disponible_informes_nuevos":{"type":"integer","minimum":0,"description":"Cuántos informes NUEVOS alcanza cupo_disponible_unidades + saldo_comprado_unidades juntos (floor)."},"disponible_actualizaciones":{"type":"integer","minimum":0,"description":"Cuántas actualizaciones alcanza cupo_disponible_unidades + saldo_comprado_unidades juntos (floor)."}},"required":["cupo_disponible_unidades","saldo_comprado_unidades","disponible_informes_nuevos","disponible_actualizaciones"],"additionalProperties":false},"alcanza":{"type":"boolean","description":"true si cupo_disponible + saldo_comprado ya cubre costo_maximo_unidades."},"mensaje":{"type":"string","nullable":true}},"required":["cuit","tipo_accion_estimado","costo_maximo_unidades","saldo","alcanza","mensaje"],"additionalProperties":false},"BalanceResponse":{"type":"object","properties":{"cupo":{"type":"object","properties":{"unidades_disponibles":{"type":"integer","minimum":0},"informes_nuevos":{"type":"integer","minimum":0,"description":"Cuántos informes NUEVOS alcanza este bolsillo (floor)."},"actualizaciones":{"type":"integer","minimum":0,"description":"Cuántas actualizaciones alcanza este bolsillo (floor)."},"unidades_mensuales":{"type":"integer","nullable":true,"description":"null = sin cupo automático definido (hoy team/enterprise, 'a convenir')."},"unidades_usadas":{"type":"integer","minimum":0}},"required":["unidades_disponibles","informes_nuevos","actualizaciones","unidades_mensuales","unidades_usadas"],"additionalProperties":false},"comprado":{"type":"object","properties":{"unidades_disponibles":{"type":"integer","minimum":0},"informes_nuevos":{"type":"integer","minimum":0,"description":"Cuántos informes NUEVOS alcanza este bolsillo (floor)."},"actualizaciones":{"type":"integer","minimum":0,"description":"Cuántas actualizaciones alcanza este bolsillo (floor)."}},"required":["unidades_disponibles","informes_nuevos","actualizaciones"],"additionalProperties":false}},"required":["cupo","comprado"],"additionalProperties":false},"PlanPrice":{"type":"object","properties":{"plan_tier":{"type":"string","enum":["free","starter","pro","ultimate","team","enterprise"]},"price_ars_monthly":{"type":"number","nullable":true,"description":"ARS/mes. 0 = gratis. null = a convenir (team/enterprise)."},"display_label":{"type":"string"},"mcp_calls_monthly":{"type":"integer","nullable":true,"description":"null = ilimitado, 0 = sin acceso, N = cuota mensual."},"csv_downloads_monthly":{"type":"integer","nullable":true},"parquet_enabled":{"type":"boolean"},"api_rest_enabled":{"type":"boolean"},"informe_cuit_cupo_mensual_unidades":{"type":"integer","nullable":true}},"required":["plan_tier","price_ars_monthly","display_label","mcp_calls_monthly","csv_downloads_monthly","parquet_enabled","api_rest_enabled","informe_cuit_cupo_mensual_unidades"],"additionalProperties":false},"PricesResponse":{"type":"object","properties":{"plans":{"type":"array","items":{"$ref":"#/components/schemas/PlanPrice"}},"informe_cuit_packs":{"type":"array","items":{"$ref":"#/components/schemas/InformeCuitPack"}}},"required":["plans","informe_cuit_packs"],"additionalProperties":false},"DatasetSummary":{"type":"object","properties":{"dataset_id":{"type":"string","example":"bcra.monetarias.indicadores"},"name":{"type":"string","example":"Indicadores monetarios diarios"},"description":{"type":"string","nullable":true},"source":{"type":"object","properties":{"id":{"type":"string","example":"bcra"},"name":{"type":"string","example":"BCRA"}},"required":["id","name"],"additionalProperties":false},"frequency":{"type":"string","nullable":true,"example":"diaria"},"tags":{"type":"array","nullable":true,"items":{"type":"string"}},"country":{"type":"string","nullable":true,"example":"AR"},"detail_url":{"type":"string","description":"URL absoluta a GET /v1/datasets/{id} — la ficha completa de este dataset.","example":"https://api.almanac.ar/v1/datasets/bcra.monetarias.indicadores"}},"required":["dataset_id","name","description","source","frequency","tags","country","detail_url"],"additionalProperties":false},"DatasetsListResponse":{"type":"object","properties":{"count":{"type":"integer","minimum":0},"datasets":{"type":"array","items":{"$ref":"#/components/schemas/DatasetSummary"}}},"required":["count","datasets"],"additionalProperties":false},"DatasetFreshnessSla":{"type":"object","nullable":true,"properties":{"declared_frequency":{"type":"string","enum":["daily","weekly","monthly","quarterly","annual","irregular","intraday"]},"max_acceptable_lag_hours":{"type":"number"}},"required":["declared_frequency","max_acceptable_lag_hours"],"additionalProperties":false},"DatasetComplianceNotes":{"type":"object","nullable":true,"properties":{"license":{"type":"string"},"attribution_required":{"type":"string","nullable":true},"commercial_use":{"type":"string","enum":["ok","restricted","prohibited"]},"notes":{"type":"string","nullable":true}},"required":["license","commercial_use"],"additionalProperties":false},"DatasetExampleQuery":{"type":"object","properties":{"question":{"type":"string"},"approach":{"type":"string"},"polars":{"type":"string","nullable":true},"sql":{"type":"string","nullable":true}},"required":["question","approach"],"additionalProperties":false},"DatasetGotcha":{"type":"object","properties":{"title":{"type":"string"},"detail":{"type":"string"}},"required":["title","detail"],"additionalProperties":false},"DatasetRelated":{"type":"object","properties":{"id":{"type":"string"},"relation":{"type":"string"},"derived":{"type":"boolean","description":"true si ESTE dataset es una VIEW derivada del relacionado (hereda su snapshot)."}},"required":["id","relation"],"additionalProperties":false},"DatasetColumn":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"},"description":{"type":"string"},"unit":{"type":"string","nullable":true},"sample_value":{"nullable":true},"nullable":{"type":"boolean"}},"required":["name","type","description"],"additionalProperties":false},"DatasetAiMetadata":{"type":"object","properties":{"llm_intro":{"type":"string","nullable":true},"business_questions":{"type":"array","nullable":true,"items":{"type":"string"}},"example_queries":{"type":"array","nullable":true,"items":{"$ref":"#/components/schemas/DatasetExampleQuery"}},"methodology_notes":{"type":"string","nullable":true},"gotchas":{"type":"array","nullable":true,"items":{"$ref":"#/components/schemas/DatasetGotcha"}},"related_datasets":{"type":"array","nullable":true,"items":{"$ref":"#/components/schemas/DatasetRelated"}},"columns":{"type":"array","nullable":true,"items":{"$ref":"#/components/schemas/DatasetColumn"}},"summary_columns":{"type":"array","nullable":true,"items":{"type":"string"}},"explorable_columns":{"type":"array","nullable":true,"items":{"type":"string"}},"last_updated":{"type":"string","nullable":true}},"required":["llm_intro","business_questions","example_queries","methodology_notes","gotchas","related_datasets","columns","summary_columns","explorable_columns","last_updated"],"additionalProperties":false},"DatasetDetailResponse":{"type":"object","properties":{"dataset_id":{"type":"string","example":"bcra.monetarias.indicadores"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"source":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},"frequency":{"type":"string","nullable":true},"granularity":{"type":"string","nullable":true},"historical_depth":{"type":"string","nullable":true},"tags":{"type":"array","nullable":true,"items":{"type":"string"}},"access":{"type":"string","enum":["included_in_pro"]},"country":{"type":"string","nullable":true},"source_native_language":{"type":"string","nullable":true},"update_pattern":{"type":"string","nullable":true,"enum":["incremental_append","full_refresh","scd2_snapshots"]},"freshness_sla":{"$ref":"#/components/schemas/DatasetFreshnessSla"},"content_advisory":{"type":"string","nullable":true},"compliance_notes":{"$ref":"#/components/schemas/DatasetComplianceNotes"},"snapshot_date":{"type":"string","nullable":true,"description":"Fecha (YYYY-MM-DD) del snapshot vigente (`is_latest=true`), o null si el dataset todavía no tiene snapshot publicado. Si es una VIEW derivada, hereda la fecha del dataset padre.","example":"2026-08-05"},"row_count":{"type":"integer","nullable":true,"minimum":0,"description":"Cantidad de filas del snapshot vigente, o null si no hay snapshot todavía.","example":1347124},"ai_metadata":{"$ref":"#/components/schemas/DatasetAiMetadata"},"updated_at":{"type":"string"}},"required":["dataset_id","name","description","source","frequency","granularity","historical_depth","tags","access","country","source_native_language","update_pattern","freshness_sla","content_advisory","compliance_notes","snapshot_date","row_count","ai_metadata","updated_at"],"additionalProperties":false},"DatasetNotFoundError":{"type":"object","properties":{"error":{"type":"string","enum":["dataset_not_found"]},"dataset_id":{"type":"string"}},"required":["error","dataset_id"],"additionalProperties":false,"description":"404 — el dataset no existe, no está publicado, no alcanza el plan del caller, o es admin-only. Mismo status/shape en los cuatro casos a propósito: no revela cuál aplica (no filtra existencia)."},"SnapshotResponse":{"type":"object","properties":{"url":{"type":"string","description":"URL firmada R2, válida por expires_in_seconds."},"expires_in_seconds":{"type":"integer","minimum":0,"exclusiveMinimum":true,"example":3600},"dataset_id":{"type":"string"},"format":{"type":"string","enum":["parquet","csv"]},"snapshot":{"type":"object","properties":{"snapshot_at":{"type":"string","example":"2026-05-30"},"rows_count":{"type":"integer","nullable":true,"minimum":0},"file_size_bytes":{"type":"integer","nullable":true,"minimum":0}},"required":["snapshot_at","rows_count","file_size_bytes"],"additionalProperties":false}},"required":["url","expires_in_seconds","dataset_id","format","snapshot"],"additionalProperties":false},"SnapshotFormatNotAvailableError":{"type":"object","properties":{"error":{"type":"string","enum":["format_not_available"]},"message":{"type":"string"}},"required":["error","message"],"additionalProperties":false,"description":"400 — el formato pedido (`?format=csv`) no existe para este dataset (no todos publican CSV)."},"TierRequiredError":{"type":"object","properties":{"error":{"type":"string","enum":["tier_required","channel_disabled","internal"]},"message":{"type":"string"},"upgrade_url":{"type":"string"},"required_tier":{"type":"string"},"current_tier":{"type":"string"}},"required":["error","message"],"additionalProperties":false,"description":"403 — el plan actual no alcanza para este endpoint. `tier_required`/`channel_disabled` (plan insuficiente, ver requireMcpAccess/assertApiRestAccess) o `internal` (no se pudo verificar el entitlement). GET /v1/datasets/{id}/snapshot requiere Ultimate, Team, Enterprise o admin — Free/Starter/Pro no alcanzan."}},"parameters":{}},"paths":{"/v1/reports":{"post":{"tags":["Reports"],"summary":"Generar o actualizar un Informe por CUIT","description":"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.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"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`.","example":"6e1b9e0a-8f3b-4e9a-9d1e-2b1a5b7d9c10"},"required":false,"name":"Idempotency-Key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportsPostBody"}}}},"responses":{"200":{"description":"Informe generado (o cobrado y devuelto por replay de Idempotency-Key / carrera concurrente).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportPostResponse"}}}},"400":{"description":"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.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CuitRequeridoError"},{"$ref":"#/components/schemas/CuitInvalidoError"},{"$ref":"#/components/schemas/BodyInvalidoError"},{"$ref":"#/components/schemas/IdempotencyKeyInvalidoError"}]}}}},"401":{"description":"Sin sesión ni API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthenticatedError"}}}},"402":{"description":"Saldo insuficiente (sólo con el modelo de saldo habilitado).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaldoInsuficienteError"}}}},"403":{"description":"Cuenta suspendida, origen no confiable (CSRF, sólo sesión), o canal API no habilitado en el plan.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AccountSuspendedError"},{"$ref":"#/components/schemas/ForbiddenCsrfError"},{"$ref":"#/components/schemas/ChannelDisabledError"}]}}}},"409":{"description":"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).","headers":{"Retry-After":{"schema":{"type":"string","description":"Segundos a esperar antes de reintentar."},"required":true}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/GeneracionEnCursoError"},{"$ref":"#/components/schemas/IdempotencyKeyConflictError"}]}}}},"429":{"description":"rate_limited (usuario o IP). El tope diario de producto se eliminó (migración 0663, 2026-08-06).","headers":{"Retry-After":{"schema":{"type":"string","description":"Segundos a esperar antes de reintentar."},"required":true}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedError"}}}},"500":{"description":"Error inesperado, o el informe se generó pero no se pudo persistir (informe_no_persistido — no se cobró nada).","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/InternalError"},{"$ref":"#/components/schemas/InformeNoPersistidoError"}]}}}}}},"get":{"tags":["Reports"],"summary":"Listar los informes de la cuenta","description":"Paginado, más reciente primero. Excluye informes 'no_resuelto' (sin contenido, no se cobraron).","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Filtro por substring del CUIT (con o sin guiones)."},"required":false,"name":"cuit","in":"query"},{"schema":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":50,"description":"Default 10, máximo 50."},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","nullable":true,"minimum":0,"description":"Default 0."},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Página de informes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportsListResponse"}}}},"401":{"description":"Sin sesión ni API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthenticatedError"}}}},"403":{"description":"Cuenta suspendida (requireAuth, cualquier ruta autenticada), o canal API no habilitado en el plan.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AccountSuspendedError"},{"$ref":"#/components/schemas/ChannelDisabledError"}]}}}},"429":{"description":"rate_limited.","headers":{"Retry-After":{"schema":{"type":"string","description":"Segundos a esperar antes de reintentar."},"required":true}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedError"}}}},"500":{"description":"Error inesperado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/reports/{id}":{"get":{"tags":["Reports"],"summary":"Obtener un informe por id","description":"Sólo si la cuenta lo generó (o si es admin). Mismo criterio de acceso que la descarga de PDF.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","example":"6e1b9e0a-8f3b-4e9a-9d1e-2b1a5b7d9c10"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"El informe.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ReportResult"},{"type":"object","properties":{"informe_id":{"type":"string"}},"required":["informe_id"],"additionalProperties":false}]}}}},"401":{"description":"Sin sesión ni API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthenticatedError"}}}},"403":{"description":"Cuenta suspendida (requireAuth, cualquier ruta autenticada), o canal API no habilitado en el plan.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AccountSuspendedError"},{"$ref":"#/components/schemas/ChannelDisabledError"}]}}}},"404":{"description":"No existe, o no pertenece a esta cuenta.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotFoundError"}}}},"429":{"description":"rate_limited.","headers":{"Retry-After":{"schema":{"type":"string","description":"Segundos a esperar antes de reintentar."},"required":true}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedError"}}}}}}},"/v1/reports/quote":{"get":{"tags":["Reports"],"summary":"Presupuesto previo (lectura pura, no gasta saldo)","description":"Costo MÁXIMO de un POST /v1/reports subsiguiente para este CUIT — nunca puede ser mayor una vez corrido el Motor, sólo puede bajar a 0 (ver `costo_maximo_unidades`).","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","pattern":"^\\d{11}$","description":"CUIT/CUIL de 11 dígitos, sin guiones ni puntos.","example":"30000000007"},"required":true,"name":"cuit","in":"query"}],"responses":{"200":{"description":"Presupuesto.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportQuoteResponse"}}}},"400":{"description":"cuit inválido o ausente.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CuitInvalidoError"}}}},"401":{"description":"Sin sesión ni API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthenticatedError"}}}},"403":{"description":"Cuenta suspendida (requireAuth, cualquier ruta autenticada), o canal API no habilitado en el plan.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AccountSuspendedError"},{"$ref":"#/components/schemas/ChannelDisabledError"}]}}}},"429":{"description":"rate_limited.","headers":{"Retry-After":{"schema":{"type":"string","description":"Segundos a esperar antes de reintentar."},"required":true}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedError"}}}}}}},"/v1/balance":{"get":{"tags":["Account"],"summary":"Saldo de la cuenta (cupo del plan + comprado)","description":"En lenguaje de cliente: cuántos informes nuevos y actualizaciones le quedan a la cuenta. El saldo no vence.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Saldo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BalanceResponse"}}}},"401":{"description":"Sin sesión ni API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthenticatedError"}}}},"403":{"description":"Cuenta suspendida (requireAuth, cualquier ruta autenticada), o canal API no habilitado en el plan.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AccountSuspendedError"},{"$ref":"#/components/schemas/ChannelDisabledError"}]}}}},"429":{"description":"rate_limited.","headers":{"Retry-After":{"schema":{"type":"string","description":"Segundos a esperar antes de reintentar."},"required":true}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedError"}}}}}}},"/v1/prices":{"get":{"tags":["Account"],"summary":"Catálogo de precios de planes y packs","description":"Público, sin auth — misma información que /pricing.","responses":{"200":{"description":"Precios vigentes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricesResponse"}}}}}}},"/v1/datasets":{"get":{"tags":["Datasets"],"summary":"Listar el catálogo de datasets publicados","description":"Público, sin auth. Índice liviano: un ítem por dataset (id, nombre, descripción, fuente, frecuencia, tags, país) con `detail_url` a la ficha completa (GET /v1/datasets/{id}). Es el primer paso del flujo de ingesta — ver https://almanac.ar/developers/api.","responses":{"200":{"description":"Catálogo completo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatasetsListResponse"}}}}}}},"/v1/datasets/{id}":{"get":{"tags":["Datasets"],"summary":"Ficha completa de un dataset (AI metadata)","description":"Público, sin auth. Schema de columnas, ejemplos, gotchas, patrón de actualización, SLA de frescura, y `snapshot_date`/`row_count` del snapshot vigente. Equivalente a lo que el MCP server devuelve vía `get_dataset(id)`.","parameters":[{"schema":{"type":"string","example":"bcra.monetarias.indicadores"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"La ficha del dataset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatasetDetailResponse"}}}},"404":{"description":"dataset_not_found — no existe, no está publicado, no alcanza el plan del caller (anónimo = tier free), o es admin-only. Mismo status/shape en los cuatro casos: no filtra cuál aplica.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatasetNotFoundError"}}}}}}},"/v1/datasets/{id}/snapshot":{"get":{"tags":["Datasets"],"summary":"URL firmada al snapshot vigente (Parquet/CSV)","description":"Requiere plan Ultimate, Team, Enterprise o admin (mismo gate que el canal MCP). Devuelve una URL firmada R2 (60 min) al snapshot completo, para ingesta a un Data Warehouse — no corre SQL ni filtra server-side (para eso está el canal MCP). Con `?redirect=1` responde 302 directo al archivo en vez de JSON con la URL.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","example":"bcra.monetarias.indicadores"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","enum":["parquet","csv"],"description":"Default 'parquet'."},"required":false,"name":"format","in":"query"},{"schema":{"type":"string","enum":["1"],"description":"Con '1', responde 302 al archivo directo en vez de JSON con la URL."},"required":false,"name":"redirect","in":"query"}],"responses":{"200":{"description":"URL firmada + metadata del snapshot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SnapshotResponse"}}}},"400":{"description":"format_not_available — el formato pedido no existe para este dataset.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SnapshotFormatNotAvailableError"}}}},"401":{"description":"Sin sesión ni API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnauthenticatedError"}}}},"403":{"description":"Plan insuficiente (Free/Starter/Pro no alcanzan) o no se pudo verificar el entitlement.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TierRequiredError"}}}},"404":{"description":"not_found — dataset o snapshot inexistente, o admin-only.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotFoundError"}}}},"500":{"description":"Error inesperado al generar la URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalError"}}}}}}},"/v1/openapi.json":{"get":{"tags":["Meta"],"summary":"Este contrato OpenAPI 3.0, en JSON","description":"Público, sin auth. Generado como artefacto de build desde estos mismos schemas Zod — ver scripts/generate-openapi.ts.","responses":{"200":{"description":"Documento OpenAPI 3.0.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"nullable":true}}}}}}}}}}