{"components":{"parameters":{"InvoiceId":{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},"NotificationDestinationId":{"description":"El `id` del destino de avisos (UUID). El de otro emisor responde 404 `not_found`.","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},"NotificationThresholdEvent":{"description":"El evento con umbral: `cae.running_low`, `cae.expiring` o `certificate.expiring`.","in":"path","name":"event","required":true,"schema":{"type":"string"}},"OrderId":{"description":"El `id` de la orden (UUID). El de otro emisor responde 404 `order_not_found`.","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},"PaperFormat":{"description":"Papel: `a4` o un rollo térmico de `80mm` o `57mm` para impresoras de punto de venta. El rollo sólo admite e-Tickets y sus notas, salvo que el tenant publique todos sus CFE (`publication = all`): *Formato CFE v25.2*, p. 79. Un valor desconocido responde 422 `invalid_format`; un tipo que el rollo no admite, 422 `thermal_paper_not_admitted`. Sin `format`, el `default_format` de la plantilla con que se imprimió el comprobante (`GET /v1/printing/template`), si está habilitado y el papel admite el tipo; si no, A4.","in":"query","name":"format","required":false,"schema":{"default":"a4","enum":["a4","80mm","57mm"],"type":"string"}},"PosColumns":{"description":"Caracteres por renglón de la fuente A: `48` (por defecto, rollo de 80 mm) o `32` (57 mm). Un valor desconocido responde 422 `invalid_columns`. El rollo tiene que estar entre los formatos de impresión (`printing.formats`: `80mm` o `57mm`). Sin `columns`, 32 si el papel de siempre de la plantilla es el rollo de 57 mm y está habilitado; si no, 48.","in":"query","name":"columns","required":false,"schema":{"enum":[48,32],"type":"integer"}},"PosEncoding":{"description":"`json` (por defecto): los bloques de `cfe-pos/1`; `escpos`: los bytes ESC/POS en la página de códigos PC850; `text`: texto plano UTF-8 de ancho fijo. Un valor desconocido responde 422 `invalid_encoding`.","in":"query","name":"encoding","required":false,"schema":{"default":"json","enum":["json","escpos","text"],"type":"string"}},"PublicAmount":{"description":"Monto total del comprobante, el del QR (A-C130 en el e-Ticket). Acepta `1234.50`, `1234,50` y `1.234,50`.","in":"query","name":"amount","required":true,"schema":{"type":"string"}},"PublicCode":{"description":"Código de seguridad: los 6 caracteres impresos debajo del QR (o el código completo).","in":"query","name":"code","required":true,"schema":{"minLength":6,"type":"string"}},"PublicNumber":{"description":"Número del comprobante.","in":"query","name":"number","required":true,"schema":{"maximum":9999999,"minimum":1,"type":"integer"}},"PublicRuc":{"description":"RUC del emisor (12 dígitos, con dígito verificador).","in":"query","name":"ruc","required":true,"schema":{"pattern":"^[0-9]{12}$","type":"string"}},"PublicSeries":{"description":"Serie del comprobante.","in":"query","name":"series","required":true,"schema":{"maxLength":2,"type":"string"}},"PublicType":{"description":"Tipo de CFE (Tabla A), por ejemplo 101.","in":"query","name":"type","required":true,"schema":{"type":"integer"}},"SandboxOutcome":{"description":"Sólo con una clave de prueba (`cfe_test_…`): lo que contesta la DGI simulada a este comprobante. `accepted` (`AE`), `rejected` o `rejected:<causa E01 a E15>` (`BE`, `E05` por defecto; los motivos que emite la DGI, Mensaje de Respuesta 4.3), `delay:<1 a 120 segundos>` (`AE` después de ese tiempo) o `timeout` (las consultas de su respuesta vencen 30 segundos, después `AE`). No hay `observed`: la DGI sólo observa (`CE`) comprobantes de contingencia (Mensaje de Respuesta p. 9), que el sandbox no lleva. Sin la cabecera, el `sandbox_outcome` de la clave, y si no tiene, `accepted`. Un valor que no se lee es `422 invalid_sandbox_outcome`, antes de tomar número. Una clave real la ignora.","in":"header","name":"Cfe-Sandbox-Outcome","required":false,"schema":{"examples":["accepted","rejected:E04","delay:30","timeout"],"type":"string"}},"WebhookId":{"description":"El `id` del destino (UUID). El de otro emisor responde 404 `not_found`.","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}},"responses":{"AccountSuspended":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/AccountProblem"}}},"description":"La cuenta está suspendida o la membresía venció"},"BadRequest":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Cuerpo inválido (`invalid_body`): JSON mal formado, con miembros faltantes o de otro tipo, o con un miembro que la operación no tiene (un nombre mal escrito, un campo de otra ruta); `field` dice cuál (`lines[0].discont`)"},"Conflict":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Conflicto de estado (sin numeración, idempotencia)"},"EmissionTooLarge":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`payload_too_large`: el cuerpo supera 2.381.912 bytes (`MAX_EMISSION_BODY_BYTES`), el tope de las rutas que emiten: el comprobante en JSON (hasta 1 MiB, como cualquier otra ruta) más el adjunto de la adenda en Base64 (hasta 1.000.000 bytes antes de codificar, un tercio más codificado). Se rechaza por el `Content-Length` antes de leerlo, o al pasarse leyéndolo."},"FeatureDisabled":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`feature_disabled`: la configuración del cliente apaga algo que la solicitud usa (`GET /v1/tenant/features`). Se rechaza antes de tomar número, de reclamar la `Idempotency-Key` y de contar la cuota. `feature` es la clave de la primera función apagada, `how_to_enable` dice quién la enciende (`by`: `staff` u `owner`) y cómo, y `errors[]` trae cada miembro del pedido que la usa, con su `path` y `params.feature` (y `params.value` para una lista: la moneda, el indicador, el formato)."},"Forbidden":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El rol no alcanza (`forbidden`): la operación es solo para OWNER"},"LimitReached":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/LimitProblem"}}},"description":"Un límite de la membresía alcanzado"},"NotFound":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe para este tenant"},"ReasonRequired":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Falta el motivo (`reason_required`) o un valor no es válido"},"ScopeRequired":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`scope_required`: la clave de API no tiene el permiso (`x-scope`) de la ruta. `errors[0].params` trae `required` (el que pide) y `granted` (los que tiene). También `forbidden` si el rol de la sesión no alcanza."},"ServiceUnavailable":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No disponible por un momento; vuelva a intentarlo después de `Retry-After` segundos (con la misma `Idempotency-Key` si estaba emitiendo). `database_unavailable`: la base de datos no contesta (failover, reinicio, un primario recién degradado, un conflicto de serialización); la transacción se deshizo. `restore_pending`: la numeración está detenida hasta conciliar los rangos de CAE después de restaurar la base; no se consumió ningún número.","headers":{"Retry-After":{"schema":{"type":"integer"}}}},"SessionRequired":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`session_required`: la ruta es de la API del portal o de la consola de la plataforma y la credencial es una clave de API. Una clave no gestiona la cuenta (usuarios, claves, contraseña, sesiones, certificado de firma)."},"StaffRoleRequired":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El rol del equipo no alcanza (`staff_role_required`; `role` y `errors[0].params.required`), o no es personal de la plataforma (`forbidden`), o una clave (`session_required`)"},"TooManyRequests":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Se superó el límite del minuto","headers":{"Retry-After":{"schema":{"type":"integer"}}}},"Unauthorized":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Falta la clave o no es válida"},"Unprocessable":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El documento no cumple el formato; `field` indica el campo DGI y `errors` trae todos los errores, cada uno con la ruta JSON de su miembro"},"UnsupportedMediaType":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El cuerpo no es `application/json` (`unsupported_media_type`)"},"ViewOnly":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Una sesión de ver como el cliente no escribe (`view_only`) ni alcanza la consola (`view_as_out_of_scope`)"}},"schemas":{"AccountApi":{"properties":{"billable":{"items":{"$ref":"#/components/schemas/ApiBillableItem"},"type":"array"},"cycle":{"$ref":"#/components/schemas/ApiCycle"},"generated_at":{"format":"date-time","type":"string"},"keys":{"items":{"$ref":"#/components/schemas/ApiKeyView"},"type":"array"},"range":{"$ref":"#/components/schemas/ApiRange"},"sandbox":{"$ref":"#/components/schemas/ApiSandboxSummary"},"tenant_id":{"format":"uuid","type":"string"},"usage":{"$ref":"#/components/schemas/ApiUsageReport"}},"required":["tenant_id","generated_at","keys","usage","cycle","range","sandbox","billable"],"type":"object"},"AccountProblem":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"properties":{"ended_at":{"format":"date-time","type":["string","null"]},"since":{"format":"date-time","type":["string","null"]},"state":{"enum":["SUSPENDED","EXPIRED"],"type":"string"}},"type":"object"}],"description":"`403 account_suspended` o `403 membership_expired`: la cuenta no emite (antes de numerar), pero consulta, descarga y recibe, y el reporte diario sigue saliendo."},"AdendaAttachment":{"description":"El binario de la adenda (zona J-C2) de una emisión, sin sus bytes.","properties":{"file_name":{"type":["string","null"]},"media_type":{"description":"El tipo que declaró el emisor; la descarga va siempre como `application/octet-stream`","type":["string","null"]},"size_bytes":{"type":"integer"},"url":{"description":"`/v1/invoices/{id}/adenda-attachment`","type":"string"}},"required":["size_bytes","url"],"type":"object"},"AdendaAttachmentInput":{"description":"Zona J-C2 \"Otro\" (Formato CFE v25.2, p. 74): un objeto binario para el receptor (un plano, un remito en PDF). Viaja en la adenda junto al CFE, como hijo `Otro` en Base64 con los atributos `nombre` y `tipo`; no se firma ni va a la DGI. La DGI no define su estructura (HOMOLOGATION §11).","properties":{"content":{"contentEncoding":"base64","description":"Los bytes en Base64 (alfabeto estándar; se ignoran los espacios). Hasta 1.000.000 bytes antes de codificar (`MAX_ADENDA_BINARY_BYTES`), y la solicitud entera no supera el tope de las rutas que emiten (2.381.912 bytes, `MAX_EMISSION_BODY_BYTES`: 1 MiB de JSON más el Base64 de un adjunto de 1.000.000 bytes)","type":"string"},"file_name":{"description":"Nombre del archivo, sin directorios ni caracteres de control","maxLength":150,"type":["string","null"]},"media_type":{"description":"Tipo de medio, como `application/pdf`","examples":["application/pdf"],"type":["string","null"]}},"required":["content"],"type":"object"},"AdminCertificate":{"properties":{"certificate_id":{"format":"uuid","type":["string","null"]},"chain":{"enum":["VALID","UNTRUSTED","NOT_CHECKED",null],"type":["string","null"]},"days_to_expiry":{"type":["integer","null"]},"issuer":{"type":["string","null"]},"name":{"type":"string"},"not_after":{"format":"date-time","type":["string","null"]},"not_before":{"format":"date-time","type":["string","null"]},"revocation":{"enum":["GOOD","REVOKED","UNKNOWN","NOT_CHECKED",null],"type":["string","null"]},"revocation_checked_at":{"format":"date-time","type":["string","null"]},"revoked_at":{"format":"date-time","type":["string","null"]},"ruc":{"type":"string"},"sandbox":{"description":"Es el sandbox de un cliente: sólo se lista con `include_sandbox`","type":"boolean"},"serial":{"type":["string","null"]},"status":{"description":"El estado del certificado propio; sin uno, `platform` cuando firma con el de la plataforma (`CFE_ALLOW_GLOBAL_CERTIFICATE`) y `missing` cuando no puede firmar","enum":["valid","expiring","expired","not_yet_valid","revoked","platform","missing"],"type":"string"},"subject":{"type":["string","null"]},"tenant_id":{"format":"uuid","type":"string"},"uploaded_at":{"format":"date-time","type":["string","null"]}},"required":["tenant_id","ruc","name","status","sandbox"],"type":"object"},"AdminSettings":{"description":"La configuración del despliegue que viene de variables de entorno, de sólo lectura: cambiarla es un deploy nuevo. Dice si un secreto está configurado, nunca el secreto.","properties":{"certificates":{"properties":{"allow_global":{"description":"`CFE_ALLOW_GLOBAL_CERTIFICATE` con un certificado de la plataforma cargado (`CFE_CERT_*`): un cliente sin el suyo firma con el de la plataforma. Sólo desarrollo y pruebas","type":"boolean"},"global_not_after":{"format":"date-time","type":["string","null"]},"global_subject":{"type":["string","null"]}},"required":["allow_global","global_subject","global_not_after"],"type":"object"},"delivery":{"properties":{"cutoff_above_cap":{"description":"El corte supera las 5.000 UI: un e-Ticket que debe ir primero puede esperar. Sólo hasta la próxima vuelta del worker (un minuto), que lo baja al tope cuando éste cambia, o mientras no corre ningún worker","type":"boolean"},"priority_cutoff_updated_at":{"format":"date-time","type":["string","null"]},"priority_cutoff_uyu":{"description":"El corte de `emission_delivery_class` que aplicó el worker (`CFE_WORKER_PRIORITY_CUTOFF_UYU`, migración 44): un e-Ticket en pesos por debajo puede esperar detrás de lo que va primero a la DGI (Formato del Sobre p. 4)","type":["string","null"]},"recipient_cap_uyu":{"description":"El tope de lo que llega al receptor para un CFE emitido hoy (Formato del Sobre p. 4): el de la UI o, sin ella, el corte de prioridad (`recipient_cap_uyu`, migración 54)","type":["string","null"]},"ui_cap_uyu":{"description":"5.000 UI a la UI del año anterior a hoy (`ui_cap_uyu`, migración 54), la que leen la regla del receptor y el worker; `null` mientras esa UI no está cargada","type":["string","null"]},"ui_missing_year":{"description":"El año anterior a hoy mientras su UI del 31/12 no está cargada: el tope de la Tabla E se controla con una UI menor (la última anterior cargada o el piso de 2 pesos), la vista previa avisa `ui_value_unknown` y el reporte diario omite B-C27. Se carga con `PUT /v1/admin/rates`; `null` con la UI cargada","type":["integer","null"]},"ui_year":{"description":"El año de esa UI","type":["integer","null"]}},"type":"object"},"dgi":{"properties":{"contact_service":{"description":"`CFE_DGI_SOLICITUD_ENDPOINT` está configurado: se puede llamar a `ws_efacsolicitud`","type":"boolean"},"environment":{"description":"`CFE_DGI_ENVIRONMENT`","type":"string"},"mode":{"description":"`CFE_DGI_MODE`","type":"string"}},"type":"object"},"mail":{"properties":{"answer_personal_certificates":{"type":"boolean"},"answers_per_domain_day":{"type":"integer"},"answers_per_ruc_day":{"type":"integer"},"authserv_ids":{"description":"`CFE_MAIL_AUTHSERV_ID`","items":{"type":"string"},"type":"array"},"imap":{"type":"boolean"},"inbound_route":{"description":"`CFE_MAIL_INBOUND_SECRET` está configurado","type":"boolean"},"max_attempts":{"type":"integer"},"sender_auth":{"description":"`CFE_MAIL_SENDER_AUTH`","enum":["none","aligned","dmarc"],"type":"string"},"smtp":{"type":"boolean"}},"type":"object"},"public_verification":{"properties":{"jitter_ms":{"type":"integer"},"limit_global":{"type":"integer"},"limit_per_ip":{"type":"integer"},"min_response_ms":{"type":"integer"},"page":{"description":"`CFE_PUBLIC_URL` está configurado","type":"boolean"}},"type":"object"},"reports":{"properties":{"automatic":{"description":"`CFE_REPORT_AUTOMATIC`","type":"boolean"},"r05_advances":{"description":"`CFE_REPORT_R05_ADVANCES`","type":"integer"},"reliquidate":{"description":"`CFE_REPORT_RELIQUIDATE`","type":"boolean"},"reliquidation_days":{"description":"`CFE_REPORT_RELIQUIDATION_DAYS`","type":"integer"}},"type":"object"},"security":{"properties":{"cookie_secure":{"type":"boolean"},"login_limit_per_email":{"type":"integer"},"login_limit_per_ip":{"type":"integer"},"metrics_token":{"description":"`CFE_METRICS_TOKEN` está configurado","type":"boolean"},"trust_forwarded_for":{"type":"boolean"},"webhook_allow_private_networks":{"type":"boolean"},"webhook_require_https":{"type":"boolean"}},"type":"object"}},"required":["dgi","delivery","reports","mail","public_verification","security","certificates"],"type":"object"},"AdminTenant":{"properties":{"created_at":{"format":"date-time","type":"string"},"emissions_this_month":{"type":"integer"},"id":{"format":"uuid","type":"string"},"monthly_quota":{"type":"integer"},"name":{"type":"string"},"plan":{"type":"string"},"rate_limit_per_minute":{"type":"integer"},"ruc":{"type":"string"},"users":{"type":"integer"}},"type":"object"},"AdminTenantDetail":{"allOf":[{"$ref":"#/components/schemas/AdminTenant"},{"properties":{"address":{"description":"Domicilio fiscal (`DomFiscal`); `null` hasta que el emisor lo configure","type":["string","null"]},"city":{"type":["string","null"]},"department":{"type":["string","null"]}},"required":["address","city","department"],"type":"object"}]},"AdminTenantFeatures":{"allOf":[{"$ref":"#/components/schemas/TenantFeatures"},{"properties":{"membership":{"$ref":"#/components/schemas/StaffMembership","description":"Sólo cuando la solicitud trajo `limits`: la membresía como la devuelve `PATCH /v1/admin/tenants/{id}/membership`."}},"type":"object"}]},"AdminTenantFeaturesRequest":{"allOf":[{"$ref":"#/components/schemas/TenantFeaturesRequest"},{"properties":{"limits":{"additionalProperties":false,"description":"Las excepciones de los límites de la membresía, como en `PATCH /v1/admin/tenants/{id}/membership`, guardadas en la misma transacción que `changes`.","properties":{"overrides":{"description":"`{límite: valor}` (null: sin límite), `at_limit`, `overage_cap`, `safety_block`","type":"object"},"remove":{"description":"Excepciones que se quitan: vuelve a regir el valor de la membresía.","items":{"type":"string"},"type":"array"}},"type":"object"}},"type":"object"}]},"Annulment":{"properties":{"annulled_at":{"format":"date-time","type":"string"},"annulled_by":{"properties":{"api_key_id":{"description":"La clave de API, si fue una integración","format":"uuid","type":["string","null"]},"name":{"description":"Email del usuario o nombre de la clave en ese momento","type":"string"},"user_id":{"description":"El usuario del portal, si fue uno","format":"uuid","type":["string","null"]}},"required":["name"],"type":"object"},"cfe_type":{"type":"integer"},"cfe_type_name":{"type":"string"},"id":{"format":"uuid","type":"string"},"number":{"type":"integer"},"reason":{"type":"string"},"report_date":{"description":"Fecha del reporte diario que lo informa (el día de `annulled_at` en Uruguay)","format":"date","type":"string"},"series":{"type":"string"}},"required":["id","cfe_type","cfe_type_name","series","number","reason","annulled_at","report_date","annulled_by"],"type":"object"},"AnnulmentRequest":{"properties":{"cfe_type":{"description":"Código del tipo de CFE (no de contingencia), por ejemplo 101","example":101,"type":"integer"},"number":{"example":5,"minimum":1,"type":"integer"},"reason":{"example":"Comprobante anulado del set de pruebas","maxLength":500,"minLength":1,"type":"string"},"series":{"example":"A","type":"string"}},"required":["cfe_type","series","number","reason"],"type":"object"},"ApiBillableItem":{"description":"Lo que se cobra y lo que no, con las rutas de cada cosa.","properties":{"billable":{"type":"boolean"},"description":{"type":"string"},"item":{"examples":["emitted_cfe","received_cfe","read_request","overage","status","catalog","events","account","health_meta","sandbox","portal_session","refused"],"type":"string"},"label":{"type":"string"},"routes":{"items":{"examples":["GET /v1/emissions"],"type":"string"},"type":"array"},"source":{"description":"`ledger`: los comprobantes, exactos; `meter`: las peticiones, contadas en lote.","enum":["ledger","meter",null],"type":["string","null"]},"unit":{"enum":["cfe","request",null],"type":["string","null"]}},"required":["item","billable","unit","source","label","description","routes"],"type":"object"},"ApiCaeLeft":{"properties":{"cfe_type":{"type":"integer"},"expires_on":{"format":"date","type":["string","null"]},"ranges":{"type":"integer"},"remaining":{"description":"Números que quedan en los rangos que numeran (ni vencidos ni retirados)","type":"integer"},"series":{"type":"string"},"status":{"enum":["ok","low","exhausted","expired"],"type":"string"}},"type":"object"},"ApiClosedCycle":{"properties":{"billable_requests":{"type":"integer"},"closed_at":{"format":"date-time","type":"string"},"currency":{"type":"string"},"cycle_day":{"type":"integer"},"emitted":{"type":"integer"},"ends_on":{"description":"Último día (inclusive)","format":"date","type":"string"},"estimate":{"$ref":"#/components/schemas/ApiEstimate"},"plan_code":{"type":["string","null"]},"received":{"type":"integer"},"requests":{"type":"integer"},"ruc":{"type":["string","null"]},"sandbox_requests":{"type":"integer"},"starts_on":{"format":"date","type":"string"},"tenant_id":{"format":"uuid","type":"string"},"tenant_name":{"type":["string","null"]},"total":{"description":"Importe con dos decimales","examples":["1500.00"],"type":"string"}},"type":"object"},"ApiConsumption":{"properties":{"billable_requests":{"type":"integer"},"cfe_final":{"description":"Cada día del ciclo se volvió a contar del libro una vez terminado.","type":"boolean"},"emitted":{"type":"integer"},"received":{"type":"integer"},"refused_requests":{"type":"integer"},"requests":{"type":"integer"},"sandbox_requests":{"type":"integer"},"session_requests":{"type":"integer"}},"type":"object"},"ApiCycle":{"properties":{"cfe_counted_until":{"format":"date-time","type":["string","null"]},"closes_at":{"description":"El próximo cierre: la medianoche de Uruguay después del último día","format":"date-time","type":"string"},"consumption":{"$ref":"#/components/schemas/ApiConsumption"},"cycle_day":{"maximum":28,"minimum":1,"type":"integer"},"days_left":{"type":"integer"},"ends_on":{"description":"Último día del ciclo (inclusive)","format":"date","type":"string"},"estimate":{"description":"null en el portal: los precios son del equipo.","oneOf":[{"$ref":"#/components/schemas/ApiEstimate"},{"type":"null"}]},"source":{"enum":["set","default"],"type":"string"},"starts_on":{"format":"date","type":"string"}},"required":["cycle_day","source","starts_on","ends_on","closes_at","days_left","consumption","estimate","cfe_counted_until"],"type":"object"},"ApiCycleRequest":{"properties":{"cycle_day":{"maximum":28,"minimum":1,"type":"integer"},"reason":{"maxLength":2000,"type":"string"}},"required":["cycle_day","reason"],"type":"object"},"ApiCycles":{"properties":{"closed":{"items":{"$ref":"#/components/schemas/ApiClosedCycle"},"type":"array"},"current":{"$ref":"#/components/schemas/ApiCycle"},"tenant_id":{"format":"uuid","type":"string"}},"type":"object"},"ApiEstimate":{"description":"El importe estimado de un ciclo con los precios que rigen.","properties":{"currency":{"type":"string"},"lines":{"items":{"properties":{"amount":{"description":"Importe con dos decimales","examples":["1500.00"],"type":"string"},"item":{"enum":["base_fee","emitted_cfe","overage","received_cfe","read_request"],"type":"string"},"priced":{"type":"boolean"},"quantity":{"type":"integer"},"tiers":{"items":{"properties":{"amount":{"description":"Importe con dos decimales","examples":["1500.00"],"type":"string"},"from":{"type":"integer"},"quantity":{"type":"integer"},"to":{"type":["integer","null"]},"unit_price":{"description":"Precio decimal, hasta 4 decimales","examples":["2.5"],"type":"string"}},"type":"object"},"type":"array"}},"type":"object"},"type":"array"},"total":{"description":"Importe con dos decimales","examples":["1500.00"],"type":"string"}},"required":["currency","lines","total"],"type":"object"},"ApiKey":{"properties":{"api_key":{"description":"Sólo en la creación y en `POST /v1/api-keys/{id}/reveal`","type":"string"},"created_at":{"format":"date-time","type":"string"},"hint":{"description":"Últimos 4 caracteres","type":["string","null"]},"id":{"format":"uuid","type":"string"},"kind":{"description":"`live`: una clave real. `test`: una clave de prueba (`cfe_test_…`) contra el sandbox de la cuenta.","enum":["live","test"],"type":"string"},"last_used_at":{"format":"date-time","type":["string","null"]},"name":{"type":"string"},"revealable":{"description":"Si la clave se puede volver a ver (`POST /v1/api-keys/{id}/reveal`): las creadas desde la migración 105 y no revocadas","type":"boolean"},"revoked_at":{"format":"date-time","type":["string","null"]},"sandbox_outcome":{"description":"Sólo una clave de prueba: la respuesta de la DGI simulada cuando la solicitud no incluye `Cfe-Sandbox-Outcome`; `null` = `accepted`.","type":["string","null"]},"scopes":{"description":"Permisos de una clave restringida, en orden fijo; `null` = todos los de la API de cliente (y los que se agreguen), como toda clave creada antes de los permisos","items":{"$ref":"#/components/schemas/Scope"},"type":["array","null"]}},"type":"object"},"ApiKeyClient":{"description":"Una dirección y un agente desde los que se usó la clave (las últimas diez).","properties":{"first_seen":{"format":"date-time","type":"string"},"ip":{"type":"string"},"last_seen":{"format":"date-time","type":"string"},"requests":{"type":"integer"},"user_agent":{"type":"string"}},"type":"object"},"ApiKeyRevealRequest":{"additionalProperties":false,"properties":{"password":{"description":"La contraseña del usuario, otra vez","type":"string"}},"required":["password"],"type":"object"},"ApiKeyView":{"properties":{"active":{"type":"boolean"},"clients":{"items":{"$ref":"#/components/schemas/ApiKeyClient"},"type":"array"},"created_at":{"format":"date-time","type":"string"},"created_by":{"oneOf":[{"properties":{"email":{"type":["string","null"]},"id":{"format":"uuid","type":"string"},"name":{"type":["string","null"]}},"type":"object"},{"type":"null"}]},"hint":{"type":["string","null"]},"id":{"format":"uuid","type":"string"},"kind":{"description":"`live`: una clave real. `test`: una clave de prueba (`cfe_test_…`), como en `GET /v1/api-keys`.","enum":["live","test"],"type":"string"},"last_used_at":{"format":"date-time","type":["string","null"]},"name":{"type":"string"},"revoked_at":{"format":"date-time","type":["string","null"]},"scopes":{"items":{"type":"string"},"type":"array"},"usage":{"description":"Los últimos 30 días","properties":{"billable_requests":{"type":"integer"},"errors":{"type":"integer"},"last_day":{"format":"date","type":["string","null"]},"requests":{"type":"integer"}},"type":"object"}},"type":"object"},"ApiKeysRevokeRequest":{"properties":{"all":{"description":"Todas las claves activas del cliente","type":"boolean"},"key_ids":{"items":{"format":"uuid","type":"string"},"type":"array"},"reason":{"maxLength":2000,"type":"string"}},"required":["reason"],"type":"object"},"ApiKeysRevoked":{"properties":{"keys":{"items":{"$ref":"#/components/schemas/ApiKey"},"type":"array"},"revoked":{"items":{"format":"uuid","type":"string"},"type":"array"}},"type":"object"},"ApiPanel":{"properties":{"billable":{"items":{"$ref":"#/components/schemas/ApiBillableItem"},"type":"array"},"cycle":{"$ref":"#/components/schemas/ApiCycle"},"features":{"items":{"$ref":"#/components/schemas/TenantFeature"},"type":"array"},"generated_at":{"format":"date-time","type":"string"},"keys":{"items":{"$ref":"#/components/schemas/ApiKeyView"},"type":"array"},"membership":{"$ref":"#/components/schemas/Membership"},"pricing":{"$ref":"#/components/schemas/ApiPricingView"},"range":{"$ref":"#/components/schemas/ApiRange"},"sandbox":{"$ref":"#/components/schemas/ApiSandboxSummary"},"tenant":{"properties":{"id":{"format":"uuid","type":"string"},"name":{"type":"string"},"ruc":{"type":"string"}},"type":"object"}},"required":["tenant","generated_at","features","membership","pricing","billable","range","cycle","keys","sandbox"],"type":"object"},"ApiPlanPricing":{"properties":{"billable":{"items":{"$ref":"#/components/schemas/ApiBillableItem"},"type":"array"},"effective":{"$ref":"#/components/schemas/ApiPricingEffective"},"exceptions":{"type":"integer"},"plan_code":{"type":"string"},"plan_id":{"format":"uuid","type":"string"},"pricing":{"$ref":"#/components/schemas/ApiPricing"},"tenants":{"type":"integer"}},"type":"object"},"ApiPricing":{"additionalProperties":false,"description":"Precios de un plan, o la excepción de un cliente (sólo lo que cambia). Una estimación para facturación: la plataforma no cobra.","properties":{"base_fee":{"description":"Precio decimal, hasta 4 decimales","examples":["2.5"],"type":"string"},"currency":{"pattern":"^[A-Z]{3}$","type":"string"},"emitted_tiers":{"items":{"$ref":"#/components/schemas/ApiPricingTier"},"type":"array"},"overage_unit_price":{"description":"Precio decimal, hasta 4 decimales","examples":["2.5"],"type":"string"},"read_request_tiers":{"items":{"$ref":"#/components/schemas/ApiPricingTier"},"type":"array"},"received_tiers":{"items":{"$ref":"#/components/schemas/ApiPricingTier"},"type":"array"}},"type":"object"},"ApiPricingChanged":{"properties":{"changed":{"items":{"type":"string"},"type":"array"},"pricing":{"$ref":"#/components/schemas/ApiPricingView"}},"type":"object"},"ApiPricingEffective":{"properties":{"base_fee":{"description":"Precio decimal, hasta 4 decimales","examples":["2.5"],"type":["string","null"]},"currency":{"type":"string"},"emitted_tiers":{"items":{"$ref":"#/components/schemas/ApiPricingTier"},"type":"array"},"overage_unit_price":{"description":"Precio decimal, hasta 4 decimales","examples":["2.5"],"type":["string","null"]},"read_request_tiers":{"items":{"$ref":"#/components/schemas/ApiPricingTier"},"type":"array"},"received_tiers":{"items":{"$ref":"#/components/schemas/ApiPricingTier"},"type":"array"},"sources":{"additionalProperties":{"enum":["override","plan","membership_plan","default"],"type":"string"},"description":"De dónde sale cada campo: la excepción del cliente, los precios del plan, los tramos que el plan tenía (`price_tiers`) o nada.","type":"object"}},"required":["currency","base_fee","emitted_tiers","received_tiers","read_request_tiers","overage_unit_price","sources"],"type":"object"},"ApiPricingRequest":{"properties":{"pricing":{"description":"null (o `{}`) quita los precios","oneOf":[{"$ref":"#/components/schemas/ApiPricing"},{"type":"null"}]},"reason":{"maxLength":2000,"type":"string"}},"required":["pricing","reason"],"type":"object"},"ApiPricingTier":{"description":"Un tramo: de `from` a `to` unidades (inclusive; null es abierto), cada una a `unit_price` (escalonado).","properties":{"from":{"type":"integer"},"to":{"type":["integer","null"]},"unit_price":{"description":"Precio decimal, hasta 4 decimales","examples":["2.5"],"type":"string"}},"required":["from","to","unit_price"],"type":"object"},"ApiPricingView":{"properties":{"effective":{"$ref":"#/components/schemas/ApiPricingEffective"},"exception":{"oneOf":[{"$ref":"#/components/schemas/ApiPricing"},{"type":"null"}]},"plan":{"$ref":"#/components/schemas/ApiPricing"}},"required":["effective","plan","exception"],"type":"object"},"ApiRange":{"description":"Lo que queda en el período (cada límite con su uso, máximo y renovación) y los números de CAE por tipo y serie.","properties":{"cae":{"items":{"$ref":"#/components/schemas/ApiCaeLeft"},"type":"array"},"limits":{"items":{"$ref":"#/components/schemas/LimitUsage"},"type":"array"}},"required":["limits","cae"],"type":"object"},"ApiSandboxSummary":{"properties":{"active_keys":{"type":"integer"},"max_keys":{"description":"Las claves de prueba que puede tener activas: las de su membresía (`sandbox_keys`), 3 como máximo","type":"integer"},"requests":{"description":"Peticiones de las claves de prueba en los últimos 30 días: nunca se cobran","type":"integer"}},"type":"object"},"ApiTenantUsage":{"properties":{"active_keys":{"type":"integer"},"billable_requests":{"type":"integer"},"emitted":{"type":"integer"},"errors":{"type":"integer"},"last_used_at":{"format":"date-time","type":["string","null"]},"limited_requests":{"type":"integer"},"p50_ms":{"type":["integer","null"]},"p95_ms":{"type":["integer","null"]},"plan_code":{"type":["string","null"]},"received":{"type":"integer"},"requests":{"type":"integer"},"ruc":{"type":"string"},"sandbox_requests":{"type":"integer"},"tenant_id":{"format":"uuid","type":"string"},"tenant_name":{"type":"string"}},"type":"object"},"ApiUsageAll":{"properties":{"from":{"format":"date","type":"string"},"generated_at":{"format":"date-time","type":"string"},"order":{"enum":["asc","desc"],"type":"string"},"sort":{"type":"string"},"tenants":{"items":{"$ref":"#/components/schemas/ApiTenantUsage"},"type":"array"},"to":{"format":"date","type":"string"}},"type":"object"},"ApiUsageErrors":{"properties":{"code":{"type":["string","null"]},"requests":{"type":"integer"},"status":{"type":"integer"}},"type":"object"},"ApiUsageReport":{"properties":{"alerts":{"items":{"$ref":"#/components/schemas/MembershipAlert"},"type":"array"},"days":{"items":{"properties":{"billable_requests":{"type":"integer"},"cfe_final":{"type":"boolean"},"day":{"format":"date","type":"string"},"emitted":{"type":"integer"},"errors":{"type":"integer"},"p50_ms":{"type":["integer","null"]},"p95_ms":{"type":["integer","null"]},"received":{"type":"integer"},"requests":{"type":"integer"}},"type":"object"},"type":"array"},"errors":{"items":{"$ref":"#/components/schemas/ApiUsageErrors"},"type":"array"},"from":{"format":"date","type":"string"},"granularity":{"enum":["day"],"type":"string"},"keys":{"items":{"properties":{"billable_requests":{"type":"integer"},"errors":{"type":"integer"},"key_id":{"format":"uuid","type":["string","null"]},"kind":{"enum":["live","sandbox","session"],"type":"string"},"last_day":{"format":"date","type":["string","null"]},"name":{"type":["string","null"]},"p50_ms":{"type":["integer","null"]},"p95_ms":{"type":["integer","null"]},"requests":{"type":"integer"}},"type":"object"},"type":"array"},"limits_reached":{"items":{"$ref":"#/components/schemas/ApiUsageErrors"},"type":"array"},"recent_errors":{"description":"Los últimos errores, por día, clave, ruta, estado y código: hasta 20, el día más reciente primero y, dentro del día, los más frecuentes.","items":{"properties":{"code":{"type":["string","null"]},"day":{"format":"date","type":"string"},"key_id":{"description":"Nulo para las sesiones del portal","format":"uuid","type":["string","null"]},"kind":{"enum":["live","sandbox","session"],"type":"string"},"method":{"type":"string"},"name":{"type":["string","null"]},"requests":{"type":"integer"},"route":{"description":"La plantilla de la ruta: `/v1/invoices/{id}`","type":"string"},"status":{"type":"integer"}},"type":"object"},"type":"array"},"routes":{"items":{"properties":{"billable":{"type":"boolean"},"category":{"type":"string"},"errors":{"type":"integer"},"method":{"type":"string"},"p50_ms":{"type":["integer","null"]},"p95_ms":{"type":["integer","null"]},"requests":{"type":"integer"},"route":{"examples":["/v1/invoices/{id}"],"type":"string"}},"type":"object"},"type":"array"},"tenant_id":{"format":"uuid","type":"string"},"to":{"format":"date","type":"string"},"totals":{"properties":{"billable_requests":{"type":"integer"},"emitted":{"type":"integer"},"errors":{"type":"integer"},"limited_requests":{"type":"integer"},"p50_ms":{"type":["integer","null"]},"p95_ms":{"type":["integer","null"]},"received":{"type":"integer"},"requests":{"type":"integer"},"sandbox_requests":{"type":"integer"},"session_requests":{"type":"integer"}},"type":"object"}},"required":["tenant_id","from","to","granularity","totals","days","keys","routes","errors","limits_reached","alerts"],"type":"object"},"AssistantCard":{"description":"Una tarjeta de la respuesta del asistente, según `kind`. Todas llevan `kind`, `source` y `link`.","discriminator":{"mapping":{"facts":"#/components/schemas/AssistantFactsCard","invoice":"#/components/schemas/AssistantInvoiceCard","order":"#/components/schemas/AssistantOrderCard","receiver":"#/components/schemas/AssistantReceiverCard","table":"#/components/schemas/AssistantTableCard"},"propertyName":"kind"},"oneOf":[{"$ref":"#/components/schemas/AssistantInvoiceCard"},{"$ref":"#/components/schemas/AssistantOrderCard"},{"$ref":"#/components/schemas/AssistantReceiverCard"},{"$ref":"#/components/schemas/AssistantTableCard"},{"$ref":"#/components/schemas/AssistantFactsCard"}]},"AssistantConsole":{"properties":{"attempts":{"items":{"$ref":"#/components/schemas/AssistantProvider"},"type":"array"},"controls":{"items":{"properties":{"description":{"type":"string"},"key":{"type":"string"},"title":{"type":"string"},"value":{}},"required":[],"type":"object"},"type":"array"},"in_use":{"properties":{"activated_at":{"format":"date-time","type":["string","null"]},"activated_by":{"type":["string","null"]},"base_url":{"type":["string","null"]},"data_location":{"type":["string","null"]},"id":{"format":"uuid","type":"string"},"key_last4":{"type":["string","null"]},"label":{"type":"string"},"model":{"type":"string"},"on":{"type":"boolean"},"provider":{"enum":["anthropic","openai","openai_compatible"],"type":"string"},"source":{"enum":["console","environment"],"type":"string"}},"required":[],"type":"object"},"key_storage":{"type":"boolean"},"max_prompt_chars":{"type":"integer"},"prompts":{"items":{"properties":{"chars":{"type":"integer"},"edited":{"type":"boolean"},"kind":{"type":"string"},"name":{"type":"string"},"path":{"type":"string"},"summary":{"type":"string"},"title":{"type":"string"},"updated_at":{"format":"date-time","type":["string","null"]},"updated_by":{"type":["string","null"]}},"required":[],"type":"object"},"type":"array"},"providers":{"items":{"properties":{"data_location":{"type":["string","null"]},"label":{"type":"string"},"model":{"type":["string","null"]},"needs_base_url":{"type":"boolean"},"needs_confirmation":{"type":"boolean"},"provider":{"enum":["anthropic","openai","openai_compatible"],"type":"string"}},"required":[],"type":"object"},"type":"array"},"smoke_cases":{"items":{"properties":{"category":{"type":"string"},"id":{"type":"string"},"text":{"type":"string"}},"required":[],"type":"object"},"type":"array"}},"required":[],"type":"object"},"AssistantConversation":{"properties":{"busy":{"description":"Si hay una respuesta en curso","type":"boolean"},"context_tokens":{"type":"integer"},"created_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"order_ids":{"description":"Las órdenes que preparó esta conversación","items":{"format":"uuid","type":"string"},"type":"array"},"title":{"description":"El primer mensaje respondido, recortado","type":["string","null"]},"turns":{"type":"integer"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","title","turns","context_tokens","order_ids","busy","created_at","updated_at"],"type":"object"},"AssistantConversationAudit":{"properties":{"created_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"input_tokens":{"type":"integer"},"messages":{"items":{"properties":{"activity":{"items":{},"type":"array"},"cards":{"items":{},"type":"array"},"created_at":{"format":"date-time","type":"string"},"guides":{"items":{"type":"string"},"type":"array"},"input_tokens":{"type":"integer"},"kind":{"type":"string"},"orders":{"items":{},"type":"array"},"outcome":{"type":["string","null"]},"output_tokens":{"type":"integer"},"role":{"type":"string"},"sent_again":{"type":"boolean"},"seq":{"type":"integer"},"text":{"type":["string","null"]},"tool_calls":{"items":{"properties":{"id":{"type":"string"},"input":{},"name":{"type":"string"}},"required":[],"type":"object"},"type":"array"},"tool_results":{"items":{"properties":{"data":{},"is_error":{"type":"boolean"},"tool":{"type":"string"},"tool_use_id":{"type":"string"}},"required":[],"type":"object"},"type":"array"}},"required":[],"type":"object"},"type":"array"},"order_ids":{"items":{"format":"uuid","type":"string"},"type":"array"},"output_tokens":{"type":"integer"},"tenant":{"properties":{"id":{"format":"uuid","type":"string"},"name":{"type":"string"},"ruc":{"type":"string"}},"required":[],"type":"object"},"title":{"type":["string","null"]},"turns":{"type":"integer"},"updated_at":{"format":"date-time","type":"string"},"user":{"properties":{"email":{"type":"string"},"id":{"format":"uuid","type":"string"},"name":{"type":"string"}},"required":[],"type":"object"}},"required":[],"type":"object"},"AssistantConversationDetail":{"allOf":[{"$ref":"#/components/schemas/AssistantConversation"},{"properties":{"messages":{"items":{"$ref":"#/components/schemas/AssistantMessage"},"type":"array"}},"required":["messages"],"type":"object"}]},"AssistantConversationList":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AssistantConversation"},"type":"array"},"next_before":{"description":"El `before` de la página siguiente","format":"uuid","type":["string","null"]}},"required":["items","next_before"],"type":"object"},"AssistantConversationPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AssistantConversationSummary"},"type":"array"},"next_cursor":{"type":["string","null"]}},"required":["items"],"type":"object"},"AssistantConversationRename":{"additionalProperties":false,"properties":{"title":{"description":"El nombre, en una línea","maxLength":80,"minLength":1,"type":"string"}},"required":["title"],"type":"object"},"AssistantConversationSummary":{"properties":{"created_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"input_tokens":{"type":"integer"},"orders":{"type":"integer"},"output_tokens":{"type":"integer"},"tenant":{"properties":{"id":{"format":"uuid","type":"string"},"name":{"type":"string"},"ruc":{"type":"string"}},"required":[],"type":"object"},"title":{"type":["string","null"]},"turns":{"type":"integer"},"updated_at":{"format":"date-time","type":"string"},"user":{"properties":{"email":{"type":"string"},"id":{"format":"uuid","type":"string"},"name":{"type":"string"}},"required":[],"type":"object"}},"required":[],"type":"object"},"AssistantFactsCard":{"description":"Datos con su nombre: la cuenta, su configuración, lo pendiente, los errores.","properties":{"download":{"description":"El único resultado de un reporte se descarga igual que su tabla","properties":{"format":{"const":"csv","type":"string"},"max_rows":{"description":"Las filas que tiene como máximo una descarga (100.000)","type":"integer"},"path":{"description":"`GET` de la API: `/v1/assistant/conversations/{id}/reports/{report_id}/download`","type":"string"},"report_id":{"format":"uuid","type":"string"}},"required":["report_id","path","format","max_rows"],"type":["object","null"]},"items":{"items":{"properties":{"currency":{"description":"Un importe del único resultado de un reporte: su moneda (la de su fila, o la que lee el reporte)","type":["string","null"]},"kind":{"description":"El único resultado de un reporte: el tipo de su columna, que dice cómo se muestra el valor","enum":["text","money","count","number","date","month","percent",null],"type":["string","null"]},"label":{"type":"string"},"tone":{"description":"Cómo se destaca","enum":["ok","warning","error",null],"type":["string","null"]},"value":{"description":"Texto, número o sí/no","type":["string","number","boolean","null"]}},"required":["label","value","tone"],"type":"object"},"maxItems":16,"type":"array"},"kind":{"const":"facts","type":"string"},"link":{"description":"Ruta del portal (`/app/...`); nunca una dirección externa","type":["string","null"]},"note":{"description":"El único resultado de un reporte conserva la aclaración de su tabla","type":["string","null"]},"source":{"description":"La herramienta que la armó (`search_invoices`, `sales_report`...)","type":"string"},"title":{"type":"string"}},"required":["kind","source","title","items","link"],"type":"object"},"AssistantInvoiceCard":{"description":"Un comprobante de la empresa, con su orden y sus notas.","properties":{"cfe_type":{"type":"integer"},"cfe_type_name":{"type":"string"},"currency":{"type":"string"},"id":{"format":"uuid","type":"string"},"issue_date":{"format":"date","type":"string"},"kind":{"const":"invoice","type":"string"},"link":{"description":"Ruta del portal (`/app/...`); nunca una dirección externa","type":["string","null"]},"notes":{"description":"Las notas de crédito y débito que lo referencian (hasta 10)","items":{"properties":{"amount":{"type":["string","null"]},"cfe_type":{"type":"integer"},"cfe_type_name":{"type":"string"},"invoice_id":{"format":"uuid","type":"string"},"number":{"type":"integer"},"series":{"type":"string"},"status":{"description":"El estado en la DGI","enum":["PENDING","ACCEPTED","REJECTED","CANCELLED"],"type":"string"}},"required":["invoice_id","cfe_type","cfe_type_name","series","number","status","amount"],"type":"object"},"type":"array"},"number":{"type":"integer"},"order":{"description":"La orden de la que salió","properties":{"number":{"description":"`ORD-0000000012`","type":["string","null"]},"order_id":{"format":"uuid","type":"string"}},"required":["order_id","number"],"type":["object","null"]},"receiver":{"properties":{"document":{"type":"string"},"document_type":{"description":"`ruc`, `ci`, `passport`, `dni`, `nife` u `other`","type":["string","null"]},"name":{"type":["string","null"]}},"required":["document_type","document","name"],"type":["object","null"]},"series":{"type":"string"},"source":{"description":"La herramienta que la armó (`search_invoices`, `sales_report`...)","type":"string"},"status":{"description":"El estado en la DGI","enum":["PENDING","ACCEPTED","REJECTED","CANCELLED"],"type":"string"},"status_label":{"type":"string"},"total":{"description":"Importe decimal, como texto","type":"string"}},"required":["kind","source","id","cfe_type","cfe_type_name","series","number","issue_date","currency","total","status","status_label","receiver","order","notes","link"],"type":"object"},"AssistantMessage":{"properties":{"activity":{"items":{"properties":{"label":{"type":"string"},"skill":{"description":"La habilidad de la herramienta; `null` para `decline` o una que no existe","type":["string","null"]},"state":{"enum":["done","error","not_allowed"],"type":"string"},"tool":{"type":"string"}},"required":["tool","label","state"],"type":"object"},"type":"array"},"cards":{"description":"Las tarjetas que se mostraron con la respuesta, en orden","items":{"$ref":"#/components/schemas/AssistantCard"},"type":"array"},"created_at":{"format":"date-time","type":"string"},"kind":{"enum":["person","model","tool_results"],"type":"string"},"orders":{"items":{"$ref":"#/components/schemas/Order"},"type":"array"},"outcome":{"enum":["answered","refused","failed","stopped",null],"type":["string","null"]},"role":{"enum":["user","assistant"],"type":"string"},"seq":{"type":"integer"},"text":{"type":["string","null"]}},"required":["seq","role","kind","text","orders","activity","cards","outcome","created_at"],"type":"object"},"AssistantMessageRequest":{"additionalProperties":false,"properties":{"text":{"description":"El mensaje; el tope es `limits.max_message_chars` (2.000 por defecto)","maxLength":10000,"minLength":1,"type":"string"}},"required":["text"],"type":"object"},"AssistantOrderCard":{"description":"Una orden de la empresa, con el comprobante en que se convirtió.","properties":{"cfe_type":{"type":"integer"},"cfe_type_name":{"type":"string"},"currency":{"type":"string"},"id":{"format":"uuid","type":"string"},"invoice":{"properties":{"cfe_type":{"type":["integer","null"]},"invoice_id":{"format":"uuid","type":"string"},"number":{"type":["integer","null"]},"series":{"type":["string","null"]},"status":{"type":["string","null"]},"status_label":{"type":["string","null"]}},"required":["invoice_id","cfe_type","series","number","status","status_label"],"type":["object","null"]},"kind":{"const":"order","type":"string"},"link":{"description":"Ruta del portal (`/app/...`); nunca una dirección externa","type":["string","null"]},"number":{"description":"`ORD-0000000012`","type":"string"},"receiver":{"properties":{"document":{"type":"string"},"document_type":{"description":"`ruc`, `ci`, `passport`, `dni`, `nife` u `other`","type":["string","null"]},"name":{"type":["string","null"]}},"required":["document_type","document","name"],"type":["object","null"]},"source":{"description":"La herramienta que la armó (`search_invoices`, `sales_report`...)","type":"string"},"state":{"enum":["OPEN","EXECUTED","CANCELLED","EXPIRED"],"type":"string"},"state_label":{"type":"string"},"total":{"description":"Importe decimal, como texto","type":"string"}},"required":["kind","source","id","number","state","state_label","cfe_type","cfe_type_name","currency","total","receiver","invoice","link"],"type":"object"},"AssistantPrompt":{"properties":{"current":{"type":"string"},"edited":{"type":"boolean"},"history":{"items":{"$ref":"#/components/schemas/AssistantPromptVersion"},"type":"array"},"kind":{"enum":["system","guardrails","skill"],"type":"string"},"max_chars":{"type":"integer"},"name":{"type":"string"},"original":{"type":"string"},"path":{"description":"El archivo del repositorio: el original","type":"string"},"summary":{"type":"string"},"title":{"type":"string"}},"required":["name","current","original","edited","history"],"type":"object"},"AssistantPromptRequest":{"additionalProperties":false,"properties":{"body":{"maxLength":20000,"type":"string"},"reason":{"type":["string","null"]}},"required":["body"],"type":"object"},"AssistantPromptVersion":{"properties":{"at":{"format":"date-time","type":"string"},"body":{"description":"null: volvió al original","type":["string","null"]},"by":{"type":"string"},"id":{"type":"integer"},"original":{"type":"boolean"},"reason":{"type":["string","null"]}},"required":[],"type":"object"},"AssistantProvider":{"properties":{"activated_at":{"format":"date-time","type":["string","null"]},"activated_by":{"type":["string","null"]},"base_url":{"type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"created_by":{"type":"string"},"data_location":{"type":"string"},"data_location_confirmed":{"type":"boolean"},"id":{"format":"uuid","type":"string"},"key_last4":{"description":"Lo único que se vuelve a mostrar de la clave","type":"string"},"label":{"type":"string"},"model":{"type":"string"},"price_input_per_mtok":{"type":["string","null"]},"price_output_per_mtok":{"type":["string","null"]},"provider":{"enum":["anthropic","openai","openai_compatible"],"type":"string"},"retired_at":{"format":"date-time","type":["string","null"]},"state":{"enum":["testing","passed","failed","active","retired"],"type":"string"},"test":{"oneOf":[{"$ref":"#/components/schemas/AssistantSmokeReport"},{"type":"null"}]},"tested_at":{"format":"date-time","type":["string","null"]}},"required":["id","provider","model","key_last4","state"],"type":"object"},"AssistantProviderActivateRequest":{"additionalProperties":false,"properties":{"id":{"format":"uuid","type":"string"},"reason":{"type":["string","null"]}},"required":["id"],"type":"object"},"AssistantProviderTestRequest":{"additionalProperties":false,"properties":{"api_key":{"description":"Se guarda cifrada con la clave maestra y nunca se vuelve a mostrar (solo sus últimos cuatro caracteres)","type":["string","null"]},"base_url":{"description":"Solo `openai_compatible`: la dirección de su API, hasta `/v1`","type":["string","null"]},"data_location":{"description":"Solo `openai_compatible`: dónde procesa los datos","maxLength":200,"type":["string","null"]},"data_location_confirmed":{"default":false,"type":"boolean"},"model":{"maxLength":100,"type":"string"},"price_input_per_mtok":{"description":"US$ por millón de tokens, de 0 a 1000; sin él, el del entorno","type":["string","number","null"]},"price_output_per_mtok":{"description":"US$ por millón de tokens, de 0 a 1000; sin él, el del entorno","type":["string","number","null"]},"provider":{"enum":["anthropic","openai","openai_compatible"],"type":"string"},"reason":{"type":["string","null"]}},"required":["provider","model"],"type":"object"},"AssistantReceiverCard":{"description":"Un cliente que la empresa ya usó, con su último comprobante.","properties":{"city":{"type":["string","null"]},"document":{"type":"string"},"document_type":{"type":["string","null"]},"kind":{"const":"receiver","type":"string"},"last_invoice":{"properties":{"cfe_type":{"type":"integer"},"cfe_type_name":{"type":"string"},"currency":{"type":"string"},"invoice_id":{"format":"uuid","type":"string"},"issue_date":{"format":"date","type":"string"},"number":{"type":"integer"},"series":{"type":"string"},"status":{"description":"El estado en la DGI","enum":["PENDING","ACCEPTED","REJECTED","CANCELLED"],"type":"string"},"status_label":{"type":"string"},"total":{"type":"string"}},"required":["invoice_id","cfe_type","cfe_type_name","series","number","issue_date","currency","total","status","status_label"],"type":["object","null"]},"last_used":{"format":"date","type":"string"},"link":{"description":"Ruta del portal (`/app/...`); nunca una dirección externa","type":["string","null"]},"name":{"type":["string","null"]},"source":{"description":"La herramienta que la armó (`search_invoices`, `sales_report`...)","type":"string"}},"required":["kind","source","document_type","document","name","city","last_used","last_invoice","link"],"type":"object"},"AssistantSmokeReport":{"properties":{"calls":{"type":"integer"},"cases":{"type":"integer"},"cost_micro_usd":{"type":"integer"},"passed":{"type":"boolean"},"passed_cases":{"type":"integer"},"results":{"items":{"properties":{"answer":{"type":"string"},"category":{"type":"string"},"id":{"type":"string"},"outcome":{"type":"string"},"passed":{"type":"boolean"},"text":{"type":"string"},"tools":{"items":{"properties":{"state":{"type":"string"},"tool":{"type":"string"}},"required":[],"type":"object"},"type":"array"},"why":{"items":{"type":"string"},"type":"array"}},"required":[],"type":"object"},"type":"array"},"stopped":{"type":["string","null"]}},"required":[],"type":"object"},"AssistantStatus":{"description":"Si el asistente está disponible para esta persona, por qué no, sus límites y lo usado este mes por la empresa.","properties":{"available":{"type":"boolean"},"can_create_orders":{"description":"Si la persona tiene `invoices:write`: sin él, el asistente no prepara órdenes","type":"boolean"},"enabled":{"type":"boolean"},"included":{"type":"boolean"},"instructions_version":{"description":"La versión de las instrucciones y las reglas","type":"string"},"limits":{"properties":{"max_conversation_tokens":{"type":"integer"},"max_message_chars":{"type":"integer"},"max_tool_iterations":{"type":"integer"},"max_turns":{"type":"integer"},"per_user_per_minute":{"type":"integer"},"retention_days":{"type":"integer"}},"required":["max_message_chars","max_turns","max_conversation_tokens","per_user_per_minute","max_tool_iterations","retention_days"],"type":"object"},"model":{"description":"El modelo (`CFE_ASSISTANT_MODEL`); vacío sin la clave","type":["string","null"]},"provider":{"const":"Anthropic","type":"string"},"reason":{"description":"`not_configured`: la instalación no tiene la clave del proveedor; `not_included`: el plan no lo incluye (`assistant.included`); `not_enabled`: el dueño no lo prendió (`assistant.enabled`); `view_as`: el personal mira como el cliente","enum":["not_configured","not_included","not_enabled","view_as",null],"type":["string","null"]},"usage":{"properties":{"messages":{"type":"integer"},"messages_max":{"type":["integer","null"]},"resets_at":{"format":"date-time","type":"string"},"tokens":{"type":"integer"},"tokens_max":{"type":["integer","null"]}},"required":["messages","messages_max","tokens","tokens_max","resets_at"],"type":"object"}},"required":["available","reason","included","enabled","provider","model","instructions_version","can_create_orders","limits","usage"],"type":"object"},"AssistantTableCard":{"description":"Filas y columnas: un reporte (ventas, emisiones, el listado de comprobantes), los rangos de CAE, los envíos a la DGI, los productos. Un reporte trae además sus totales, cuántas filas tiene, sus parámetros y dónde descargarlo entero; el portal muestra las primeras 10 filas.","properties":{"columns":{"items":{"properties":{"key":{"description":"El miembro de cada fila","type":"string"},"kind":{"description":"Cómo se muestra el valor (`month`: `AAAA-MM`)","enum":["text","money","count","number","date","month","percent"],"type":"string"},"label":{"type":"string"}},"required":["key","label","kind"],"type":"object"},"type":"array"},"currency":{"description":"Un informe que lee una sola moneda la nombra (la pedida, o pesos)","type":["string","null"]},"download":{"description":"Dónde descargar el reporte entero, cuando tiene más filas de las que se muestran","properties":{"format":{"const":"csv","type":"string"},"max_rows":{"description":"Las filas que tiene como máximo una descarga (100.000)","type":"integer"},"path":{"description":"`GET` de la API: `/v1/assistant/conversations/{id}/reports/{report_id}/download`","type":"string"},"report_id":{"format":"uuid","type":"string"}},"required":["report_id","path","format","max_rows"],"type":["object","null"]},"kind":{"const":"table","type":"string"},"link":{"description":"Ruta del portal (`/app/...`); nunca una dirección externa","type":["string","null"]},"note":{"description":"Una aclaración (el período recortado, las filas que no se muestran)","type":["string","null"]},"parameters":{"additionalProperties":true,"description":"Con qué se generó un reporte: `from`, `to` (AAAA-MM-DD) y, según el reporte, `group_by`, `cfe_type`, `status`, `receiver_document`","type":["object","null"]},"rows":{"description":"Las primeras filas (hasta 10), un objeto por fila con un miembro por `columns[].key`; también puede traer `link`","items":{"additionalProperties":true,"type":"object"},"maxItems":10,"type":"array"},"rows_capped":{"description":"El reporte tiene más de 100.000 filas: se descargan las primeras","type":"boolean"},"rows_total":{"description":"Cuántas filas tiene la tabla entera (sin los totales); un listado se cuenta hasta 100.000","minimum":0,"type":"integer"},"source":{"description":"La herramienta que la armó (`search_invoices`, `sales_report`...)","type":"string"},"title":{"type":"string"},"totals":{"description":"Los totales del reporte entero, con las mismas columnas (uno por moneda en las ventas; uno en los conteos; ninguno en un listado)","items":{"additionalProperties":true,"type":"object"},"type":"array"}},"required":["kind","source","title","columns","rows","note","link"],"type":"object"},"CaeRange":{"allOf":[{"$ref":"#/components/schemas/CaeRangeRequest"},{"properties":{"available":{"description":"Números que el rango todavía puede usar: `0` si está vencido (pasó `expires_on`) o retirado (`withdrawn_at`). Los números sin usar de un rango vencido se siguen anulando con `POST /v1/annulments` (de `next_number` a `last_number`), como pide la DGI","type":"integer"},"cfe_type_name":{"type":"string"},"explicit_numbers":{"description":"Se usaron números suyos fuera de la secuencia (reemisión E09, papel de contingencia): la numeración saltea lo que la serie ya usó, y un rango de contingencia con papeles no se numera en línea","type":"boolean"},"id":{"format":"uuid","type":"string"},"issuer_ruc":{"description":"`RucE`, si el rango vino del archivo de DGI","type":["string","null"]},"next_number":{"type":"integer"},"signature":{"description":"Firma del archivo de DGI: VALID (certificado de DGI configurado) o UNPINNED (verifica con el certificado que trae; no hay certificado de DGI configurado); `null` si se declaró a mano","enum":["VALID","UNPINNED",null],"type":["string","null"]},"withdrawn_at":{"description":"Cuándo dejó de numerar: se cargó después otro rango del mismo tipo y serie que comparte números (el último cargado es el que numera)","format":"date-time","type":["string","null"]},"withdrawn_reason":{"type":["string","null"]}},"type":"object"}]},"CaeRangeRequest":{"properties":{"authorized_on":{"description":"`FA`: fecha en que DGI autorizó el rango. Con ella, `expires_on` es a lo sumo `FA` + 24 meses calendario (A-C10); uno anterior es un vencimiento especial y se acepta solo con `special_expiry`","format":"date","type":"string"},"cae_id":{"type":"string"},"cfe_type":{"type":"integer"},"expires_on":{"format":"date","type":"string"},"first_number":{"minimum":1,"type":"integer"},"last_number":{"type":"integer"},"series":{"description":"Serie: un rango nuevo lleva una o dos letras, de `A` a `ZZ` (Formato CAE v05, A-C4). Un rango ya guardado en `1A` (el `SerieType` del XSD lo admite) sigue numerando","maxLength":2,"type":"string"},"special":{"description":"`CAEEspecial`: 1 exonerado, 2 IVA mínimo, 3 Monotributo, 4 Monotributo Social MIDES","enum":[1,2,3,4],"type":"integer"},"special_cause":{"description":"`CausalCAEEsp`: obligatoria con `special` 1, no admitida con otro","maximum":999,"minimum":1,"type":"integer"},"special_expiry":{"default":false,"description":"Con `authorized_on`: el vencimiento es el especial que dio la DGI, anterior a `FA` + 24 meses (A-C10, «la menor de los plazos»). Sin esto, un vencimiento anterior se rechaza (`422`, campo `FVD`) por ser probablemente un error de tipeo. En la respuesta: si el vencimiento es anterior a `FA` + 24 meses; `false` sin `FA`","type":"boolean"},"special_norm":{"description":"Sólo con `special` 1: la referencia a la norma que otorga la exoneración, impresa tras «Contribuyente Exonerado» en cada CFE del rango (Formato CFE p. 81; FAQ 8.19). El archivo de CAE trae sólo el código de la causal (FAQ 4.40), así que un rango cargado desde el archivo toma su norma declarando el mismo CAE acá con `special_norm`; volver a declararlo sin ella la conserva. En blanco, sólo la frase.","examples":["Literal E) art. 52 Título 4 T.O. 2023"],"maxLength":150,"type":["string","null"]}},"required":["cae_id","cfe_type","series","first_number","last_number","expires_on"],"type":"object"},"CatalogCfeType":{"properties":{"adjustment_indicators":{"items":{"type":"integer"},"type":"array"},"code":{"type":"integer"},"contingency":{"type":"boolean"},"credit_note":{"type":["integer","null"]},"debit_note":{"type":["integer","null"]},"default_indicator":{"type":["integer","null"]},"description":{"type":"string"},"family":{"type":"string"},"family_label":{"type":"string"},"fields":{"additionalProperties":{"$ref":"#/components/schemas/CatalogFieldRule"},"type":"object"},"indicators":{"description":"`lines[].indicator`, con el número de la DGI; algunos sólo bajo una condición del campo","items":{"type":"integer"},"type":"array"},"kind":{"enum":["document","credit_note","debit_note"],"type":"string"},"kind_label":{"type":"string"},"max_lines":{"type":["integer","null"]},"name":{"description":"Tabla A, como sale impreso","type":"string"},"referenceable_types":{"items":{"type":"integer"},"type":"array"},"rules_of":{"description":"El tipo en línea cuyas reglas sigue un tipo de contingencia","type":"integer"},"sections":{"additionalProperties":{"enum":["required","optional","forbidden","conditional"],"type":"string"},"type":"object"},"thermal_roll":{"type":"boolean"},"third_party":{"type":"boolean"}},"type":"object"},"CatalogCfeTypes":{"properties":{"dates":{"$ref":"#/components/schemas/CatalogDates"},"integration":{"additionalProperties":true,"description":"Lo que la solicitud puede incluir además del comprobante.","properties":{"sandbox":{"properties":{"active":{"description":"Si quien pregunta es una clave de prueba","type":"boolean"},"key_prefix":{"const":"cfe_test_","type":"string"},"outcome_header":{"const":"Cfe-Sandbox-Outcome","type":"string"},"outcomes":{"items":{"type":"string"},"type":"array"},"series":{"const":"SB","type":"string"}},"type":"object"}},"type":"object"},"types":{"items":{"$ref":"#/components/schemas/CatalogCfeType"},"type":"array"}},"type":"object"},"CatalogCode":{"properties":{"label":{"type":"string"},"value":{"description":"Lo que va en el JSON"}},"type":"object"},"CatalogCodes":{"properties":{"adjustment_kinds":{"items":{"$ref":"#/components/schemas/CatalogCode"},"type":"array"},"adjustment_movements":{"items":{"$ref":"#/components/schemas/CatalogCode"},"type":"array"},"agent_roles":{"items":{"$ref":"#/components/schemas/CatalogCode"},"type":"array"},"billing_indicators":{"items":{"properties":{"code":{"type":"integer"},"families":{"items":{"type":"string"},"type":"array"},"label":{"type":"string"},"value":{"type":"string"}},"type":"object"},"type":"array"},"countries":{"items":{"properties":{"code":{"type":"string"},"label":{"type":"string"}},"type":"object"},"type":"array"},"currencies":{"items":{"properties":{"bcu_quoted":{"type":"boolean"},"code":{"type":"string"}},"type":"object"},"type":"array"},"dgi_contact_codes":{"description":"Los contactos que `POST /v1/tenant/dgi-contacts` actualiza en la DGI (`ws_efacsolicitud`): `code` 20 (correo técnico) y 19 (URL `https` del web service), con `kind` (`email` o `url`) y su nombre.","items":{"properties":{"code":{"type":"integer"},"kind":{"enum":["email","url"],"type":"string"},"label":{"type":"string"}},"required":["code","kind","label"],"type":"object"},"type":"array"},"dgi_states":{"description":"Estados que responde la DGI: de un sobre (`AS`, `BS`, `BA`), de cada CFE (`AE`, `BE`, `CE`, `FE`) y de un reporte diario (`AR`, `BR`), con lo que significan (`outcome`: `received`, `rejected`, `observed`, `reliquidated`) y su nombre en el idioma de la solicitud.","items":{"properties":{"code":{"type":"string"},"label":{"type":"string"},"of":{"enum":["envelope","document","report"],"type":"string"},"outcome":{"enum":["received","rejected","observed","reliquidated"],"type":"string"}},"required":["code","of","outcome","label"],"type":"object"},"type":"array"},"document_types":{"items":{"properties":{"check_digit":{"enum":["ruc","ci",null],"type":["string","null"]},"code":{"type":"integer"},"countries":{"description":"`null`: cualquiera","items":{"type":"string"},"type":["array","null"]},"fiscal_complement":{"type":"boolean"},"label":{"type":"string"},"max_length":{"type":["integer","null"]},"min_length":{"type":["integer","null"]},"recipient":{"type":"boolean"},"value":{"type":"string"},"waybill_owner":{"type":"boolean"}},"type":"object"},"type":"array"},"gross_amounts":{"items":{"$ref":"#/components/schemas/CatalogCode"},"type":"array"},"item_code_types":{"items":{"properties":{"check_digit":{"type":["string","null"]},"length":{"type":["integer","null"]},"value":{"type":"string"}},"type":"object"},"type":"array"},"iva_status":{"items":{"$ref":"#/components/schemas/CatalogCode"},"type":"array"},"ownership_indicators":{"items":{"$ref":"#/components/schemas/CatalogCode"},"type":"array"},"payment":{"items":{"$ref":"#/components/schemas/CatalogCode"},"type":"array"},"professional_secrecy":{"items":{"$ref":"#/components/schemas/CatalogCode"},"type":"array"},"purchase_for_resale":{"items":{"$ref":"#/components/schemas/CatalogCode"},"type":"array"},"rejection_causes":{"description":"Motivos que un receptor puede dar al rechazar un CFE que recibió (`POST /v1/received-envelopes/{id}/rejections`): los comerciales `E20` a `E60` primero, después `E02` a `E07` y `E10` a `E12`. `gloss` es lo que lleva el `ACKCFE` (el texto de la DGI, en español); `label`, en el idioma de la solicitud.","items":{"properties":{"code":{"type":"string"},"commercial":{"type":"boolean"},"gloss":{"type":"string"},"label":{"type":"string"}},"required":["code","gloss","label","commercial"],"type":"object"},"type":"array"},"sale_keys":{"properties":{"max_length":{"type":"integer"},"min_length":{"type":"integer"},"suggested":{"items":{"type":"string"},"type":"array"}},"type":"object"},"sale_modalities":{"items":{"$ref":"#/components/schemas/CatalogCode"},"type":"array"},"special_cae":{"items":{"$ref":"#/components/schemas/CatalogCode"},"type":"array"},"transfer_types":{"items":{"$ref":"#/components/schemas/CatalogCode"},"type":"array"},"transport_modes":{"items":{"$ref":"#/components/schemas/CatalogCode"},"type":"array"},"withholding_codes":{"properties":{"codes":{"items":{"properties":{"agent":{"type":"string"},"code":{"type":"string"},"role":{"type":"string"},"subject":{"type":"string"}},"type":"object"},"type":"array"},"forms":{"items":{"type":"string"},"type":"array"},"unadministered_from":{"type":"string"},"unadministered_to":{"type":"string"}},"type":"object"}},"type":"object"},"CatalogDateBound":{"description":"Un límite de una fecha: un día (`date`), hoy en Uruguay más días (`today_plus_days`), la fecha de emisión más días, el fin del mes de emisión o el valor de otro campo (`field`).","properties":{"date":{"format":"date","type":"string"},"end_of_issue_month":{"type":"boolean"},"field":{"type":"string"},"issue_date_plus_days":{"type":"integer"},"today_plus_days":{"type":"integer"}},"type":"object"},"CatalogDates":{"properties":{"days_ahead":{"type":"integer"},"earliest":{"format":"date","type":"string"},"earliest_due":{"format":"date","type":"string"},"latest":{"format":"date","type":"string"},"today":{"description":"Hoy en Uruguay según el servidor: desde acá cuentan los `today_plus_days`","format":"date","type":"string"},"ui_cap":{"items":{"properties":{"from":{"format":"date","type":"string"},"to":{"format":"date","type":["string","null"]},"units":{"type":"string"}},"type":"object"},"type":"array"},"utc_offset":{"type":"string"}},"type":"object"},"CatalogFieldRule":{"properties":{"catalog":{"description":"Los valores son los códigos de esa tabla de `GET /v1/catalog/codes` (`currencies`, `countries`, `withholding_codes`).","type":"string"},"conditions":{"description":"Lo que cambia cuando se cumple `when`: la presencia, los valores o los dos.","items":{"properties":{"presence":{"enum":["required","optional","forbidden"],"type":"string"},"values":{"items":{},"type":"array"},"when":{"items":{"$ref":"#/components/schemas/CatalogWhen"},"type":"array"}},"type":"object"},"type":"array"},"decimals":{"type":"integer"},"example":{"description":"Un valor que el validador acepta acá."},"integers":{"description":"Dígitos enteros.","type":"integer"},"max":{"type":"integer"},"max_date":{"$ref":"#/components/schemas/CatalogDateBound"},"max_items":{"type":"integer"},"max_length":{"type":"integer"},"max_value":{"description":"El mayor valor cuando es menor que lo que dan sus enteros (`\"100\"` en un porcentaje).","type":"string"},"min":{"type":"integer"},"min_date":{"$ref":"#/components/schemas/CatalogDateBound"},"min_length":{"type":"integer"},"presence":{"enum":["required","optional","forbidden"],"type":"string"},"requires":{"description":"Lo que tiene que ir con el campo para que se acepte.","items":{"$ref":"#/components/schemas/CatalogWhen"},"type":"array"},"sign":{"enum":["positive","non_negative","any"],"type":"string"},"tenant":{"description":"`fills`: si falta, la API lo toma del perfil del emisor (`/v1/tenant`); `must_match`: tiene que ser el del emisor.","enum":["fills","must_match"],"type":"string"},"type":{"description":"`decimal`: un número escrito como texto (`\"190.50\"`); `date`: `YYYY-MM-DD`.","enum":["string","decimal","date","integer","boolean","object","array"],"type":"string"},"values":{"description":"Los valores que toma, tal como van en el JSON.","items":{},"type":"array"}},"required":["presence","type"],"type":"object"},"CatalogWhen":{"description":"Cuándo rige una condición: el campo `path` vale `equals`, no vale `not_equals`, está (`present: true`) o no (`present: false`); `above_ui_cap`: el neto en pesos supera el tope de la Tabla E (`GET /v1/rates`, `ui_cap`).","properties":{"above_ui_cap":{"type":"boolean"},"equals":{},"not_equals":{},"path":{"type":"string"},"present":{"type":"boolean"}},"type":"object"},"CertificateInfo":{"description":"Metadatos de un certificado. Nunca incluye la clave privada.","properties":{"chain":{"description":"Cadena del certificado hasta las CA acreditadas de PKI Uruguay (`certificates/ca/`), verificada al subirlo.","properties":{"code":{"description":"Con `UNTRUSTED`, por qué no encadena: `chain_unreadable` (no se puede leer el certificado o una CA del camino), `chain_is_ca` (es el certificado de una CA de la lista, no el de un firmante), `chain_untrusted` (lo emitió una CA que no está en la lista de PKI Uruguay), `chain_signature_invalid` (la firma de un eslabón no verifica con la clave de su CA), `chain_ca_cannot_sign` (una CA del camino no puede firmar certificados, keyUsage), `chain_path_length` (una CA admite menos CA debajo, pathLenConstraint), `chain_expired` (una CA del camino no estaba vigente cuando se firmó) y `chain_too_long` (el camino es más largo que cualquiera de PKI Uruguay). La pantalla dice la frase a partir del código; `detail` nombra las CA en inglés","enum":["chain_unreadable","chain_is_ca","chain_untrusted","chain_signature_invalid","chain_ca_cannot_sign","chain_path_length","chain_expired","chain_too_long"],"type":"string"},"detail":{"description":"Por qué no es `VALID`, en inglés y con los nombres de las CA (el texto del control)","type":"string"},"status":{"description":"`NOT_CHECKED`: subido antes de que existiera el control","enum":["VALID","UNTRUSTED","NOT_CHECKED"],"type":"string"}},"required":["status"],"type":"object"},"days_to_expiry":{"description":"Días enteros que faltan; negativo si venció","type":"integer"},"fingerprint_sha256":{"description":"SHA-256 del DER, en hexadecimal","type":"string"},"id":{"format":"uuid","type":"string"},"issuer":{"description":"`X509IssuerName` tal como lo escribe la firma","type":"string"},"key":{"description":"La clave del certificado. Se aceptan claves RSA de 2048 a 8192 bits; uno guardado antes de esa regla sigue firmando con `supported: false`, y conviene reemplazarlo.","properties":{"algorithm":{"enum":["RSA","OTHER"],"type":"string"},"bits":{"description":"El tamaño de una clave RSA","type":["integer","null"]},"supported":{"description":"`false`: la clave no cumple la regla actual; suba un certificado nuevo","type":"boolean"}},"required":["algorithm","bits","supported"],"type":"object"},"not_after":{"format":"date-time","type":"string"},"not_before":{"format":"date-time","type":"string"},"revocation":{"description":"Lo que se sabe de su revocación (CRL de la CA, u OCSP si la CRL no responde). Lo actualiza el pase de fondo cada `CFE_PKI_REFRESH_SECONDS`; solo `REVOKED` bloquea la firma (salvo `CFE_PKI_REVOCATION=hard`).","properties":{"checked_at":{"format":"date-time","type":"string"},"detail":{"type":"string"},"reason":{"description":"Motivo RFC 5280 (`KeyCompromise`, `CessationOfOperation`...)","type":"string"},"revoked_at":{"format":"date-time","type":"string"},"source":{"enum":["CRL","OCSP"],"type":"string"},"status":{"enum":["GOOD","REVOKED","UNKNOWN","NOT_CHECKED"],"type":"string"}},"required":["status"],"type":"object"},"ruc":{"description":"RUC encontrado en el subject; es el del emisor","type":"string"},"serial":{"description":"`X509SerialNumber`, decimal","type":"string"},"status":{"enum":["valid","expiring","expired","not_yet_valid","revoked"],"type":"string"},"subject":{"type":"string"},"superseded_at":{"description":"Solo en el historial: cuándo lo reemplazó otro","format":"date-time","type":"string"},"uploaded_at":{"format":"date-time","type":"string"},"uploaded_by":{"format":"uuid","type":["string","null"]}},"required":["id","subject","issuer","serial","ruc","fingerprint_sha256","not_before","not_after","days_to_expiry","status","uploaded_at","chain","revocation","key"],"type":"object"},"CertificateStatus":{"properties":{"certificate":{"oneOf":[{"$ref":"#/components/schemas/CertificateInfo"},{"type":"null"}]},"history":{"description":"Certificados anteriores, el más reciente primero","items":{"$ref":"#/components/schemas/CertificateInfo"},"type":"array"},"signs_with":{"description":"Con qué se firman los documentos nuevos: el certificado propio, el de plataforma (desarrollo o un despliegue de un solo emisor) o nada (el tenant no puede emitir)","enum":["tenant","platform","none"],"type":"string"},"status":{"description":"`expiring`: vence en menos de 30 días; `revoked`: la CA lo revocó y no firma documentos nuevos","enum":["valid","expiring","expired","not_yet_valid","revoked","missing"],"type":"string"}},"required":["status","signs_with","certificate","history"],"type":"object"},"CertificateUpload":{"description":"Un archivo PKCS#12 (`.p12`/`.pfx`, en Base64) con su contraseña, o un par PEM (certificado y clave privada sin contraseña). Se verifica que la clave sea la del certificado, que sea RSA, que el subject tenga el RUC del emisor y que esté vigente. PKCS#12 con PBES2/AES (OpenSSL 3), 3DES o el RC2 de las exportaciones viejas (`openssl pkcs12 -legacy`, Windows, Java); uno sin MAC de integridad responde `certificate_without_integrity`. Los errores vienen en el idioma de `Accept-Language`.","oneOf":[{"required":["pkcs12"]},{"required":["certificate_pem","private_key_pem"]}],"properties":{"certificate_pem":{"type":"string"},"password":{"format":"password","type":"string"},"pkcs12":{"contentEncoding":"base64","type":"string"},"private_key_pem":{"format":"password","type":"string"}},"type":"object"},"CfeTypeSelection":{"description":"Cómo se eligió el tipo, cuando la solicitud pidió `cfe_type: \"auto\"` (o no mandó tipo). Falta si la solicitud indicó el tipo","properties":{"chosen":{"enum":[111,101],"type":"integer"},"detail":{"type":"string"},"reason":{"enum":["recipient_has_ruc","recipient_without_ruc"],"type":"string"},"requested":{"enum":["auto"],"type":"string"}},"required":["requested","chosen","reason","detail"],"type":"object"},"ClientActivity":{"properties":{"events":{"items":{"$ref":"#/components/schemas/ClientEvent"},"type":"array"},"next":{"type":["string","null"]}},"type":"object"},"ClientEvent":{"properties":{"at":{"format":"date-time","type":"string"},"detail":{"type":"object"},"id":{"type":"string"},"kind":{"enum":["change","report","rejection","envelope_rejected","expiry","limit_alert"],"type":"string"},"title":{"type":"string"}},"type":"object"},"ClientHealth":{"properties":{"can_emit":{"type":"boolean"},"flags":{"items":{"$ref":"#/components/schemas/HealthFlag"},"type":"array"},"status":{"description":"La peor señal (`info` cuenta como `ok`); `offboarded` para un dado de baja que no le debe nada a la DGI","enum":["ok","warning","critical","offboarded"],"type":"string"}},"type":"object"},"ClientOverview":{"description":"La ficha de un cliente: las pestañas Resumen, Certificado y CAE, DGI e intercambio, Usuarios y claves, y el resumen de Configuración y Notas.","properties":{"api_keys":{"items":{"$ref":"#/components/schemas/ApiKey"},"type":"array"},"cae":{"items":{"properties":{"cfe_type":{"type":"integer"},"exhausted":{"type":"boolean"},"expiring":{"type":"boolean"},"last_expiry":{"format":"date","type":["string","null"]},"low":{"type":"boolean"},"ranges":{"type":"integer"},"soonest_expiry":{"format":"date","type":["string","null"]},"usable":{"type":"integer"}},"type":"object"},"type":"array"},"certificate":{"properties":{"days_left":{"type":"integer"},"issuer":{"type":"string"},"key":{"description":"La clave del certificado. Se aceptan claves RSA de 2048 a 8192 bits; uno guardado antes de esa regla sigue firmando con `supported: false`, y conviene reemplazarlo.","properties":{"algorithm":{"enum":["RSA","OTHER"],"type":"string"},"bits":{"description":"El tamaño de una clave RSA","type":["integer","null"]},"supported":{"description":"`false`: la clave no cumple la regla actual; suba un certificado nuevo","type":"boolean"}},"required":["algorithm","bits","supported"],"type":"object"},"not_after":{"format":"date-time","type":"string"},"not_before":{"format":"date-time","type":"string"},"serial":{"type":"string"},"state":{"enum":["valid","expiring","expired"],"type":"string"},"subject":{"type":"string"},"uploaded_at":{"format":"date-time","type":"string"}},"type":["object","null"]},"configuration":{"properties":{"disabled":{"items":{"type":"string"},"type":"array"},"fingerprint":{"type":"string"},"from_membership":{"items":{"type":"string"},"type":"array"},"overrides":{"items":{"type":"string"},"type":"array"}},"type":"object"},"dgi":{"properties":{"backlog":{"properties":{"oldest_pending":{"format":"date-time","type":["string","null"]},"pending":{"type":"integer"}},"type":"object"},"failed":{"items":{"format":"date","type":"string"},"type":"array"},"in_progress":{"type":"integer"},"last_received":{"format":"date","type":["string","null"]},"mail":{"type":["object","null"]},"overdue":{"items":{"format":"date","type":"string"},"type":"array"},"rejections":{"type":["object","null"]},"reports":{"items":{"type":"object"},"type":"array"},"schedule_enabled":{"type":"boolean"}},"type":"object"},"health":{"$ref":"#/components/schemas/ClientHealth"},"invitations":{"description":"Las invitaciones a su equipo que todavía no se aceptaron: quien fue invitado no es usuario hasta elegir su contraseña.","items":{"$ref":"#/components/schemas/TeamInvitation"},"type":"array"},"links":{"additionalProperties":{"type":"string"},"type":"object"},"membership":{"description":"La membresía como `GET /v1/usage` (`plan_code`, `class`, `state`, `can_emit`…) más `stored_state`, `state_reason`, `overrides`, `limits[]` y `alerts[]`","type":["object","null"]},"notes":{"properties":{"count":{"type":"integer"},"pinned":{"items":{"$ref":"#/components/schemas/StaffNote"},"type":"array"}},"type":"object"},"offboarding":{"properties":{"completed_at":{"format":"date-time","type":["string","null"]},"last_day":{"format":"date","type":"string"},"reason":{"type":"string"},"requested_at":{"format":"date-time","type":"string"},"requested_by":{"format":"uuid","type":["string","null"]},"requested_by_email":{"type":["string","null"]}},"type":["object","null"]},"tenant":{"$ref":"#/components/schemas/AdminTenantDetail"},"users":{"items":{"$ref":"#/components/schemas/ConsoleTenantUser"},"type":"array"},"view_sessions":{"items":{"$ref":"#/components/schemas/ViewSession"},"type":"array"}},"type":"object"},"ClientPage":{"properties":{"counts":{"properties":{"all":{"type":"integer"},"classes":{"additionalProperties":{"type":"integer"},"type":"object"},"health":{"additionalProperties":{"type":"integer"},"type":"object"},"offboarded":{"type":"integer"},"states":{"additionalProperties":{"type":"integer"},"type":"object"}},"type":"object"},"items":{"items":{"$ref":"#/components/schemas/ClientRow"},"type":"array"},"next_cursor":{"type":["string","null"]},"total":{"type":"integer"}},"type":"object"},"ClientRow":{"properties":{"active_api_keys":{"description":"Claves de producción activas; las de prueba están en `sandbox`.","type":"integer"},"certificate_not_after":{"format":"date-time","type":["string","null"]},"class":{"enum":["LIMITED","USAGE",null],"type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"emissions_this_month":{"type":"integer"},"health":{"$ref":"#/components/schemas/ClientHealth"},"id":{"format":"uuid","type":"string"},"last_emission_at":{"format":"date-time","type":["string","null"]},"month_limit":{"description":"El paquete del mes (LIMITED) o el tope de seguridad del mes (USAGE)","type":["integer","null"]},"name":{"type":"string"},"notes":{"type":"integer"},"offboarded":{"type":"boolean"},"offboarded_at":{"format":"date-time","type":["string","null"]},"plan_code":{"type":["string","null"]},"plan_name":{"type":["string","null"]},"received_this_month":{"type":"integer"},"ruc":{"type":"string"},"sandbox":{"description":"Su ambiente de pruebas, si lo tiene: nunca suma en los totales de la plataforma.","oneOf":[{"$ref":"#/components/schemas/ClientSandbox"},{"type":"null"}]},"state":{"enum":["TRIAL","ACTIVE","EXPIRED","SUSPENDED",null],"type":["string","null"]},"usage_percent":{"type":["number","null"]},"users":{"type":"integer"}},"type":"object"},"ClientSandbox":{"properties":{"created_at":{"format":"date-time","type":"string"},"emissions_this_month":{"type":"integer"},"last_emission_at":{"format":"date-time","type":["string","null"]},"test_keys":{"description":"Claves de prueba activas.","type":"integer"}},"type":"object"},"CommercialRejection":{"properties":{"documents":{"items":{"properties":{"causes":{"items":{"$ref":"#/components/schemas/ReceptionCause"},"type":"array"},"document_id":{"format":"uuid","type":"string"}},"type":"object"},"type":"array"},"envelope_id":{"format":"uuid","type":"string"},"file_name":{"description":"`ME_<IDRespuesta>_Sob_<RUC>_<AAAAMMDD>_<Idemisor>.xml`","type":"string"},"id":{"format":"uuid","type":"string"},"message_id":{"description":"El mensaje que lo lleva al emisor; `null` si no se conoce su dirección","format":"uuid","type":["string","null"]},"response_id":{"description":"`IDRespuesta` del nuevo `ACKCFE`","type":"integer"},"xml_url":{"type":"string"}},"required":["id","envelope_id","response_id","file_name","xml_url","documents"],"type":"object"},"CommercialRejectionRequest":{"properties":{"documents":{"items":{"properties":{"causes":{"items":{"properties":{"code":{"description":"`E02`-`E07`, `E10`-`E12` o los comerciales `E20`-`E60` (MR, tabla 4.3)","examples":["E21","E24"],"type":"string"},"detail":{"maxLength":500,"type":"string"}},"required":["code"],"type":"object"},"maxItems":10,"minItems":1,"type":"array"},"document_id":{"format":"uuid","type":"string"}},"required":["document_id","causes"],"type":"object"},"maxItems":250,"minItems":1,"type":"array"},"send":{"description":"Encolarlo a la dirección del emisor (por defecto `true`)","type":"boolean"}},"required":["documents"],"type":"object"},"CompanyDeliveryRequest":{"properties":{"email":{"description":"Por defecto la dirección de intercambio del receptor (la del tenant o la publicada por la DGI)","format":"email","type":"string"},"rut_receptor":{"description":"Si el CFE no tiene receptor RUC","type":"string"}},"type":"object"},"ConfigHistory":{"properties":{"changes":{"items":{"properties":{"actor":{"properties":{"id":{"format":"uuid","type":["string","null"]},"kind":{"enum":["staff","owner","member","api_key","system"],"type":"string"},"name":{"type":["string","null"]},"role":{"type":["string","null"]}},"type":"object"},"after":{},"at":{"format":"date-time","type":"string"},"before":{},"category":{"description":"`feature`, `membership`, `limit`, `account`...","type":"string"},"id":{"type":"integer"},"key":{"type":"string"},"reason":{"type":["string","null"]},"request_id":{"type":["string","null"]}},"type":"object"},"type":"array"},"next":{"description":"`before` de la página siguiente.","type":["integer","null"]}},"type":"object"},"ConsoleTenantUser":{"properties":{"active":{"type":"boolean"},"created_at":{"format":"date-time","type":"string"},"display_name":{"type":"string"},"email":{"type":"string"},"environment":{"description":"`sandbox` para un usuario de prueba de la cuenta (trabaja sólo en su ambiente de pruebas)","enum":["production","sandbox"],"type":"string"},"id":{"format":"uuid","type":"string"},"last_login_at":{"format":"date-time","type":["string","null"]},"pending_link":{"enum":["INVITATION","RESET",null],"type":["string","null"]},"pending_link_expires_at":{"format":"date-time","type":["string","null"]},"role":{"enum":["OWNER","MEMBER"],"type":"string"},"tenant_id":{"format":"uuid","type":"string"}},"type":"object"},"ConsoleUserUpdateRequest":{"properties":{"active":{"type":"boolean"},"reason":{"maxLength":2000,"type":"string"},"role":{"enum":["OWNER","MEMBER"],"type":"string"}},"required":["reason"],"type":"object"},"ContingencyAnnulmentRequest":{"properties":{"cfe_type":{"maximum":282,"minimum":201,"type":"integer"},"number":{"maximum":9999999,"minimum":1,"type":"integer"},"reason":{"maxLength":500,"minLength":1,"type":"string"},"series":{"type":"string"}},"required":["cfe_type","series","number","reason"],"type":"object"},"ContingencyDocument":{"properties":{"action":{"description":"Qué hay que hacer con él, si algo","type":["string","null"]},"annulled_at":{"format":"date-time","type":["string","null"]},"annulled_by":{"type":["string","null"]},"annulled_reason":{"type":["string","null"]},"cfe_type":{"type":"integer"},"cfe_type_name":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"invoice_id":{"description":"La emisión que lo informa a la DGI ahora (la corregida, tras un CE)","format":"uuid","type":["string","null"]},"loaded_by":{"type":"string"},"number":{"type":"integer"},"observations":{"description":"`ObsCFC` del CE (C03-C06, C08-C15)","items":{"properties":{"code":{"type":"string"},"detail":{"type":["string","null"]},"gloss":{"type":"string"}},"type":"object"},"type":"array"},"paper_date":{"description":"Fecha del papel; `null` en un papel anulado sin cargar","format":"date","type":["string","null"]},"range_id":{"format":"uuid","type":"string"},"series":{"type":"string"},"status":{"description":"`OBSERVED`: la DGI lo observó (CE); se informa de nuevo corregido o se anula el papel","enum":["PENDING","RECEIVED","OBSERVED","REJECTED","ANNULLED"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"ContingencyLoadRequest":{"properties":{"invoice":{"allOf":[{"$ref":"#/components/schemas/InvoiceRequest"}],"description":"El documento como dice el papel: tipo 2xx e `issue_date` (la fecha del papel) obligatoria"},"number":{"description":"Número impreso en el papel","maximum":9999999,"minimum":1,"type":"integer"},"series":{"description":"Serie impresa en el papel","type":"string"}},"required":["series","number","invoice"],"type":"object"},"ContingencyLoaded":{"properties":{"document":{"$ref":"#/components/schemas/ContingencyDocument"},"invoice":{"$ref":"#/components/schemas/Invoice"}},"type":"object"},"ContingencyRange":{"properties":{"cae_id":{"type":"string"},"cfe_type":{"type":"integer"},"cfe_type_name":{"type":"string"},"expires_on":{"format":"date","type":"string"},"first_number":{"type":"integer"},"gaps":{"items":{"properties":{"from":{"type":"integer"},"to":{"type":"integer"}},"type":"object"},"maxItems":200,"type":"array"},"highest":{"type":["integer","null"]},"id":{"format":"uuid","type":"string"},"last_number":{"type":"integer"},"missing":{"description":"Números por debajo del más alto registrado que nada registra: cargarlos o anularlos","type":"integer"},"recorded":{"description":"Números registrados: papeles cargados o anulados y CFC emitidos en línea","type":"integer"},"series":{"type":"string"},"withdrawn":{"type":"boolean"}},"type":"object"},"CounterpartyCertificate":{"description":"Lo que dijo el certificado de otra empresa: el de la carátula de un sobre recibido o el del `KeyInfo` de una respuesta. Cadena hasta las CA acreditadas y revocación según la CRL que mantiene el pase de fondo (no espera a la CA).","properties":{"checked_at":{"format":"date-time","type":"string"},"code":{"description":"Con `trust` = `UNTRUSTED`, por qué no encadena: `chain_unreadable` (no se puede leer el certificado o una CA del camino), `chain_is_ca` (es el certificado de una CA de la lista, no el de un firmante), `chain_untrusted` (lo emitió una CA que no está en la lista de PKI Uruguay), `chain_signature_invalid` (la firma de un eslabón no verifica con la clave de su CA), `chain_ca_cannot_sign` (una CA del camino no puede firmar certificados, keyUsage), `chain_path_length` (una CA admite menos CA debajo, pathLenConstraint), `chain_expired` (una CA del camino no estaba vigente cuando se firmó) y `chain_too_long` (el camino es más largo que cualquiera de PKI Uruguay). La pantalla dice la frase a partir del código; `detail` nombra las CA en inglés","enum":["chain_unreadable","chain_is_ca","chain_untrusted","chain_signature_invalid","chain_ca_cannot_sign","chain_path_length","chain_expired","chain_too_long"],"type":"string"},"detail":{"type":"string"},"fingerprint_sha256":{"type":["string","null"]},"issuer":{"type":["string","null"]},"revocation":{"enum":["GOOD","REVOKED","UNKNOWN","NOT_CHECKED"],"type":"string"},"serial":{"description":"Decimal, como `X509SerialNumber`","type":["string","null"]},"subject":{"type":["string","null"]},"subject_ruc":{"type":["string","null"]},"trust":{"description":"`REVOKED`: revocado antes de que se firmara el documento (Formato del Sobre A-C20); un sobre así recibe `BS` con `S03`. `UNTRUSTED`: no encadena a una CA acreditada; se registra, y con `CFE_PKI_COUNTERPARTY_UNTRUSTED=enforce` también es `S03`","enum":["VALID","UNTRUSTED","REVOKED"],"type":"string"}},"required":["trust","revocation","checked_at"],"type":"object"},"CounterpartyCertificateEntry":{"allOf":[{"$ref":"#/components/schemas/CounterpartyCertificate"},{"properties":{"source":{"description":"`RECEPTION`: un sobre recibido; `ANSWER`: una respuesta a un sobre nuestro","enum":["RECEPTION","ANSWER"],"type":"string"},"source_id":{"description":"La recepción (`/v1/received-envelopes/{id}`) o la respuesta","format":"uuid","type":"string"}},"required":["source","source_id"],"type":"object"}]},"CreateTenant":{"properties":{"feature_template":{"description":"Plantilla de configuración con la que arranca (`GET /v1/admin/feature-templates`); sin ella, todo habilitado.","type":"string"},"monthly_quota":{"type":"integer"},"name":{"type":"string"},"owner_display_name":{"type":"string"},"owner_email":{"description":"El primer dueño, invitado en la misma llamada: elige su contraseña desde el enlace.","format":"email","type":"string"},"plan":{"type":"string"},"rate_limit_per_minute":{"type":"integer"},"ruc":{"type":"string"}},"required":["ruc","name"],"type":"object"},"CreateTestUser":{"properties":{"display_name":{"description":"Ausente o vacío, «Usuario de prueba»","maxLength":120,"type":["string","null"]},"email":{"description":"Único en la plataforma, como el de cualquier usuario","format":"email","type":"string"},"password":{"minLength":12,"type":"string"}},"required":["email","password"],"type":"object"},"CreateUser":{"description":"A quién se invita al equipo. La persona elige su contraseña desde el enlace.","properties":{"display_name":{"maxLength":200,"type":"string"},"email":{"format":"email","type":"string"},"role":{"description":"`MEMBER` por defecto.","enum":["OWNER","MEMBER"],"type":"string"}},"required":["email","display_name"],"type":"object"},"CreatedTenant":{"properties":{"owner_invitation":{"$ref":"#/components/schemas/TeamInvitationSent","description":"La invitación del primer dueño, con el enlace cuando no hay correo para mandarlo (se muestra esta única vez)."},"tenant":{"$ref":"#/components/schemas/AdminTenant"}},"required":["tenant"],"type":"object"},"Delivery":{"properties":{"submissions":{"items":{"properties":{"accepted":{"type":"integer"},"acknowledged":{"type":"boolean"},"documents":{"type":"integer"},"error":{"type":["string","null"]},"reissue":{"description":"Rechazados con `E09` (RUC emisor y/o tipo de CFE no se corresponden con el CAE): no se anulan y hay que emitirlos de nuevo con el CAE correcto. Llega además el webhook `invoice.reissue_required`.","type":"integer"},"rejected":{"description":"Rechazados por la DGI y anulados","type":"integer"},"retry_at":{"format":"date-time","type":["string","null"]},"submission_id":{"format":"uuid","type":["string","null"]}},"type":"object"},"type":"array"}},"type":"object"},"DgiContact":{"properties":{"accepted":{"description":"`Codigo` 0","type":"boolean"},"code":{"type":"integer"},"created_at":{"format":"date-time","type":"string"},"detail":{"description":"`Detalle` de la DGI","type":["string","null"]},"dgi_code":{"type":["string","null"]},"error":{"description":"Por qué la llamada no tuvo respuesta","type":["string","null"]},"id":{"format":"uuid","type":"string"},"request_number":{"description":"Número de solicitud generado","type":["string","null"]},"status":{"enum":["ANSWERED","FAILED"],"type":"string"},"value":{"type":"string"}},"required":["id","code","value","status","accepted","created_at"],"type":"object"},"DgiContactRequest":{"properties":{"code":{"description":"19: URL del web service; 20: mail de contacto técnico","enum":[19,20],"type":"integer"},"value":{"description":"Una URL https (19) o una dirección de correo (20)","maxLength":255,"type":"string"}},"required":["code","value"],"type":"object"},"DgiExchange":{"description":"Una llamada HTTP a la DGI, sin los cuerpos","properties":{"at":{"description":"Cuándo salió la solicitud","format":"date-time","type":"string"},"attempt":{"description":"1 el primero","minimum":1,"type":"integer"},"call_id":{"description":"La llamada lógica: sus intentos lo comparten","format":"uuid","type":"string"},"causes":{"description":"Códigos de causa (`S03`...)","items":{"type":"string"},"type":"array"},"dgi_operation":{"description":"Nombre del método en la DGI (`EFACRECEPCIONSOBRE`...)","type":"string"},"documents":{"description":"CFE en el sobre","type":["integer","null"]},"duration_ms":{"type":"integer"},"endpoint":{"type":"string"},"environment":{"description":"`test` o `production`","type":"string"},"error":{"description":"Qué falló, sin citar el cuerpo","type":["string","null"]},"finished_at":{"description":"Cuándo volvió la respuesta (o el error)","format":"date-time","type":"string"},"http_status":{"description":"Null si no hubo respuesta HTTP","type":["integer","null"]},"id":{"description":"UUIDv7: su instante es `at`","format":"uuid","type":"string"},"idemisor":{"description":"`Idemisor` del sobre o del reporte","type":["integer","null"]},"operation":{"enum":["RECEIVE_ENVELOPE","QUERY_STATUS","RECEIVE_REPORT","UPDATE_CONTACT","QUERY_CFE_ENVELOPES","OTHER"],"type":"string"},"outcome":{"enum":["OK","SOAP_FAULT","HTTP_ERROR","TIMEOUT","NOT_SENT","UNREADABLE","TRANSPORT_ERROR"],"type":"string"},"reception_id":{"description":"`IDReceptor` de la DGI","type":["integer","null"]},"rejected":{"description":"La DGI rechazó algo (`BS`, `BA`, `BE`, `BR`)","type":"boolean"},"report_id":{"format":"uuid","type":["string","null"]},"request_bytes":{"type":"integer"},"response_bytes":{"type":["integer","null"]},"soap_action":{"type":"string"},"soap_fault":{"description":"`faultstring` de un SOAP Fault","type":["string","null"]},"states":{"description":"Estados de la respuesta (`AS`, `BS`, `AE`, `BE`, `CE`...)","items":{"type":"string"},"type":"array"},"submission_id":{"format":"uuid","type":["string","null"]},"tenant_id":{"description":"Null en una llamada de la plataforma","format":"uuid","type":["string","null"]},"tenant_name":{"type":["string","null"]},"tenant_ruc":{"type":["string","null"]},"token_hint":{"description":"Primeros 8 hexadecimales del SHA-256 del token, como en el log","type":["string","null"]}},"required":["id","at","finished_at","call_id","attempt","tenant_id","tenant_name","tenant_ruc","submission_id","report_id","idemisor","documents","environment","operation","dgi_operation","soap_action","endpoint","http_status","outcome","soap_fault","error","duration_ms","states","causes","rejected","reception_id","token_hint","request_bytes","response_bytes"],"type":"object"},"DgiExchangeBody":{"properties":{"bytes":{"description":"Tamaño tal como viajó","type":"integer"},"download":{"description":"Ruta de la descarga de los bytes tal como viajaron","type":"string"},"encoding":{"description":"Cómo se guarda","enum":["zstd","identity"],"type":"string"},"payload":{"description":"Lo que lleva `xmlData`, formateado","type":["string","null"]},"payload_truncated":{"type":"boolean"},"sha256":{"description":"SHA-256 de los bytes tal como viajaron, hexadecimal","type":"string"},"soap":{"description":"El mensaje SOAP formateado","type":"string"},"soap_truncated":{"description":"Cortado a 512 KiB: el resto está en la descarga","type":"boolean"},"stored_bytes":{"description":"Tamaño guardado","type":"integer"}},"required":["bytes","stored_bytes","encoding","sha256","soap","soap_truncated","payload","payload_truncated","download"],"type":"object"},"DgiExchangeDetail":{"allOf":[{"$ref":"#/components/schemas/DgiExchange"},{"properties":{"attempts":{"description":"Todos los intentos de la misma llamada lógica, este incluido, los más viejos primero","items":{"$ref":"#/components/schemas/DgiExchange"},"type":"array"},"related":{"description":"Las otras llamadas de su sobre o reporte, las más viejas primero","items":{"$ref":"#/components/schemas/DgiExchange"},"type":"array"},"request":{"$ref":"#/components/schemas/DgiExchangeBody"},"response":{"description":"Null si no volvió nada","oneOf":[{"$ref":"#/components/schemas/DgiExchangeBody"},{"type":"null"}]},"signature":{"description":"La firma de la DGI en el acuse; null si la respuesta no es un acuse","oneOf":[{"properties":{"checked":{"description":"Si este despliegue la verifica (`CFE_DGI_CERTIFICATE_PEM`)","type":"boolean"},"detail":{"type":["string","null"]},"result":{"enum":["VALID","UNSIGNED","UNTRUSTED","INVALID",null],"type":["string","null"]},"valid":{"type":["boolean","null"]}},"required":["checked","result","valid","detail"],"type":"object"},{"type":"null"}]},"token":{"description":"El token entero del sobre: solo en la consola","type":"string"}},"required":["request","response","signature","attempts","related"],"type":"object"}]},"DgiExchangePage":{"properties":{"exchanges":{"items":{"$ref":"#/components/schemas/DgiExchange"},"type":"array"},"next_cursor":{"description":"`cursor` de la página siguiente; null al final","format":"uuid","type":["string","null"]}},"required":["exchanges","next_cursor"],"type":"object"},"DiscardedEnvelope":{"description":"Sobre recibido por correo que no prueba quién lo emitió: no se respondió y el archivo no se guardó; queda este registro hasta `CFE_MAIL_DISCARD_RETENTION_DAYS`","properties":{"causes":{"items":{"$ref":"#/components/schemas/ReceptionCause"},"type":"array"},"file_name":{"type":"string"},"id":{"format":"uuid","type":"string"},"issuer_ruc":{"description":"`RUCEmisor` de la carátula, sin verificar","type":["string","null"]},"reason":{"enum":["UNPROVEN","PERSONAL_CERTIFICATE"],"type":"string"},"received_at":{"format":"date-time","type":"string"},"sender":{"description":"`From` del correo tal como vino: no está autenticado","type":"string"},"sender_id":{"description":"`Idemisor` de la carátula, sin verificar","type":["integer","null"]},"size":{"description":"Bytes del archivo, que no se guarda","type":"integer"},"tenant_id":{"description":"Sólo en la lista del personal","format":"uuid","type":"string"},"tenant_name":{"description":"Sólo en la lista del personal","type":"string"},"tenant_ruc":{"description":"Sólo en la lista del personal","type":"string"}},"required":["id","received_at","file_name","sender","reason","causes","size"],"type":"object"},"EventsPage":{"properties":{"events":{"items":{"$ref":"#/components/schemas/FeedEvent"},"type":"array"},"has_more":{"description":"Hay más eventos listos: vuelva a solicitarlos enseguida","type":"boolean"},"next_cursor":{"description":"Dónde sigue: pasalo en `since`. Siempre viene, también en una página vacía, y avanza aunque no pase nada","type":"string"},"retention_days":{"description":"Los días que se guardan los eventos (30 por defecto, `CFE_EVENTS_RETENTION_DAYS`)","type":"integer"}},"required":["events","next_cursor","has_more","retention_days"],"type":"object"},"ExchangeAddress":{"properties":{"confirmed":{"description":"`MANUAL`, o `INBOUND` confirmada por el tenant o el personal: entonces vale como la del tenant","type":"boolean"},"confirmed_at":{"description":"Cuándo se confirmó una `INBOUND`","format":"date-time","type":["string","null"]},"email":{"format":"email","type":"string"},"ruc":{"type":"string"},"source":{"description":"`INBOUND`: aprendida del remitente de un sobre recibido por correo; nunca reemplaza una `MANUAL` ni una confirmada, y mientras no se confirma sólo se usa si ni el tenant ni el directorio de la DGI tienen una dirección para el RUC","enum":["MANUAL","INBOUND"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["ruc","email","source","updated_at","confirmed"],"type":"object"},"ExchangeAddressConfirm":{"properties":{"email":{"description":"La dirección como se revisó: si cambió desde entonces, 409 `address_changed`","format":"email","type":"string"},"ruc":{"type":"string"}},"required":["ruc","email"],"type":"object"},"ExchangeAddressRequest":{"properties":{"email":{"format":"email","type":"string"},"ruc":{"type":"string"}},"required":["ruc","email"],"type":"object"},"ExchangeAnswer":{"properties":{"causes":{"items":{"$ref":"#/components/schemas/ReceptionCause"},"type":"array"},"documents":{"description":"`[{ordinal, cfe_type, series, number, issued_on, state, causes}]`","items":{"type":"object"},"type":"array"},"id":{"format":"uuid","type":"string"},"kind":{"enum":["ENVELOPE_ACK","DOCUMENTS_ACK"],"type":"string"},"received_at":{"format":"date-time","type":"string"},"response_id":{"description":"`IDRespuesta` de la otra empresa","type":["integer","null"]},"signature":{"description":"Firma verificada con el certificado que trae la respuesta","enum":["VALID","UNSIGNED","INVALID"],"type":"string"},"signature_detail":{"type":["string","null"]},"state":{"type":["string","null"]}},"required":["id","kind","causes","documents","signature","received_at"],"type":"object"},"ExchangeDirectoryEntry":{"properties":{"email":{"format":"email","type":"string"},"name":{"type":["string","null"]},"ruc":{"type":"string"},"updated_at":{"format":"date-time","readOnly":true,"type":["string","null"]}},"required":["ruc","email"],"type":"object"},"ExchangeMessage":{"properties":{"annulment_message_id":{"description":"`ENVELOPE`: la comunicación que se lo avisó al receptor","format":"uuid","type":["string","null"]},"answers":{"description":"Solo en `GET /v1/exchange/messages/{id}`","items":{"$ref":"#/components/schemas/ExchangeAnswer"},"type":"array"},"attempts":{"type":"integer"},"created_at":{"format":"date-time","type":"string"},"dgi_rejected_at":{"description":"`ENVELOPE`: la DGI rechazó el CFE después de encolarlo","format":"date-time","type":["string","null"]},"file_name":{"type":["string","null"]},"id":{"format":"uuid","type":"string"},"invoice_id":{"format":"uuid","type":["string","null"]},"kind":{"description":"`ENVELOPE`: `EnvioCFE_entreEmpresas` de un CFE (`Sob_RUC_AAAAMMDD_Idemisor.xml`); `ENVELOPE_ACK`/`DOCUMENTS_ACK`: nuestros `ACKSobre`/`ACKCFE` (`M_…`, `ME_…`); `REJECTION_ACK`: un `ACKCFE` posterior con rechazo comercial; `ANNULMENT`: `CFEs_Anulados_x_RechazoDGI` (`Rech_RUC_Id.xml`); `ANSWER_REFUSAL`: el rechazo de un `ACKSobre` o `ACKCFE` recibido por correo que no se pudo tomar, con el código 2001 (acuse de recibo rechazado) o 3001 (ACKCFE rechazado) del Estándar de intercambio y su motivo (`Respuestas_código_RUC_….xml`)","enum":["ENVELOPE","ENVELOPE_ACK","DOCUMENTS_ACK","REJECTION_ACK","ANNULMENT","ANSWER_REFUSAL"],"type":"string"},"last_error":{"type":["string","null"]},"mail_id":{"description":"`Message-ID` del correo","type":["string","null"]},"next_attempt_at":{"format":"date-time","type":"string"},"number":{"description":"`Idemisor`, `IDRespuesta` o `IDComunicacion`","type":["integer","null"]},"received_envelope_id":{"format":"uuid","type":["string","null"]},"recipient_answer":{"description":"`ENVELOPE`: el `ACKSobre` del receptor","oneOf":[{"$ref":"#/components/schemas/RecipientAnswer"},{"type":"null"}]},"recipient_documents_answer":{"description":"`ENVELOPE`: su `ACKCFE`; un `BE` posterior (rechazo comercial) gana sobre un `AE`","oneOf":[{"$ref":"#/components/schemas/RecipientAnswer"},{"type":"null"}]},"recipient_email":{"type":"string"},"recipient_ruc":{"type":"string"},"rejection_id":{"format":"uuid","type":["string","null"]},"sent_at":{"format":"date-time","type":["string","null"]},"status":{"description":"`PENDING`: en cola o esperando reintento; `SENT`: el servidor SMTP lo aceptó; `FAILED`: rechazado por el servidor (5xx) o agotó los intentos; `CANCELLED`: la DGI rechazó el CFE antes de que saliera","enum":["PENDING","SENT","FAILED","CANCELLED"],"type":"string"},"xml_url":{"type":"string"}},"required":["id","kind","status","recipient_ruc","recipient_email","attempts","next_attempt_at","created_at","xml_url"],"type":"object"},"ExchangeSettings":{"properties":{"auto_send":{"description":"Los CFE con receptor RUC salen solos hacia su dirección de intercambio cuando la DGI recibió el sobre que los lleva (por defecto `true`)","type":"boolean"}},"required":["auto_send"],"type":"object"},"FeatureDisabledProblem":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"properties":{"feature":{"examples":["currency.allowed"],"type":"string"},"how_to_enable":{"properties":{"by":{"enum":["staff","owner"],"type":"string"},"detail":{"type":"string"}},"type":"object"}},"type":"object"}]},"FeatureRegistry":{"properties":{"features":{"items":{"properties":{"advanced":{"description":"Una opción que la mayoría de las cuentas no cambia: la consola la muestra en «Opciones avanzadas», plegada","type":"boolean"},"default":{},"description":{"description":"Qué gobierna, en palabras simples: sin rutas ni nombres de campo","type":"string"},"editable_by":{"enum":["staff","owner"],"type":"string"},"effect":{"enum":["enforced","default","planned"],"type":"string"},"group":{"description":"Uno de `groups[].key`: tipos de comprobante, monedas, receptor, montos, funciones del comprobante, envío y recepción, impresión y ticket, API y webhooks, avisos y sus canales, órdenes, asistente y Pruebas","type":"string"},"in_membership":{"description":"Una membresía la puede fijar (las que son ajustes del cliente no)","type":"boolean"},"key":{"type":"string"},"kind":{"enum":["bool","list","enum"],"type":"string"},"label":{"type":"string"},"min_items":{"type":"integer"},"option_labels":{"additionalProperties":{"type":"string"},"description":"Las palabras de cada valor de la lista, cuando la API las tiene (los eventos de los webhooks, los canales y los avisos): `{valor: etiqueta}`","type":"object"},"options":{"description":"Lo que toma una lista o un enum (las monedas, los tipos...)","items":{"type":"string"},"type":"array"},"technical":{"description":"Las rutas, campos y códigos que gobierna, cuando tiene","type":"string"}},"required":["key","group","label","kind","default","editable_by","effect","in_membership","advanced"],"type":"object"},"type":"array"},"groups":{"items":{"properties":{"key":{"type":"string"},"label":{"type":"string"}},"type":"object"},"type":"array"}},"required":["groups","features"],"type":"object"},"FeatureTemplate":{"properties":{"description":{"type":"string"},"key":{"examples":["pyme"],"type":"string"},"name":{"type":"string"},"values":{"additionalProperties":true,"type":"object"}},"type":"object"},"FeedEvent":{"properties":{"created_at":{"format":"date-time","type":"string"},"event":{"description":"`invoice.emitted`, `invoice.processed`, `invoice.reissue_required`, `contingency.correction_required`, `dgi.document_rejected`, `dgi.document_observed`, `dgi.envelope_rejected`, `dgi.report_rejected`, `dgi.acknowledgement_held`, `reception.received`, `cae.running_low`, `cae.expiring`, `cae.exhausted`, `certificate.expiring`, `membership.limit_warning`, `membership.limit_reached`, `membership.renewed`, `tenant.configuration_changed`, `api_key.revealed`, `order.executed`, `order.expired`…","type":"string"},"id":{"description":"El id del evento: el `event_id` de su entrega por webhook, para no procesarlo dos veces. Opaco (`evt_` y 26 caracteres): no es un número de la plataforma ni se puede ordenar.","pattern":"^evt_[a-z2-7]{26}$","type":"string"},"payload":{"additionalProperties":true,"description":"Lo mismo que el `payload` del webhook","type":"object"},"sandbox":{"description":"Un evento del sandbox: una clave de prueba lee sólo esos, una real nunca. El webhook trae el mismo `sandbox` en el cuerpo.","type":"boolean"}},"required":["id","event","created_at","payload"],"type":"object"},"FiscalRates":{"properties":{"rates":{"items":{"properties":{"currency":{"description":"ISO 4217 (`UYI` la UI, `UYR` la UR)","type":"string"},"date":{"description":"Día del cierre","format":"date","type":"string"},"rate":{"description":"Pesos por unidad: comprador billete del BCU (o arbitraje), con todos los decimales","type":"string"},"source":{"enum":["BCU","MANUAL"],"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"type":"array"},"ui_cap":{"description":"El tope de la Tabla E para los comprobantes de hoy: la UI con que se mide y el tope en pesos. `null` mientras no hay UI cargada (el tope no se aplica).","properties":{"cap_uyu":{"type":"string"},"date":{"format":"date","type":"string"},"ui_value":{"type":"string"},"ui_year":{"type":"integer"},"units":{"type":"string"}},"type":["object","null"]},"ui_values":{"items":{"$ref":"#/components/schemas/UiValue"},"type":"array"}},"type":"object"},"HealthFlag":{"properties":{"code":{"enum":["membership_suspended","membership_expired","membership_missing","offboarded","address_missing","branch_missing","certificate_missing","certificate_expired","certificate_expiring","cae_missing","cae_unusable","cae_low","dgi_rejections","report_not_accepted","limit_reached","near_limit"],"type":"string"},"params":{"type":"object"},"reason":{"type":"string"},"severity":{"enum":["info","warning","critical"],"type":"string"}},"type":"object"},"HeldAcknowledgement":{"description":"Un acuse de la DGI cuya firma no verifica, guardado y no aplicado hasta que alguien lo revisa (producción y homologación).","properties":{"created_at":{"format":"date-time","type":"string"},"id":{"type":"integer"},"kind":{"description":"Acuse del sobre, de los comprobantes o del reporte diario","enum":["ACKSobre","ACKCFE","ACKRep"],"type":"string"},"review_note":{"type":["string","null"]},"reviewed_at":{"format":"date-time","type":["string","null"]},"reviewed_by":{"type":["string","null"]},"ruc":{"description":"En la lista","type":"string"},"signature":{"enum":["INVALID","UNTRUSTED","UNSIGNED"],"type":"string"},"signature_detail":{"type":["string","null"]},"status":{"enum":["HELD","APPLIED","DISCARDED"],"type":"string"},"submission_id":{"format":"uuid","type":"string"},"tenant_id":{"format":"uuid","type":"string"},"xml":{"description":"En el detalle: el acuse tal como lo devolvió el servicio de la DGI","type":"string"}},"required":["id","tenant_id","submission_id","kind","signature","status","created_at"],"type":"object"},"InboundMailResult":{"properties":{"files":{"items":{"properties":{"answers":{"description":"Para un sobre: qué pasó con sus dos respuestas; para un `ACKSobre` o `ACKCFE` rechazado (`invalid`): qué pasó con el rechazo 2001 o 3001 que vuelve al remitente (las mismas reglas de dirección y límite). `queued` a la dirección conocida del RUC emisor (la del tenant o la que publica la DGI), `queued_to_sender` al remitente cuyo From avaló el servidor de correo (sin dirección conocida), `already_queued` en una entrega anterior. No se mandan: `withheld_unproven` (sus CFE no verifican con un certificado del emisor), `withheld_no_address` (sin dirección conocida y remitente sin autenticar), `withheld_limit` (el RUC o el dominio llegó a su límite del día).","enum":["queued","queued_to_sender","already_queued","withheld_unproven","withheld_no_address","withheld_limit",null],"type":["string","null"]},"detail":{"type":["string","null"]},"file_name":{"type":"string"},"id":{"description":"La recepción, la respuesta o la comunicación guardada","format":"uuid","type":["string","null"]},"kind":{"enum":["ENVELOPE","ENVELOPE_ACK","DOCUMENTS_ACK","ANNULMENT",null],"type":["string","null"]},"outcome":{"enum":["received","duplicate","unknown_recipient","invalid","failed","ignored"],"type":"string"},"ruc":{"description":"RUC al que está dirigido","type":["string","null"]}},"required":["file_name","outcome"],"type":"object"},"type":"array"},"message_id":{"type":["string","null"]}},"required":["files"],"type":"object"},"InsightAnswer":{"properties":{"chart":{"$ref":"#/components/schemas/InsightChart"},"columns":{"items":{"$ref":"#/components/schemas/InsightColumn"},"type":"array"},"comparison":{"description":"Sólo con `compare=previous`: la cifra principal y las secundarias del mismo informe en el período anterior, de igual largo y que termina el día antes de `from`. `headline` es `null` cuando ese período empieza antes de lo que la membresía deja consultar, y en un informe que lee el pedido de cada comprobante (clientes, productos, listas) con un período de más de 400 días, que leería otro tanto; `null` en un informe que ya compara («Este período contra el anterior»).","properties":{"from":{"format":"date","type":"string"},"headline":{"oneOf":[{"$ref":"#/components/schemas/InsightHeadline"},{"type":"null"}]},"note":{"description":"Contra qué días se compara, en español","type":["string","null"]},"to":{"format":"date","type":"string"}},"required":["from","to","headline","note"],"type":["object","null"]},"headline":{"$ref":"#/components/schemas/InsightHeadline"},"meta":{"properties":{"clipped":{"description":"La membresía movió el comienzo del período","type":"boolean"},"csv_path":{"description":"El mismo informe en CSV, todas las filas, con el período como fechas","type":"string"},"currency":{"type":"string"},"max_days":{"description":"El período más largo de esta forma del informe","type":"integer"},"notes":{"description":"Lo que la persona tiene que saber, en español: la membresía, la página («Filas 51 a 100 de 1.234: hay 1.134 filas más.»), la moneda","items":{"type":"string"},"type":"array"},"rows_shown":{"type":"integer"},"rows_total":{"type":"integer"},"rows_total_exact":{"type":"boolean"},"time_zone":{"type":"string"}},"required":["rows_shown","rows_total","rows_total_exact","notes","csv_path"],"type":"object"},"page":{"$ref":"#/components/schemas/InsightPage"},"parameters":{"additionalProperties":true,"description":"Los parámetros resueltos: `period`, `from`, `to` y los demás que el informe toma (`null` si no se usan)","type":"object"},"report":{"properties":{"category":{"type":"string"},"description":{"type":"string"},"editable":{"description":"El armador lo expresa: se puede duplicar como informe propio","type":"boolean"},"id":{"type":"string"},"title":{"type":"string"}},"type":"object"},"rows":{"description":"Cada fila como un objeto por las `key` de las columnas","items":{"additionalProperties":true,"type":"object"},"type":"array"},"title":{"description":"El título con su período","type":"string"}},"required":["report","title","parameters","columns","rows","headline","chart","page","meta"],"type":"object"},"InsightBuiltAnswer":{"properties":{"chart":{"properties":{"kind":{"type":"string"},"x":{"type":["string","null"]},"y":{"items":{"type":"string"},"type":"array"}},"type":"object"},"columns":{"items":{"$ref":"#/components/schemas/InsightColumn"},"type":"array"},"definition":{"$ref":"#/components/schemas/InsightDefinition"},"meta":{"properties":{"clipped":{"type":"boolean"},"currency":{"type":"string"},"from":{"format":"date","type":"string"},"grouped":{"type":"boolean"},"max_days":{"type":"integer"},"notes":{"items":{"type":"string"},"type":"array"},"paging":{"enum":["offset","keyset"],"type":"string"},"rows_shown":{"type":"integer"},"rows_total":{"type":"integer"},"rows_total_exact":{"type":"boolean"},"time_zone":{"type":"string"},"to":{"format":"date","type":"string"}},"type":"object"},"name":{"description":"El nombre del informe guardado","type":["string","null"]},"page":{"$ref":"#/components/schemas/InsightPage"},"rows":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"saved":{"$ref":"#/components/schemas/InsightSaved"},"source":{"properties":{"key":{"type":"string"},"label":{"type":"string"}},"type":"object"},"title":{"type":"string"}},"required":["title","source","definition","columns","rows","chart","page","meta"],"type":"object"},"InsightCatalog":{"properties":{"categories":{"items":{"properties":{"key":{"type":"string"},"label":{"type":"string"}},"required":["key","label"],"type":"object"},"type":"array"},"limits":{"additionalProperties":true,"description":"Los límites: el período más largo de cada forma (`periods`), las filas por página (`page_size`, `max_page_size`), hasta cuántas filas se cuentan exacto (`count_cap`), las filas de un CSV (`max_export_rows`), los segundos de una consulta y cuántos informes a la vez (`per_tenant`, `per_replica`)","type":"object"},"presets":{"items":{"$ref":"#/components/schemas/InsightOption"},"type":"array"},"reports":{"items":{"$ref":"#/components/schemas/InsightReport"},"type":"array"},"time_zone":{"type":"string"}},"required":["categories","presets","reports","limits","time_zone"],"type":"object"},"InsightChart":{"properties":{"kind":{"enum":["bar","hbar","line","stacked","none"],"type":"string"},"x":{"description":"La columna de las categorías","type":"string"},"y":{"description":"Las columnas que dibuja","items":{"type":"string"},"type":"array"}},"required":["kind","x","y"],"type":"object"},"InsightColumn":{"properties":{"currency":{"description":"La moneda de una columna `money`","type":"string"},"currency_column":{"description":"La columna con la moneda de cada fila, cuando cambia por fila","type":"string"},"key":{"type":"string"},"kind":{"description":"`date` y `week` son `AAAA-MM-DD` (una semana, su lunes), `month` es `AAAA-MM`, `count` un entero, `money`, `number` y `percent` texto con dos decimales (`percent` 12.50 es 12,5 %)","enum":["text","code","type","date","week","month","count","money","number","percent"],"type":"string"},"label":{"description":"El encabezado, en español","type":"string"}},"required":["key","label","kind"],"type":"object"},"InsightDefinition":{"additionalProperties":false,"description":"Un informe armado por la persona: datos, nunca SQL. Cada campo es de la lista de su fuente (`GET /v1/insights/sources`) y cada valor de un filtro va como parámetro de la consulta. Con alguna columna con función (`aggregate`), las demás agrupan (hasta 4); sin ninguna, lista filas una por una.","properties":{"chart":{"enum":["bar","hbar","line","stacked","none"],"type":"string"},"columns":{"items":{"oneOf":[{"description":"Un campo, por su clave","type":"string"},{"additionalProperties":false,"properties":{"aggregate":{"enum":["count","count_distinct","sum","avg","min","max"],"type":"string"},"field":{"type":"string"},"grain":{"description":"Una fecha agrupada (en días de Uruguay)","enum":["day","week","month","quarter","year"],"type":"string"},"label":{"description":"El título de la columna","maxLength":80,"type":"string"}},"type":"object"}]},"maxItems":20,"minItems":1,"type":"array"},"filters":{"items":{"additionalProperties":false,"properties":{"field":{"type":"string"},"op":{"enum":["eq","ne","in","between","gte","lte","contains","empty"],"type":"string"},"value":{"description":"El valor de `eq`, `ne`, `gte`, `lte` y `contains`; de `empty`, `true` (vacío) o `false` (con valor)"},"values":{"description":"Los valores de `in` (hasta 200) o los dos de `between`","maxItems":200,"type":"array"}},"required":["field","op"],"type":"object"},"maxItems":20,"type":"array"},"limit":{"description":"Sólo las primeras filas","maximum":10000,"minimum":1,"type":"integer"},"period":{"description":"Un período por su nombre, o sus días. Sin él, `last_30_days`.","oneOf":[{"enum":["today","yesterday","last_7_days","last_30_days","last_90_days","this_month","last_month","this_quarter","last_quarter","this_year","last_year","last_12_months"],"type":"string"},{"additionalProperties":false,"properties":{"from":{"format":"date","type":"string"},"preset":{"enum":["today","yesterday","last_7_days","last_30_days","last_90_days","this_month","last_month","this_quarter","last_quarter","this_year","last_year","last_12_months","custom"],"type":"string"},"to":{"format":"date","type":"string"}},"type":"object"}]},"sort":{"items":{"additionalProperties":false,"properties":{"column":{"description":"La clave de una columna: el campo, `campo_grano` (`issue_date_month`), `función_campo` (`sum_signed_total_pesos`) o `count`","type":"string"},"direction":{"enum":["asc","desc"],"type":"string"}},"required":["column"],"type":"object"},"maxItems":5,"type":"array"},"source":{"enum":["documents","lines","clients","orders","dgi_responses","received"],"type":"string"}},"required":["source","columns"],"type":"object"},"InsightDuplicateRequest":{"additionalProperties":false,"properties":{"description":{"maxLength":500,"type":["string","null"]},"name":{"description":"Sin él, «<título> (copia)»","maxLength":120,"minLength":1,"type":"string"},"shared":{"default":false,"type":"boolean"}},"type":"object"},"InsightFigure":{"description":"Una cifra secundaria del informe, junto a la principal: los comprobantes, el ticket promedio, el IVA…","properties":{"currency":{"type":["string","null"]},"key":{"description":"Estable por informe: con ella se compara la misma cifra del período anterior","type":"string"},"kind":{"type":"string"},"label":{"type":"string"},"value":{"description":"Como una celda de su `kind`; `null` sin datos"}},"required":["key","label","value","kind"],"type":"object"},"InsightHeadline":{"properties":{"currency":{"type":["string","null"]},"detail":{"description":"Una línea de contexto, en español","type":["string","null"]},"figures":{"description":"Dos o tres cifras más del mismo período, cada una con su `key`","items":{"$ref":"#/components/schemas/InsightFigure"},"type":"array"},"kind":{"type":"string"},"label":{"type":"string"},"value":{"description":"Como una celda de su `kind`; `null` sin datos"}},"required":["label","value","kind"],"type":"object"},"InsightOption":{"properties":{"label":{"type":"string"},"value":{}},"required":["value","label"],"type":"object"},"InsightPage":{"description":"Dónde está una página y cómo pedir la siguiente.","properties":{"first_row":{"type":"integer"},"has_more":{"type":"boolean"},"kind":{"description":"`offset`: la página es la posición sellada (un informe agrupado o del catálogo); `keyset`: empieza después de la última fila (una lista de filas, que una fila nueva no corre)","enum":["offset","keyset"],"type":"string"},"last_row":{"type":"integer"},"next_cursor":{"description":"El `cursor` de la página siguiente, opaco; `null` en la última","type":["string","null"]},"number":{"description":"El número de la página, desde 1","type":"integer"},"rows":{"description":"Las filas de esta página","type":"integer"},"rows_after":{"description":"Cuántas filas quedan después de esta página; `null` si el total no es exacto","type":["integer","null"]},"size":{"description":"Las filas pedidas por página","type":"integer"},"total":{"description":"Cuántas filas tiene la consulta; si `total_exact` es `false`, al menos esas (`más de 10.000`)","type":"integer"},"total_exact":{"type":"boolean"}},"required":["size","number","rows","total","total_exact","has_more","next_cursor","kind"],"type":"object"},"InsightParameter":{"properties":{"default":{"description":"El valor sin el parámetro; `null` es ninguno"},"description":{"type":"string"},"key":{"description":"`period` (que toma `period`, `from` y `to`), `group`, `currency`, `cfe_type`, `by`, `limit` o `range` (`min` y `max`)","type":"string"},"kind":{"enum":["period","enum","currency","cfe_type","integer","range"],"type":"string"},"label":{"type":"string"},"max":{"type":"integer"},"max_days":{"type":"integer"},"min":{"type":"integer"},"names":{"items":{"type":"string"},"type":"array"},"options":{"items":{"$ref":"#/components/schemas/InsightOption"},"type":"array"}},"required":["key","label","kind"],"type":"object"},"InsightQueryCsvRequest":{"additionalProperties":false,"properties":{"definition":{"$ref":"#/components/schemas/InsightDefinition"}},"required":["definition"],"type":"object"},"InsightQueryRequest":{"additionalProperties":false,"properties":{"cursor":{"description":"El `page.next_cursor` de la página anterior, con la misma definición","type":"string"},"definition":{"$ref":"#/components/schemas/InsightDefinition"},"page_size":{"maximum":500,"minimum":1,"type":"integer"}},"required":["definition"],"type":"object"},"InsightReport":{"properties":{"category":{"enum":["sales","clients","products","orders","dgi","usage"],"type":"string"},"category_label":{"type":"string"},"chart":{"$ref":"#/components/schemas/InsightChart"},"columns":{"description":"Las de los parámetros por defecto: la primera sigue a `group`","items":{"$ref":"#/components/schemas/InsightColumn"},"type":"array"},"definition":{"description":"Su definición en el armador, con sus parámetros por defecto","oneOf":[{"$ref":"#/components/schemas/InsightDefinition"},{"type":"null"}]},"description":{"type":"string"},"editable":{"description":"El armador lo expresa (`POST /v1/insights/{insight}/duplicate`)","type":"boolean"},"id":{"type":"string"},"limits":{"description":"El período más largo (`max_days`) y el de cada agrupación (`by_group`)","type":"object"},"not_editable_reason":{"description":"Por qué queda predefinido","type":["string","null"]},"parameters":{"items":{"$ref":"#/components/schemas/InsightParameter"},"type":"array"},"title":{"type":"string"}},"required":["id","category","title","description","parameters","columns","chart"],"type":"object"},"InsightSaved":{"properties":{"created_at":{"format":"date-time","type":"string"},"csv_path":{"type":"string"},"definition":{"$ref":"#/components/schemas/InsightDefinition"},"description":{"type":["string","null"]},"editable":{"description":"Quien pregunta lo puede cambiar o borrar","type":"boolean"},"id":{"format":"uuid","type":"string"},"name":{"type":"string"},"owner":{"properties":{"gone":{"description":"Quien lo armó ya no está (la persona se quitó o la clave se revocó): quien administra la cuenta lo ve, lo cambia y lo borra aunque sea privado","type":"boolean"},"kind":{"enum":["user","api_key"],"type":"string"},"name":{"type":"string"},"you":{"type":"boolean"}},"type":"object"},"run_path":{"type":"string"},"shared":{"description":"`true`: lo ve todo el equipo; `false`: sólo quien lo armó","type":"boolean"},"template":{"description":"El informe del catálogo del que se duplicó","type":["string","null"]},"updated_at":{"format":"date-time","type":"string"},"visibility":{"enum":["team","private"],"type":"string"}},"required":["id","name","definition","shared","owner","editable","created_at","updated_at"],"type":"object"},"InsightSavedPatch":{"additionalProperties":false,"properties":{"definition":{"$ref":"#/components/schemas/InsightDefinition"},"description":{"maxLength":500,"type":["string","null"]},"name":{"maxLength":120,"minLength":1,"type":"string"},"shared":{"type":"boolean"}},"type":"object"},"InsightSavedRequest":{"additionalProperties":false,"properties":{"definition":{"$ref":"#/components/schemas/InsightDefinition"},"description":{"maxLength":500,"type":["string","null"]},"name":{"description":"Una vez por cuenta","maxLength":120,"minLength":1,"type":"string"},"shared":{"default":false,"type":"boolean"}},"required":["name","definition"],"type":"object"},"InsightSources":{"properties":{"aggregates":{"items":{"properties":{"key":{"type":"string"},"label":{"type":"string"}},"type":"object"},"type":"array"},"charts":{"items":{"type":"string"},"type":"array"},"grains":{"items":{"properties":{"key":{"type":"string"},"label":{"type":"string"}},"type":"object"},"type":"array"},"limits":{"additionalProperties":true,"type":"object"},"operators":{"items":{"properties":{"key":{"type":"string"},"label":{"type":"string"}},"type":"object"},"type":"array"},"presets":{"items":{"$ref":"#/components/schemas/InsightOption"},"type":"array"},"sources":{"items":{"properties":{"date_field":{"type":"string"},"description":{"type":"string"},"fields":{"items":{"properties":{"aggregates":{"items":{"type":"string"},"type":"array"},"currency":{"description":"`UYU` o `document` (la de cada comprobante)","type":["string","null"]},"description":{"type":"string"},"grains":{"items":{"type":"string"},"type":"array"},"join":{"description":"`request`: se lee del pedido del comprobante","type":["string","null"]},"key":{"type":"string"},"label":{"type":"string"},"nullable":{"type":"boolean"},"operators":{"items":{"type":"string"},"type":"array"},"role":{"enum":["dimension","measure"],"type":"string"},"type":{"enum":["text","code","cfe_type","choice","date","count","number","money","bool"],"type":"string"},"values":{"items":{"properties":{"label":{"type":"string"},"value":{"type":"string"}},"type":"object"},"type":"array"}},"type":"object"},"type":"array"},"key":{"type":"string"},"label":{"type":"string"},"max_days":{"type":"integer"},"reads_requests":{"type":"boolean"},"row":{"properties":{"many":{"type":"string"},"one":{"type":"string"}},"type":"object"}},"type":"object"},"type":"array"},"time_zone":{"type":"string"}},"required":["sources","operators","aggregates","grains","limits"],"type":"object"},"InvitationAcceptRequest":{"properties":{"password":{"maxLength":128,"minLength":12,"type":"string"},"token":{"type":"string"}},"required":["token","password"],"type":"object"},"InvitationAccepted":{"properties":{"email":{"type":"string"},"tenant_id":{"format":"uuid","type":"string"}},"type":"object"},"Invoice":{"properties":{"adenda":{"description":"Adenda tal como se guardó (saltos de línea normalizados a `\\n`); no está en el XML firmado. `null` si no tiene.","type":["string","null"]},"adenda_attachment":{"allOf":[{"$ref":"#/components/schemas/AdendaAttachment"}],"description":"Sólo en `GET /v1/invoices/{id}`, cuando la adenda lleva un binario (zona J-C2): su nombre, tipo, tamaño y dónde bajarlo"},"adenda_distribution":{"description":"Las líneas de distribución de `adenda`, sin su rótulo","items":{"type":"string"},"type":"array"},"adenda_legends":{"description":"Las leyendas de `adenda`, sin su rótulo, como las toma la emisión","items":{"type":"string"},"type":"array"},"adenda_other":{"description":"El resto del texto de `adenda`; `null` si no queda nada","type":["string","null"]},"cfe_type":{"type":"integer"},"cfe_type_name":{"type":"string"},"cfe_type_selection":{"$ref":"#/components/schemas/CfeTypeSelection"},"created_at":{"format":"date-time","type":"string"},"currency":{"type":"string"},"external_id":{"description":"El número de pedido de la tienda que trajo la solicitud; `null` sin él","type":["string","null"]},"fiscal_complement":{"description":"Zona K tal como la escribió el emisor (migración 36): el mandante de una venta por cuenta ajena o de una e-Boleta de entrada con `purchase_for_resale` 2. Con `encrypted` el XML firmado sólo lleva el `xenc:EncryptedData` de la DGI: ésta es la copia del emisor. `null` en los demás CFE.","properties":{"country":{"description":"`Pais`","type":"string"},"document_type":{"description":"`TipoDocMdte`: 1 NIE, 2 RUC, 3 CI, 4 otros, 5 pasaporte, 6 DNI, 7 NIFE.","enum":[1,2,3,4,5,6,7],"type":"integer"},"encrypted":{"description":"Si viajó cifrada para la DGI.","type":"boolean"},"name":{"description":"`NombreMdte`","type":"string"},"number":{"description":"`DocMdte`","type":"string"}},"required":["document_type","number","country","name","encrypted"],"type":["object","null"]},"id":{"format":"uuid","type":"string"},"input":{"additionalProperties":true,"description":"La solicitud tal como llegó (sin el Base64 del adjunto de la adenda). Solo en `GET /v1/invoices/{id}` y solo en las emisiones desde la migración 66; falta en las anteriores","type":"object"},"issue_date":{"format":"date","type":"string"},"links":{"properties":{"company_envelope":{"description":"`EnvioCFE_entreEmpresas` con este CFE y su adenda, para el receptor electrónico","type":"string"},"self":{"type":"string"},"xml":{"type":"string"}},"type":"object"},"number":{"type":"integer"},"order_id":{"description":"La orden de la que se emitió (`POST /v1/orders/{id}/execute`); `null` si no salió de una orden","format":"uuid","type":["string","null"]},"order_number":{"description":"El número visible de esa orden, `ORD-` y diez dígitos (`ORD-0000000012`); `null` si no salió de una orden","examples":["ORD-0000000012"],"type":["string","null"]},"payable":{"type":"string"},"pdf_url":{"description":"Link estable al PDF, sin credenciales (`GET /v1/public/pdf/{token}`); `null` si se revocó, si la cuenta no publica ese tipo (`printing.public_verification`) o en un CFC","format":"uri","type":["string","null"]},"recipient_delivery":{"description":"Sólo en `GET /v1/invoices/{id}`: si ya puede entregarse al receptor (Formato Sobre v05, p. 4)","properties":{"detail":{"type":"string"},"status":{"enum":["allowed","wait_for_dgi","never","void"],"type":"string"}},"type":"object"},"reissuable":{"description":"Si `POST /v1/invoices/{id}/reissue` lo toma: la DGI lo rechazó con `E09` y ninguna otra emisión tomó su número todavía","type":"boolean"},"rejection_causes":{"description":"Las causas de un rechazo de la DGI una por una (`code`, `gloss`, `detail`): el cliente lee los códigos de acá, nunca del texto de `rejection_reason`. Vacía si la DGI no lo rechazó.","items":{"properties":{"code":{"type":"string"},"detail":{"type":["string","null"]},"gloss":{"type":["string","null"]}},"required":["code","gloss","detail"],"type":"object"},"type":"array"},"rejection_reason":{"description":"Causas del rechazo de la DGI en una línea (`E04: …; E25: …`); `null` si no fue rechazado","type":["string","null"]},"sandbox":{"description":"Un comprobante del sandbox (emitido con una clave de prueba): sin valor fiscal, numerado en la serie `SB`, nunca enviado a la DGI. Una clave real nunca lo ve.","type":"boolean"},"seal":{"properties":{"printed_code":{"type":"string"},"security_code":{"type":"string"},"verification_url":{"type":"string"}},"type":"object"},"series":{"type":"string"},"status":{"enum":["PENDING","ACCEPTED","REJECTED","CANCELLED"],"type":"string"},"status_name":{"type":"string"},"submission_id":{"description":"Sobre que llevó el CFE a la DGI; `null` mientras no se envió","format":"uuid","type":["string","null"]},"superseded_at":{"description":"Cuándo otro comprobante tomó este número (reemisión de un E09, CFC corregido tras un CE); `null` si no","format":"date-time","type":["string","null"]},"superseded_by":{"description":"Sólo en `GET /v1/invoices/{id}`, cuando otro comprobante tomó este número (`superseded_at`): cuál","format":"uuid","type":["string","null"]},"supersedes":{"description":"El comprobante con el mismo tipo, serie y número que éste reemplaza","format":"uuid","type":["string","null"]},"total":{"type":"string"},"xml_sha256":{"type":"string"}},"type":"object"},"InvoiceList":{"properties":{"count":{"type":"integer"},"date":{"format":"date","type":["string","null"]},"has_more":{"description":"Hay otra página después de esta.","type":"boolean"},"invoices":{"items":{"$ref":"#/components/schemas/Invoice"},"type":"array"},"limit":{"type":"integer"},"next_cursor":{"description":"Para pedir la página siguiente en `after`; `null` en la última.","type":["string","null"]},"offset":{"deprecated":true,"description":"El offset pedido; 0 cuando la página se pidió por cursor.","type":"integer"},"total":{"description":"Coincidencias con los filtros (sin contar cursor ni offset), hasta 10.000.","maximum":10000,"type":"integer"},"total_capped":{"description":"Hay más de 10.000 coincidencias y `total` se detuvo ahí.","type":"boolean"}},"type":"object"},"InvoicePreview":{"description":"Lo que emitiría `POST /v1/invoices` con el mismo cuerpo, sin emitir. Importes como texto con dos decimales.","properties":{"adenda":{"description":"La adenda como se guardaría; `null` si no tiene","type":["string","null"]},"cae":{"description":"El rango CAE del que numeraría la emisión ahora, leído sin reservar nada. `null` sin rango (ver `warnings`) y en un tipo de contingencia, que se carga como papel con el suyo.","properties":{"expires_on":{"format":"date","type":"string"},"next_number":{"description":"El número que daría si nadie emite antes","type":"integer"},"series":{"type":"string"},"special":{"description":"`CAEEspecial`: 1 exonerado, 2 IVA mínimo, 3 Monotributo, 4 Monotributo MIDES","type":["integer","null"]},"special_cause":{"type":["integer","null"]}},"type":["object","null"]},"cfe_type":{"examples":[111],"type":"integer"},"cfe_type_name":{"examples":["e-Factura"],"type":"string"},"cfe_type_selection":{"$ref":"#/components/schemas/CfeTypeSelection"},"currency":{"examples":["UYU"],"type":"string"},"exchange_rate":{"description":"Tipo de cambio con tres decimales; `null` en pesos","examples":[null,"39.500"],"type":["string","null"]},"lines":{"items":{"properties":{"amount":{"description":"`MontoItem`","examples":["900.00"],"type":"string"},"description":{"type":"string"},"number":{"description":"`NroLinDet`, desde 1","type":"integer"}},"required":["number","description","amount"],"type":"object"},"type":"array"},"totals":{"properties":{"export":{"description":"`MntExpoyAsim`","type":"string"},"line_count":{"description":"`CantLinDet`","type":"integer"},"net_basic_rate":{"description":"`MntNetoIVATasaBasica`","type":"string"},"net_minimum_rate":{"description":"`MntNetoIvaTasaMin`","type":"string"},"net_other_rate":{"description":"`MntNetoIVAOtra` (indicador 4)","type":"string"},"non_billable":{"description":"`MontoNF` (indicadores 6 y 7)","type":"string"},"non_taxed":{"description":"`MntNoGrv`","type":"string"},"payable":{"description":"`MntPagar`","type":"string"},"perceived_tax":{"description":"`MntImpuestoPerc` (indicador 11)","type":"string"},"suspended_vat":{"description":"`MntIVaenSusp` (indicador 12)","type":"string"},"total":{"description":"`MntTotal`","type":"string"},"vat_basic_rate":{"description":"`MntIVATasaBasica`","type":"string"},"vat_minimum_rate":{"description":"`MntIVATasaMin`","type":"string"},"vat_other_rate":{"description":"`MntIVAOtra`","type":"string"},"withheld":{"description":"`MntTotRetenido`","type":"string"}},"required":["non_taxed","export","net_minimum_rate","vat_minimum_rate","net_basic_rate","vat_basic_rate","perceived_tax","net_other_rate","vat_other_rate","suspended_vat","non_billable","total","withheld","payable","line_count"],"type":"object"},"warnings":{"description":"Lo que frenaría la emisión ahora sin ser un error del documento, con los códigos que respondería la emisión: sin rango para numerar (`no_numbering`, `contingency_range_on_paper`) o un CAE que no lo autoriza (un CAE especial y sus indicadores o `MntBruto`, A-C10); y `ui_value_unknown` (campo `A-C60`) cuando el tope de la Tabla E de un e-Ticket sin receptor se controló sin la UI del 31/12 del año anterior, con una menor: no frena la emisión, avisa que mientras tanto se rechazan e-Tickets sin receptor que la DGI aceptaría; sus `params` traen `missing_ui_year`, `cap` (en pesos) y, si se usó la UI de un año anterior, `used_ui_year`. Cada uno con la forma de un elemento de `errors`; la vista previa sigue respondiendo `200`.","items":{"$ref":"#/components/schemas/ProblemError"},"type":"array"}},"required":["cfe_type","cfe_type_name","currency","exchange_rate","lines","totals","adenda"],"type":"object"},"InvoiceRefunds":{"properties":{"cfe_type":{"type":"integer"},"currency":{"type":"string"},"external_id":{"type":["string","null"]},"invoice_id":{"format":"uuid","type":"string"},"lines":{"items":{"properties":{"amount":{"type":"string"},"description":{"type":"string"},"index":{"type":"integer"},"indicator":{"type":["string","null"]},"quantity":{"type":"string"},"refundable":{"type":"boolean"},"refunded_amount":{"type":"string"},"refunded_quantity":{"type":"string"},"remaining_amount":{"type":"string"},"remaining_quantity":{"type":"string"},"shipping":{"type":"boolean"}},"type":"object"},"type":"array"},"note_type":{"description":"Tipo de la nota; `null` si el tipo no se devuelve","type":["integer","null"]},"number":{"type":"integer"},"payable":{"type":"string"},"prices_include_vat":{"description":"`MntBruto` = 1: los importes van con IVA","type":"boolean"},"rates":{"items":{"properties":{"amount":{"type":"string"},"indicator":{"type":"string"},"refunded":{"type":"string"},"remaining":{"type":"string"}},"type":"object"},"type":"array"},"refunded":{"description":"Lo que descuentan las notas de crédito que cuentan, también las emitidas por fuera","type":"string"},"refunds":{"items":{"$ref":"#/components/schemas/Refund"},"type":"array"},"remaining":{"type":"string"},"series":{"type":"string"}},"type":"object"},"InvoiceRequest":{"description":"El mismo JSON de la CLI. Ver docs/API.md para el detalle de cada campo. Qué miembros pide, admite o no admite cada tipo, con sus largos, valores y fechas, lo dice `GET /v1/catalog/cfe-types` por la ruta de cada uno (`lines[].unit_price`).","properties":{"additional_information":{"type":"string"},"adenda":{"description":"Adenda (zona J): texto libre para el receptor, se recomienda `etiqueta: valor` por línea. Viaja junto al CFE firmado al receptor (`EnvioCFE_entreEmpresas`), no la cubre la firma y nunca se envía a la DGI. Obligatoria con `professional_secrecy` y sin `recipient`: los datos del receptor van acá. Vacía equivale a no tenerla.","examples":["Orden de compra: 4512\nEntrega: Rincón 500"],"maxLength":20000,"type":["string","null"]},"adenda_attachment":{"allOf":[{"$ref":"#/components/schemas/AdendaAttachmentInput"}],"description":"Zona J-C2: el binario de la adenda. Con él la adenda existe aunque no tenga texto; con secreto profesional y sin receptor igual hace falta el texto. En una reemisión (`POST /v1/invoices/{id}/reissue`) o una corrección de CFC (`POST /v1/contingency-documents/{id}/correction`), sin este campo va el del comprobante reemplazado; `null` para que vaya sin él."},"adenda_distribution":{"description":"Hasta dos líneas con el código y símbolo necesarios para la distribución del CFE (p. 85): viajan en la adenda como `Distribución: ...` y la representación impresa las muestra fuera del recuadro de la adenda.","examples":[["Zona 12 - Ruta 3"]],"items":{"minLength":1,"type":"string"},"maxItems":2,"type":"array"},"adenda_legends":{"description":"Leyendas o constancias que la normativa de la operación exige y a las que no les fija otra ubicación (Formato CFE v25.2, p. 74): van primero en la adenda como líneas `Leyenda: ...` y se imprimen antes que el resto, con caracteres de al menos 3 mm (p. 85). La adenda queda obligatoria con ellas. Una leyenda con lugar propio va en ese lugar (`additional_information`, la descripción del ítem...).","examples":[["Constancia exigida por la norma"]],"items":{"minLength":1,"type":"string"},"type":"array"},"cfe_type":{"description":"Tipo de CFE: 101-103, 111-113, 121-124, 131-133 y 141-143 (por cuenta ajena, con `fiscal_complement`), 151-153 (e-Boleta de entrada), 181, 182 y sus contingencias 2xx. Con `integration.auto_cfe_type` encendido, `\"auto\"` (o sin `cfe_type`) elige e-Factura (111) si el receptor tiene RUC y e-Ticket (101) si no; nunca exportación, contingencia ni notas. Apagado, `\"auto\"` es `403 feature_disabled`. La respuesta dice qué eligió (`cfe_type_selection`).","oneOf":[{"type":"integer"},{"enum":["auto"],"type":"string"}]},"currency":{"default":"UYU","description":"ISO 4217. Sin `currency` el comprobante es en pesos (`UYU`): la API no aplica la moneda por defecto de la configuración del cliente (`currency.default` es sólo el valor inicial del formulario del portal).","type":"string"},"due_date":{"format":"date","type":"string"},"exchange_rate":{"type":"string"},"export":{"description":"`ClauVenta`, `ViaTransp` y `ModVenta`. Cada uno puede faltar: qué pide y qué no admite cada tipo lo dice `GET /v1/catalog/cfe-types` (la factura de exportación lleva los tres, sus notas no piden la modalidad, el e-Remito de exportación no pide la cláusula, y un e-Ticket o una e-Factura sólo admiten la modalidad 80 o 90).","properties":{"sale_key":{"type":"string"},"sale_modality":{"type":"integer"},"transport_mode":{"type":"integer"}},"type":"object"},"external_id":{"description":"El número de pedido de la tienda (un entero se toma por sus dígitos; se recorta). Único por cuenta: otra emisión con el mismo es `409 external_id_taken` con el `invoice_id` de la que lo tiene, antes de tomar número (un reintento con la misma `Idempotency-Key` contesta lo de la primera). Con `integration.external_id_required` encendido es obligatorio (`422 external_id_required`). Vuelve en el CFE, en cada webhook y en `GET /v1/invoices?external_id=`.","oneOf":[{"maxLength":128,"minLength":1,"type":"string"},{"type":"integer"}]},"fiscal_complement":{"description":"Zona K (`Compl_Fiscal`, Formato CFE v25.2 p. 75-78): el mandante de una venta por cuenta ajena (131-133, 141-143 y contingencias; obligatoria salvo `professional_secrecy` 2) o de la compra de moneda extranjera por cuenta ajena de la e-Boleta de entrada (`purchase_for_resale` 2, obligatoria). En cualquier otro CFE es 422 en `Compl_Fiscal`. `RUCEmisor` (K-C1) es el del emisor. Cifrada (XML-Enc con la clave pública de la DGI) sólo la DGI la puede leer; si el servicio no tiene ese certificado responde 503 `dgi_encryption_unavailable` antes de reservar número.","properties":{"country":{"default":"UY","description":"`Pais`: UY para NIE, RUC y CI; AR, BR, CL o PY para DNI; un código de la tabla o `99` para los demás.","type":"string"},"document_type":{"default":"ruc","description":"`TipoDocMdte`. Con `purchase_for_resale` 2 sólo `nie`, `ruc` o `nife`.","enum":["ruc","ci","nie","passport","dni","nife","other"],"type":"string"},"encrypted":{"default":true,"description":"`true`: la zona viaja cifrada para la DGI (`xenc:EncryptedData`) y el receptor no la puede leer; `false`: en claro (`Compl_Fiscal_Data`).","type":"boolean"},"name":{"description":"`NombreMdte`.","maxLength":150,"minLength":1,"type":"string"},"number":{"description":"`DocMdte`, con dígito verificador si es NIE, RUC o CI. No puede ser el RUC del emisor.","maxLength":20,"type":"string"}},"required":["number","name"],"type":["object","null"]},"food_donation":{"description":"Donación de alimentos al amparo de la Ley 20.177 (FAQ 4.47): sólo en una e-Factura (al sujeto intermediario), con dos líneas por ítem donado —la de su valor y a continuación la que lo anula, el mismo ítem con la cantidad en negativo (B-C9) y el mismo indicador— y sin el indicador 5. La leyenda «Donación alimentos Ley N° 20.177» abre la descripción (`DscItem`) de la primera línea, en la zona de detalle, y así se imprime; por eso la descripción extendida de esa primera línea admite 966 caracteres (los 1000 de `DscItem` menos la leyenda y su separador) y el exceso es 422 `length` en `ItemDescription`. Si no se cumple: 422 con `field` = `Detalle/Donación`.","type":"boolean"},"global_adjustments":{"description":"Zona D (`DscRcgGlobal`): cada ítem ajusta la base de las líneas con su `indicator`. Con ítems a distintas tasas, exentos o no facturables va un ítem por indicador (Formato CFE p. 60).","items":{"properties":{"code":{"type":"string"},"description":{"description":"`GlosaDR`, hasta 100 caracteres contando el porcentaje que se le agrega con `kind: percent` (si ya trae un `%` no se agrega)","type":"string"},"indicator":{"type":"string"},"kind":{"description":"`amount`: `value` es el monto. `percent`: `value` es el porcentaje (0 a 100) sobre la suma de las líneas del indicador; el XML lleva `TpoDR` 2 y en `ValorDR` el monto que resulta, redondeado al centavo (Formato CFE D-C6, p. 61: `ValorDR` es siempre el monto), y el porcentaje queda en la glosa, `Pronto pago (10 %)`","enum":["amount","percent"],"type":"string"},"movement":{"enum":["discount","surcharge"],"type":"string"},"value":{"description":"Siempre positivo, hasta 2 decimales; el signo lo da `movement`","type":"string"}},"required":["movement","kind","description","value","indicator"],"type":"object"},"type":"array"},"gross_amounts":{"description":"`MntBruto`: 1 = líneas con IVA incluido, 2 = IMEBA y adicionales incluidos, 3 = venta de un contribuyente de IVA mínimo o Monotributo (requiere un CAE especial 2, 3 o 4 y líneas con indicador 16, 5, 6, 7 o 10). Sin `gross_amounts` los precios van sin IVA: la API no aplica `amounts.gross_amounts_default` de la configuración del cliente (es sólo el valor inicial del formulario del portal).","enum":[1,2,3],"type":"integer"},"internal_number":{"type":"string"},"issue_date":{"format":"date","type":"string"},"issuer":{"description":"Optativo entero: la API completa lo que falta desde el emisor y su perfil.","properties":{"additional_information":{"description":"`InfoAdicionalEmisor`","maxLength":150,"type":"string"},"address":{"description":"`DomFiscal`; si falta, el del perfil.","type":"string"},"branch_code":{"description":"`CdgDGISucur`. Si falta, la sucursal predeterminada del perfil; si el emisor registró sucursales, tiene que ser una de ellas (su domicilio gana sobre el de la solicitud). Sin código en ningún lado: 422.","maximum":9999,"minimum":0,"type":"integer"},"branch_name":{"description":"`EmiSucursal`","maxLength":20,"type":"string"},"business_activity":{"description":"`GiroEmis`","maxLength":100,"type":"string"},"city":{"description":"`Ciudad`; si falta, la del perfil. No hay valor por defecto.","maxLength":30,"type":"string"},"department":{"description":"`Departamento`; si falta, el del perfil. No hay valor por defecto.","maxLength":30,"type":"string"},"email":{"type":"string"},"legal_name":{"description":"`RznSoc`. Si falta, la razón social del emisor.","type":"string"},"phone":{"maxLength":20,"type":"string"},"ruc":{"description":"`RUCEmisor`. Si falta, el del emisor de la clave o la sesión; si viene, tiene que ser ése (`issuer_mismatch`).","type":"string"},"second_phone":{"maxLength":20,"type":"string"},"trade_name":{"type":"string"}},"type":"object"},"iva_status":{"description":"`IVAalDia`: 1 el emisor, 2 el mandante, 3 los dos.","type":"integer"},"lines":{"items":{"properties":{"code":{"properties":{"code":{"type":"string"},"type":{"type":"string"}},"type":"object"},"codes":{"description":"`CodItem`: hasta 5 códigos del ítem, sumados a `code`","items":{"properties":{"code":{"description":"`Cod` (B-C3); un GTIN se valida con su dígito verificador","maxLength":35,"type":"string"},"type":{"description":"`TpoCod` (B-C2)","enum":["GTIN8","GTIN12","GTIN13","GTIN14","PLU","INT1","INT2","ARCE"],"type":"string"}},"required":["type","code"],"type":"object"},"maxItems":5,"type":"array"},"description":{"maxLength":80,"type":"string"},"discount_percent":{"type":"string"},"extended_description":{"type":"string"},"indicator":{"description":"basic, minimum, exempt, export, other_rate (4), perceived_tax (11), minimum_vat_obligation (16, con `gross_amounts` 3, o en una venta por cuenta ajena)… En la e-Boleta de entrada (151-153): non_taxpayer (13, vendedor sin RUC), minimum_vat_taxpayer (14) y taxpayer (15, vendedor con RUC), suspended_vat (12, con `gross_amounts` 2), foreign_currency_resale (17, con `purchase_for_resale`), free_of_charge, non_billable y non_billable_negative. Obligatorio salvo que la línea traiga `vat_rate`.","type":"string"},"ncm":{"type":"string"},"other_rate_vat":{"description":"Sólo con `indicator` other_rate (4): el IVA de la línea a otra tasa o sobre fictos, que suma `MntIVAOtra` (A-C123). `MntNetoIVAOtra` y `MntIVAOtra` van juntos.","type":"string"},"quantity":{"type":"string"},"sub_discounts":{"description":"`SubDescuento` (B-C14, B-C15): cómo se compone el descuento","items":{"properties":{"kind":{"description":"1 = $, 2 = %","enum":["amount","percent"],"type":"string"},"value":{"description":"Dos decimales, admite negativo","type":"string"}},"required":["kind","value"],"type":"object"},"maxItems":5,"type":"array"},"sub_surcharges":{"description":"`SubRecargo` (B-C18, B-C19): cómo se compone el recargo","items":{"properties":{"kind":{"description":"1 = $, 2 = %","enum":["amount","percent"],"type":"string"},"value":{"description":"Dos decimales, admite negativo","type":"string"}},"required":["kind","value"],"type":"object"},"maxItems":5,"type":"array"},"unit":{"type":"string"},"unit_price":{"description":"Puede faltar sólo en un e-Remito (181, 281) y un e-Resguardo (182, 282), que no llevan precio (es `0`); los demás tipos lo piden.","type":"string"},"vat_rate":{"description":"La tasa de IVA de la línea (`22`, `10`, `0`) en lugar del indicador, según las tasas de la fecha de emisión (`GET /v1/catalog/vat-rates`): la básica es `basic`, la mínima `minimum` y `0` `exempt`. Con `indicator` también, los dos tienen que decir la misma tasa (`vat_rate_mismatch`); una tasa que ningún indicador tiene es `vat_rate_unknown`. Apagado (`integration.line_vat_rate`), `403 feature_disabled`.","oneOf":[{"type":"number"},{"type":"string"}]},"withholdings":{"items":{"properties":{"amount":{"type":"string"},"code":{"type":"string"},"subject_amount":{"type":"string"}},"type":"object"},"type":"array"}},"required":["description","quantity"],"type":"object"},"minItems":1,"type":"array"},"own_collection":{"description":"`IndCobPropia`.","type":"boolean"},"payment":{"enum":["cash","credit"],"type":"string"},"payment_means":{"description":"Zona E (`MediosPago`), en e-Ticket, e-Factura y e-Factura de exportación y sus notas","items":{"properties":{"code":{"description":"`CodMP` (E-C2)","maximum":999,"minimum":0,"type":"integer"},"description":{"description":"`GlosaMP` (E-C3)","maxLength":100,"type":"string"},"order":{"description":"`OrdenMP` (E-C4)","maximum":99,"minimum":0,"type":"integer"},"value":{"description":"`ValorPago` (E-C5), dos decimales, admite negativo","type":"string"}},"required":["description","value"],"type":"object"},"maxItems":40,"type":"array"},"period":{"description":"`FchDesde` y `FchHasta`: el período facturado.","items":{"format":"date","type":"string"},"maxItems":2,"minItems":2,"type":"array"},"professional_secrecy":{"description":"`SecProf`: 1 la operación, 2 la venta por cuenta ajena.","type":"integer"},"purchase_for_resale":{"description":"`IndCompraMEReventa` (A-C21) de la e-Boleta de entrada: 1 por cuenta propia, 2 por cuenta ajena; `true` vale 1 y `false` ausente.","enum":[1,2,true,false],"type":["integer","boolean"]},"recipient":{"properties":{"additional_information":{"description":"`InfoAdicional` (A-C68)","maxLength":150,"type":"string"},"address":{"description":"`DirRecep`: obligatoria en e-Factura y sus notas (A-C64), salvo secreto profesional.","type":"string"},"city":{"description":"`CiudadRecep`: obligatoria en e-Factura y sus notas (A-C65), salvo secreto profesional.","type":"string"},"country":{"default":"UY","type":"string"},"country_name":{"description":"`PaisRecep` (A-C66.1): el nombre del país como se imprime, obligatorio en una exportación (el código va en `country`).","maxLength":30,"minLength":1,"type":"string"},"delivery_place":{"description":"`LugarDestEnt` (A-C69); no existe en e-Resguardo.","maxLength":100,"type":"string"},"department":{"description":"`DeptoRecep`: obligatorio en una exportación.","type":"string"},"document_type":{"enum":["ruc","ci","nie","passport","dni","nife","other"],"type":"string"},"legal_name":{"type":"string"},"number":{"type":"string"},"postal_code":{"description":"`CP`: código postal, hasta 5 dígitos.","pattern":"^[0-9]{1,5}$","type":"string"},"purchase_id":{"description":"`CompraID` (A-C70): orden de compra; no existe en e-Resguardo.","maxLength":50,"type":"string"}},"type":"object"},"references":{"items":{"description":"Una referencia nombra un CFE (`cfe_type`, `series`, `number`) o es global (`global`: true, sólo con `reason`; no corresponde para más de 40 CFE: se emite otra nota). Si el CFE es del emisor, lo que no viene (`date`, `currency`, `exchange_rate` y, en una nota con esa única referencia en su misma moneda, `amount`) se completa desde el comprobante guardado, y lo que viene se compara con él (F-C7 a F-C10: `422 reference_mismatch` con `FechaCFEref`, `TpoMonedaRef`, `TpoCambioRef`; `reference_amount_above_payable` con `MntCFEref`). Si el CFE no está en la plataforma (papel, otro sistema), se acepta con `amount` y `currency` (y `exchange_rate` si no es UYU), como pide la FAQ v28 4.8, y la DGI verifica que exista (E12); sin ellos, `422 reference_needs_amount`. En una nota, el monto (F-C8) tampoco puede pasar lo que le dejaron al CFE las notas anteriores del mismo tipo, crédito con crédito y débito con débito (`422` con `field` `MntCFEref`; `CFE_REFERENCE_ACCUMULATION`, `docs/HOMOLOGATION.md` §11).","properties":{"amount":{"description":"`MntCFEref` (F-C8): el monto que se ajusta, en la moneda del CFE referenciado, ≤ su `MntPagar`. En una nota es obligatorio (FAQ v28 4.8); si el CFE es del emisor y es la única referencia de la nota, en su misma moneda, se completa con el `MntPagar` de la nota (y si ese total supera lo que el CFE admite, el `422` lo dice y pide `amount`)","type":"string"},"cfe_type":{"type":"integer"},"currency":{"description":"`TpoMonedaRef` (F-C9): la moneda del CFE referenciado. En una nota es obligatoria; para un CFE del emisor se completa sola si no viene","type":"string"},"date":{"description":"`FechaCFEref` (F-C7): opcional; si va, exactamente la fecha del CFE referenciado (FAQ v28 4.8). Para un CFE del emisor se completa sola si no viene","format":"date","type":"string"},"exchange_rate":{"description":"`TpoCambioRef` (F-C10): obligatorio si `currency` no es UYU; igual al del CFE referenciado. Para un CFE del emisor se completa sola si no viene","type":"string"},"global":{"description":"`IndGlobal` (F-C2): no se pueden identificar los CFE referenciados (Res. 545/2025 y 546/2025); requiere `reason` y no admite los demás campos","type":"boolean"},"number":{"type":"integer"},"reason":{"type":"string"},"series":{"type":"string"}},"type":"object"},"type":"array"},"subtotals":{"description":"`SubTotInfo`: subtotales informativos del impreso.","items":{"properties":{"description":{"type":"string"},"order":{"type":"integer"},"value":{"type":"string"}},"required":["description","value"],"type":"object"},"type":"array"},"third_party_payment":{"description":"`IndPagCta3ros`.","type":"boolean"},"transfer":{"properties":{"ownership_indicator":{"description":"`IndPropiedad`: sólo 1, bienes de terceros.","enum":[1],"type":"integer"},"transfer_type":{"type":"integer"}},"type":"object"},"value_date":{"description":"`FchValor` de un e-Resguardo.","format":"date","type":"string"},"waybill_owner":{"description":"Propietario de la mercadería de un e-Remito con `transfer.ownership_indicator` = 1 (A-C6.2 a A-C6.6). Se escribe siempre `TipoDocProp`.","properties":{"country":{"default":"UY","description":"ISO 3166 de la tabla de la DGI, o `99` para un país fuera de ella (sólo `other`, `passport` y `nife`). RUC y CI: `UY`; DNI: AR, BR, CL o PY.","type":"string"},"document_type":{"description":"Por defecto `ruc`, u `other` si viene `foreign_document`. El NIE no está en A-C6.2.","enum":["ruc","ci","other","passport","dni","nife"],"type":"string"},"foreign_document":{"description":"Número de un documento extranjero (`DocPropExt`); equivale a `number`.","maxLength":20,"type":"string"},"name":{"maxLength":150,"type":"string"},"number":{"type":"string"}},"required":["name"],"type":"object"},"withholdings":{"description":"`RetencPercep` de los totales: una fila por código. Si falta, es la suma de las retenciones de los ítems por código (A-C127, A-C128); si viene, se controla contra ellos.","items":{"properties":{"additional_info":{"type":"string"},"amount":{"type":"string"},"code":{"description":"`CodRet`, de la Tabla C (`GET /v1/catalog/codes`, `withholding_codes`)","type":"string"},"rate":{"type":"string"},"subject_amount":{"type":"string"}},"required":["code","amount"],"type":"object"},"type":"array"}},"required":["cfe_type","lines"],"type":"object"},"InvoiceSendRequest":{"additionalProperties":false,"properties":{"email":{"description":"A quién se envía","format":"email","maxLength":254,"type":"string"}},"required":["email"],"type":"object"},"InvoiceSent":{"properties":{"file_name":{"description":"El nombre del PDF adjunto","type":"string"},"invoice_id":{"format":"uuid","type":"string"},"sent_at":{"format":"date-time","type":"string"},"sent_to":{"format":"email","type":"string"}},"required":["invoice_id","sent_to","sent_at","file_name"],"type":"object"},"LearnedExchangeAddress":{"properties":{"confirmed":{"type":"boolean"},"confirmed_at":{"format":"date-time","type":["string","null"]},"directory_email":{"description":"La del directorio de la DGI para el RUC, que gana sobre una no confirmada","type":["string","null"]},"email":{"format":"email","type":"string"},"ruc":{"type":"string"},"tenant_id":{"format":"uuid","type":"string"},"tenant_name":{"type":"string"},"tenant_ruc":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["tenant_id","tenant_ruc","tenant_name","ruc","email","confirmed","updated_at"],"type":"object"},"LimitProblem":{"allOf":[{"$ref":"#/components/schemas/Problem"},{"properties":{"limit":{"enum":["emissions_per_month","emissions_per_day","api_requests_per_minute","portal_users","active_api_keys","branches","active_series","received_per_month","webhook_destinations","notification_destinations","attachment_max_bytes","portal_history_months","assistant_messages_per_month","assistant_tokens_per_month","sandbox_keys","open_orders","safety_cap_day","safety_cap_month","overage"],"type":"string"},"max":{"type":"integer"},"resets_at":{"description":"Cuándo se renueva; null para lo que no se renueva (usuarios, claves, sucursales...)","format":"date-time","type":["string","null"]},"used":{"type":"integer"}},"type":"object"}],"description":"Un límite de la membresía alcanzado (`429 quota_exceeded`, `429 limit_reached`, `429 rate_limited`, `422 limit_reached` para el adjunto de la adenda). Lo rechazado no reservó número ni escribió nada."},"LimitUsage":{"properties":{"limit":{"enum":["emissions_per_month","emissions_per_day","api_requests_per_minute","portal_users","active_api_keys","branches","active_series","received_per_month","webhook_destinations","notification_destinations","attachment_max_bytes","portal_history_months","assistant_messages_per_month","assistant_tokens_per_month","sandbox_keys","open_orders","safety_cap_day","safety_cap_month","overage"],"type":"string"},"max":{"description":"null: sin límite","type":["integer","null"]},"period":{"enum":["month","day","minute","current","value"],"type":"string"},"period_label":{"examples":["2026-10","2026-10-19"],"type":["string","null"]},"remaining":{"type":["integer","null"]},"resets_at":{"format":"date-time","type":["string","null"]},"source":{"enum":["plan","override"],"type":"string"},"status":{"enum":["ok","warning","reached"],"type":"string"},"used":{"type":["integer","null"]}},"type":"object"},"LoadFiscalRates":{"properties":{"rates":{"items":{"properties":{"currency":{"type":"string"},"date":{"format":"date","type":"string"},"rate":{"type":"string"}},"required":["currency","date","rate"],"type":"object"},"maxItems":1000,"type":"array"},"ui_values":{"items":{"$ref":"#/components/schemas/UiValue"},"type":"array"}},"type":"object"},"Membership":{"properties":{"at_limit":{"enum":["BLOCK","OVERAGE"],"type":"string"},"auto_renew":{"description":"Si la vigencia se renueva sola al terminar (la cambia el equipo de la plataforma: `PATCH /v1/admin/tenants/{id}/membership`). Apagada, la membresía vence como siempre.","type":"boolean"},"can_emit":{"type":"boolean"},"class":{"enum":["LIMITED","USAGE"],"type":"string"},"ends_at":{"format":"date-time","type":["string","null"]},"next_renewal":{"description":"La próxima renovación automática; `null` si no se renueva (opción apagada, sin fecha de fin, una prueba sin membresía programada, suspendida o vencida hace más de 12 horas). Se renueva hasta una hora antes de `at`, sin cortar la emisión. Con `renewable: false` no se va a hacer: la membresía vence en `at`.","properties":{"at":{"description":"El fin de la vigencia (o de la prueba) que se renueva.","format":"date-time","type":"string"},"ends_at":{"description":"El nuevo fin: la vigencia dura lo mismo que la actual (meses enteros del calendario de Uruguay si lo son; un mes si dura menos de un día). `null`: una prueba que pasa a activa sin fin.","format":"date-time","type":["string","null"]},"from_trial":{"description":"Una prueba que pasa a activa con la membresía programada.","type":"boolean"},"plan_code":{"type":["string","null"]},"plan_id":{"description":"La membresía del período nuevo: la programada si empieza a más tardar con él, si no la actual.","format":"uuid","type":"string"},"plan_name":{"type":["string","null"]},"refusal":{"description":"`renewal_period_too_long`: la vigencia dura más de un año (366 días), y renovarla daría otro lapso igual. El equipo ajusta «Desde» (`starts_at`).","enum":["renewal_period_too_long",null],"type":["string","null"]},"renewable":{"description":"`false` si al llegar `at` no se renueva (`refusal` dice por qué) y la membresía vence ahí, como sin la opción.","type":"boolean"},"starts_at":{"format":"date-time","type":"string"}},"type":["object","null"]},"pending":{"properties":{"from":{"format":"date-time","type":"string"},"plan_code":{"type":["string","null"]},"plan_id":{"format":"uuid","type":"string"},"plan_name":{"type":["string","null"]}},"type":["object","null"]},"plan_code":{"type":"string"},"plan_id":{"format":"uuid","type":["string","null"]},"plan_name":{"type":"string"},"safety_block":{"type":"boolean"},"starts_at":{"format":"date-time","type":["string","null"]},"state":{"enum":["TRIAL","ACTIVE","SUSPENDED","EXPIRED"],"type":"string"},"trial_ends_at":{"format":"date-time","type":["string","null"]}},"type":"object"},"MembershipAlert":{"properties":{"created_at":{"format":"date-time","type":"string"},"limit":{"type":"string"},"mailed_at":{"format":"date-time","type":["string","null"]},"max":{"type":"integer"},"period":{"type":"string"},"tenant_id":{"description":"Sólo en la consola","format":"uuid","type":"string"},"tenant_name":{"description":"Sólo en la consola","type":"string"},"tenant_ruc":{"description":"Sólo en la consola","type":"string"},"threshold":{"enum":[80,100],"type":"integer"},"used":{"type":"integer"}},"type":"object"},"MembershipAssignRequest":{"additionalProperties":false,"properties":{"clear_overrides":{"default":false,"type":"boolean"},"effective":{"default":"now","enum":["now","next_period"],"type":"string"},"plan":{"description":"id o código de la membresía","type":"string"},"reason":{"maxLength":2000,"type":"string"}},"required":["plan","reason"],"type":"object"},"MembershipChangeRequest":{"additionalProperties":false,"properties":{"auto_renew":{"description":"Renovación automática al terminar la vigencia (va en el historial como `membership.auto_renew`).","type":"boolean"},"ends_at":{"format":"date-time","type":["string","null"]},"overrides":{"description":"`{límite: valor}` (null: sin límite), `at_limit`, `overage_cap`, `safety_block`","type":"object"},"reason":{"maxLength":2000,"type":"string"},"remove":{"items":{"type":"string"},"type":"array"},"starts_at":{"format":"date-time","type":"string"},"trial_ends_at":{"format":"date-time","type":["string","null"]}},"required":["reason"],"type":"object"},"MembershipPlan":{"properties":{"at_limit":{"enum":["BLOCK","OVERAGE"],"type":"string"},"class":{"enum":["LIMITED","USAGE"],"type":"string"},"code":{"pattern":"^[a-z0-9][a-z0-9_-]{0,39}$","type":"string"},"created_at":{"format":"date-time","type":"string"},"currency":{"examples":["UYU"],"type":"string"},"description":{"maxLength":500,"type":["string","null"]},"features":{"description":"`{función: valor}` con las claves de la configuración","type":"object"},"id":{"format":"uuid","type":"string"},"is_default":{"type":"boolean"},"limits":{"description":"`{límite: máximo}`, null sin límite; `overage` es el tope del excedente","properties":{"active_api_keys":{"type":["integer","null"]},"active_series":{"type":["integer","null"]},"api_requests_per_minute":{"type":["integer","null"]},"assistant_messages_per_month":{"description":"Mensajes al asistente por mes; vacío, sin tope del plan","type":["integer","null"]},"assistant_tokens_per_month":{"description":"Tokens del asistente por mes (entrada, con o sin caché, y salida); vacío, sin tope del plan","type":["integer","null"]},"attachment_max_bytes":{"type":["integer","null"]},"branches":{"type":["integer","null"]},"emissions_per_day":{"type":["integer","null"]},"emissions_per_month":{"type":["integer","null"]},"notification_destinations":{"type":["integer","null"]},"open_orders":{"description":"Órdenes abiertas a la vez; vacío, el tope de la plataforma (`CFE_ORDER_MAX_OPEN`)","type":["integer","null"]},"overage":{"type":["integer","null"]},"portal_history_months":{"type":["integer","null"]},"portal_users":{"type":["integer","null"]},"received_per_month":{"type":["integer","null"]},"safety_cap_day":{"type":["integer","null"]},"safety_cap_month":{"type":["integer","null"]},"sandbox_keys":{"description":"Claves de prueba activas; vacío, el tope de la plataforma (10). No cuentan en `active_api_keys`","type":["integer","null"]},"webhook_destinations":{"type":["integer","null"]}},"type":"object"},"name":{"maxLength":80,"type":"string"},"on_sale":{"type":"boolean"},"price_tiers":{"items":{"properties":{"from":{"minimum":1,"type":"integer"},"unit_price":{"type":"string"}},"type":"object"},"type":"array"},"safety_block":{"type":"boolean"},"tenants":{"type":"integer"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"MembershipPlanRequest":{"additionalProperties":false,"properties":{"at_limit":{"enum":["BLOCK","OVERAGE"],"type":"string"},"class":{"enum":["LIMITED","USAGE"],"type":"string"},"code":{"pattern":"^[a-z0-9][a-z0-9_-]{0,39}$","type":"string"},"currency":{"examples":["UYU"],"type":"string"},"description":{"maxLength":500,"type":["string","null"]},"features":{"description":"`{función: valor}` con las claves de la configuración","type":"object"},"is_default":{"type":"boolean"},"limits":{"description":"`{límite: máximo}`, null sin límite; `overage` es el tope del excedente","properties":{"active_api_keys":{"type":["integer","null"]},"active_series":{"type":["integer","null"]},"api_requests_per_minute":{"type":["integer","null"]},"assistant_messages_per_month":{"description":"Mensajes al asistente por mes; vacío, sin tope del plan","type":["integer","null"]},"assistant_tokens_per_month":{"description":"Tokens del asistente por mes (entrada, con o sin caché, y salida); vacío, sin tope del plan","type":["integer","null"]},"attachment_max_bytes":{"type":["integer","null"]},"branches":{"type":["integer","null"]},"emissions_per_day":{"type":["integer","null"]},"emissions_per_month":{"type":["integer","null"]},"notification_destinations":{"type":["integer","null"]},"open_orders":{"description":"Órdenes abiertas a la vez; vacío, el tope de la plataforma (`CFE_ORDER_MAX_OPEN`)","type":["integer","null"]},"overage":{"type":["integer","null"]},"portal_history_months":{"type":["integer","null"]},"portal_users":{"type":["integer","null"]},"received_per_month":{"type":["integer","null"]},"safety_cap_day":{"type":["integer","null"]},"safety_cap_month":{"type":["integer","null"]},"sandbox_keys":{"description":"Claves de prueba activas; vacío, el tope de la plataforma (10). No cuentan en `active_api_keys`","type":["integer","null"]},"webhook_destinations":{"type":["integer","null"]}},"type":"object"},"name":{"maxLength":80,"type":"string"},"on_sale":{"type":"boolean"},"price_tiers":{"items":{"properties":{"from":{"minimum":1,"type":"integer"},"unit_price":{"type":"string"}},"type":"object"},"type":"array"},"reason":{"maxLength":2000,"type":"string"},"safety_block":{"type":"boolean"}},"required":["reason"],"type":"object"},"MembershipRenewal":{"properties":{"created_at":{"format":"date-time","type":"string"},"ends_at":{"description":"`null`: una prueba que pasó a activa sin fin.","format":"date-time","type":["string","null"]},"from_trial":{"type":"boolean"},"id":{"type":"integer"},"mail_attempts":{"type":"integer"},"mailed_at":{"description":"Cuándo salió el correo a los dueños; `null` mientras espera.","format":"date-time","type":["string","null"]},"plan_code":{"description":"La membresía del período nuevo, con el nombre que tenía entonces.","type":"string"},"plan_id":{"format":"uuid","type":"string"},"plan_name":{"type":"string"},"previous_ends_at":{"description":"El fin que siguió: el de la vigencia o el de la prueba.","format":"date-time","type":"string"},"starts_at":{"format":"date-time","type":"string"}},"required":["id","previous_ends_at","starts_at","plan_id","plan_code","plan_name","from_trial","created_at","mail_attempts"],"type":"object"},"MembershipRenewalPage":{"properties":{"next":{"description":"`before` de la página siguiente; `null` en la última.","type":["integer","null"]},"renewals":{"items":{"$ref":"#/components/schemas/MembershipRenewal"},"type":"array"}},"required":["renewals","next"],"type":"object"},"MembershipRenewalRefusal":{"description":"Una renovación automática que no se haría (ver `API_PORTAL.md`, «Renovación automática»).","properties":{"at":{"description":"El fin del que se trata.","format":"date-time","type":"string"},"code":{"description":"`renewal_period_too_long`: la vigencia dura más de un año. `renewal_end_already_renewed`: esa fecha de fin ya se renovó una vez (una renovación por fin) y vencería ahí.","enum":["renewal_period_too_long","renewal_end_already_renewed"],"type":"string"},"days":{"description":"Cuántos días dura la vigencia.","type":["integer","null"]},"message":{"description":"Qué pasa y qué hacer, para el equipo.","type":"string"}},"required":["code","message","at"],"type":"object"},"MembershipTrialRequest":{"additionalProperties":false,"properties":{"days":{"maximum":366,"minimum":1,"type":"integer"},"reason":{"maxLength":2000,"type":"string"},"until":{"format":"date-time","type":"string"}},"required":["reason"],"type":"object"},"NoteRequest":{"properties":{"body":{"maxLength":5000,"type":"string"},"pinned":{"type":"boolean"}},"required":["body"],"type":"object"},"NoteUpdateRequest":{"properties":{"body":{"maxLength":5000,"type":"string"},"pinned":{"type":"boolean"}},"type":"object"},"Notice":{"properties":{"created_at":{"format":"date-time","type":"string"},"detail":{"description":"El primer párrafo del mensaje que recibiría un destino","type":"string"},"facts":{"additionalProperties":true,"description":"Los datos del evento, los mismos de su webhook","type":"object"},"id":{"description":"El aviso, como lo nombra `up_to`. Opaco (`ntc_` y 26 caracteres): no es un número de la plataforma ni se puede ordenar.","pattern":"^ntc_[a-z2-7]{26}$","type":"string"},"kind":{"description":"El evento del catálogo (`GET /v1/notifications/events`), por ejemplo `cae.running_low`","type":"string"},"read":{"description":"Si esta persona ya lo leyó","type":"boolean"},"severity":{"description":"`danger`: la emisión se detuvo o la DGI rechazó algo; `warning`: hay que hacer algo antes de que se detenga; `info`: sólo pasó","enum":["danger","warning","info"],"type":"string"},"title":{"type":"string"}},"required":["id","kind","severity","title","detail","created_at","read","facts"],"type":"object"},"NoticesPage":{"properties":{"count":{"type":"integer"},"has_more":{"type":"boolean"},"limit":{"type":"integer"},"next_cursor":{"description":"Opaco (el `id` del último aviso de la página); `null` en la última","type":["string","null"]},"notices":{"items":{"$ref":"#/components/schemas/Notice"},"type":"array"},"unread":{"description":"Cuántos avisos de la cuenta le quedan sin leer a esta persona, en total","format":"int64","type":"integer"}},"required":["count","has_more","next_cursor","limit","unread","notices"],"type":"object"},"NoticesRead":{"properties":{"read_up_to":{"description":"El `id` del aviso más nuevo que esta persona leyó; `null` si todavía no leyó ninguno","type":["string","null"]},"unread":{"format":"int64","type":"integer"}},"required":["read_up_to","unread"],"type":"object"},"NoticesReadRequest":{"properties":{"up_to":{"description":"El `id` del aviso más nuevo leído, como lo da `GET /v1/notices` (opaco, `ntc_…`)","pattern":"^ntc_[a-z2-7]{26}$","type":"string"}},"required":["up_to"],"type":"object"},"Notification":{"properties":{"attempts":{"type":"integer"},"created_at":{"format":"date-time","type":"string"},"dead_at":{"format":"date-time","type":["string","null"]},"destination_id":{"format":"uuid","type":"string"},"facts":{"additionalProperties":true,"description":"De qué trata el aviso: los mismos datos que su evento de webhook","type":"object"},"id":{"description":"El mensaje. Opaco (`ntf_` y 26 caracteres): no es un número de la plataforma ni se puede ordenar.","pattern":"^ntf_[a-z2-7]{26}$","type":"string"},"last_attempt_at":{"format":"date-time","type":["string","null"]},"last_error":{"type":["string","null"]},"next_attempt_at":{"format":"date-time","type":["string","null"]},"retried_by":{"description":"El `id` del reenvío más reciente de el mensaje; `null` si nunca se volvió a enviar Opaco (`ntf_` y 26 caracteres): no es un número de la plataforma ni se puede ordenar.","pattern":"^ntf_[a-z2-7]{26}$","type":["string","null"]},"retry_of":{"description":"El `id` de el mensaje que esta vuelve a enviar (`POST /v1/notifications/destinations/{id}/history/{notification_id}/retry`); `null` si no es un reenvío Opaco (`ntf_` y 26 caracteres): no es un número de la plataforma ni se puede ordenar.","pattern":"^ntf_[a-z2-7]{26}$","type":["string","null"]},"sent_at":{"format":"date-time","type":["string","null"]},"status":{"description":"`pending`: espera su primer intento; `retrying`: falló y se reintenta en `next_attempt_at` (6 intentos, de 30 segundos a 3 horas); `paused`: su destino está pausado, sale cuando se reanude; `sent`; `dead`: el canal lo rechazó o se agotaron los intentos","enum":["pending","retrying","paused","sent","dead"],"type":"string"},"title":{"description":"Lo que dijo el mensaje, en español","type":"string"},"trigger":{"description":"El evento, `verification` (un código), `destination.verified` (la confirmación del destino) o `test`","type":"string"}},"required":["id","destination_id","trigger","title","status","attempts","last_error","created_at","last_attempt_at","next_attempt_at","sent_at","dead_at","facts","retry_of","retried_by"],"type":"object"},"NotificationCatalog":{"properties":{"all":{"const":"*","type":"string"},"channels":{"items":{"properties":{"available":{"description":"Si okCFE tiene el canal configurado: sin él, crear un destino responde `422 channel_not_available`","type":"boolean"},"channel":{"$ref":"#/components/schemas/NotificationChannel"},"method":{"enum":["code","link"],"type":"string"},"name":{"type":"string"}},"required":["channel","name","method","available"],"type":"object"},"type":"array"},"default_events":{"description":"Los eventos de un destino nuevo que no los elige","items":{"type":"string"},"type":"array"},"events":{"items":{"$ref":"#/components/schemas/WebhookEvent"},"type":"array"},"telegram_bot":{"description":"El usuario del bot de Telegram, sin `@`","type":["string","null"]},"verification":{"properties":{"code_minutes":{"type":"integer"},"link_minutes":{"type":"integer"},"max_attempts":{"type":"integer"}},"required":["code_minutes","link_minutes","max_attempts"],"type":"object"}},"required":["all","channels","events","default_events","verification","telegram_bot"],"type":"object"},"NotificationChannel":{"description":"`email`, `whatsapp` (WhatsApp Business de Meta), `telegram` (el bot de okCFE), `slack` o `teams` (webhooks entrantes).","enum":["email","whatsapp","telegram","slack","teams"],"type":"string"},"NotificationDestination":{"properties":{"address":{"description":"El correo, el número en E.164 (`+59899123456`) o el chat de Telegram una vez vinculado. De un webhook de Slack o Teams, sólo lo necesario para distinguirlo: la URL es un secreto.","type":["string","null"]},"channel":{"$ref":"#/components/schemas/NotificationChannel"},"consecutive_failures":{"type":"integer"},"created_at":{"format":"date-time","type":"string"},"enabled":{"description":"Si recibe los avisos ahora: `false` pausado o sin confirmar","type":"boolean"},"events":{"description":"Los eventos que recibe, como un webhook: `[\"*\"]`, todos (también los que se agreguen después)","items":{"type":"string"},"type":"array"},"id":{"format":"uuid","type":"string"},"label":{"description":"Telegram: el título o el usuario del chat","type":["string","null"]},"last_error":{"type":["string","null"]},"last_failure_at":{"format":"date-time","type":["string","null"]},"last_success_at":{"format":"date-time","type":["string","null"]},"name":{"description":"1 a 80 caracteres","type":"string"},"owner_user_id":{"description":"El usuario dueño del destino: si deja la empresa, el destino se revoca","format":"uuid","type":["string","null"]},"state":{"description":"`pending`: espera la verificación; `active`; `disabled`: pausado en el portal; `unsubscribed`: se dio de baja (STOP, /stop, bloqueó el bot o el webhook ya no existe); `revoked`: su usuario dejó la empresa. Los dos últimos vuelven con una verificación nueva.","enum":["pending","active","disabled","unsubscribed","revoked"],"type":"string"},"state_changed_at":{"format":"date-time","type":"string"},"state_reason":{"description":"`user`, `stop`, `blocked`, `gone` o `member_removed`","type":["string","null"]},"updated_at":{"format":"date-time","type":"string"},"verification":{"$ref":"#/components/schemas/NotificationVerification"},"verified_at":{"format":"date-time","type":["string","null"]}},"required":["id","channel","name","address","label","state","state_reason","state_changed_at","verified_at","owner_user_id","consecutive_failures","last_success_at","last_failure_at","last_error","created_at","updated_at","events","enabled"],"type":"object"},"NotificationDestinationCreate":{"additionalProperties":false,"properties":{"address":{"description":"El correo, el número con código de país (`+59899123456`; `099 123 456` se toma como uruguayo) o la URL del webhook entrante de Slack o Teams. Telegram no lleva: el chat se vincula con el enlace de la respuesta.","type":["string","null"]},"channel":{"$ref":"#/components/schemas/NotificationChannel"},"events":{"description":"Nombres del catálogo (`GET /v1/notifications/events`) que no sean sólo de webhook, o `[\"*\"]` para todos. Omitido: `default_events`.","items":{"type":"string"},"minItems":1,"type":"array"},"name":{"examples":["Celular de Ana"],"maxLength":80,"type":"string"},"owner_user_id":{"description":"Omitido: el usuario de la sesión. Sólo `OWNER` (o una clave) da un destino a otro usuario o a ninguno.","format":"uuid","type":["string","null"]}},"required":["channel","name"],"type":"object"},"NotificationDestinationList":{"properties":{"destinations":{"items":{"$ref":"#/components/schemas/NotificationDestination"},"type":"array"}},"required":["destinations"],"type":"object"},"NotificationDestinationUpdate":{"additionalProperties":false,"properties":{"enabled":{"description":"`false` pausa un destino activo: lo que pase mientras tanto no se le envía y lo pendiente espera; `true` lo reanuda y lo pendiente sale. Uno dado de baja o revocado responde `409 verification_required`.","type":"boolean"},"events":{"description":"Como en la creación. Lo pendiente de un evento que deja de recibir se descarta.","items":{"type":"string"},"minItems":1,"type":"array"},"name":{"maxLength":80,"type":"string"},"owner_user_id":{"format":"uuid","type":["string","null"]}},"type":"object"},"NotificationHistoryPage":{"properties":{"count":{"type":"integer"},"has_more":{"type":"boolean"},"limit":{"type":"integer"},"next_cursor":{"type":["string","null"]},"notifications":{"items":{"$ref":"#/components/schemas/Notification"},"type":"array"}},"required":["count","has_more","next_cursor","limit","notifications"],"type":"object"},"NotificationTestResult":{"properties":{"duration_ms":{"type":"integer"},"error":{"type":["string","null"]},"notification":{"anyOf":[{"$ref":"#/components/schemas/Notification"},{"type":"null"}]},"sent":{"type":"boolean"}},"required":["sent","error","duration_ms","notification"],"type":"object"},"NotificationThreshold":{"properties":{"default_settings":{"$ref":"#/components/schemas/NotificationThresholdSettings"},"event":{"enum":["cae.running_low","cae.expiring","certificate.expiring"],"type":"string"},"kind":{"enum":["low","days","repeating"],"type":"string"},"settings":{"$ref":"#/components/schemas/NotificationThresholdSettings"},"settings_fields":{"description":"Lo que toma el umbral, para armar el formulario","items":{"additionalProperties":true,"type":"object"},"type":"array"},"title":{"type":"string"},"updated_at":{"description":"`null`: el del catálogo, sin cambios","format":"date-time","type":["string","null"]}},"required":["event","title","kind","settings","default_settings","settings_fields","updated_at"],"type":"object"},"NotificationThresholdList":{"properties":{"thresholds":{"items":{"$ref":"#/components/schemas/NotificationThreshold"},"type":"array"}},"required":["thresholds"],"type":"object"},"NotificationThresholdSettings":{"additionalProperties":true,"description":"Según el evento. `cae.running_low`: `{\"by\": \"percent\" | \"count\" | \"days\", \"value\": n}` (porcentaje 1-99 de lo cargado, cantidad de números 1-1.000.000, o días al ritmo actual 1-365). `cae.expiring`: `{\"days\": [30, 7, 1]}` (1 a 8 umbrales de 1 a 365 días). `certificate.expiring`: `{\"days\": [30, 15, 7, 1], \"repeat_every_days\": null | 1-30}` (`null`: un aviso por umbral; un número: se repite cada tantos días hasta que se sube otro certificado). Los demás: `{}`.","examples":[{"by":"percent","value":10},{"days":[30,15,7,1],"repeat_every_days":3}],"type":"object"},"NotificationThresholdUpdate":{"additionalProperties":false,"properties":{"settings":{"anyOf":[{"$ref":"#/components/schemas/NotificationThresholdSettings"},{"type":"null"}],"description":"Lo que cambia; lo que no nombra toma el valor del catálogo. `null`: el del catálogo."}},"type":"object"},"NotificationVerification":{"properties":{"error":{"type":["string","null"]},"expires_at":{"description":"El código vale 10 minutos; el enlace de Telegram, 15 y una sola vez.","format":"date-time","type":"string"},"link":{"description":"Telegram: `https://t.me/<bot>?start=<token>`. Vincula el chat que lo abre con este destino y con ningún otro.","type":["string","null"]},"max_attempts":{"description":"Códigos incorrectos que admite antes de pedir otro","type":"integer"},"method":{"description":"`code`: llega un código de 6 dígitos a la dirección y se escribe en `POST .../verify`; `link`: Telegram, se abre `link` desde el chat que recibirá los avisos.","enum":["code","link"],"type":"string"},"sent":{"description":"Si el código salió; `false` con `error` cuando el canal lo rechazó (se puede pedir otro).","type":"boolean"},"sent_to":{"type":["string","null"]}},"required":["method","expires_at","sent_to","sent","error","link","max_attempts"],"type":"object"},"NotificationVerifyRequest":{"additionalProperties":false,"properties":{"code":{"examples":["123456"],"type":"string"}},"required":["code"],"type":"object"},"Offboarding":{"properties":{"completed_at":{"format":"date-time","type":["string","null"]},"last_day":{"format":"date","type":"string"},"reason":{"type":"string"},"requested_at":{"format":"date-time","type":"string"},"requested_by":{"format":"uuid","type":["string","null"]},"requested_by_email":{"type":["string","null"]},"tenant_id":{"format":"uuid","type":"string"}},"type":"object"},"Operations":{"description":"Lo que necesita a un operador, por cliente. Cada fila nombra su cliente; ninguna lleva un CFE, una clave ni un contenido.","properties":{"attention":{"$ref":"#/components/schemas/OperationsAttention"},"backlog":{"items":{"$ref":"#/components/schemas/OperationsBacklog"},"type":"array"},"cae":{"items":{"$ref":"#/components/schemas/OperationsCae"},"type":"array"},"certificates":{"description":"Los certificados revocados, vencidos, todavía no vigentes o que vencen en 30 días, lo peor primero, sin los sandbox (salvo `include_sandbox`)","items":{"$ref":"#/components/schemas/AdminCertificate"},"type":"array"},"days":{"description":"Ventana de `rejections` y `reports`, en días (7)","type":"integer"},"generated_at":{"format":"date-time","type":"string"},"mail":{"items":{"$ref":"#/components/schemas/OperationsMail"},"type":"array"},"membership_alerts":{"description":"Avisos del 80 % y el 100 % de los límites de las membresías en la ventana, lo más nuevo primero, con el nombre del cliente (hasta 100).","items":{"$ref":"#/components/schemas/MembershipAlert"},"type":"array"},"pki":{"$ref":"#/components/schemas/OperationsPki"},"rejections":{"items":{"$ref":"#/components/schemas/OperationsRejection"},"type":"array"},"reports":{"items":{"$ref":"#/components/schemas/OperationsReport"},"type":"array"},"review":{"$ref":"#/components/schemas/OperationsReview"},"without_certificate":{"description":"Los clientes reales sin certificado propio","properties":{"missing":{"description":"No pueden firmar hasta subir uno","type":"integer"},"platform":{"description":"Firman con el de la plataforma (`CFE_ALLOW_GLOBAL_CERTIFICATE`)","type":"integer"}},"required":["platform","missing"],"type":"object"},"workers":{"items":{"$ref":"#/components/schemas/OperationsWorker"},"type":"array"}},"required":["generated_at","days","cae","reports","rejections","backlog","workers","mail","review","pki","certificates","without_certificate","attention"],"type":"object"},"OperationsAttention":{"description":"Lo que necesita a alguien, una cosa por fila de su sección: cada worker trancado o sin latido, cada circuito hacia la DGI abierto (y una si no corre ningún worker), cada acuse retenido y sobre desconocido, cada certificado de `certificates`, cada tipo de CFE cuya numeración se agota o vence, cada cliente con reportes diarios sin recibir y cada cliente con rechazos. El atraso, el correo y los avisos de consumo no cuentan: son para saber.","properties":{"cae":{"type":"integer"},"certificates":{"type":"integer"},"critical":{"description":"Algo frena ahora: ningún worker, una revisión pendiente, un tipo sin números o un certificado que no firma","type":"boolean"},"rejections":{"type":"integer"},"reports":{"type":"integer"},"review":{"type":"integer"},"total":{"description":"La suma de las demás","type":"integer"},"workers":{"type":"integer"}},"required":["total","workers","review","certificates","cae","reports","rejections","critical"],"type":"object"},"OperationsBacklog":{"description":"Un cliente con emisiones que la DGI todavía no contestó.","properties":{"held_envelopes":{"description":"Sobres con el acuse retenido para revisión","type":"integer"},"name":{"type":"string"},"oldest_pending":{"format":"date-time","type":"string"},"pending":{"description":"Contadas hasta 10.001","type":"integer"},"ruc":{"type":"string"},"sending_envelopes":{"description":"Sobres en camino o esperando la respuesta de la DGI","type":"integer"},"tenant_id":{"format":"uuid","type":"string"},"unsent":{"description":"De ellas, en ningún sobre todavía","type":"integer"}},"type":"object"},"OperationsCae":{"description":"Un tipo de CFE de un cliente cuya numeración se agota o vence (las razones de `cfe_cae_*` de `/metrics`). Los rangos retirados (`withdrawn_at`: otro rango tomó sus números) no suman números usables.","properties":{"cfe_type":{"type":"integer"},"exhausted":{"description":"Sin números en rangos vigentes","type":"boolean"},"expired":{"description":"Todos sus rangos vencieron (en los últimos 90 días)","type":"boolean"},"expiring":{"description":"Todos sus números vencen en menos de 30 días","type":"boolean"},"last_expiry":{"format":"date","type":["string","null"]},"loaded":{"description":"Tamaño de los rangos que todavía tienen números","type":"integer"},"low_percent":{"description":"Menos del 10 % de lo cargado","type":"boolean"},"name":{"type":"string"},"per_day":{"description":"Números usados por día, al ritmo de sus rangos","type":"number"},"ruc":{"type":"string"},"short_pace":{"description":"Menos de 15 días de números a su ritmo","type":"boolean"},"soonest_expiry":{"format":"date","type":["string","null"]},"tenant_id":{"format":"uuid","type":"string"},"usable":{"description":"Números que quedan en rangos no vencidos","type":"integer"}},"type":"object"},"OperationsMail":{"description":"Un cliente con mensajes del intercambio entre empresas fallidos o en espera.","properties":{"failed":{"description":"Fallidos, hasta que alguien los reintente","type":"integer"},"last_error":{"type":["string","null"]},"last_failed_at":{"format":"date-time","type":["string","null"]},"name":{"type":"string"},"oldest_due":{"format":"date-time","type":["string","null"]},"pending":{"type":"integer"},"ruc":{"type":"string"},"tenant_id":{"format":"uuid","type":"string"}},"type":"object"},"OperationsPki":{"description":"Las listas de revocación (CRL) de las CA, como las juzga `GET /v1/admin/pki` (que tiene cada una): vencida es la que pasó su `nextUpdate` más `CFE_PKI_CRL_GRACE_HOURS`; en modo `soft`, un certificado que su CA revocó mientras tanto sigue firmando. En `/metrics`: `cfe_pki_crl_stale`, `cfe_pki_crl_missing` y `cfe_pki_crl_oldest_age_seconds`.","properties":{"lists":{"description":"Listas guardadas","type":"integer"},"missing":{"description":"Pedidas y nunca bajadas (`MISSING`)","type":"integer"},"oldest_age_seconds":{"description":"Segundos desde el `thisUpdate` de la lista bajada más vieja","type":["number","null"]},"stale":{"description":"Bajadas alguna vez y vencidas (`STALE`)","type":"integer"},"stale_urls":{"description":"Las vencidas, la más atrasada primero (hasta 20)","items":{"type":"string"},"maxItems":20,"type":"array"}},"required":["lists","stale","missing","oldest_age_seconds","stale_urls"],"type":"object"},"OperationsRejection":{"description":"Un cliente con rechazos de la DGI en los últimos `days` días.","properties":{"envelopes":{"description":"Sobres rechazados enteros (`BS`)","type":"integer"},"last_causes":{"description":"Motivos del último CFE rechazado","items":{"$ref":"#/components/schemas/ReceptionCause"},"type":["array","null"]},"last_issue_date":{"format":"date","type":["string","null"]},"name":{"type":"string"},"reissue":{"description":"De ellos, rechazados con `E09`: el número no se anula, se vuelve a emitir","type":"integer"},"rejected":{"description":"CFE rechazados (`BE`), por fecha de emisión","type":"integer"},"ruc":{"type":"string"},"tenant_id":{"format":"uuid","type":"string"}},"type":"object"},"OperationsReport":{"description":"Un cliente con días cerrados sin reporte diario recibido por la DGI (`AR`).","properties":{"failed":{"description":"Días cuyo reporte se abandonó o fue rechazado (`BR`), sin uno recibido después","items":{"format":"date","type":"string"},"type":"array"},"in_progress":{"description":"Reportes en cola, esperando o enviándose","type":"integer"},"last_received":{"format":"date","type":["string","null"]},"name":{"type":"string"},"overdue":{"description":"Días pasada su espera sin reporte recibido","items":{"format":"date","type":"string"},"type":"array"},"ruc":{"type":"string"},"scheduled":{"description":"El cliente tiene el envío automático encendido","type":"boolean"},"tenant_id":{"format":"uuid","type":"string"}},"type":"object"},"OperationsReview":{"description":"Lo que espera una revisión: se lista en `/v1/admin/acknowledgements` y `/v1/admin/submissions`.","properties":{"held_acknowledgements":{"type":"integer"},"held_oldest_seconds":{"type":"number"},"unknown_envelopes":{"type":"integer"},"unknown_oldest_seconds":{"type":"number"}},"type":"object"},"OperationsWorker":{"description":"Un worker de envío, según su latido (último día).","properties":{"beat_at":{"format":"date-time","type":"string"},"circuit_failures":{"type":"integer"},"circuit_open":{"description":"El circuito hacia la DGI está abierto","type":"boolean"},"host":{"type":"string"},"last_tick_at":{"description":"Cuándo dio la vuelta su loop más atrasado","format":"date-time","type":"string"},"started_at":{"format":"date-time","type":"string"},"state":{"enum":["running","stuck","silent","stopped"],"type":"string"},"stopped_at":{"format":"date-time","type":["string","null"]},"version":{"type":"string"},"worker_id":{"format":"uuid","type":"string"}},"type":"object"},"Order":{"allOf":[{"$ref":"#/components/schemas/InvoicePreview"},{"properties":{"cancelled_at":{"format":"date-time","type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"executed_at":{"format":"date-time","type":["string","null"]},"expired_at":{"format":"date-time","type":["string","null"]},"expires_at":{"format":"date-time","type":"string"},"external_id":{"description":"El número de pedido de la tienda; único entre las órdenes abiertas y facturadas y las emisiones de la cuenta","type":["string","null"]},"id":{"format":"uuid","type":"string"},"invoice_id":{"format":"uuid","type":["string","null"]},"last_error":{"description":"El problema de la última vez que no se pudo facturar (la orden sigue `OPEN`); `null` sin error o después de un `PUT`","oneOf":[{"$ref":"#/components/schemas/Problem"},{"type":"null"}]},"links":{"properties":{"execute":{"type":"string"},"invoice":{"type":["string","null"]},"self":{"type":"string"}},"type":"object"},"number":{"description":"Número visible, de una secuencia por emisor: `ORD-` y diez dígitos con ceros a la izquierda. No es un número fiscal: la serie y el número del comprobante son los de la DGI","examples":["ORD-0000000012"],"type":"string"},"payment_reference":{"description":"Lo que dijo el pago de sí mismo al facturar","type":["string","null"]},"receiver":{"description":"El receptor del documento; `null` sin receptor","properties":{"document":{"type":"string"},"document_type":{"examples":["ruc","ci"],"type":"string"},"name":{"type":["string","null"]}},"type":["object","null"]},"request":{"description":"El cuerpo tal como se recibió (sin el Base64 del adjunto de la adenda). No viene en la lista.","type":"object"},"state":{"$ref":"#/components/schemas/OrderState"},"state_name":{"examples":["Abierta"],"type":"string"},"updated_at":{"format":"date-time","type":"string"},"version":{"description":"Sube en uno con cada `PUT`; `execute` pide la que se pagó","minimum":1,"type":"integer"}},"required":["id","number","state","state_name","version","expires_at","created_at","updated_at","links"],"type":"object"}],"description":"Una orden: lo que respondería `POST /v1/invoices/preview` con su cuerpo (líneas, totales, CAE que la numeraría hoy, `warnings`) y los datos de la orden. Los textos están en el idioma en que se creó o modificó."},"OrderDuplicateRequest":{"properties":{"external_id":{"description":"El `external_id` de la orden nueva; el de la original no se copia","maxLength":128,"type":["string","null"]}},"type":"object"},"OrderExecuteRequest":{"properties":{"paid_amount":{"description":"Lo que se pagó; si viene tiene que ser el `payable` de la orden (409 `order_amount_mismatch`)","examples":["1220.00"],"type":["string","number","null"]},"payment_reference":{"description":"El identificador del pago en el medio de pago; se guarda con la orden y va en `order.executed`. No se escribe en el CFE.","maxLength":128,"type":["string","null"]},"version":{"description":"La versión que se pagó: otra responde 409 `order_version_mismatch`","minimum":1,"type":"integer"}},"required":["version"],"type":"object"},"OrderExecution":{"properties":{"invoice":{"$ref":"#/components/schemas/Invoice"},"order":{"$ref":"#/components/schemas/Order"}},"required":["order","invoice"],"type":"object"},"OrderList":{"properties":{"count":{"type":"integer"},"has_more":{"description":"Hay otra página después de esta.","type":"boolean"},"limit":{"type":"integer"},"next_cursor":{"description":"Para pedir la página siguiente en `after`; `null` en la última.","type":["string","null"]},"orders":{"items":{"$ref":"#/components/schemas/Order"},"type":"array"}},"required":["count","has_more","next_cursor","limit","orders"],"type":"object"},"OrderState":{"description":"`OPEN` (Abierta): se puede modificar, cancelar o facturar. `EXECUTED` (Facturada): se emitió su factura (`invoice_id`). `CANCELLED` (Cancelada) y `EXPIRED` (Vencida): cerradas, liberan su `external_id`. Una orden `OPEN` después de `expires_at` se lee `EXPIRED` aunque el barrido todavía no la haya escrito.","enum":["OPEN","EXECUTED","CANCELLED","EXPIRED"],"type":"string"},"PdfLink":{"properties":{"generation":{"description":"Cada link nuevo revoca los anteriores","type":"integer"},"invoice_id":{"format":"uuid","type":"string"},"pdf_url":{"description":"El link nuevo; `null` si se revocó o si la cuenta no publica ese tipo","format":"uri","type":["string","null"]},"published":{"description":"Si la ruta pública sirve ese tipo para la cuenta ahora (`printing.public_verification`)","type":"boolean"},"revoked":{"type":"boolean"}},"required":["invoice_id","pdf_url","generation","revoked","published"],"type":"object"},"PkiState":{"description":"Confianza en certificados: el conjunto de CA, las CRL y su frescura, el certificado de la DGI y la revocación de los certificados de los emisores.","properties":{"counterparty_untrusted":{"description":"`CFE_PKI_COUNTERPARTY_UNTRUSTED`","enum":["enforce","warn"],"type":"string"},"crls":{"items":{"properties":{"fetched_at":{"format":"date-time","type":["string","null"]},"issuer":{"type":["string","null"]},"last_attempt_at":{"format":"date-time","type":["string","null"]},"last_error":{"type":["string","null"]},"next_update":{"format":"date-time","type":["string","null"]},"revoked_count":{"type":["integer","null"]},"size_bytes":{"type":["integer","null"]},"state":{"description":"`STALE`: pasó su `nextUpdate` más `CFE_PKI_CRL_GRACE_HOURS`; la revocación de sus certificados es desconocida (alerta)","enum":["CURRENT","STALE","MISSING"],"type":"string"},"this_update":{"format":"date-time","type":["string","null"]},"url":{"type":"string"}},"required":["url","state"],"type":"object"},"type":"array"},"dgi_certificates":{"items":{"properties":{"detail":{"type":"string"},"revoked":{"type":"boolean"},"subject":{"type":"string"}},"required":["subject","revoked"],"type":"object"},"type":"array"},"last_pass":{"description":"Último pase de fondo de esta réplica","properties":{"changed":{"type":"integer"},"downloaded":{"type":"integer"},"errors":{"items":{"type":"string"},"type":"array"},"failed":{"type":"integer"},"finished_at":{"format":"date-time","type":["string","null"]},"revoked":{"type":"integer"},"stale":{"items":{"type":"string"},"type":"array"},"started_at":{"format":"date-time","type":["string","null"]},"tenant_certificates":{"type":"integer"}},"type":["object","null"]},"refresh_seconds":{"type":"integer"},"revocation_mode":{"description":"`CFE_PKI_REVOCATION`. `soft`: solo un `REVOKED` bloquea la firma; `hard`: también un estado que no sea `GOOD` reciente","enum":["off","soft","hard"],"type":"string"},"ruc_check":{"description":"`CFE_CERTIFICATE_RUC_CHECK`","type":"boolean"},"stale_crls":{"type":"integer"},"tenant_certificates":{"additionalProperties":{"type":"integer"},"description":"Certificados activos por estado de revocación (`GOOD`, `REVOKED`, `UNKNOWN`, `NOT_CHECKED`)","type":"object"},"tenant_chain":{"description":"`CFE_PKI_TENANT_CHAIN`","enum":["enforce","warn"],"type":"string"},"trust_bundle":{"items":{"properties":{"fingerprint_sha256":{"type":"string"},"not_after":{"format":"date-time","type":"string"},"root":{"type":"boolean"},"source":{"description":"`builtin:<archivo>` o la ruta de `CFE_PKI_TRUST_BUNDLE_PATH`","type":"string"},"subject":{"type":"string"}},"required":["subject","source","fingerprint_sha256","not_after","root"],"type":"object"},"type":"array"}},"required":["revocation_mode","tenant_chain","counterparty_untrusted","ruc_check","refresh_seconds","trust_bundle","crls","stale_crls","dgi_certificates","tenant_certificates"],"type":"object"},"PlatformHealth":{"description":"La salud de la plataforma: cada réplica de la API, cada worker, la base, la DGI, las colas y el asistente, juzgados contra umbrales fijos, y la última hora de la telemetría minuto a minuto. Nunca lleva un CFE, una clave, un secreto ni un contenido; de los webhooks que fallan, sólo el cliente y el host de la dirección.","properties":{"api":{"description":"Las réplicas de la API, desde su latido (migración 93); la que responde, en vivo","properties":{"replicas":{"items":{"$ref":"#/components/schemas/PlatformHealthReplica"},"type":"array"},"status":{"description":"OK, sin dato (una consulta falló), Atención o Problema: lo peor de sus hallazgos","enum":["ok","unknown","warning","problem"],"type":"string"}},"required":["status","replicas"],"type":"object"},"assistant":{"$ref":"#/components/schemas/PlatformHealthAssistant"},"database":{"$ref":"#/components/schemas/PlatformHealthDatabase"},"dgi":{"$ref":"#/components/schemas/PlatformHealthDgi"},"findings":{"description":"Lo que hay que mirar, lo peor primero","items":{"$ref":"#/components/schemas/PlatformHealthFinding"},"type":"array"},"generated_at":{"format":"date-time","type":"string"},"queues":{"$ref":"#/components/schemas/PlatformHealthQueues"},"refresh_seconds":{"description":"Cada cuántos segundos la consola vuelve a pedirla (5)","type":"integer"},"series":{"description":"Los últimos 60 minutos, el más viejo primero; el último está en curso (`partial`)","items":{"$ref":"#/components/schemas/PlatformHealthPoint"},"type":"array"},"status":{"description":"OK, sin dato (una consulta falló), Atención o Problema: lo peor de sus hallazgos","enum":["ok","unknown","warning","problem"],"type":"string"},"summary":{"$ref":"#/components/schemas/PlatformHealthSummary"},"window_minutes":{"description":"Los minutos sobre los que se juzgan los errores, los 429 y las latencias (5, el actual incluido)","type":"integer"},"workers":{"description":"Los workers, desde `worker_heartbeat`","properties":{"status":{"description":"OK, sin dato (una consulta falló), Atención o Problema: lo peor de sus hallazgos","enum":["ok","unknown","warning","problem"],"type":"string"},"workers":{"items":{"$ref":"#/components/schemas/PlatformHealthWorker"},"type":"array"}},"required":["status","workers"],"type":"object"}},"required":["generated_at","status","refresh_seconds","window_minutes","findings","summary","series","api","workers","database","dgi","queues","assistant"],"type":"object"},"PlatformHealthAssistant":{"description":"El asistente: si tiene su modelo, sus errores y su costo estimado","properties":{"cost_micro_usd_window":{"description":"Costo estimado de la ventana, en millonésimas de dólar","type":"integer"},"enabled":{"type":"boolean"},"failed":{"type":"integer"},"messages":{"type":"integer"},"model":{"type":["string","null"]},"model_calls":{"type":"integer"},"model_errors":{"type":"integer"},"month":{"oneOf":[{"type":"null"},{"description":"El mes en curso, todos los clientes (`assistant_usage`)","properties":{"calls":{"type":"integer"},"cost_micro_usd":{"type":"integer"},"input_tokens":{"type":"integer"},"messages":{"type":"integer"},"output_tokens":{"type":"integer"},"refused":{"type":"integer"},"tenants":{"type":"integer"}},"required":["tenants","messages","calls","input_tokens","output_tokens","cost_micro_usd","refused"],"type":"object"}]},"status":{"description":"OK, sin dato (una consulta falló), Atención o Problema: lo peor de sus hallazgos","enum":["ok","unknown","warning","problem"],"type":"string"}},"required":["status","enabled","model","messages","failed","model_calls","model_errors","cost_micro_usd_window","month"],"type":"object"},"PlatformHealthDatabase":{"description":"La base: migraciones, replicación, conexiones y tamaño (`health_database()`)","properties":{"applied_migration":{"type":["integer","null"]},"connections":{"type":["integer","null"]},"expected_migration":{"description":"La última migración que trae este binario","type":"integer"},"in_recovery":{"type":["boolean","null"]},"last_migration_at":{"format":"date-time","type":["string","null"]},"max_connections":{"type":["integer","null"]},"migrations_applied":{"type":["integer","null"]},"migrations_failed":{"type":["integer","null"]},"read_replica":{"description":"La réplica de `CFE_READ_DATABASE_URL`","properties":{"configured":{"type":"boolean"},"lag_seconds":{"type":["number","null"]},"reachable":{"type":["boolean","null"]}},"required":["configured","reachable","lag_seconds"],"type":"object"},"size_bytes":{"type":["integer","null"]},"standby_lag_seconds":{"type":["number","null"]},"standbys":{"type":["integer","null"]},"status":{"description":"OK, sin dato (una consulta falló), Atención o Problema: lo peor de sus hallazgos","enum":["ok","unknown","warning","problem"],"type":"string"}},"required":["status","expected_migration","applied_migration","migrations_applied","migrations_failed","last_migration_at","in_recovery","standbys","standby_lag_seconds","read_replica","size_bytes","connections","max_connections"],"type":"object"},"PlatformHealthDgi":{"description":"La DGI: el circuito, los envíos, el atraso y los reportes diarios","properties":{"backlog_oldest_seconds":{"type":"number"},"backlog_tenants":{"type":"integer"},"circuit_open":{"type":"boolean"},"consecutive_failures":{"type":"integer"},"daily_reports_failed":{"type":"integer"},"daily_reports_in_progress":{"type":"integer"},"daily_reports_overdue":{"type":"integer"},"envelopes_failed":{"type":"integer"},"envelopes_pending":{"type":"integer"},"envelopes_sending":{"type":"integer"},"envelopes_sent":{"type":"integer"},"environment":{"type":"string"},"held_acknowledgements":{"type":"integer"},"mode":{"type":"string"},"status":{"description":"OK, sin dato (una consulta falló), Atención o Problema: lo peor de sus hallazgos","enum":["ok","unknown","warning","problem"],"type":"string"},"unapplied_answers":{"description":"Envíos `SENT` cuya última respuesta de la DGI se guardó sin aplicar: un `ACKCFE` que no valida contra el formato (MR p. 10) o responde por otro envío (MR 3.3.A C7-C8), o un `ACKSobre` que no valida y sólo presta sus parámetros de consulta; se vuelve a consultar a la DGI","type":"integer"},"unknown_envelopes":{"type":"integer"},"unknown_oldest_seconds":{"type":"number"}},"required":["status","environment","mode","circuit_open","consecutive_failures","envelopes_pending","envelopes_sending","envelopes_sent","envelopes_failed","unknown_envelopes","unknown_oldest_seconds","held_acknowledgements","unapplied_answers","backlog_tenants","backlog_oldest_seconds","daily_reports_in_progress","daily_reports_failed","daily_reports_overdue"],"type":"object"},"PlatformHealthFailingWebhook":{"description":"Un destino de webhook que falla: el cliente y el host de la dirección, nunca su ruta ni su secreto","properties":{"blocked_until":{"format":"date-time","type":["string","null"]},"consecutive_failures":{"type":"integer"},"destination_id":{"format":"uuid","type":"string"},"destination_name":{"type":["string","null"]},"enabled":{"type":"boolean"},"host":{"type":["string","null"]},"last_error":{"type":["string","null"]},"last_failure_at":{"format":"date-time","type":["string","null"]},"last_success_at":{"format":"date-time","type":["string","null"]},"ruc":{"type":"string"},"tenant_id":{"format":"uuid","type":"string"},"tenant_name":{"type":"string"}},"required":["tenant_id","ruc","tenant_name","destination_id","destination_name","host","enabled","consecutive_failures","blocked_until","last_failure_at","last_success_at","last_error"],"type":"object"},"PlatformHealthFinding":{"description":"Un hallazgo: su código estable, su gravedad, los valores con que se dice y la página de la consola que ayuda","properties":{"area":{"enum":["api","workers","database","dgi","queues","assistant"],"type":"string"},"code":{"description":"`api_replica_silent`, `api_pool_exhausted`, `api_pool_slow`, `api_pool_full`, `api_in_flight_high`, `api_errors`, `api_overloaded`, `api_rate_limited`, `emission_latency`, `versions_differ`, `workers_none`, `worker_silent`, `worker_stuck`, `database_migrations_pending`, `database_migrations_ahead`, `database_migration_failed`, `database_replica_unreachable`, `database_replica_lag`, `database_standby_lag`, `database_connections_high`, `dgi_circuit_open`, `dgi_failing`, `dgi_calls_failing`, `dgi_slow`, `dgi_backlog`, `dgi_unknown_envelopes`, `dgi_held_acknowledgements`, `dgi_unapplied_answers`, `dgi_reports_failed`, `dgi_reports_overdue`, `webhooks_late`, `webhooks_failing`, `notifications_late`, `notifications_failed`, `mail_not_configured`, `mail_late`, `mail_failed`, `exchange_mail_failed`, `assistant_model_errors` o `health_unavailable` (una consulta de esa área falló)","type":"string"},"link":{"description":"Ruta de la consola (`/admin/dgi-exchanges`, `/admin/operations#ops-backlog`...)","type":["string","null"]},"params":{"additionalProperties":true,"type":"object"},"severity":{"enum":["warning","problem"],"type":"string"}},"required":["area","code","severity","params","link"],"type":"object"},"PlatformHealthLoop":{"description":"Un ciclo de un worker y su última vuelta","properties":{"last_tick_at":{"format":"date-time","type":"string"},"name":{"enum":["envelopes","answers","webhooks","reports"],"type":"string"},"seconds_ago":{"type":"number"},"stalled":{"description":"Más de 120 s sin dar la vuelta","type":"boolean"}},"required":["name","last_tick_at","seconds_ago","stalled"],"type":"object"},"PlatformHealthPoint":{"description":"Un minuto, todos los procesos juntos. Las latencias salen de los mismos baldes de `/metrics`","properties":{"assistant_messages":{"type":"integer"},"assistant_model_errors":{"type":"integer"},"at":{"format":"date-time","type":"string"},"dgi_calls":{"type":"integer"},"dgi_failures":{"type":"integer"},"dgi_p95_ms":{"type":["number","null"]},"emission_p50_ms":{"type":["number","null"]},"emission_p95_ms":{"type":["number","null"]},"emission_p99_ms":{"type":["number","null"]},"emissions":{"type":"integer"},"latency_p50_ms":{"type":["number","null"]},"latency_p95_ms":{"type":["number","null"]},"latency_p99_ms":{"type":["number","null"]},"overloaded":{"type":"integer"},"partial":{"type":"boolean"},"rate_limited":{"type":"integer"},"requests":{"type":"integer"},"sandbox_emissions":{"type":"integer"},"server_errors":{"type":"integer"}},"required":["at","partial","requests","server_errors","rate_limited","overloaded","emissions","sandbox_emissions","latency_p50_ms","latency_p95_ms","latency_p99_ms","emission_p50_ms","emission_p95_ms","emission_p99_ms","dgi_calls","dgi_failures","dgi_p95_ms","assistant_messages","assistant_model_errors"],"type":"object"},"PlatformHealthPool":{"description":"El pool de conexiones de un proceso","properties":{"acquire_ms":{"description":"Lo que esperó la sonda por una conexión; null si no hubo una libre en 2 s","type":["number","null"]},"connections":{"type":"integer"},"idle":{"type":"integer"},"max":{"type":"integer"}},"required":["connections","idle","max","acquire_ms"],"type":"object"},"PlatformHealthQueueRow":{"description":"Una cola de avisos o del correo de la cuenta","properties":{"failed_24h":{"type":"integer"},"oldest_pending_seconds":{"type":"number"},"pending":{"type":"integer"},"queue":{"description":"`notification.email`, `notification.telegram`, `notification.whatsapp`, `notification.slack`, `notification.teams` o `account_mail`","type":"string"},"sent_1h":{"type":"integer"}},"required":["queue","pending","oldest_pending_seconds","failed_24h","sent_1h"],"type":"object"},"PlatformHealthQueues":{"description":"Las colas: eventos de webhook, avisos por canal, el correo de la cuenta y el de entre empresas","properties":{"account_mail":{"$ref":"#/components/schemas/PlatformHealthQueueRow"},"exchange_mail_failed":{"type":"integer"},"exchange_mail_pending":{"type":"integer"},"mail_configured":{"description":"`CFE_SMTP_URL` está configurada","type":"boolean"},"notifications":{"items":{"$ref":"#/components/schemas/PlatformHealthQueueRow"},"type":"array"},"status":{"description":"OK, sin dato (una consulta falló), Atención o Problema: lo peor de sus hallazgos","enum":["ok","unknown","warning","problem"],"type":"string"},"webhooks":{"description":"Los eventos de webhook y los destinos que fallan (hasta 10, lo peor primero)","properties":{"dead":{"type":"integer"},"failing":{"items":{"$ref":"#/components/schemas/PlatformHealthFailingWebhook"},"type":"array"},"failing_destinations":{"type":"integer"},"lag_seconds":{"type":"number"},"undelivered":{"type":"integer"}},"required":["undelivered","dead","lag_seconds","failing_destinations","failing"],"type":"object"}},"required":["status","webhooks","notifications","account_mail","mail_configured","exchange_mail_pending","exchange_mail_failed"],"type":"object"},"PlatformHealthReplica":{"description":"Una réplica de la API","properties":{"beat_at":{"format":"date-time","type":"string"},"host":{"type":"string"},"in_flight":{"type":"integer"},"latency_p95_ms":{"type":["number","null"]},"max_in_flight":{"description":"0: sin tope","type":"integer"},"pool":{"$ref":"#/components/schemas/PlatformHealthPool"},"replica_id":{"format":"uuid","type":"string"},"requests":{"type":"integer"},"server_errors":{"type":"integer"},"started_at":{"format":"date-time","type":"string"},"state":{"enum":["running","draining","silent","stopped"],"type":"string"},"this_replica":{"description":"La réplica que respondió","type":"boolean"},"version":{"type":"string"}},"required":["replica_id","host","version","started_at","beat_at","state","this_replica","in_flight","max_in_flight","pool","requests","server_errors","latency_p95_ms"],"type":"object"},"PlatformHealthSummary":{"description":"Los números de la ventana, todas las réplicas juntas","properties":{"dgi_calls":{"type":"integer"},"dgi_failures":{"description":"Llamadas sin respuesta: tiempo agotado, error de transporte o circuito cortado","type":"integer"},"dgi_p95_ms":{"type":["number","null"]},"emission_p50_ms":{"type":["number","null"]},"emission_p95_ms":{"type":["number","null"]},"emission_p99_ms":{"type":["number","null"]},"emissions":{"description":"Emisiones confirmadas, por cualquier ruta; sin las de Pruebas","type":"integer"},"emissions_last_minute":{"description":"El último minuto entero","type":"integer"},"emissions_per_minute":{"type":"number"},"error_rate":{"description":"0–1: respuestas 5xx sobre las solicitudes bajo `/v1`","type":"number"},"latency_p95_ms":{"type":["number","null"]},"overloaded":{"description":"Respuestas `503 overloaded` por saturación","type":"integer"},"rate_limited":{"description":"Respuestas 429","type":"integer"},"requests":{"type":"integer"},"requests_per_minute":{"type":"number"},"sandbox_emissions":{"type":"integer"},"server_errors":{"type":"integer"}},"required":["requests","requests_per_minute","server_errors","error_rate","rate_limited","overloaded","emissions","emissions_per_minute","emissions_last_minute","sandbox_emissions","emission_p50_ms","emission_p95_ms","emission_p99_ms","latency_p95_ms","dgi_calls","dgi_failures","dgi_p95_ms"],"type":"object"},"PlatformHealthWorker":{"description":"Un worker","properties":{"answers":{"type":"integer"},"beat_at":{"format":"date-time","type":"string"},"circuit_failures":{"type":"integer"},"circuit_open":{"type":"boolean"},"documents":{"type":"integer"},"envelopes":{"type":"integer"},"events_delivered":{"type":"integer"},"events_failed":{"type":"integer"},"host":{"type":"string"},"last_tick_at":{"format":"date-time","type":"string"},"loops":{"items":{"$ref":"#/components/schemas/PlatformHealthLoop"},"type":"array"},"send_failures":{"type":"integer"},"started_at":{"format":"date-time","type":"string"},"state":{"enum":["running","stuck","silent","stopped"],"type":"string"},"version":{"type":"string"},"worker_id":{"format":"uuid","type":"string"}},"required":["worker_id","host","version","started_at","beat_at","last_tick_at","state","circuit_open","circuit_failures","loops","envelopes","documents","send_failures","answers","events_delivered","events_failed"],"type":"object"},"PosAlign":{"enum":["left","center","right"],"type":"string"},"PosBlock":{"oneOf":[{"$ref":"#/components/schemas/PosText"},{"$ref":"#/components/schemas/PosLine"},{"$ref":"#/components/schemas/PosColumns"},{"$ref":"#/components/schemas/PosMoney"},{"$ref":"#/components/schemas/PosQr"},{"$ref":"#/components/schemas/PosImage"},{"$ref":"#/components/schemas/PosFeed"},{"$ref":"#/components/schemas/PosCut"}]},"PosColumns":{"properties":{"bold":{"type":"boolean"},"cells":{"items":{"properties":{"align":{"$ref":"#/components/schemas/PosAlign"},"content":{"type":"string"},"width":{"description":"En caracteres; los anchos más los espacios entre celdas suman `columns`.","minimum":1,"type":"integer"}},"required":["content","width","align"],"type":"object"},"minItems":1,"type":"array"},"gap":{"minimum":0,"type":"integer"},"rows":{"$ref":"#/components/schemas/PosRows","description":"Las celdas lado a lado: una celda larga sigue en los renglones siguientes, dentro de su columna."},"type":{"const":"columns"}},"required":["type","cells","gap","bold","rows"],"type":"object"},"PosCut":{"properties":{"mode":{"enum":["full","partial"],"type":"string"},"type":{"const":"cut"}},"required":["type","mode"],"type":"object"},"PosFeed":{"properties":{"lines":{"maximum":255,"minimum":0,"type":"integer"},"type":{"const":"feed"}},"required":["type","lines"],"type":"object"},"PosImage":{"properties":{"align":{"$ref":"#/components/schemas/PosAlign"},"data":{"contentEncoding":"base64","description":"Base64 del mapa de bits: height filas de ceil(width / 8) bytes, el punto de la izquierda en el bit más significativo, 1 es negro (ESC/POS GS v 0).","type":"string"},"height":{"minimum":1,"type":"integer"},"type":{"const":"image"},"width":{"description":"En puntos, a lo sumo 576 (48 columnas) o 384 (32).","maximum":576,"minimum":1,"type":"integer"}},"required":["type","width","height","align","data"],"type":"object"},"PosLine":{"properties":{"rows":{"$ref":"#/components/schemas/PosRows"},"style":{"description":"single: -, double: =, dotted: .","enum":["single","double","dotted"],"type":"string"},"type":{"const":"line"}},"required":["type","style","rows"],"type":"object"},"PosMoney":{"properties":{"amount":{"description":"Como se escribe en Uruguay: 1.234,50 (miles con punto, decimales con coma); puede terminar en ' %'.","type":"string"},"bold":{"type":"boolean"},"currency":{"description":"ISO 4217, impresa antes del monto; null si no es un monto del comprobante (un porcentaje, un subtotal informativo).","type":["string","null"]},"label":{"type":"string"},"rows":{"$ref":"#/components/schemas/PosRows","description":"La etiqueta a la izquierda y el monto contra el borde derecho del primer renglón."},"type":{"const":"money"},"value":{"description":"El mismo monto como decimal simple, 1234.50.","type":"string"}},"required":["type","label","amount","value","currency","bold","rows"],"type":"object"},"PosQr":{"properties":{"align":{"$ref":"#/components/schemas/PosAlign"},"data":{"description":"El enlace de verificación de la DGI, todo el contenido del QR.","type":"string"},"error_correction":{"enum":["L","M","Q","H"],"type":"string"},"max_size_mm":{"minimum":1,"type":"integer"},"min_size_mm":{"minimum":1,"type":"integer"},"model":{"const":2},"module_size":{"description":"Puntos de un cabezal de 203 dpi por módulo: los menos que dejan el QR en al menos min_size_mm (p. 84). Se puede usar uno mayor, nunca uno menor.","maximum":16,"minimum":1,"type":"integer"},"type":{"const":"qr"}},"required":["type","data","model","error_correction","module_size","min_size_mm","max_size_mm","align"],"type":"object"},"PosRows":{"description":"El contenido ya acomodado, en el repertorio de la página de códigos PC850 (lo que no tiene se translitera), sin espacios al final.","items":{"type":"string"},"type":"array"},"PosText":{"properties":{"align":{"$ref":"#/components/schemas/PosAlign"},"bold":{"type":"boolean"},"content":{"type":"string"},"rows":{"$ref":"#/components/schemas/PosRows","description":"`content` cortado en `columns / size.width` caracteres, sin el relleno de `align` (la alineación la aplica la impresora o la aplicación)."},"size":{"description":"Veces el ancho y el alto de la fuente A (ESC/POS GS !). El alto 2 es lo que el formato pide de al menos 3 mm.","properties":{"height":{"maximum":2,"minimum":1,"type":"integer"},"width":{"maximum":2,"minimum":1,"type":"integer"}},"required":["width","height"],"type":"object"},"type":{"const":"text"},"underline":{"type":"boolean"}},"required":["type","content","align","bold","underline","size","rows"],"type":"object"},"PosTicket":{"description":"Ticket de un CFE para impresoras POS: la representación impresa en rollo térmico (Formato CFE v25.2, p. 79-86) como una lista de bloques. La plataforma ya calculó los anchos para `columns`: cada bloque de texto trae sus `rows`, que nunca pasan de `columns` caracteres (`columns / size.width` en un texto). Un campo o un tipo de bloque desconocido se ignora: la versión 1 sólo agrega.","properties":{"blocks":{"items":{"$ref":"#/components/schemas/PosBlock"},"type":"array"},"columns":{"description":"Caracteres de la fuente A por renglón: 48 en rollo de 80 mm, 32 en 57 mm.","enum":[48,32],"type":"integer"},"format":{"const":"cfe-pos/1"},"test_environment":{"description":"Impreso fuera del ambiente de producción de la DGI: no tiene validez fiscal y lo dice arriba y abajo.","type":"boolean"}},"required":["format","columns","test_environment","blocks"],"title":"cfe-pos/1","type":"object"},"PrintLogo":{"properties":{"bytes":{"description":"Del PNG guardado","type":"integer"},"created_at":{"format":"date-time","type":"string"},"height":{"description":"Hasta 600","type":"integer"},"id":{"format":"uuid","type":"string"},"in_use":{"description":"Alguna versión lo usa: no se puede borrar","type":"boolean"},"sha256":{"description":"Del PNG guardado, en hexadecimal","type":"string"},"source_type":{"description":"Lo que se subió","enum":["png","jpeg","svg"],"type":"string"},"url":{"description":"El PNG","type":"string"},"width":{"description":"Píxeles del PNG guardado (hasta 1200)","type":"integer"}},"required":["id","width","height","bytes","source_type","sha256","created_at","in_use","url"],"type":"object"},"PrintLogoList":{"properties":{"logos":{"items":{"$ref":"#/components/schemas/PrintLogo"},"type":"array"}},"required":["logos"],"type":"object"},"PrintLogoRef":{"additionalProperties":false,"properties":{"id":{"description":"Un logo de la cuenta (`POST /v1/printing/logos`)","format":"uuid","type":"string"},"position":{"default":"left","description":"Dónde va en la franja de arriba","enum":["left","center","right"],"type":"string"}},"required":["id"],"type":"object"},"PrintOptionalData":{"additionalProperties":false,"description":"Los datos que el formato no exige en papel. Los que faltan quedan como en okCFE.","properties":{"email":{"default":true,"description":"`CorreoEmisor`","type":"boolean"},"item_code":{"default":false,"description":"`CodItem` de cada línea","type":"boolean"},"phones":{"default":true,"description":"`Telefono` del emisor (hasta dos)","type":"boolean"},"unit":{"default":true,"description":"La unidad de medida en cada renglón. Es obligatoria salvo N/A (p. 54): en `false`, si todas las líneas tienen la misma va una vez en el título de la columna; si no, sigue en cada renglón","type":"boolean"},"website":{"default":false,"description":"El sitio del emisor (su perfil)","type":"boolean"}},"type":"object"},"PrintPreviewRequest":{"additionalProperties":false,"properties":{"encoding":{"default":"json","description":"Con `output=pos`","enum":["json","escpos","text"],"type":"string"},"format":{"description":"Por defecto, el `default_format` del borrador","enum":["a4","80mm","57mm"],"type":"string"},"invoice_id":{"description":"Un comprobante de la cuenta; `null`: el de ejemplo","format":"uuid","type":["string","null"]},"output":{"default":"pdf","enum":["pdf","pos"],"type":"string"},"template":{"description":"El borrador; `null` u omitido: la vigente","oneOf":[{"$ref":"#/components/schemas/PrintTemplateInput"},{"type":"null"}]}},"type":"object"},"PrintTemplate":{"properties":{"accent_color":{"default":"#0C1240","description":"El acento: nombre del emisor, títulos, reglas y bordes. Contraste de al menos 4.5:1 sobre blanco (`accent_too_light`)","pattern":"^#[0-9A-Fa-f]{6}$","type":"string"},"default_format":{"default":"a4","description":"El papel de una solicitud que no lo indica, si está habilitado y el papel admite el tipo; si no, A4","enum":["a4","80mm","57mm"],"type":"string"},"detail_font_size":{"default":"normal","description":"La letra del detalle: 8, 9 o 10 pt (el ticket POS usa la de la impresora)","enum":["small","normal","large"],"type":"string"},"footer_text":{"description":"Al final: hasta 300 caracteres y 4 renglones","maxLength":300,"type":["string","null"]},"header_text":{"description":"Debajo del logo, en cada hoja: hasta 160 caracteres y 3 renglones","maxLength":160,"type":["string","null"]},"logo":{"oneOf":[{"$ref":"#/components/schemas/PrintLogoRef"},{"type":"null"}]},"show":{"$ref":"#/components/schemas/PrintOptionalData"}},"required":["logo","accent_color","header_text","footer_text","show","detail_font_size","default_format"],"type":"object"},"PrintTemplateInput":{"additionalProperties":false,"description":"Lo que se puede cambiar del impreso. Lo que falta queda como en okCFE.","properties":{"accent_color":{"default":"#0C1240","description":"El acento: nombre del emisor, títulos, reglas y bordes. Contraste de al menos 4.5:1 sobre blanco (`accent_too_light`)","pattern":"^#[0-9A-Fa-f]{6}$","type":"string"},"base_version":{"description":"La versión desde la que se editó: si ya no es la vigente, `409 template_conflict`","minimum":0,"type":"integer"},"default_format":{"default":"a4","description":"El papel de una solicitud que no lo indica, si está habilitado y el papel admite el tipo; si no, A4","enum":["a4","80mm","57mm"],"type":"string"},"detail_font_size":{"default":"normal","description":"La letra del detalle: 8, 9 o 10 pt (el ticket POS usa la de la impresora)","enum":["small","normal","large"],"type":"string"},"footer_text":{"description":"Al final: hasta 300 caracteres y 4 renglones","maxLength":300,"type":["string","null"]},"header_text":{"description":"Debajo del logo, en cada hoja: hasta 160 caracteres y 3 renglones","maxLength":160,"type":["string","null"]},"logo":{"oneOf":[{"$ref":"#/components/schemas/PrintLogoRef"},{"type":"null"}]},"show":{"$ref":"#/components/schemas/PrintOptionalData"}},"type":"object"},"PrintTemplateVersion":{"properties":{"created_at":{"format":"date-time","type":["string","null"]},"created_by":{"description":"Quién la guardó: `kind` (`owner`, `member`, `staff`, `api_key`), `id`, `name` (el email o el nombre de la clave) y `role`","properties":{"id":{"format":"uuid","type":["string","null"]},"kind":{"type":"string"},"name":{"type":["string","null"]},"role":{"type":["string","null"]}},"type":["object","null"]},"current":{"description":"Es la vigente","type":"boolean"},"defaults":{"$ref":"#/components/schemas/PrintTemplate"},"features":{"description":"Lo que la configuración permite: `printing.logo` y `printing.custom_template`","properties":{"custom_template":{"type":"boolean"},"logo":{"type":"boolean"}},"required":["logo","custom_template"],"type":"object"},"limits":{"description":"Los topes que se controlan","properties":{"accent_min_contrast":{"type":"number"},"footer_text_max_chars":{"type":"integer"},"footer_text_max_lines":{"type":"integer"},"header_text_max_chars":{"type":"integer"},"header_text_max_lines":{"type":"integer"},"logo_max_bytes":{"type":"integer"},"logo_max_pixels":{"type":"integer"},"logo_max_side_px":{"type":"integer"},"logo_min_side_px":{"type":"integer"},"logo_stored_max_px":{"items":{"type":"integer"},"maxItems":2,"minItems":2,"type":"array"},"unused_logos_kept":{"type":"integer"}},"type":"object"},"logo":{"oneOf":[{"$ref":"#/components/schemas/PrintLogo"},{"type":"null"}]},"template":{"$ref":"#/components/schemas/PrintTemplate"},"unchanged":{"description":"Sólo en un `PUT` igual a la vigente: no se hizo versión","type":"boolean"},"version":{"description":"`0`: la de okCFE, la de una cuenta que nunca guardó una","type":"integer"}},"required":["version","current","created_at","created_by","template","defaults","logo","features","limits"],"type":"object"},"PrintTemplateVersionList":{"properties":{"next_before":{"description":"`before` de la página siguiente; `null` al llegar a la primera","type":["integer","null"]},"versions":{"items":{"properties":{"created_at":{"format":"date-time","type":"string"},"created_by":{"type":"object"},"current":{"type":"boolean"},"logo_id":{"format":"uuid","type":["string","null"]},"version":{"type":"integer"}},"required":["version","created_at","created_by","logo_id","current"],"type":"object"},"type":"array"}},"required":["versions","next_before"],"type":"object"},"Problem":{"properties":{"chain_code":{"description":"Sólo en un `422 certificate_untrusted`: por qué el certificado no encadena a una CA acreditada de PKI Uruguay, con los códigos de `chain.code` del certificado del emisor. Ausente en los demás problemas","enum":["chain_unreadable","chain_is_ca","chain_untrusted","chain_signature_invalid","chain_ca_cannot_sign","chain_path_length","chain_expired","chain_too_long"],"type":"string"},"code":{"description":"Código estable para el cliente. En un documento que no valida es la clase del primer error (`invalid_cfe`, `rule_violation` o `unsupported`); el motivo fino de cada error está en `errors[].code`","type":"string"},"detail":{"description":"Texto localizado. En un documento que no valida es el `detail` del primer error de `errors`","type":"string"},"errors":{"description":"Todos los errores de un documento que no valida (422 de `POST /v1/invoices`, `POST /v1/invoices/preview`, `POST /v1/contingency-documents` y sus correcciones, y `POST /v1/invoices/{id}/reissue`), en el orden en que se verifican. El primero es también `code` (su clase), `field` y `detail`. Lo que depende de un error anterior no se informa: los totales de una línea mal formada, el tope de la Tabla E de un documento con errores o el libro de una referencia con errores propios. Ausente en los demás problemas.","items":{"$ref":"#/components/schemas/ProblemError"},"type":"array"},"field":{"description":"Campo DGI involucrado o, si el cuerpo no se pudo leer, la ruta JSON del miembro (`lines[0].quantity`). En un documento que no valida es el `field` del primer error de `errors`","type":"string"},"instance":{"type":"string"},"status":{"type":"integer"},"title":{"description":"Motivo del estado HTTP, en el idioma de `Accept-Language`, como `detail`","type":"string"},"type":{"type":"string"}},"required":["type","title","status","code","detail"],"type":"object"},"ProblemError":{"description":"Un error de un documento que no valida, con el miembro de la solicitud al que se refiere.","properties":{"code":{"description":"Código estable del motivo, para que el cliente decida sin leer el texto: `required`, `length`, `max_digits`, `too_many_decimals`, `must_be_positive`, `not_in_catalogue`, `invalid_ruc`, `invalid_ci`, `ruc_recipient_required`, `recipient_above_ui_cap`, `issuer_mismatch`, `reference_needs_amount`, `reference_mismatch`… Un motivo nuevo trae un código nuevo; los existentes no cambian","type":"string"},"detail":{"description":"Explicación en el idioma de `Accept-Language`","type":"string"},"field":{"description":"Nombre DGI del campo (`PrecioUnitario`, `DocRecep`) o código de la regla (`A-C60`)","type":["string","null"]},"params":{"additionalProperties":true,"description":"Los valores con los que se arma `detail` (`{\"max\": 80, \"got\": 81}`), con los nombres del problema, para un cliente que escribe su propio mensaje; `{}` cuando no tiene. Los errores que no son de un documento (una anulación, un rango CAE) también traen `errors[]` con el miembro de la solicitud, con cualquier estado 4xx. En `recipient_above_ui_cap`: `net` y `cap` en pesos; `missing_ui_year` y `used_ui_year` cuando falta la UI del año anterior; en otra moneda, `rate` (pesos por unidad con que se convirtió el neto) y `rate_source`: `document` (el `TpoCambio` del comprobante) o `bcu` (la cotización del BCU del día anterior, más alta). El tope se mide con las dos y se aplica si cualquiera lo supera.","type":"object"},"path":{"description":"Ruta JSON del miembro tal como lo mandó el cliente (`lines[2].unit_price`, `recipient.number`, `references[0].date`; `invoice.lines[0].quantity` en un comprobante de contingencia). `null` cuando el error no es de un miembro en particular","type":["string","null"]}},"required":["path","code","field","detail"],"type":"object"},"PublicVerification":{"description":"Lo que muestra un comprobante verificado: sólo lo que ya está impreso en él.","properties":{"cfe_type":{"type":"integer"},"currency":{"type":"string"},"issue_date":{"format":"date","type":"string"},"issuer_name":{"type":"string"},"issuer_ruc":{"type":"string"},"number":{"type":"integer"},"payable":{"type":"string"},"pdf_url":{"type":"string"},"print_url":{"description":"Representación impresa (HTML, A4); agregar `&format=80mm` o `57mm` para el rollo.","type":"string"},"series":{"type":"string"},"status":{"enum":["PENDING","ACCEPTED","REJECTED","CANCELLED"],"type":"string"},"status_label":{"description":"El estado como lo lee el consumidor, por ejemplo \"Aceptado por la DGI\".","type":"string"},"total":{"type":"string"},"type_name":{"description":"Descripción de la Tabla A.","type":"string"}},"required":["issuer_ruc","issuer_name","cfe_type","type_name","series","number","issue_date","currency","total","payable","status","status_label","print_url","pdf_url"],"type":"object"},"Publication":{"properties":{"printed_site":{"description":"Lo que imprimen los e-Tickets tras \"Puede verificar comprobante en\": el `verification_site` del perfil, si no la página de la plataforma; `null` es ningún sitio, y entonces el e-Ticket no se imprime (422 `verification_site_missing`): el de la DGI no verifica e-Tickets (FAQ 7.1).","type":["string","null"]},"publication":{"description":"Qué CFE del tenant publica la página pública de la plataforma. `e_tickets` (por defecto): e-Tickets, e-Tickets por cuenta ajena y sus notas, lo que pide el *Instructivo* v11, p. 17. `all`: todos, y entonces cualquier CFE se puede imprimir en rollo térmico (*Formato CFE*, p. 79). `none`: ninguno, el emisor los publica en su propio sitio. `none` exige un `verification_site` en el perfil (422 `verification_site_required`): la leyenda del e-Ticket tiene que nombrar un sitio (p. 84; FAQ 7.1 y 7.2).","enum":["e_tickets","all","none"],"type":"string"},"thermal_paper_for_every_type":{"type":"boolean"},"verification_page":{"description":"La página de la plataforma para este emisor (`CFE_PUBLIC_URL`/v1/public/verify?ruc=...), si la plataforma tiene dirección pública y publica algo.","type":["string","null"]}},"required":["publication","verification_page","printed_site","thermal_paper_for_every_type"],"type":"object"},"Readiness":{"properties":{"api_version":{"type":"string"},"database":{"enum":["ok","unavailable","not_checked"],"type":"string"},"status":{"description":"`ready`: atiende. `degraded`: la base no contesta, pero hace menos de `CFE_READINESS_GRACE_SECONDS` (60 s): sigue en el balanceador para no sacar a todos los nodos durante un failover. `unavailable`: la base no contesta hace más que eso (o `strict=1`). `draining`: el proceso se está apagando; sigue atendiendo `CFE_SHUTDOWN_DELAY_SECONDS` y después cierra.","enum":["ready","degraded","unavailable","draining"],"type":"string"}},"required":["status","database","api_version"],"type":"object"},"ReadinessCheck":{"properties":{"cfe_type":{"description":"En `cae`: el tipo","type":"integer"},"check":{"enum":["certificate","cae","numbering","branch","cfe_types","membership"],"type":"string"},"code":{"description":"Código estable: `certificate_valid`, `certificate_expiring`, `certificate_platform`, `certificate_missing`, `certificate_expired`, `certificate_revoked`, `certificate_not_yet_valid`, `cae_ready`, `cae_running_out`, `cae_expiring`, `cae_exhausted`, `cae_expired`, `numbering_ready`, `no_numbering`, `branch_ready`, `branch_not_default`, `branch_missing`, `types_enabled`, `no_type_enabled`, `membership_ready`, `membership_near_limit`, `membership_suspended`, `membership_expired`, `membership_limit_reached`","type":"string"},"details":{"additionalProperties":true,"description":"Las cifras del chequeo (`days_to_expiry`, `numbers_left`, `expires_on`, `month.used`…)","type":"object"},"message":{"description":"En el idioma de la solicitud","type":"string"},"series":{"description":"En `cae`: la serie","type":"string"},"status":{"description":"`error` impide emitir; `warning` emite pero hay que hacer algo pronto","enum":["ok","warning","error"],"type":"string"}},"required":["check","status","code","message","details"],"type":"object"},"ReasonRequest":{"additionalProperties":false,"properties":{"reason":{"maxLength":2000,"type":"string"}},"required":["reason"],"type":"object"},"ReceivedAnnulment":{"properties":{"communication_id":{"description":"`IDComunicacion`","type":["integer","null"]},"documents":{"items":{"properties":{"cfe_type":{"type":"integer"},"issued_on":{"format":"date","type":"string"},"number":{"type":"integer"},"received_document_id":{"description":"La copia aceptada que se marcó; `null` si no se recibió","format":"uuid","type":["string","null"]},"series":{"type":"string"}},"required":["cfe_type","series","number","issued_on"],"type":"object"},"type":"array"},"id":{"format":"uuid","type":"string"},"issuer_ruc":{"type":"string"},"signed_at":{"format":"date-time","type":"string"}},"required":["id","issuer_ruc","signed_at","documents"],"type":"object"},"ReceivedDocument":{"properties":{"adenda":{"description":"Solo en `GET /v1/received-documents/{id}`","type":"string"},"annulled_at":{"description":"Cuando el emisor comunicó que la DGI lo rechazó","format":"date-time","type":["string","null"]},"answer_pending":{"description":"El `ACKCFE` de su sobre todavía espera un CFE que referencia una nota del sobre (`E12`): `state` es lo que dice hasta ahora","type":"boolean"},"causes":{"items":{"$ref":"#/components/schemas/ReceptionCause"},"type":"array"},"cfe_type":{"type":["integer","null"]},"cfe_type_name":{"type":["string","null"]},"commercial_rejection":{"description":"El tenant lo rechazó comercialmente después de recibirlo (`ACKCFE` posterior con `BE`)","oneOf":[{"$ref":"#/components/schemas/ReceivedDocumentRejection"},{"type":"null"}]},"currency":{"type":["string","null"]},"envelope_id":{"format":"uuid","type":"string"},"has_adenda":{"type":"boolean"},"id":{"format":"uuid","type":"string"},"issued_on":{"format":"date","type":["string","null"]},"issuer_name":{"type":["string","null"]},"issuer_ruc":{"type":"string"},"number":{"type":["integer","null"]},"ordinal":{"description":"`Nro_ordinal`","type":"integer"},"received_at":{"format":"date-time","type":"string"},"reception_number":{"description":"`IDReceptor` del sobre","type":"integer"},"series":{"type":["string","null"]},"signed_at":{"format":"date-time","type":["string","null"]},"state":{"enum":["AE","BE"],"type":"string"},"total":{"description":"`MntTotal` tal como viene en el CFE","type":["string","null"]},"xml_url":{"type":"string"}},"required":["id","envelope_id","reception_number","ordinal","issuer_ruc","state","causes","has_adenda","received_at","xml_url"],"type":"object"},"ReceivedDocumentRejection":{"properties":{"causes":{"items":{"$ref":"#/components/schemas/ReceptionCause"},"type":"array"},"id":{"format":"uuid","type":"string"},"rejected_at":{"format":"date-time","type":"string"},"response_id":{"type":"integer"},"xml_url":{"type":"string"}},"required":["id","response_id","causes","rejected_at","xml_url"],"type":"object"},"Reception":{"properties":{"accepted_count":{"type":"integer"},"causes":{"items":{"$ref":"#/components/schemas/ReceptionCause"},"type":"array"},"certificate_check":{"$ref":"#/components/schemas/CounterpartyCertificate","description":"Cadena y revocación del certificado del sobre; no en los listados"},"channel":{"enum":["API","EMAIL","WS"],"type":"string"},"declared_count":{"description":"`CantCFE`","type":["integer","null"]},"documents":{"description":"En el detalle y al recibir; no en la lista","items":{"$ref":"#/components/schemas/ReceivedDocument"},"type":"array"},"documents_ack":{"description":"`ACKCFE` de un sobre `AS`; `null` mientras espera los CFE que referencian sus notas (`documents_answer_due_at`)","oneOf":[{"$ref":"#/components/schemas/ReceptionAnswer"},{"type":"null"}]},"documents_answer_due_at":{"description":"Mientras el `ACKCFE` espera un CFE que una nota referencia y todavía no llegó: cuándo se firma a más tardar, la `Fechahora` que anunció el `ACKSobre` (MR v19, C28). Se firma una vez, antes si llega el CFE; las notas que siguen sin él van con `E12`","format":"date-time","type":["string","null"]},"envelope_ack":{"$ref":"#/components/schemas/ReceptionAnswer"},"envelope_url":{"type":"string"},"file_name":{"description":"`NomArch`","type":"string"},"id":{"format":"uuid","type":"string"},"issuer_created_at":{"description":"`Fecha` de la carátula","format":"date-time","type":["string","null"]},"issuer_ruc":{"description":"`RUCEmisor`: a quién van las respuestas","type":"string"},"received_at":{"format":"date-time","type":"string"},"reception_number":{"description":"`IDReceptor`","type":"integer"},"rejected_count":{"type":"integer"},"sender_id":{"description":"`Idemisor`","type":["integer","null"]},"sha256":{"type":"string"},"size_bytes":{"type":"integer"},"state":{"enum":["AS","BS"],"type":"string"}},"required":["id","reception_number","received_at","channel","file_name","size_bytes","sha256","issuer_ruc","state","causes","accepted_count","rejected_count","envelope_ack","envelope_url"],"type":"object"},"ReceptionAnswer":{"properties":{"file_name":{"type":"string"},"response_id":{"description":"`IDRespuesta`","type":"integer"},"url":{"type":"string"}},"required":["response_id","file_name","url"],"type":"object"},"ReceptionCause":{"properties":{"code":{"examples":["S02","E04"],"type":"string"},"detail":{"description":"Detalle (hasta 500 caracteres)","type":["string","null"]},"gloss":{"description":"Glosa publicada por la DGI","type":["string","null"]}},"required":["code"],"type":"object"},"ReceptionRules":{"description":"Lo que la recepción rechaza sola en el `ACKCFE` (MR v19, tabla 4.3). `E03`, `E11` y `E10` contra el propio CFE se controlan siempre; `E06`, `E12` y `E10` contra la cotización del BCU según estas reglas. Lo demás de la tabla (`E20`-`E60`) lo decide una persona con `POST /v1/received-envelopes/{id}/rejections`. En el `PUT`, `reference_wait_minutes` y `exchange_rate_tolerance` que no vienen conservan su valor.","properties":{"amount_factor":{"description":"`E06` (importe que excede los montos habituales): se rechaza un CFE cuyo `MntTotal` supera este múltiplo del mayor aceptado del mismo emisor en la misma moneda. Decimal de 1 a 999999.99 como texto; `null` lo apaga (el valor por defecto)","pattern":"^[0-9]{1,6}(\\.[0-9]{1,2})?$","type":["string","null"]},"amount_min_history":{"default":10,"description":"`E06` sólo con al menos tantos CFE aceptados del emisor en esa moneda","maximum":10000,"minimum":1,"type":"integer"},"check_references":{"default":true,"description":"`E12`: se rechaza una referencia (zona F) a un CFE del emisor que no se recibió (si es de un tipo que va al receptor y su fecha es posterior a la primera recepción), que su emisor anuló por rechazo de la DGI, o cuya fecha, moneda, monto o tipo de cambio no son los del CFE recibido","type":"boolean"},"exchange_rate_tolerance":{"description":"`E10` (tipo de cambio no válido): se rechaza un CFE cuyo `TpoCambio` difiere de la cotización fiscal del BCU de su fecha (la del día hábil anterior, Formato Reporte 1.B) en más de este porcentaje. Mayor que 0 y hasta 100, con hasta 2 decimales, como texto; `null` lo apaga (el valor por defecto). Sin cotización no se rechaza nada; las notas, el e-Resguardo, la UI y la UR no se comparan","pattern":"^[0-9]{1,3}(\\.[0-9]{1,2})?$","type":["string","null"]},"reference_wait_minutes":{"default":240,"description":"`E12` de un CFE que todavía no se recibió: minutos que el `ACKCFE` espera que llegue (la nota y su factura suelen venir en sobres distintos) antes de rechazar la nota. El `ACKSobre` anuncia el fin de la espera como `Fechahora`; llega el CFE y se responde en ese momento. `0` rechaza en el acto","maximum":2880,"minimum":0,"type":"integer"},"updated_at":{"description":"Último cambio; `null` mientras son los valores por defecto","format":"date-time","readOnly":true,"type":["string","null"]}},"required":["amount_factor","amount_min_history","check_references"],"type":"object"},"RecipientAnswer":{"properties":{"answered_at":{"format":"date-time","type":["string","null"]},"causes":{"items":{"$ref":"#/components/schemas/ReceptionCause"},"type":"array"},"state":{"enum":["AS","BS","AE","BE"],"type":"string"}},"required":["state","causes"],"type":"object"},"ReconcileRequest":{"properties":{"action":{"description":"`resend`: sus CFE van en un sobre nuevo ya; `received`: la DGI confirmó que lo tiene, con este `IDReceptor` y `Token`","enum":["resend","received"],"type":"string"},"reception_id":{"description":"Con `received`","type":"integer"},"token":{"description":"Con `received`","type":"string"}},"required":["action"],"type":"object"},"Refund":{"properties":{"amount":{"description":"Total de la nota (F-C8)","type":"string"},"cfe_type":{"type":"integer"},"counts":{"description":"Si descuenta de lo que queda (la nota está pendiente o aceptada)","type":"boolean"},"created_at":{"format":"date-time","type":"string"},"currency":{"type":"string"},"external_id":{"description":"El `external_id` del CFE devuelto","type":["string","null"]},"invoice_id":{"description":"El CFE devuelto","format":"uuid","type":"string"},"lines":{"items":{"properties":{"amount":{"type":"string"},"index":{"type":"integer"},"indicator":{"type":"string"},"quantity":{"type":"string"}},"type":"object"},"type":"array"},"note_id":{"description":"La nota de crédito (la que hoy tiene su número)","format":"uuid","type":"string"},"number":{"type":"integer"},"rates":{"items":{"properties":{"amount":{"type":"string"},"indicator":{"type":"string"}},"type":"object"},"type":"array"},"reason":{"type":["string","null"]},"refund_id":{"type":"string"},"series":{"type":"string"},"status":{"enum":["PENDING","ACCEPTED","REJECTED","CANCELLED"],"type":"string"},"status_name":{"type":"string"}},"type":"object"},"RefundCreated":{"allOf":[{"$ref":"#/components/schemas/Refund"},{"properties":{"note":{"$ref":"#/components/schemas/Invoice"}},"type":"object"}]},"RefundRequest":{"description":"Al menos una de `lines`, `amounts` o `shipping`.","examples":[{"lines":[{"index":0,"quantity":"1"}],"reason":"Talle equivocado","refund_id":"creditmemo-1042","shipping":{}}],"properties":{"amounts":{"items":{"description":"Sin `indicator` ni `vat_rate`, el importe se reparte en proporción entre las tasas del CFE.","properties":{"amount":{"description":"Hasta 2 decimales, en los términos de precio del original","oneOf":[{"type":"string"},{"type":"number"}]},"description":{"description":"`NomItem` de la línea. Por defecto `Devolución`.","type":"string"},"indicator":{"description":"Indicador de facturación (`IndFact`) por nombre, como `lines[].indicator` de `POST /v1/invoices` (`basic`, `minimum`, `exempt`, `export`, …)","type":"string"},"vat_rate":{"description":"Tasa de IVA (10, 22 o 0) en lugar de `indicator`","oneOf":[{"type":"string"},{"type":"number"}]}},"required":["amount"],"type":"object"},"type":"array"},"lines":{"items":{"properties":{"index":{"description":"Índice de la línea del CFE (desde 0), como en `GET .../refunds`","minimum":0,"type":"integer"},"quantity":{"description":"Hasta 3 decimales; la última cantidad de la línea lleva exactamente lo que queda","oneOf":[{"type":"string"},{"type":"number"}]}},"required":["index","quantity"],"type":"object"},"type":"array"},"reason":{"description":"`RazonRef` de la nota. Por defecto `Devolución`.","maxLength":90,"type":"string"},"refund_id":{"description":"Identificador de la devolución en la tienda (credit memo). Único por CFE; la clave de idempotencia.","maxLength":128,"minLength":1,"type":"string"},"shipping":{"description":"El envío: `{}` devuelve lo que queda de la línea de envío; con `index` esa línea; con `amount` parte de ella; con `amount` e `indicator`/`vat_rate` un importe sin línea.","properties":{"amount":{"oneOf":[{"type":"string"},{"type":"number"}]},"description":{"description":"Por defecto `Envío`","type":"string"},"index":{"minimum":0,"type":"integer"},"indicator":{"description":"Indicador de facturación (`IndFact`) por nombre, como `lines[].indicator` de `POST /v1/invoices` (`basic`, `minimum`, `exempt`, `export`, …)","type":"string"},"vat_rate":{"description":"Tasa de IVA (10, 22 o 0) en lugar de `indicator`","oneOf":[{"type":"string"},{"type":"number"}]}},"type":"object"}},"required":["refund_id"],"type":"object"},"Report":{"properties":{"anomalies":{"description":"Donde el acuse de la DGI no coincide con el reporte o con su formato (RUC, `NomArch`, `IDEmisor`, `version`). No impide aplicarlo","items":{"type":"string"},"type":"array"},"answered_at":{"format":"date-time","type":["string","null"]},"attempts":{"type":"integer"},"causes":{"items":{"properties":{"code":{"type":"string"},"detail":{"type":["string","null"]},"gloss":{"type":["string","null"]}},"type":"object"},"type":"array"},"date":{"description":"Fecha de resumen (A-C3)","format":"date","type":"string"},"dgi_state":{"description":"El estado que la DGI le dio después de `AR`, que ningún servicio web devuelve (Preguntas frecuentes 9.7): `DR` \"Reporte Procesado\" y `ER` \"Reporte en Gestión\" como los registró un operador con la comunicación de la DGI; `FR` \"Reporte Reliquidado\" cuando la DGI recibió otro reporte de la fecha con una secuencia mayor","enum":["DR","ER","FR",null],"type":["string","null"]},"dgi_state_at":{"format":"date-time","type":["string","null"]},"force":{"type":"boolean"},"id":{"format":"uuid","type":"string"},"last_error":{"type":["string","null"]},"next_attempt_at":{"description":"Cuándo se vuelve a mirar, mientras está en camino","format":"date-time","type":["string","null"]},"origin":{"enum":["API","SCHEDULE",null],"type":["string","null"]},"pending":{"description":"CFE de ese día sin respuesta de la DGI: los que espera, o los que quedaron fuera","type":["integer","null"]},"processed_at":{"description":"Cuándo se registró \"Reporte Procesado\"","format":"date-time","type":["string","null"]},"processed_by":{"description":"Quién lo registró: `user:<id>` o `api-key:<nombre>`","type":["string","null"]},"reason":{"description":"Por qué lo encoló el envío automático: `DAILY`, `CORRECTION` (CFE del día que la DGI contestó tarde) o `RELIQUIDATION` (un tipo de cambio fiscal que llegó después). Nulo si lo pidió la API","enum":["DAILY","CORRECTION","RELIQUIDATION",null],"type":["string","null"]},"reception_id":{"description":"`IDReceptor` del acuse de la DGI","type":["integer","null"]},"records":{"description":"`CantComprobantes` (A-C7), una vez armado","type":["integer","null"]},"requested_at":{"format":"date-time","type":"string"},"sent_at":{"format":"date-time","type":["string","null"]},"sequence":{"description":"`SecEnvio`, una vez armado","type":["integer","null"]},"signature":{"description":"Firma de la DGI en el acuse, si hay certificado de la DGI configurado","enum":["VALID","UNSIGNED","UNTRUSTED","INVALID",null],"type":["string","null"]},"state":{"enum":["AR","BR",null],"type":["string","null"]},"status":{"description":"`WAITING`: espera la respuesta de la DGI a CFE de ese día; `SENDING`: armado y en camino (se reenvía igual); `RECEIVED` (`AR`) y `REJECTED` (`BR`): lo que contestó la DGI; `PROCESSED`: recibido y registrado como \"Reporte Procesado\" en el portal de la DGI (Instructivo p. 8); `IN_MANAGEMENT`: recibido y registrado como \"Reporte en Gestión\" (la DGI encontró inconsistencias: se analizan y, si corresponde, se reliquida); `RELIQUIDATED`: \"Reporte Reliquidado\", la DGI recibió después otro reporte de la fecha con una secuencia mayor (Preguntas frecuentes 9.7); `FAILED`: no se pudo enviar (ver `last_error`). Un `R05` a un envío nuevo no lo rechaza: vuelve a salir con la secuencia siguiente (ver `/v1/reports/{id}/events`)","enum":["QUEUED","WAITING","SENDING","RECEIVED","PROCESSED","IN_MANAGEMENT","RELIQUIDATED","REJECTED","FAILED"],"type":"string"},"wait_until":{"description":"Hasta cuándo espera a los CFE sin respuesta","format":"date-time","type":["string","null"]},"warnings":{"description":"`ui_value_unknown`: sin el valor de la UI del cierre del año anterior no se informa `CantDocsMay_topeUI` (B-C27); `pending_excluded`: salió sin CFE que la DGI no había contestado; `provisional_rate`: un grupo en moneda extranjera fue al tipo de cambio del propio CFE porque el fiscal no se conocía (fecha posterior a la firma del reporte, o sin cotización del BCU): si después cambia, el reporte se reliquida solo (Formato Reporte p. 8)","items":{"enum":["ui_value_unknown","pending_excluded","provisional_rate"],"type":"string"},"type":"array"}},"required":["id","date","status","causes","warnings","force","attempts","requested_at","anomalies"],"type":"object"},"ReportEvent":{"properties":{"actor":{"type":["string","null"]},"created_at":{"format":"date-time","type":"string"},"date":{"format":"date","type":"string"},"detail":{"description":"Motivos de la DGI, la nota o lo que sabía el restore","type":"object"},"from_sequence":{"type":["integer","null"]},"id":{"description":"El evento. Opaco (`rev_` y 26 caracteres): no es un número de la plataforma ni se puede ordenar.","pattern":"^rev_[a-z2-7]{26}$","type":"string"},"kind":{"description":"`SEQUENCE_ADVANCED`: la DGI contestó `R05` a un envío nuevo y el reporte salió con la secuencia siguiente; `RELIQUIDATION`: el día cambió después de recibido y se reenvió; `RESTORE_FLOOR`: `--after-restore` fijó el piso de secuencia de la fecha; `PROCESSED`: se registró \"Reporte Procesado\"; `IN_MANAGEMENT`: se registró \"Reporte en Gestión\" con la comunicación de la DGI (`detail.note`); `RELIQUIDATED`: \"Reporte Reliquidado\", por otro reporte de la fecha que la DGI recibió (`detail.by_report`) o registrado (Preguntas frecuentes 9.7); `EXPIRED_ANNULMENT`: los números que una numeración (CAE) vencida dejó sin usar se anularon y van en el reporte de la fecha (Preguntas frecuentes 3.2; `detail`: `cae_id`, `cfe_type`, `series`, `first`, `last`, `annulled`, `expired_on`)","enum":["SEQUENCE_ADVANCED","RELIQUIDATION","RESTORE_FLOOR","PROCESSED","IN_MANAGEMENT","RELIQUIDATED","EXPIRED_ANNULMENT"],"type":"string"},"report_id":{"format":"uuid","type":["string","null"]},"to_sequence":{"type":["integer","null"]}},"required":["id","kind","date","detail","created_at"],"type":"object"},"ReportProcessedRequest":{"properties":{"note":{"maxLength":500,"type":["string","null"]}},"type":"object"},"ReportSchedule":{"description":"Envío automático del reporte diario. Desde la migración 43 está encendido para todos los tenants (los existentes y los nuevos) y cada uno lo puede apagar; sólo encola el reporte de un tenant que cargó algún rango de CAE","properties":{"enabled":{"type":"boolean"},"last_queued":{"format":"date","type":["string","null"]},"max_wait_minutes":{"description":"Espera a los CFE sin respuesta después del fin del día","maximum":10080,"minimum":0,"type":"integer"},"send_at":{"description":"Hora de Uruguay desde la que se encola el reporte del día anterior","pattern":"^[0-2][0-9]:[0-5][0-9]$","type":"string"},"updated_at":{"format":"date-time","type":["string","null"]}},"required":["enabled","send_at","max_wait_minutes"],"type":"object"},"ReportScheduleRequest":{"properties":{"enabled":{"type":"boolean"},"max_wait_minutes":{"default":720,"maximum":10080,"minimum":0,"type":"integer"},"send_at":{"default":"01:00","pattern":"^[0-2][0-9]:[0-5][0-9]$","type":"string"}},"required":["enabled"],"type":"object"},"ReviewRequest":{"properties":{"note":{"description":"Qué se confirmó con la DGI, para la auditoría","maxLength":1000,"type":"string"}},"type":"object"},"SandboxKeyRequest":{"properties":{"name":{"maxLength":80,"type":"string"},"reason":{"type":"string"},"sandbox_outcome":{"description":"La respuesta por defecto de la DGI simulada","type":["string","null"]},"scopes":{"items":{"$ref":"#/components/schemas/Scope"},"minItems":1,"type":["array","null"]}},"required":["name","reason"],"type":"object"},"SandboxOverview":{"properties":{"created_at":{"format":"date-time","type":["string","null"]},"documents":{"description":"Comprobantes del sandbox","type":"integer"},"emissions_this_month":{"description":"Comprobantes de prueba emitidos este mes (nunca cuentan en el plan).","type":"integer"},"exists":{"description":"El sandbox se crea con la primera clave de prueba","type":"boolean"},"idle_days":{"description":"Días sin emitir tras los que el worker lo purga","type":"integer"},"key_prefix":{"const":"cfe_test_","type":"string"},"keys":{"description":"Claves de prueba activas","type":"integer"},"last_emission_at":{"format":"date-time","type":["string","null"]},"max_documents":{"description":"Con ese total, `409 sandbox_full` hasta purgarlo","type":"integer"},"max_keys":{"description":"Las claves de prueba que puede tener activas: las de su membresía (`sandbox_keys`), 3 como máximo. No cuentan en sus claves de API.","type":"integer"},"max_test_users":{"const":3,"description":"Los usuarios de prueba que puede tener","type":"integer"},"monthly_cap":{"description":"Comprobantes por mes del sandbox","type":"integer"},"numbering":{"items":{"properties":{"cfe_type":{"type":"integer"},"next_number":{"type":"integer"},"series":{"type":"string"}},"required":["cfe_type","series","next_number"],"type":"object"},"type":"array"},"outcomes":{"description":"Los valores de `Cfe-Sandbox-Outcome`","items":{"type":"string"},"type":"array"},"series":{"const":"SB","type":"string"},"test_users":{"description":"Usuarios de prueba de la cuenta","type":"integer"}},"required":["exists","keys","max_keys","test_users","max_test_users","documents","max_documents","monthly_cap","idle_days","numbering","key_prefix","series","outcomes"],"type":"object"},"SandboxPurge":{"properties":{"purged":{"description":"Lo que se borró; todo en cero si no había sandbox","properties":{"emissions":{"type":"integer"},"events":{"type":"integer"},"exchanges":{"type":"integer"},"numberings":{"type":"integer"},"refunds":{"type":"integer"},"submissions":{"type":"integer"}},"required":["emissions","events","submissions","exchanges","refunds","numberings"],"type":"object"},"sandbox":{"$ref":"#/components/schemas/SandboxOverview"}},"required":["purged","sandbox"],"type":"object"},"SandboxPurgeRequest":{"properties":{"confirm":{"description":"El RUC del cliente, como confirmación (`422 confirmation_required`)","type":"string"},"reason":{"description":"Sólo la consola, obligatorio (`422 reason_required`)","type":"string"}},"required":["confirm"],"type":"object"},"Scope":{"description":"Permiso de una clave dentro de la API de cliente: `read` (toda lectura), `emit` (emitir, vista previa, reemisión, contingencia, anulaciones, envío a la DGI, entrega a otra empresa y sus direcciones), `receive` (recepción, rechazo comercial, reglas de recepción), `reports` (reporte diario y su programación), `settings` (perfil del emisor, CAE, webhook, publicación, intercambio, contactos ante la DGI). El cliente debe tolerar valores nuevos.","enum":["read","emit","receive","reports","settings"],"type":"string"},"Session":{"properties":{"access_token":{"description":"Solo en login/refresh; el navegador lo guarda en memoria","type":"string"},"expires_in":{"type":"integer"},"permissions":{"items":{"type":"string"},"type":"array"},"suspension":{"description":"Sólo mientras la cuenta está suspendida: su portal está cerrado (cualquier otra operación de la sesión responde `403 account_suspended`). También en la vista del cliente del personal.","properties":{"since":{"description":"Desde cuándo está suspendida; `null` si no se registró","format":"date-time","type":["string","null"]}},"required":["since"],"type":"object"},"tenant":{"$ref":"#/components/schemas/Tenant"},"token_type":{"const":"Bearer","type":"string"},"user":{"$ref":"#/components/schemas/User"}},"type":"object"},"StaffAuditEntry":{"properties":{"at":{"format":"date-time","type":"string"},"environment":{"description":"`sandbox` para un pedido de \"ver como el cliente\" hecho en Pruebas (`Cfe-Environment: sandbox`); `null` es la cuenta real.","enum":["sandbox",null],"type":["string","null"]},"id":{"type":"integer"},"method":{"type":"string"},"path":{"type":"string"},"request_id":{"type":["string","null"]},"route":{"type":"string"},"staff_email":{"type":"string"},"staff_role":{"type":"string"},"staff_user_id":{"format":"uuid","type":"string"},"status":{"type":"integer"},"tenant_id":{"format":"uuid","type":["string","null"]},"tenant_name":{"type":["string","null"]},"view_session_id":{"format":"uuid","type":["string","null"]}},"type":"object"},"StaffAuditPage":{"properties":{"entries":{"items":{"$ref":"#/components/schemas/StaffAuditEntry"},"type":"array"},"next":{"description":"`before` de la página siguiente","type":["integer","null"]}},"type":"object"},"StaffCreateRequest":{"properties":{"display_name":{"maxLength":120,"type":"string"},"email":{"type":"string"},"password":{"minLength":12,"type":"string"},"reason":{"maxLength":2000,"type":"string"},"role":{"$ref":"#/components/schemas/StaffRole"}},"required":["email","display_name","password","role","reason"],"type":"object"},"StaffExchangeAddressConfirm":{"properties":{"email":{"format":"email","type":"string"},"ruc":{"type":"string"},"tenant_id":{"format":"uuid","type":"string"}},"required":["tenant_id","ruc","email"],"type":"object"},"StaffMe":{"properties":{"allowed":{"description":"Las rutas de la consola que abre su rol, `METHOD path`","items":{"type":"string"},"type":"array"},"display_name":{"type":"string"},"email":{"type":"string"},"id":{"format":"uuid","type":"string"},"role":{"$ref":"#/components/schemas/StaffRole"}},"type":"object"},"StaffMember":{"properties":{"active":{"type":"boolean"},"created_at":{"format":"date-time","type":"string"},"display_name":{"type":"string"},"email":{"type":"string"},"id":{"format":"uuid","type":"string"},"last_login_at":{"format":"date-time","type":["string","null"]},"role":{"$ref":"#/components/schemas/StaffRole"}},"type":"object"},"StaffMembership":{"allOf":[{"$ref":"#/components/schemas/Membership"},{"properties":{"alerts":{"items":{"$ref":"#/components/schemas/MembershipAlert"},"type":"array"},"effective":{"type":"object"},"limits":{"items":{"$ref":"#/components/schemas/LimitUsage"},"type":"array"},"overrides":{"type":"object"},"renewal_refusal":{"description":"Por qué el próximo fin no se renovaría solo con la opción encendida (esté encendida o no): una vigencia de más de un año o un fin que ya se renovó. `null` si se renovaría o no hay nada que renovar.","oneOf":[{"$ref":"#/components/schemas/MembershipRenewalRefusal"},{"type":"null"}]},"state_changed_at":{"format":"date-time","type":["string","null"]},"state_reason":{"type":["string","null"]},"stored_state":{"enum":["TRIAL","ACTIVE","SUSPENDED","EXPIRED"],"type":"string"},"tenant_id":{"format":"uuid","type":"string"},"warnings":{"description":"Sólo en la respuesta de un cambio, y sólo si hay algo: lo que se guardó pero conviene saber (un fin que ya se renovó, con la opción apagada).","items":{"$ref":"#/components/schemas/MembershipRenewalRefusal"},"type":"array"}},"type":"object"}]},"StaffNote":{"properties":{"author_email":{"type":"string"},"author_id":{"format":"uuid","type":["string","null"]},"body":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"deleted_at":{"format":"date-time","type":["string","null"]},"id":{"format":"uuid","type":"string"},"pinned":{"type":"boolean"},"replaces":{"description":"La nota de la que es la edición","format":"uuid","type":["string","null"]},"tenant_id":{"format":"uuid","type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"StaffReportDgiStateRequest":{"properties":{"communication":{"description":"Lo que comunicó la DGI (su correo, lo que muestra su portal, los motivos de gestión). Queda en el historial del reporte y en el del cliente","maxLength":2000,"type":"string"},"state":{"description":"`DR` Reporte Procesado, `ER` Reporte en Gestión, `FR` Reporte Reliquidado","enum":["DR","ER","FR"],"type":"string"}},"required":["state","communication"],"type":"object"},"StaffReportQueued":{"properties":{"created":{"type":"boolean"},"date":{"format":"date","type":"string"},"location":{"type":"string"},"report_id":{"format":"uuid","type":"string"},"status":{"type":"string"}},"type":"object"},"StaffReportRequest":{"properties":{"date":{"format":"date","type":"string"},"force":{"description":"Sin esperar los CFE que DGI no contestó (quedan afuera)","type":"boolean"},"reason":{"maxLength":2000,"type":"string"}},"required":["date","reason"],"type":"object"},"StaffRole":{"description":"ADMIN: todo. SUPPORT: ver, ver como el cliente, notas, reenviar invitaciones. BILLING: membresías, consumo y exportaciones.","enum":["ADMIN","SUPPORT","BILLING"],"type":"string"},"StaffUpdateRequest":{"properties":{"active":{"type":"boolean"},"reason":{"maxLength":2000,"type":"string"},"role":{"$ref":"#/components/schemas/StaffRole"}},"required":["reason"],"type":"object"},"Submission":{"properties":{"attempts":{"type":"integer"},"documents":{"type":"integer"},"id":{"format":"uuid","type":"string"},"idemisor":{"type":["integer","null"]},"kind":{"enum":["ENVELOPE","REPORT"],"type":"string"},"last_error":{"type":["string","null"]},"reception_id":{"type":["integer","null"]},"sent_at":{"format":"date-time","type":"string"},"state":{"description":"Lo que respondió DGI: AS sobre recibido, BS sobre rechazado, BA archivo rechazado (un sobre rechazado no rechaza sus CFE: vuelven a enviarse en un sobre nuevo); AR, BR o BA para el reporte diario.","type":["string","null"]},"status":{"enum":["PENDING","SENDING","SENT","ACKNOWLEDGED","REJECTED","FAILED"],"type":"string"}},"type":"object"},"SubmissionDetail":{"allOf":[{"$ref":"#/components/schemas/Submission"},{"properties":{"anomalies":{"description":"Diferencias entre las respuestas de la DGI y el sobre (RUC, IDEmisor, cantidades, Nro_ordinal)","items":{"type":"string"},"type":"array"},"available_at":{"description":"`Fechahora`: desde cuándo se consulta la respuesta por CFE (no antes)","format":"date-time","type":["string","null"]},"causes":{"description":"Motivos de rechazo de un BS o BA: `[{code, gloss, detail}]`","items":{"type":"object"},"type":"array"},"received_at":{"description":"`FecHRecibido`: cuándo la DGI recibió el sobre","format":"date-time","type":["string","null"]},"response_id":{"description":"`IDRespuesta` del acuse del sobre","type":["integer","null"]},"response_signed_at":{"description":"`Tmst` del acuse","format":"date-time","type":["string","null"]},"results":{"items":{"properties":{"causes":{"items":{"type":"object"},"type":"array"},"cfe_type":{"type":"integer"},"number":{"type":"integer"},"observations":{"description":"`ObsCFC` de un CE","items":{"type":"object"},"type":"array"},"ordinal":{"description":"`Nro_ordinal`: posición del CFE en el sobre","type":"integer"},"original":{"description":"`InfoRespOri` de un E02 (`response_id`, `sender_id`, `reception_id`), sin el token","type":["object","null"]},"outcome":{"description":"Qué significó la respuesta para el CFE (E02 y E09 quedan PENDING)","enum":["ACCEPTED","REJECTED","PENDING",null],"type":["string","null"]},"series":{"type":"string"},"state":{"description":"AE recibido, BE rechazado (anulado salvo E02 y E09), CE CFC observado (recibido, hay que informarlo corregido), FE reliquidado (recibido).","enum":["AE","BE","CE","FE"],"type":"string"}},"type":"object"},"type":"array"},"signature":{"description":"Firma de la DGI en el acuse; null si no hay certificado de la DGI configurado. Es una marca: la respuesta se guarda y se aplica igual","enum":["VALID","UNSIGNED","UNTRUSTED","INVALID",null],"type":["string","null"]},"signature_detail":{"type":["string","null"]}},"type":"object"}]},"TeamInvitation":{"properties":{"created_at":{"format":"date-time","type":"string"},"created_by_email":{"type":["string","null"]},"display_name":{"type":"string"},"email":{"type":"string"},"expires_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"mailed":{"description":"Si el último enlace salió por correo.","type":"boolean"},"role":{"enum":["OWNER","MEMBER"],"type":"string"},"sent_at":{"description":"Cuándo salió el último enlace.","format":"date-time","type":"string"},"status":{"description":"`expired`: el enlace venció; reenvíela para uno nuevo.","enum":["pending","expired"],"type":"string"}},"required":["id","email","display_name","role","status","created_at","sent_at","expires_at","mailed"],"type":"object"},"TeamInvitationSent":{"allOf":[{"$ref":"#/components/schemas/TeamInvitation"},{"properties":{"link":{"description":"Sólo sin correo configurado: el enlace de un solo uso (`{CFE_PUBLIC_URL}/invitacion#token=…`), que se muestra esta única vez para entregárselo a la persona. Queda en el historial que se mostró.","type":"string"}},"type":"object"}]},"Tenant":{"properties":{"id":{"format":"uuid","type":"string"},"name":{"type":"string"},"ruc":{"type":"string"}},"type":"object"},"TenantBranch":{"properties":{"address":{"description":"`DomFiscal` (A-C48)","maxLength":70,"type":"string"},"city":{"description":"`Ciudad` (A-C49)","maxLength":30,"type":"string"},"code":{"description":"`CdgDGISucur` (A-C47): el código que la DGI le dio a la sucursal para este RUC. Nunca se supone.","maximum":9999,"minimum":0,"type":"integer"},"default":{"description":"La sucursal de una emisión que no indica `issuer.branch_code`. Exactamente una; si hay una sola, es la predeterminada.","type":"boolean"},"department":{"description":"`Departamento` (A-C50)","maxLength":30,"type":"string"},"name":{"description":"`EmiSucursal` (A-C46): nombre propio de la casa principal o sucursal.","maxLength":20,"type":["string","null"]}},"required":["code","address","city","department"],"type":"object"},"TenantFeature":{"properties":{"advanced":{"description":"Una opción que la mayoría de las cuentas no cambia: la consola la muestra en «Opciones avanzadas», plegada","type":"boolean"},"default":{"description":"Sin membresía ni excepción: lo que la plataforma hacía antes de la configuración."},"description":{"description":"Qué gobierna, en palabras simples: sin rutas ni nombres de campo","type":"string"},"editable_by":{"description":"`owner`: el dueño también la cambia (`PATCH /v1/tenant/features`).","enum":["staff","owner"],"type":"string"},"effect":{"description":"`enforced`: lo apagado se rechaza; `default`: sólo el valor inicial del formulario del portal, la API nunca lo aplica a una solicitud (la moneda por defecto y los precios con IVA incluido); `planned`: rige cuando exista la función.","enum":["enforced","default","planned"],"type":"string"},"group":{"enum":["cfe_types","currencies","recipient","amounts","document","delivery","printing","integration","notifications","orders","assistant","sandbox"],"type":"string"},"key":{"description":"Clave estable (`cfe_types.e_invoice`, `currency.allowed`): se agregan, nunca se renombran.","type":"string"},"kind":{"enum":["bool","list","enum"],"type":"string"},"label":{"type":"string"},"membership_value":{"description":"Sólo para la consola: lo que dice la membresía."},"min_items":{"description":"Lo mínimo de una lista.","type":"integer"},"option_labels":{"additionalProperties":{"type":"string"},"description":"Las palabras de cada valor de la lista, cuando la API las tiene (los eventos de los webhooks, los canales y los avisos): `{valor: etiqueta}`","type":"object"},"options":{"description":"Lo que toma una lista o un enum.","items":{"type":"string"},"type":"array"},"override_value":{"description":"Sólo para la consola: la excepción propia del cliente."},"source":{"enum":["default","membership","override"],"type":"string"},"technical":{"description":"Las rutas, campos y códigos que gobierna, cuando tiene","type":"string"},"value":{"description":"Lo que rige: `true`/`false`, una opción o una lista de opciones."}},"required":["key","group","label","kind","value","default","source","editable_by","effect","advanced"],"type":"object"},"TenantFeatureChange":{"properties":{"after":{},"before":{},"key":{"type":"string"},"source":{"enum":["default","membership","override"],"type":"string"}},"type":"object"},"TenantFeatures":{"properties":{"changes":{"description":"Lo que cambió la solicitud (`PATCH` y `PUT`).","items":{"$ref":"#/components/schemas/TenantFeatureChange"},"type":"array"},"features":{"items":{"$ref":"#/components/schemas/TenantFeature"},"type":"array"},"fingerprint":{"description":"Cambia con cualquier valor; es el `configuration.fingerprint` del catálogo y del webhook.","type":"string"},"groups":{"items":{"properties":{"key":{"type":"string"},"label":{"type":"string"}},"type":"object"},"type":"array"},"tenant_id":{"format":"uuid","type":"string"}},"required":["tenant_id","fingerprint","groups","features"],"type":"object"},"TenantFeaturesRequest":{"properties":{"changes":{"additionalProperties":true,"description":"`{clave: valor}`; `null` borra la excepción (vuelve a la membresía o al valor por defecto).","examples":[{"cfe_types.export":false,"currency.allowed":["UYU","USD"],"document.subtotals":null}],"type":"object"},"reason":{"description":"Motivo; obligatorio para el equipo de la plataforma.","maxLength":2000,"type":"string"},"template":{"description":"Sólo la consola: una plantilla (`GET /v1/admin/feature-templates`) cuyos valores reemplazan todas las excepciones; `changes` la ajusta después.","type":"string"}},"type":"object"},"TenantMembership":{"properties":{"auto_renew":{"type":"boolean"},"can_emit":{"type":"boolean"},"class":{"type":"string"},"emissions":{"type":"integer"},"ends_at":{"format":"date-time","type":["string","null"]},"included":{"type":["integer","null"]},"month_cap":{"type":["integer","null"]},"overage":{"type":"integer"},"overrides":{"type":"object"},"pending_from":{"format":"date-time","type":["string","null"]},"pending_plan_id":{"format":"uuid","type":["string","null"]},"plan_code":{"type":"string"},"plan_id":{"format":"uuid","type":"string"},"plan_name":{"type":"string"},"received":{"type":"integer"},"renewal_refusal":{"description":"Con la renovación automática encendida, `renewal_period_too_long` si su próximo fin no se va a renovar porque la vigencia dura más de un año. La ficha también avisa de un fin que ya se renovó.","enum":["renewal_period_too_long",null],"type":["string","null"]},"renewed_at":{"description":"La última renovación automática.","format":"date-time","type":["string","null"]},"ruc":{"type":"string"},"starts_at":{"format":"date-time","type":"string"},"state":{"type":"string"},"state_reason":{"type":["string","null"]},"tenant_id":{"format":"uuid","type":"string"},"tenant_name":{"type":"string"},"trial_ends_at":{"format":"date-time","type":["string","null"]}},"type":"object"},"TenantProfile":{"description":"Perfil del emisor: domicilio fiscal, sucursales registradas en la DGI, resto de `Emisor` y datos del pie del impreso.","properties":{"additional_information":{"description":"`InfoAdicionalEmisor` (A-C51); si es una leyenda que exige la normativa, se imprime.","maxLength":150,"type":["string","null"]},"address":{"type":["string","null"]},"branches":{"items":{"$ref":"#/components/schemas/TenantBranch"},"type":"array"},"business_activity":{"description":"`GiroEmis` (A-C43)","maxLength":100,"type":["string","null"]},"city":{"type":["string","null"]},"department":{"type":["string","null"]},"email":{"description":"`CorreoEmisor` (A-C45)","maxLength":80,"type":["string","null"]},"id":{"format":"uuid","type":"string"},"issuer_since":{"description":"\"Fecha emisor\" tal como se imprime: la resolución si hay, si no la fecha.","type":["string","null"]},"missing":{"description":"Lo que le faltaría a una emisión que no trae esos datos: hasta completarlo, la emisión se rechaza con 422 en vez de inventarlo. `FechaEmisor` es la «Fecha emisor» del impreso (p. 84): no frena la emisión, frena el papel.","items":{"enum":["CdgDGISucur","DomFiscal","Ciudad","Departamento","FechaEmisor"],"type":"string"},"type":"array"},"name":{"type":"string"},"phone":{"description":"`Telefono` (A-C44)","maxLength":20,"type":["string","null"]},"regime_resolution":{"description":"Para quien ingresó por resolución, sólo ésta: se guarda como \"Res. 1234/2012\" y se imprime en lugar de la fecha.","maxLength":40,"type":["string","null"]},"regime_since":{"description":"\"Fecha emisor\" del impreso (Formato CFE p. 84; FAQ 8.1): fecha de ingreso al régimen. Ésta o `regime_resolution` es obligatoria para imprimir: sin ninguna, `missing` lista `FechaEmisor` y `/pdf`, `/print` y `/pos` responden 422 `issuer_since_missing` (la emisión no se frena: el XML es válido sin la leyenda).","format":"date","type":["string","null"]},"ruc":{"type":"string"},"second_phone":{"description":"Segundo `Telefono` (el esquema admite dos)","maxLength":20,"type":["string","null"]},"trade_name":{"description":"`NomComercial` (A-C42)","maxLength":30,"type":["string","null"]},"vat_not_up_to_date":{"description":"A-C17 «IVA al día» (Formato CFE p. 26; FAQ 4.49): `true` cuando el emisor no está al día con el IVA. Entonces cada e-Ticket, e-Factura y e-Factura de exportación lleva `IVAalDia` 1 (3 si el pedido ya decía 2, el mandante) y el impreso dice «No IVA al día emisor» en lugar de la constancia. Los emisores Monotributo (CAE especial 3 o 4) no usan el campo: se rechaza mientras haya un rango así cargado.","type":"boolean"},"verification_site":{"description":"Sitio de la empresa para la leyenda de los e-Tickets: \"Puede verificar comprobante en …\" (p. 84; FAQ 7.1 y 7.2). Sin él, la página pública de okCFE mientras `publication` no sea `none`; un e-Ticket sin ningún sitio no se imprime (422 `verification_site_missing`): el de la DGI no verifica e-Tickets. No se puede borrar mientras `publication` es `none`.","maxLength":200,"type":["string","null"]}},"type":"object"},"TenantReadiness":{"properties":{"can_emit":{"description":"Ningún chequeo es `error`","type":"boolean"},"cfe_types":{"description":"Los tipos con rangos de CAE cargados (sin los de contingencia, que se cargan en papel)","items":{"properties":{"can_emit":{"type":"boolean"},"cfe_type":{"type":"integer"},"enabled":{"type":"boolean"},"name":{"type":"string"},"numbers_left":{"type":["integer","null"]},"reasons":{"description":"`feature_disabled`, `no_numbering` y los `code` de los chequeos `error` de la cuenta","items":{"type":"string"},"type":"array"}},"required":["cfe_type","name","enabled","numbers_left","can_emit","reasons"],"type":"object"},"type":"array"},"checked_at":{"format":"date-time","type":"string"},"checks":{"items":{"$ref":"#/components/schemas/ReadinessCheck"},"type":"array"},"days":{"description":"Los días hacia adelante que cuentan como \"por vencer\"","type":"integer"}},"required":["can_emit","checked_at","days","checks","cfe_types"],"type":"object"},"TestUser":{"properties":{"created_at":{"format":"date-time","type":"string"},"display_name":{"type":"string"},"email":{"format":"email","type":"string"},"id":{"format":"uuid","type":"string"},"last_login_at":{"format":"date-time","type":["string","null"]}},"required":["id","email","display_name","created_at","last_login_at"],"type":"object"},"TestUserPassword":{"properties":{"password":{"minLength":12,"type":"string"}},"required":["password"],"type":"object"},"TestUsers":{"properties":{"items":{"items":{"$ref":"#/components/schemas/TestUser"},"type":"array"},"max_users":{"const":3,"description":"Los usuarios de prueba que puede tener la cuenta","type":"integer"}},"required":["items","max_users"],"type":"object"},"UiValue":{"properties":{"caps":{"description":"Sólo en respuestas: el tope de la Tabla E que esta UI fija para los comprobantes del año siguiente, por período (la UI del tope cambió el 01/11/2022).","items":{"properties":{"cap_uyu":{"type":"string"},"from":{"format":"date","type":"string"},"to":{"format":"date","type":"string"},"units":{"type":"string"}},"required":["from","to","units","cap_uyu"],"type":"object"},"type":"array"},"source":{"description":"Sólo en respuestas: de dónde salió. `BCU`: la cargó el worker del servicio del BCU (moneda 9800); `MANUAL`: la cargó el staff con `PUT /v1/admin/rates`, y el worker no la cambia; `null`: ninguno de los dos (el valor inicial que siembra desarrollo), y el worker la reemplaza por la del BCU cuando responde.","enum":["BCU","MANUAL",null],"type":["string","null"]},"updated_at":{"description":"Sólo en respuestas: cuándo se guardó.","format":"date-time","type":"string"},"value":{"description":"Valor de la UI al 31/12 de `year`: el tope de 5.000 UI de los e-Ticket del año siguiente (Tabla E).","type":"string"},"year":{"maximum":2050,"minimum":2011,"type":"integer"}},"required":["year","value"],"type":"object"},"UnknownOutcomeEnvelope":{"description":"Un sobre del que no se sabe si llegó a la DGI (el worker murió en medio del envío, o la DGI no contestó).","properties":{"attempts":{"type":"integer"},"documents":{"type":"integer"},"id":{"format":"uuid","type":"string"},"idemisor":{"type":["integer","null"]},"last_error":{"type":["string","null"]},"reconciliation":{"description":"`UNKNOWN`: espera; `SUPERSEDED`: sus CFE salieron en un sobre nuevo (la DGI contesta `E02` con la respuesta original por los que ya tenía); `CONFIRMED`: se cargó a mano el token que dio la DGI","enum":["UNKNOWN","SUPERSEDED","CONFIRMED"],"type":"string"},"ruc":{"type":"string"},"sent_at":{"format":"date-time","type":"string"},"tenant_id":{"format":"uuid","type":"string"}},"required":["id","tenant_id","ruc","documents","attempts","sent_at","reconciliation"],"type":"object"},"UpdateTenantProfile":{"description":"Sólo cambia lo que viene. `name`, `address`, `city` y `department` en blanco no cambian; los demás con `null` o en blanco se borran. `branches`, si viene, reemplaza la lista entera (la predeterminada se copia a `address`, `city` y `department`).","properties":{"additional_information":{"description":"`InfoAdicionalEmisor` (A-C51); si es una leyenda que exige la normativa, se imprime.","maxLength":150,"type":["string","null"]},"address":{"maxLength":70,"type":"string"},"branches":{"items":{"$ref":"#/components/schemas/TenantBranch"},"type":"array"},"business_activity":{"description":"`GiroEmis` (A-C43)","maxLength":100,"type":["string","null"]},"city":{"maxLength":30,"type":"string"},"department":{"maxLength":30,"type":"string"},"email":{"description":"`CorreoEmisor` (A-C45)","maxLength":80,"type":["string","null"]},"name":{"maxLength":150,"type":"string"},"phone":{"description":"`Telefono` (A-C44)","maxLength":20,"type":["string","null"]},"regime_resolution":{"description":"\"Res. 1234/2012\", \"res 1234/2012\" o \"1234/2012\".","type":["string","null"]},"regime_since":{"description":"AAAA-MM-DD, entre 2009-01-01 y hoy.","format":"date","type":["string","null"]},"second_phone":{"description":"Segundo `Telefono` (el esquema admite dos)","maxLength":20,"type":["string","null"]},"trade_name":{"description":"`NomComercial` (A-C42)","maxLength":30,"type":["string","null"]},"vat_not_up_to_date":{"description":"A-C17 (FAQ 4.49): `true` si el emisor no está al día con el IVA; ausente no cambia. 422 con un rango Monotributo cargado.","type":"boolean"},"verification_site":{"description":"Sitio de la empresa para la leyenda de los e-Tickets: \"Puede verificar comprobante en …\" (p. 84). `null` lo borra, salvo mientras `publication` es `none` (422: el e-Ticket tiene que nombrar un sitio, FAQ 7.1).","maxLength":200,"type":["string","null"]}},"type":"object"},"Usage":{"properties":{"alerts":{"items":{"$ref":"#/components/schemas/MembershipAlert"},"type":"array"},"can_emit":{"description":"Si el estado de la membresía admite una emisión ahora; `false` sin membresía.","type":"boolean"},"emissions":{"type":"integer"},"limits":{"items":{"$ref":"#/components/schemas/LimitUsage"},"type":"array"},"membership":{"description":"`null` para una cuenta sin membresía: sólo trabaja en su ambiente de pruebas (claves de prueba, el modo Pruebas del portal).","oneOf":[{"$ref":"#/components/schemas/Membership"},{"type":"null"}]},"period":{"type":"string"},"plan":{"type":"string"},"production":{"description":"Si la cuenta trabaja en producción: una membresía en prueba (`TRIAL`) o activa (`ACTIVE`). Sin ella sólo crea claves de prueba y emite en su ambiente de pruebas; las claves de producción que tenga no emiten (`403 membership_required`, `membership_expired` o `account_suspended`).","type":"boolean"},"quota":{"type":"integer"},"rate_limit_per_minute":{"type":"integer"},"remaining":{"type":"integer"}},"type":"object"},"UsageExport":{"properties":{"generated_at":{"format":"date-time","type":"string"},"period":{"type":"string"},"tenants":{"items":{"properties":{"amount":{"type":["string","null"]},"billable_units":{"type":"integer"},"class":{"type":"string"},"currency":{"type":"string"},"emitted":{"type":"integer"},"included":{"type":["integer","null"]},"overage":{"type":"integer"},"plan_code":{"type":"string"},"plan_name":{"type":"string"},"received":{"type":"integer"},"ruc":{"type":"string"},"state":{"type":"string"},"tenant_id":{"format":"uuid","type":"string"},"tenant_name":{"type":"string"},"tier_from":{"type":["integer","null"]},"unit_price":{"type":["string","null"]}},"type":"object"},"type":"array"}},"type":"object"},"User":{"properties":{"active":{"type":"boolean"},"display_name":{"type":"string"},"email":{"format":"email","type":"string"},"environment":{"description":"Dónde trabajan sus sesiones: `sandbox` para un usuario de prueba (siempre el ambiente de pruebas de su cuenta), `production` para los demás. En la vista del cliente del personal, el ambiente en que se abrió.","enum":["production","sandbox"],"type":"string"},"id":{"format":"uuid","type":"string"},"role":{"enum":["ADMIN","OWNER","MEMBER"],"type":"string"},"tenant_id":{"description":"null para ADMIN","format":"uuid","type":["string","null"]}},"type":"object"},"UserLinkSent":{"properties":{"email":{"type":"string"},"expires_at":{"format":"date-time","type":"string"},"link":{"description":"Sólo a un ADMIN: el enlace de una invitación cuando no hay correo configurado, o el que genera `POST /v1/admin/users/{id}/password-link`; se muestra esta única vez para entregárselo al usuario (`{CFE_PUBLIC_URL}/invitacion#token=…`). Un restablecimiento nunca lo devuelve.","type":"string"},"mailed":{"type":"boolean"},"purpose":{"enum":["INVITATION","RESET"],"type":"string"},"user_id":{"format":"uuid","type":"string"}},"type":"object"},"VatRateTable":{"properties":{"basic":{"type":"string"},"date":{"format":"date","type":"string"},"from":{"format":"date","type":"string"},"indicators":{"items":{"properties":{"code":{"type":"integer"},"label":{"type":"string"},"rate":{"type":["string","null"]},"total":{"type":"string"},"value":{"type":"string"},"vat":{"enum":["basic","minimum","other","none"],"type":"string"}},"type":"object"},"type":"array"},"minimum":{"type":"string"},"to":{"format":"date","type":["string","null"]}},"type":"object"},"ViewAsRequest":{"properties":{"environment":{"default":"production","description":"Dónde lee la sesión toda su vida: la cuenta real (`production`) o su ambiente de pruebas (`sandbox`, como lo ve un usuario de prueba). Abrirla en pruebas crea el ambiente de pruebas del cliente si no lo tenía.","enum":["production","sandbox"],"type":"string"},"minutes":{"default":30,"maximum":120,"minimum":5,"type":"integer"},"reason":{"maxLength":2000,"type":"string"}},"required":["reason"],"type":"object"},"ViewAsStarted":{"properties":{"banner":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"environment":{"description":"Dónde lee la sesión","enum":["production","sandbox"],"type":"string"},"expires_at":{"format":"date-time","type":"string"},"header":{"const":"X-CFE-View-As","type":"string"},"id":{"format":"uuid","type":"string"},"read_only":{"type":"boolean"},"tenant":{"properties":{"id":{"format":"uuid","type":"string"},"name":{"type":"string"},"ruc":{"type":"string"}},"type":"object"},"token":{"description":"Se muestra una vez","type":"string"}},"type":"object"},"ViewSession":{"properties":{"active":{"type":"boolean"},"created_at":{"format":"date-time","type":"string"},"ended_at":{"format":"date-time","type":["string","null"]},"environment":{"description":"Dónde lee la sesión","enum":["production","sandbox"],"type":"string"},"expires_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"reason":{"type":"string"},"requests":{"type":"integer"},"staff_email":{"type":"string"},"staff_user_id":{"format":"uuid","type":"string"},"tenant_id":{"format":"uuid","type":"string"},"tenant_name":{"type":"string"}},"type":"object"},"WebhookCreate":{"additionalProperties":false,"properties":{"enabled":{"default":true,"type":"boolean"},"events":{"default":["*"],"description":"Nombres del catálogo (`GET /v1/webhooks/events`), o `[\"*\"]` para todos, también los que se agreguen después","items":{"type":"string"},"minItems":1,"type":"array"},"name":{"maxLength":80,"type":["string","null"]},"secret":{"description":"El secreto propio; sin él, se genera uno y se devuelve una vez","maxLength":256,"minLength":16,"type":"string"},"url":{"format":"uri","maxLength":2048,"type":"string"}},"required":["url"],"type":"object"},"WebhookDeliveriesPage":{"properties":{"count":{"type":"integer"},"deliveries":{"items":{"$ref":"#/components/schemas/WebhookDelivery"},"type":"array"},"has_more":{"type":"boolean"},"limit":{"type":"integer"},"next_cursor":{"type":["string","null"]}},"required":["count","has_more","next_cursor","limit","deliveries"],"type":"object"},"WebhookDelivery":{"properties":{"attempts":{"type":"integer"},"created_at":{"format":"date-time","type":"string"},"dead_at":{"format":"date-time","type":["string","null"]},"delivered_at":{"format":"date-time","type":["string","null"]},"event":{"type":"string"},"event_id":{"description":"El evento de `GET /v1/events`; `null` en el evento de prueba. Opaco (`evt_` y 26 caracteres): no es un número de la plataforma ni se puede ordenar.","pattern":"^evt_[a-z2-7]{26}$","type":["string","null"]},"id":{"description":"El `id` del cuerpo que entrega. Opaco (`dlv_` y 26 caracteres): no es un número de la plataforma ni se puede ordenar.","pattern":"^dlv_[a-z2-7]{26}$","type":"string"},"last_attempt_at":{"format":"date-time","type":["string","null"]},"last_error":{"type":["string","null"]},"next_attempt_at":{"format":"date-time","type":["string","null"]},"payload":{"additionalProperties":true,"type":"object"},"response_status":{"description":"El código HTTP de la última respuesta","type":["integer","null"]},"retried_by":{"description":"El `id` del reenvío más reciente de la entrega; `null` si nunca se volvió a enviar. Opaco (`dlv_` y 26 caracteres): no es un número de la plataforma ni se puede ordenar.","pattern":"^dlv_[a-z2-7]{26}$","type":["string","null"]},"retry_of":{"description":"El `id` de la entrega que esta vuelve a enviar (`POST /v1/webhooks/{id}/deliveries/{delivery_id}/retry`); `null` si no es un reenvío. Opaco (`dlv_` y 26 caracteres): no es un número de la plataforma ni se puede ordenar.","pattern":"^dlv_[a-z2-7]{26}$","type":["string","null"]},"status":{"description":"`pending`: espera su primer intento; `retrying`: falló y se reintenta en `next_attempt_at`; `paused`: el destino está apagado; `delivered`; `dead`: agotó los intentos (12, o 24 horas con el destino fallando)","enum":["pending","retrying","paused","delivered","dead"],"type":"string"}},"required":["id","event","event_id","status","attempts","response_status","last_error","created_at","last_attempt_at","next_attempt_at","delivered_at","dead_at","payload","retry_of","retried_by"],"type":"object"},"WebhookDestination":{"properties":{"blocked_until":{"format":"date-time","type":["string","null"]},"consecutive_failures":{"minimum":0,"type":"integer"},"created_at":{"format":"date-time","type":"string"},"enabled":{"type":"boolean"},"events":{"description":"Los eventos que recibe; `[\"*\"]`: todos, también los que se agreguen después","items":{"type":"string"},"type":"array"},"id":{"format":"uuid","type":"string"},"last_attempt_at":{"format":"date-time","type":["string","null"]},"last_error":{"description":"El error de la última entrega que falló","type":["string","null"]},"last_failure_at":{"format":"date-time","type":["string","null"]},"last_success_at":{"format":"date-time","type":["string","null"]},"name":{"description":"Un nombre para distinguir el destino","maxLength":80,"type":["string","null"]},"secret":{"description":"Sólo en la respuesta que lo generó (creación sin `secret`, o `rotate-secret`); nunca se vuelve a mostrar","type":"string"},"status":{"description":"`active`; `failing`: las últimas entregas fallaron; `blocked`: falló 5 veces seguidas y sus eventos esperan hasta `blocked_until` (de 30 s a 10 min), así no demora a los otros destinos; `disabled`: apagado","enum":["active","failing","blocked","disabled"],"type":"string"},"updated_at":{"format":"date-time","type":"string"},"url":{"format":"uri","type":"string"}},"required":["id","name","url","events","enabled","status","consecutive_failures","blocked_until","last_attempt_at","last_success_at","last_failure_at","last_error","created_at","updated_at"],"type":"object"},"WebhookEvent":{"description":"Un evento del catálogo, el mismo para los webhooks y los destinos de avisos","properties":{"default_on":{"description":"Si un destino de avisos nuevo lo recibe sin elegirlo","type":"boolean"},"description":{"type":"string"},"group":{"enum":["invoices","dgi","reception","cae","certificate","orders","account"],"type":"string"},"group_name":{"type":"string"},"name":{"examples":["invoice.emitted"],"type":"string"},"reach":{"description":"`all`: cualquier destino lo puede recibir; `webhook`: sólo un webhook (llega uno por comprobante u orden)","enum":["all","webhook"],"type":"string"},"threshold":{"description":"Su umbral, de la cuenta (`GET /v1/notifications/thresholds`): `plain`, ninguno","enum":["plain","low","days","repeating"],"type":"string"},"title":{"type":"string"}},"required":["name","group","group_name","title","description","reach","default_on","threshold"],"type":"object"},"WebhookEventCatalog":{"properties":{"all":{"const":"*","type":"string"},"events":{"items":{"$ref":"#/components/schemas/WebhookEvent"},"type":"array"},"test_event":{"const":"webhook.test","type":"string"}},"required":["all","test_event","events"],"type":"object"},"WebhookList":{"properties":{"webhooks":{"items":{"$ref":"#/components/schemas/WebhookDestination"},"type":"array"}},"required":["webhooks"],"type":"object"},"WebhookTestResult":{"properties":{"delivered":{"description":"El receptor contestó 2xx","type":"boolean"},"delivery":{"anyOf":[{"$ref":"#/components/schemas/WebhookDelivery"},{"type":"null"}]},"duration_ms":{"type":"integer"},"error":{"type":["string","null"]},"response_status":{"type":["integer","null"]}},"required":["delivered","response_status","error","duration_ms","delivery"],"type":"object"},"WebhookUpdate":{"additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"events":{"description":"Nombres del catálogo (`GET /v1/webhooks/events`), o `[\"*\"]` para todos, también los que se agreguen después","items":{"type":"string"},"minItems":1,"type":"array"},"name":{"description":"`null` lo quita","maxLength":80,"type":["string","null"]},"secret":{"description":"Un secreto propio en lugar del actual; no se repite en la respuesta","maxLength":256,"minLength":16,"type":"string"},"url":{"format":"uri","maxLength":2048,"type":"string"}},"type":"object"}},"securitySchemes":{"apiKey":{"description":"API key de integración: `X-API-Key` o `Authorization: Bearer cfe_…`","in":"header","name":"X-API-Key","type":"apiKey"},"bearer":{"scheme":"bearer","type":"http"},"bearerAuth":{"bearerFormat":"JWT","description":"Access token del portal (15 min). Se obtiene en /v1/auth/login","scheme":"bearer","type":"http"},"inboundSecret":{"description":"`CFE_MAIL_INBOUND_SECRET` de la plataforma: `Authorization: Bearer <secreto>`, la contraseña de `Authorization: Basic` o `?token=`. Solo para el proveedor de correo.","scheme":"bearer","type":"http"}}},"info":{"contact":{"name":"CFE API"},"description":"Contrato de la versión mayor `v1`. Dentro de una versión mayor el contrato solo crece: se agregan campos opcionales, endpoints y valores de enum que el cliente debe tolerar. Un cambio incompatible se publica como `v2`.\n\nLa versión del formato CFE soportada es 25.2 y la de los esquemas DGI 1.44.2; `GET /v1/meta` las publica en runtime.\n\n**Superficies.** Cada operación dice en `x-surface` quién la puede llamar: `client` (la API de cliente: una clave de API o una sesión; con una clave, sólo si tiene el permiso de `x-scope`, si no `403 scope_required`), `portal` (la API del portal: sólo una sesión; una clave recibe `403 session_required`), `staff` (la consola de la plataforma: una sesión del personal) y `public` (sin credencial del emisor). La guía del integrador es `docs/INTEGRACION.md`; el portal y la consola, `docs/API_PORTAL.md`.\n\n**Roles del equipo.** Las operaciones `staff` piden además un rol del equipo de la plataforma (`ADMIN`, `SUPPORT`, `BILLING`, `GET /v1/admin/staff/me`); el que no alcanza recibe `403 staff_role_required` antes del handler, con `role` y `errors[0].params.required`. Quién puede cada una está en `docs/API_PORTAL.md`.\n\n**Ver como el cliente.** Con `X-CFE-View-As: <token>` (de `POST /v1/admin/tenants/{id}/view-as`) junto a la sesión del personal, las rutas `client` y `portal` responden como al dueño del cliente, sólo `GET`: lo demás es `403 view_only`, la consola `403 view_as_out_of_scope`, y una sesión vencida, terminada o ajena `401 view_session_invalid`. Cada respuesta lleva `X-CFE-View-As: read-only`, `X-CFE-View-As-Session`, `X-CFE-View-As-Tenant` y `X-CFE-View-As-Expires`.\n\n**Ambiente del portal.** El ambiente de una sesión es el de su usuario, y lo decide el servidor: un usuario de prueba (`POST /v1/test-users`, hasta 3 por cuenta, los crea el dueño) trabaja siempre en el ambiente de pruebas de su cuenta (el mismo de las claves de prueba), y cualquier otro usuario siempre en la cuenta real; no hay cabecera ni selector que lo cambie. En pruebas, los comprobantes y lo que sigue de ellos (emitir, previsualizar, devolver, órdenes, consultar, descargar, envíos, reportes, recibidos, contingencia y las llamadas a la DGI simulada) se hacen ahí, serie `SB`, sin valor fiscal y sin contar en el plan; `Cfe-Sandbox-Outcome` elige la respuesta de la DGI simulada. La configuración de la cuenta real se lee igual (`GET`) y no se cambia; el equipo, la membresía y su uso, el uso de la API, el asistente y los usuarios de prueba no están: `403 sandbox_not_available`, salvo la sesión, la contraseña, las claves de prueba y el borrado del sandbox. `GET /v1/api-keys` lista, y `POST` y `DELETE` manejan, sólo las claves del ambiente de la sesión: las de prueba en pruebas, las de producción en producción. Cada respuesta de una sesión en pruebas lleva `Cfe-Environment: sandbox` o `production` (dónde corrió), y `GET /v1/auth/me` dice el ambiente en `user.environment`. Un pedido puede mandar `Cfe-Environment` para decir dónde espera correr: si no coincide con su credencial (una clave real con `sandbox`, una de prueba con `production`, un usuario de producción con `sandbox`, uno de prueba con `production`), o el valor no se lee, o la sesión es del personal sin una cuenta, `400 invalid_environment`. La vista del cliente (`X-CFE-View-As`) se abre en producción o en pruebas (`environment` de `POST /v1/admin/tenants/{id}/view-as`) y queda ahí, igual de sólo lectura.\n\n**Producción con una membresía vigente.** Crear una clave de producción y emitir con valor fiscal piden una membresía en prueba o activa: sin membresía, `403 membership_required` (`state: NONE`); vencida o suspendida, las emisiones responden `membership_expired` o `account_suspended` y crear una clave de producción `membership_required` con `state`. Las claves de prueba, los usuarios de prueba y el ambiente de pruebas funcionan igual, salvo para una cuenta suspendida.\n\n**Cuenta suspendida.** El portal de una cuenta suspendida se cierra en los dos ambientes: cada operación `client` o `portal` de una sesión de sus usuarios (también los de prueba) responde `403 account_suspended` (con `state` y `since`) antes del handler, salvo iniciar y cerrar sesión, renovarla, aceptar una invitación, cambiar la contraseña y `GET /v1/auth/me`, cuyo `suspension` dice desde cuándo. Sus claves de prueba también responden `403 account_suspended`; las de producción siguen consultando, descargando y recibiendo, pero no emiten. La vista del cliente del personal (`X-CFE-View-As`) y la consola no cambian. Una cuenta vencida mantiene el portal y Pruebas: sólo no emite en producción.\n\n**Saturación.** Una réplica al límite responde enseguida `503 overloaded` con `Retry-After`, en cualquier operación de `/v1`: no se hizo nada y el pedido se puede repetir (al emitir, con la misma `Idempotency-Key`), en otra réplica si hay varias.","license":{"name":"MIT"},"summary":"Emisión y envío de comprobantes fiscales electrónicos (CFE) a la DGI de Uruguay.","title":"CFE API","version":"v1"},"openapi":"3.1.0","paths":{"/health":{"get":{"responses":{"200":{"description":"El proceso está vivo"}},"security":[],"summary":"Liveness","tags":["operación"],"x-error-codes":["internal_error"],"x-surface":"public"}},"/health/ready":{"get":{"description":"Lo consultan el balanceador y el healthcheck del contenedor. La consulta a la base tiene su propio timeout de 1 s. Falla recién cuando la base no contestó durante `CFE_READINESS_GRACE_SECONDS` seguidos (histéresis), salvo con `strict=1`; al apagarse responde 503 `draining` de inmediato.","parameters":[{"description":"Falla con el primer chequeo de la base que falle, sin esperar la gracia (el chequeo interno de Caddy).","in":"query","name":"strict","required":false,"schema":{"enum":["1","true"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Readiness"}}},"description":"Puede atender solicitudes (`ready`), o la base no contesta todavía dentro de la gracia (`degraded`)"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Readiness"}}},"description":"La base no contesta hace más que la gracia (`unavailable`), o el proceso se está apagando (`draining`)"}},"security":[],"summary":"Readiness","tags":["operación"],"x-error-codes":["internal_error"],"x-surface":"public"}},"/metrics":{"get":{"responses":{"200":{"description":"Texto en formato de exposición Prometheus"}},"security":[],"summary":"Métricas Prometheus","tags":["operación"],"x-error-codes":["internal_error"],"x-surface":"public"}},"/v1/account/api":{"get":{"description":"Sin importes: los precios son del equipo de la plataforma.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountApi"}}},"description":"La API de la cuenta"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Una clave (`session_required`) o un usuario que no es dueño (`forbidden`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"La API de la cuenta, de sólo lectura: claves, uso de 30 días, ciclo, lo que queda y sandbox (sesión de un dueño)","tags":["cuenta"],"x-error-codes":["account_suspended","database_unavailable","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","session_required","unauthorized"],"x-surface":"portal"}},"/v1/admin/acknowledgements":{"get":{"description":"El sobre, la respuesta o el reporte de cada uno espera la revisión; la métrica `cfe_dgi_acknowledgements_held` avisa.","parameters":[{"description":"`HELD` si se omite","in":"query","name":"status","required":false,"schema":{"enum":["HELD","APPLIED","DISCARDED","all"],"type":"string"}},{"in":"query","name":"limit","required":false,"schema":{"maximum":500,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/HeldAcknowledgement"},"type":"array"}}},"description":"Sin el XML"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"422":{"$ref":"#/components/responses/Unprocessable"}},"security":[{"bearerAuth":[]}],"summary":"Acuses de la DGI retenidos porque su firma no verifica, los más nuevos primero (solo ADMIN)","tags":["administración"],"x-error-codes":["internal_error","invalid_cfe","invalid_environment","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/acknowledgements/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeldAcknowledgement"}}},"description":"El acuse"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe"}},"security":[{"bearerAuth":[]}],"summary":"Un acuse retenido, con su XML (solo ADMIN)","tags":["administración"],"x-error-codes":["bad_request","internal_error","invalid_environment","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/acknowledgements/{id}/apply":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewRequest"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeldAcknowledgement"}}},"description":"`APPLIED`"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`already_reviewed`; `acknowledgement_not_applicable`: el envío ya no lo espera (descartalo)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Aplica un acuse retenido: era de la DGI (por ejemplo, rotó su certificado) (solo ADMIN)","tags":["administración"],"x-error-codes":["already_reviewed","bad_request","database_unavailable","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","restore_pending","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/acknowledgements/{id}/discard":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewRequest"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeldAcknowledgement"}}},"description":"`DISCARDED`"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`already_reviewed`"}},"security":[{"bearerAuth":[]}],"summary":"Descarta un acuse retenido: no era de la DGI. El sobre queda de resultado desconocido y se concilia, la respuesta se vuelve a pedir, el reporte se vuelve a enviar (solo ADMIN)","tags":["administración"],"x-error-codes":["already_reviewed","bad_request","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/api-usage":{"get":{"parameters":[{"description":"Primer día (Uruguay); 29 días antes de `to` por defecto","in":"query","name":"from","schema":{"format":"date","type":"string"}},{"description":"Último día; hoy por defecto","in":"query","name":"to","schema":{"format":"date","type":"string"}},{"in":"query","name":"granularity","schema":{"enum":["day"],"type":"string"}},{"in":"query","name":"sort","schema":{"default":"requests","enum":["name","requests","errors","billable_requests","sandbox_requests","emitted","received","p95_ms","last_used_at"],"type":"string"}},{"description":"`desc` por defecto (`asc` para `name`)","in":"query","name":"order","schema":{"enum":["asc","desc"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiUsageAll"}}},"description":"Uso"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, su rol no alcanza (`staff_role_required`) o una clave (`session_required`)"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un filtro o un campo que no se lee (`field` lo nombra)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Uso de la API de todos los clientes en un rango, ordenable","tags":["consola"],"x-error-codes":["bad_request","database_unavailable","forbidden","internal_error","invalid_environment","invalid_filter","not_found","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/api-usage/export":{"get":{"description":"ADMIN y BILLING.","parameters":[{"description":"Primer día (Uruguay); 29 días antes de `to` por defecto","in":"query","name":"from","schema":{"format":"date","type":"string"}},{"description":"Último día; hoy por defecto","in":"query","name":"to","schema":{"format":"date","type":"string"}},{"in":"query","name":"granularity","schema":{"enum":["day"],"type":"string"}},{"in":"query","name":"sort","schema":{"default":"requests","enum":["name","requests","errors","billable_requests","sandbox_requests","emitted","received","p95_ms","last_used_at"],"type":"string"}},{"description":"`desc` por defecto (`asc` para `name`)","in":"query","name":"order","schema":{"enum":["asc","desc"],"type":"string"}}],"responses":{"200":{"content":{"text/csv":{"schema":{"type":"string"}}},"description":"CSV. En el formato de todos los CSV de la plataforma (docs/API.md, \"Formato de los CSV\"): UTF-8 con BOM, `;` entre celdas, CRLF, números con coma decimal y sin separador de miles, fechas `20/10/2026` e instantes `20/10/2026 14:05:09` en la hora de Uruguay; un texto que una planilla tomaría por fórmula lleva `'` delante."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, su rol no alcanza (`staff_role_required`) o una clave (`session_required`)"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un filtro o un campo que no se lee (`field` lo nombra)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Lo mismo en CSV","tags":["consola"],"x-error-codes":["bad_request","database_unavailable","forbidden","internal_error","invalid_environment","invalid_filter","not_found","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/assistant":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantConsole"}}},"description":"Configuración del asistente"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"}},"security":[{"bearerAuth":[]}],"summary":"El asistente: el proveedor en uso, los ofrecidos con dónde procesan los datos, los probados, los textos y los controles del código","tags":["consola"],"x-error-codes":["forbidden","internal_error","invalid_environment","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/assistant/conversations":{"get":{"parameters":[{"description":"De un cliente","in":"query","name":"tenant_id","schema":{"format":"uuid","type":"string"}},{"description":"De un usuario","in":"query","name":"user_id","schema":{"format":"uuid","type":"string"}},{"description":"Última actividad desde este día (Uruguay)","in":"query","name":"from","schema":{"format":"date","type":"string"}},{"description":"Última actividad hasta este día, incluido","in":"query","name":"to","schema":{"format":"date","type":"string"}},{"in":"query","name":"limit","schema":{"default":25,"maximum":100,"type":"integer"}},{"description":"`next_cursor` de la página anterior","in":"query","name":"cursor","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantConversationPage"}}},"description":"Página"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"}},"security":[{"bearerAuth":[]}],"summary":"Conversaciones del asistente de los clientes, por cliente, usuario y día; cada lectura queda en la auditoría","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_body","invalid_environment","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/assistant/conversations/{id}":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantConversationAudit"}}},"description":"Conversación"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"bearerAuth":[]}],"summary":"Una conversación con cada mensaje, sus llamadas a herramientas y lo que respondieron, sin secretos; la lectura queda en la auditoría","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_environment","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}]},"/v1/admin/assistant/prompts/{name}":{"delete":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantPrompt"}}},"description":"Texto"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"bearerAuth":[]}],"summary":"Vuelve al original (el archivo del repositorio); el historial queda","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_environment","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantPrompt"}}},"description":"Texto"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"bearerAuth":[]}],"summary":"Un texto del asistente: el que está en uso, el original del repositorio y su historial","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_environment","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"parameters":[{"description":"`system` (las instrucciones), `guardrails` (los resguardos) o `skill.<nombre>` (la guía de una habilidad)","in":"path","name":"name","required":true,"schema":{"pattern":"^(system|guardrails|skill\\.[a-z_]+)$","type":"string"}}],"put":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantPromptRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantPrompt"}}},"description":"Texto"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Vacío, demasiado largo o sin la marca interna de las instrucciones (`assistant_prompt_invalid`), o el motivo (`reason_required`)"}},"security":[{"bearerAuth":[]}],"summary":"Una versión nueva de un texto (igual al original, vuelve al original)","tags":["consola"],"x-error-codes":["assistant_prompt_invalid","bad_request","forbidden","internal_error","invalid_body","invalid_environment","not_found","overloaded","payload_too_large","reason_required","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/assistant/provider":{"delete":{"responses":{"204":{"description":"Retirado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"bearerAuth":[]}],"summary":"Vuelve al proveedor del entorno (ANTHROPIC_API_KEY): retira el activado desde la consola","tags":["consola"],"x-error-codes":["forbidden","internal_error","invalid_environment","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/assistant/provider/activate":{"post":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantProviderActivateRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantProvider"}}},"description":"Activo"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No pasó la evaluación (`assistant_provider_not_tested`)"},"422":{"$ref":"#/components/responses/ReasonRequired"}},"security":[{"bearerAuth":[]}],"summary":"Activa un proveedor que pasó la evaluación (retira el anterior)","tags":["consola"],"x-error-codes":["assistant_provider_not_tested","forbidden","internal_error","invalid_body","invalid_environment","not_found","overloaded","payload_too_large","reason_required","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/assistant/provider/tests":{"post":{"description":"Sin `api_key`, usa la del último probado del mismo proveedor y dirección. Un servicio compatible (`openai_compatible`) necesita `base_url`, `data_location` y `data_location_confirmed: true` (Ley 18.331).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantProviderTestRequest"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantProvider"}}},"description":"En evaluación (`state: testing`); el resultado queda en la fila"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Ya hay una evaluación en curso (`assistant_test_running`)"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Datos del proveedor (`assistant_provider_invalid`, con `field`), un proveedor que procesa datos en China o un modelo de DeepSeek (`assistant_provider_not_allowed`) o el motivo (`reason_required`)"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sin clave maestra para guardar la clave (`assistant_key_storage_unavailable`)"}},"security":[{"bearerAuth":[]}],"summary":"Prueba un proveedor: guarda la clave cifrada y corre la evaluación en segundo plano","tags":["consola"],"x-error-codes":["assistant_key_storage_unavailable","assistant_provider_invalid","assistant_provider_not_allowed","assistant_test_running","forbidden","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","reason_required","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/audit":{"get":{"parameters":[{"description":"De un miembro","in":"query","name":"staff_id","schema":{"format":"uuid","type":"string"}},{"description":"Sobre un cliente","in":"query","name":"tenant_id","schema":{"format":"uuid","type":"string"}},{"description":"De una sesión de ver como el cliente","in":"query","name":"view_session_id","schema":{"format":"uuid","type":"string"}},{"description":"Sólo lo que escribe","in":"query","name":"writes","schema":{"type":"boolean"}},{"description":"Las anteriores a este id (`next`)","in":"query","name":"before","schema":{"type":"integer"}},{"description":"Filas","in":"query","name":"limit","schema":{"default":100,"maximum":500,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffAuditPage"}}},"description":"Auditoría"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"}},"security":[{"bearerAuth":[]}],"summary":"Auditoría de cada acción del equipo y de cada solicitud hecha en modo ver como el cliente","tags":["consola"],"x-error-codes":["forbidden","internal_error","invalid_environment","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/billing-cycles/export":{"get":{"description":"ADMIN y BILLING.","parameters":[{"description":"31 días antes de `to` por defecto","in":"query","name":"from","schema":{"format":"date","type":"string"}},{"in":"query","name":"to","schema":{"format":"date","type":"string"}}],"responses":{"200":{"content":{"text/csv":{"schema":{"type":"string"}}},"description":"CSV. En el formato de todos los CSV de la plataforma (docs/API.md, \"Formato de los CSV\"): UTF-8 con BOM, `;` entre celdas, CRLF, números con coma decimal y sin separador de miles, fechas `20/10/2026` e instantes `20/10/2026 14:05:09` en la hora de Uruguay; un texto que una planilla tomaría por fórmula lleva `'` delante."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, su rol no alcanza (`staff_role_required`) o una clave (`session_required`)"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un filtro o un campo que no se lee (`field` lo nombra)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Ciclos cerrados de todos los clientes cuyo último día cae en el rango, en CSV","tags":["consola"],"x-error-codes":["bad_request","database_unavailable","forbidden","internal_error","invalid_environment","invalid_filter","not_found","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/certificates":{"get":{"parameters":[{"description":"Solo los emisores en ese estado; `expiring` es menos de 30 días, `platform` firma con el certificado de la plataforma y `missing` no puede firmar","in":"query","name":"status","required":false,"schema":{"enum":["valid","expiring","expired","not_yet_valid","revoked","platform","missing"],"type":"string"}},{"description":"También los sandbox de los clientes (RUC `SB…`); sin él, sólo los clientes reales","in":"query","name":"include_sandbox","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/AdminCertificate"},"type":"array"}}},"description":"Un elemento por emisor"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"422":{"$ref":"#/components/responses/Unprocessable"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Certificados de todos los clientes reales, los sin certificado y los más próximos a vencer primero (solo ADMIN)","tags":["administración"],"x-error-codes":["database_unavailable","forbidden","internal_error","invalid_environment","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/clients":{"get":{"parameters":[{"description":"`TRIAL`, `ACTIVE`, `EXPIRED`, `SUSPENDED`, separados por coma (cualquiera)","in":"query","name":"state","schema":{"type":"string"}},{"description":"Clase de la membresía","in":"query","name":"class","schema":{"enum":["LIMITED","USAGE"],"type":"string"}},{"description":"Separados por coma (cualquiera): `ok`, `warning`, `critical`, `offboarded`, `can_emit`, `cannot_emit`, `attention` (`warning` o `critical`), `certificate`, `cae`, `limit`, `dgi` o el `code` de una señal","in":"query","name":"health","schema":{"type":"string"}},{"description":"Código del plan","in":"query","name":"plan","schema":{"type":"string"}},{"description":"Parte del nombre o del RUC","in":"query","name":"q","schema":{"type":"string"}},{"description":"Dados de baja o no","in":"query","name":"offboarded","schema":{"type":"boolean"}},{"description":"Orden","in":"query","name":"order","schema":{"default":"created","enum":["usage","created","last_emission","name"],"type":"string"}},{"description":"`desc` por defecto (`asc` por nombre)","in":"query","name":"direction","schema":{"enum":["asc","desc"],"type":"string"}},{"description":"`next_cursor` de la página anterior","in":"query","name":"cursor","schema":{"type":"string"}},{"description":"Filas","in":"query","name":"limit","schema":{"default":50,"maximum":200,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientPage"}}},"description":"Una página"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un filtro, el orden o el cursor no valen (`invalid_query`)"}},"security":[{"bearerAuth":[]}],"summary":"Lista de clientes con membresía, consumo, última emisión y salud","tags":["consola"],"x-error-codes":["forbidden","internal_error","invalid_environment","invalid_query","overloaded","session_required","staff_role_required","unauthorized","view_as_out_of_scope"],"x-surface":"staff"}},"/v1/admin/clients/export":{"get":{"parameters":[{"description":"`TRIAL`, `ACTIVE`, `EXPIRED`, `SUSPENDED`, separados por coma (cualquiera)","in":"query","name":"state","schema":{"type":"string"}},{"description":"Clase de la membresía","in":"query","name":"class","schema":{"enum":["LIMITED","USAGE"],"type":"string"}},{"description":"Separados por coma (cualquiera): `ok`, `warning`, `critical`, `can_emit`, `cannot_emit`, `attention`, `certificate`, `cae`, `limit`, `dgi` o el `code` de una señal","in":"query","name":"health","schema":{"type":"string"}},{"description":"Código del plan","in":"query","name":"plan","schema":{"type":"string"}},{"description":"Parte del nombre o del RUC","in":"query","name":"q","schema":{"type":"string"}},{"description":"Dados de baja o no","in":"query","name":"offboarded","schema":{"type":"boolean"}},{"description":"Orden","in":"query","name":"order","schema":{"default":"created","enum":["usage","created","last_emission","name"],"type":"string"}},{"description":"`desc` por defecto (`asc` por nombre)","in":"query","name":"direction","schema":{"enum":["asc","desc"],"type":"string"}}],"responses":{"200":{"content":{"text/csv":{"schema":{"type":"string"}}},"description":"CSV. En el formato de todos los CSV de la plataforma (docs/API.md, \"Formato de los CSV\"): UTF-8 con BOM, `;` entre celdas, CRLF, números con coma decimal y sin separador de miles, fechas `20/10/2026` e instantes `20/10/2026 14:05:09` en la hora de Uruguay; un texto que una planilla tomaría por fórmula lleva `'` delante."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un filtro no vale (`invalid_query`)"}},"security":[{"bearerAuth":[]}],"summary":"La lista con los mismos filtros, entera, en CSV","tags":["consola"],"x-error-codes":["forbidden","internal_error","invalid_environment","invalid_query","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/dgi-exchanges":{"get":{"description":"Cada llamada HTTP a los servicios de la DGI, también las que fallaron (timeouts, 5xx, respuestas ilegibles, reintentos). Sin los cuerpos: no se audita. Filtros combinables; `next_cursor` trae la página siguiente.","parameters":[{"description":"Un cliente","in":"query","name":"tenant_id","required":false,"schema":{"format":"uuid","type":"string"}},{"description":"La operación","in":"query","name":"operation","required":false,"schema":{"enum":["RECEIVE_ENVELOPE","QUERY_STATUS","RECEIVE_REPORT","UPDATE_CONTACT","QUERY_CFE_ENVELOPES","OTHER"],"type":"string"}},{"description":"Cómo terminó la llamada HTTP","in":"query","name":"outcome","required":false,"schema":{"enum":["OK","SOAP_FAULT","HTTP_ERROR","TIMEOUT","NOT_SENT","UNREADABLE","TRANSPORT_ERROR"],"type":"string"}},{"description":"Un estado de la respuesta de la DGI: `AS`, `BS`, `AE`, `BE`, `CE`, `AR`, `BR`...","in":"query","name":"result","required":false,"schema":{"maxLength":8,"type":"string"}},{"description":"Un código de causa de rechazo (`S03`, `E02`...)","in":"query","name":"cause","required":false,"schema":{"maxLength":8,"type":"string"}},{"description":"Desde (incluido)","in":"query","name":"from","required":false,"schema":{"format":"date-time","type":"string"}},{"description":"Hasta (excluido); después de `from`","in":"query","name":"to","required":false,"schema":{"format":"date-time","type":"string"}},{"description":"Las llamadas de un sobre","in":"query","name":"submission_id","required":false,"schema":{"format":"uuid","type":"string"}},{"description":"Las llamadas de un reporte diario","in":"query","name":"report_id","required":false,"schema":{"format":"uuid","type":"string"}},{"description":"Los intentos de una misma llamada lógica","in":"query","name":"call_id","required":false,"schema":{"format":"uuid","type":"string"}},{"description":"Solo lo que falló o volvió con causas","in":"query","name":"problems","required":false,"schema":{"type":"boolean"}},{"description":"El `next_cursor` de la página anterior","in":"query","name":"cursor","required":false,"schema":{"format":"uuid","type":"string"}},{"description":"Cuántas","in":"query","name":"limit","required":false,"schema":{"default":50,"maximum":500,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DgiExchangePage"}}},"description":"Las llamadas, sin los cuerpos"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"422":{"$ref":"#/components/responses/Unprocessable"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Llamadas a la DGI de todos los clientes, las más nuevas primero (ADMIN y SUPPORT)","tags":["consola"],"x-error-codes":["bad_request","database_unavailable","forbidden","internal_error","invalid_environment","invalid_filter","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/dgi-exchanges/{id}":{"get":{"description":"Los dos cuerpos formateados (y lo que lleva `xmlData`, aparte), la verificación de la firma de la DGI en el acuse, los tiempos, los intentos de la misma llamada lógica y las otras llamadas de su sobre o reporte. Con el token entero, solo en la consola.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DgiExchangeDetail"}}},"description":"La llamada","headers":{"Cache-Control":{"description":"`private, no-store`","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Una llamada a la DGI: lo enviado y lo recibido lado a lado (ADMIN y SUPPORT; se audita)","tags":["consola"],"x-error-codes":["bad_request","database_unavailable","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/dgi-exchanges/{id}/request":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"text/xml":{"schema":{"type":"string"}}},"description":"El mensaje SOAP enviado","headers":{"Cache-Control":{"description":"`private, no-store`","schema":{"type":"string"}},"Content-Disposition":{"description":"`attachment; filename=\"dgi-exchange-{id}-request.xml\"` (o `-response`)","schema":{"type":"string"}},"x-xml-sha256":{"description":"SHA-256 del cuerpo, tal como viajó","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Lo que se envió a la DGI, byte por byte (ADMIN y SUPPORT; se audita)","tags":["consola"],"x-error-codes":["bad_request","database_unavailable","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/dgi-exchanges/{id}/response":{"get":{"description":"`404` también cuando no volvió nada (un timeout, una conexión rechazada).","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"text/xml":{"schema":{"type":"string"}}},"description":"La respuesta de la DGI","headers":{"Cache-Control":{"description":"`private, no-store`","schema":{"type":"string"}},"Content-Disposition":{"description":"`attachment; filename=\"dgi-exchange-{id}-request.xml\"` (o `-response`)","schema":{"type":"string"}},"x-xml-sha256":{"description":"SHA-256 del cuerpo, tal como viajó","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Lo que respondió la DGI, byte por byte (ADMIN y SUPPORT; se audita)","tags":["consola"],"x-error-codes":["bad_request","database_unavailable","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/discarded-envelopes":{"get":{"parameters":[{"in":"query","name":"limit","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/DiscardedEnvelope"},"type":"array"}}},"description":"Registros, el más reciente primero"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"}},"security":[{"bearerAuth":[]}],"summary":"Sobres por correo descartados, de todos los tenants (solo ADMIN)","tags":["administración","intercambio"],"x-error-codes":["internal_error","invalid_environment","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/exchange-addresses":{"delete":{"description":"Sólo una `INBOUND`: la que cargó el tenant no se toca (404).","parameters":[{"in":"query","name":"tenant_id","required":true,"schema":{"format":"uuid","type":"string"}},{"in":"query","name":"ruc","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Borrada"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"bearerAuth":[]}],"summary":"Olvida la dirección aprendida de un tenant (solo ADMIN)","tags":["administración","intercambio"],"x-error-codes":["bad_request","internal_error","invalid_environment","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"get":{"parameters":[{"description":"Sólo las no confirmadas (por defecto)","in":"query","name":"unconfirmed","required":false,"schema":{"default":true,"type":"boolean"}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/LearnedExchangeAddress"},"type":"array"}}},"description":"Direcciones, la más reciente primero"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"}},"security":[{"bearerAuth":[]}],"summary":"Direcciones aprendidas de correos, de todos los tenants (solo ADMIN)","tags":["administración","intercambio"],"x-error-codes":["internal_error","invalid_environment","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/exchange-addresses/confirm":{"post":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffExchangeAddressConfirm"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeAddress"}}},"description":"Confirmada"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`address_changed` o `address_not_learned`"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"RUC o dirección inválidos"}},"security":[{"bearerAuth":[]}],"summary":"Confirma la dirección aprendida de un tenant (solo ADMIN)","tags":["administración","intercambio"],"x-error-codes":["address_changed","address_not_learned","internal_error","invalid_body","invalid_environment","not_found","overloaded","payload_too_large","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/exchange-directory":{"get":{"parameters":[{"in":"query","name":"ruc","required":false,"schema":{"type":"string"}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ExchangeDirectoryEntry"},"type":"array"}}},"description":"Entradas"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"}},"security":[{"bearerAuth":[]}],"summary":"Direcciones de intercambio publicadas por la DGI, como se cargaron (solo ADMIN)","tags":["administración","intercambio"],"x-error-codes":["internal_error","invalid_environment","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"put":{"description":"El mail «a efectos de contacto entre emisores electrónicos» que cada emisor declara y la DGI proporciona a los demás (Instructivo v11, p. 10). Reemplaza las del mismo RUC; hasta 20.000 por solicitud.","requestBody":{"content":{"application/json":{"schema":{"properties":{"entries":{"items":{"$ref":"#/components/schemas/ExchangeDirectoryEntry"},"type":"array"}},"required":["entries"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"loaded":{"type":"integer"}},"type":"object"}}},"description":"Cargadas"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"RUC o dirección inválidos (`entries[i].ruc`, `entries[i].email`)"}},"security":[{"bearerAuth":[]}],"summary":"Carga entradas del directorio (solo ADMIN)","tags":["administración","intercambio"],"x-error-codes":["internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/feature-registry":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeatureRegistry"}}},"description":"Registro"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, su rol no alcanza (`staff_role_required`) o una clave (`session_required`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Todas las funciones de la configuración, sin un cliente (para el formulario de una membresía)","tags":["administración"],"x-error-codes":["database_unavailable","forbidden","internal_error","invalid_environment","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/feature-templates":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/FeatureTemplate"},"type":"array"}}},"description":"Plantillas"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma (o una clave: `session_required`)"}},"security":[{"bearerAuth":[]}],"summary":"Plantillas de configuración para un cliente nuevo (Completa, Pyme, Exportador)","tags":["administración"],"x-error-codes":["internal_error","invalid_environment","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/health":{"get":{"description":"Las réplicas de la API y los workers desde su latido, la base (migraciones, replicación, conexiones), la DGI (circuito, llamadas y su latencia, envíos pendientes, sin resultado y retenidos, atraso y reportes diarios), las colas (webhooks y los destinos que fallan, avisos por canal, correo) y el asistente, cada sección con su estado (`ok`, `warning`, `problem`) y los hallazgos con su página de la consola. `series` son los últimos 60 minutos de emisiones, errores, 429 y latencias, sumados entre procesos, de lo que ya mide la telemetría: no depende de Prometheus. La consola la pide cada 5 segundos. Una consulta que falla deja su sección en `unknown`, no la página.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformHealth"}}},"description":"Salud"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sin sesión"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, o su rol no es ADMIN ni SUPPORT"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Salud de la plataforma: cada pieza juzgada y la última hora de la telemetría (ADMIN y SUPPORT)","tags":["administración"],"x-error-codes":["database_unavailable","forbidden","internal_error","invalid_environment","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/membership-alerts":{"get":{"parameters":[{"in":"query","name":"days","schema":{"default":30,"type":"integer"}},{"in":"query","name":"limit","schema":{"default":200,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/MembershipAlert"},"type":"array"}}},"description":"Avisos"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, o su rol no alcanza"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Avisos de límites (80 % y 100 %) de todos los clientes","tags":["membresías"],"x-error-codes":["database_unavailable","internal_error","invalid_environment","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/membership-plans":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/MembershipPlan"},"type":"array"}}},"description":"Membresías"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, o su rol no alcanza"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Catálogo de membresías","tags":["membresías"],"x-error-codes":["database_unavailable","forbidden","internal_error","invalid_environment","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"post":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MembershipPlanRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MembershipPlan"}}},"description":"Creada"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, o su rol no alcanza"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Ya hay una con ese código"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un valor no válido, o falta el motivo"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Crea una membresía (con límite o por uso)","tags":["membresías"],"x-error-codes":["database_unavailable","internal_error","invalid_body","invalid_cfe","invalid_environment","overloaded","payload_too_large","plan_exists","restore_pending","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/membership-plans/{id}":{"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"in":"query","name":"reason","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Borrada"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, o su rol no alcanza"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Hay clientes con ella (`plan_in_use`)"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un valor no válido, o falta el motivo"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Borra una membresía que ningún cliente tiene","tags":["membresías"],"x-error-codes":["bad_request","database_unavailable","internal_error","invalid_cfe","invalid_environment","overloaded","plan_in_use","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MembershipPlan"}}},"description":"Membresía"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, o su rol no alcanza"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Una membresía","tags":["membresías"],"x-error-codes":["bad_request","database_unavailable","internal_error","invalid_environment","not_found","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"patch":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MembershipPlanRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MembershipPlan"}}},"description":"Membresía"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, o su rol no alcanza"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Ya hay una con ese código"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un valor no válido, o falta el motivo"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Cambia una membresía: rige para sus clientes en la solicitud siguiente","tags":["membresías"],"x-error-codes":["bad_request","database_unavailable","internal_error","invalid_body","invalid_cfe","invalid_environment","overloaded","payload_too_large","restore_pending","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/membership-plans/{id}/pricing":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiPlanPricing"}}},"description":"Precios del plan"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, su rol no alcanza (`staff_role_required`) o una clave (`session_required`)"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Precios de un plan, lo que rige sin excepción y lo que se cobra","tags":["consola"],"x-error-codes":["bad_request","database_unavailable","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"put":{"description":"ADMIN y BILLING. Queda en el historial de la plataforma (categoría `pricing`).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiPricingRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiPlanPricing"}}},"description":"Precios del plan"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, su rol no alcanza (`staff_role_required`) o una clave (`session_required`)"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un filtro o un campo que no se lee (`field` lo nombra)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Reemplaza los precios de un plan, con motivo","tags":["consola"],"x-error-codes":["bad_request","database_unavailable","forbidden","internal_error","invalid_body","invalid_environment","not_found","overloaded","payload_too_large","reason_required","restore_pending","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/memberships":{"get":{"parameters":[{"in":"query","name":"state","schema":{"enum":["TRIAL","ACTIVE","SUSPENDED","EXPIRED"],"type":"string"}},{"in":"query","name":"class","schema":{"enum":["LIMITED","USAGE"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/TenantMembership"},"type":"array"}}},"description":"Membresías"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un filtro no válido"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, o su rol no alcanza"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"La membresía de cada cliente y su consumo del mes","tags":["membresías"],"x-error-codes":["database_unavailable","internal_error","invalid_environment","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/notes/{id}":{"delete":{"responses":{"204":{"description":"Borrada"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"bearerAuth":[]}],"summary":"Borra una nota (su autor o un ADMIN): se oculta, se conserva","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_environment","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"patch":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteUpdateRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffNote"}}},"description":"La nota nueva"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Vacía o de más de 5000 caracteres (`invalid_note`)"}},"security":[{"bearerAuth":[]}],"summary":"Edita una nota (su autor o un ADMIN); el texto anterior queda como versión borrada","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_body","invalid_environment","invalid_note","not_found","note_author_only","overloaded","payload_too_large","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/operations":{"get":{"description":"Numeración que se agota o vence, días sin reporte diario recibido, rechazos de la DGI de los últimos 7 días, atraso del worker, su latido y el circuito hacia la DGI, la cola de correo del intercambio entre empresas, cuántos acuses y sobres esperan revisión, las listas de revocación vencidas o nunca bajadas y los certificados que necesitan a alguien (todos en `/v1/admin/certificates`; las listas en `/v1/admin/pki`). `attention` cuenta una vez lo que necesita a alguien: el número del menú de la consola y de «Para atender». Nunca cuenta los sandbox. Lee de la réplica cuando hay una.","parameters":[{"description":"También los sandbox de los clientes (RUC `SB…`); sin él, sólo los clientes reales","in":"query","name":"include_sandbox","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Operations"}}},"description":"Panel"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sin sesión"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Panel de operaciones: lo que necesita a un operador, por cliente (solo ADMIN)","tags":["administración"],"x-error-codes":["database_unavailable","forbidden","internal_error","invalid_environment","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/overview":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"can_emit":{"description":"Clientes reales cuya salud dice que pueden emitir (`health=can_emit` de `/v1/admin/clients`)","type":"integer"},"dead_events":{"description":"Eventos de webhook que agotaron los intentos","type":"integer"},"emissions_today":{"type":"integer"},"needs_attention":{"description":"Clientes reales con un problema de aviso o crítico (`health=attention` de `/v1/admin/clients`); un dado de baja, sólo mientras le debe algo a la DGI","type":"integer"},"pending":{"type":"integer"},"tenants":{"type":"integer"},"undelivered_events":{"type":"integer"},"users":{"type":"integer"}},"type":"object"}}},"description":"Resumen"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Números de la plataforma (solo ADMIN)","tags":["administración"],"x-error-codes":["database_unavailable","internal_error","invalid_environment","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/pki":{"get":{"description":"Una CRL `STALE` (pasó su `nextUpdate` más la gracia) es la alerta: la revocación de los certificados de esa CA no se conoce hasta que publique otra; la firma sigue (modo `soft`).","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PkiState"}}},"description":"Estado de la confianza en certificados"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Confianza en certificados: CA de confianza, CRL y su frescura, certificado de la DGI, revocación de los emisores (solo ADMIN)","tags":["administración"],"x-error-codes":["database_unavailable","forbidden","internal_error","invalid_environment","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/pki/refresh":{"post":{"description":"Descarga las CRL vencidas o más viejas que `CFE_PKI_REFRESH_SECONDS` y recalcula el estado de los certificados de firma; útil después de que una CA publicó una revocación.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PkiState"}}},"description":"Estado de la confianza en certificados"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Corre ahora el pase de fondo de revocación y devuelve el estado (solo ADMIN)","tags":["administración"],"x-error-codes":["database_unavailable","internal_error","invalid_environment","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/provider-report":{"get":{"description":"Formato de Informe Proveedores de Software v1.3 y XSD efacinfoprov 1.5.2 (Preguntas frecuentes v28, 16.1-16.6): la plataforma es proveedor de software y declara su producto y sus clientes. La zona C sale de los clientes reales (nunca un sandbox): un alta por cada cuenta cuyo servicio empezó en el período (el día de creación de la cuenta o, si es posterior, su «Fecha emisor», C-3) y una baja por cada baja cuyo último día cae en él; con `first_report=true` (el primer informe de clientes, C-2) van además, como altas con fecha el primer día del período, los clientes que ya estaban. La zona B declara el producto `OKCFE` con sus procesos como alta, que la DGI admite una sola vez (B-5): las zonas 1 y 3 son para el primer informe del producto. El período debe estar terminado (A-3: anterior al mes en curso). El archivo se llama `Prov_RUC_AAAAMM_xx.xml` y se envía a mano en el portal, «Envíos / Informe de Proveedores de SW», dentro del mes siguiente (16.4); una corrección repite el período con `sequence` + 1 (16.5). Firma con el certificado de la plataforma, que viaja en la firma (zona D), y declara `CFE_PROVIDER_RUC` (o el RUC del certificado); ambos deben coincidir (I02).","parameters":[{"description":"El mes declarado, `AAAAMM` (A-3: desde 202010 y anterior al mes en curso); por defecto el mes anterior al actual","in":"query","name":"period","schema":{"pattern":"^[0-9]{6}$","type":"string"}},{"description":"La secuencia del período (A-5): 1 el primer informe, la recibida más uno para corregirlo","in":"query","name":"sequence","schema":{"default":1,"maximum":99,"minimum":1,"type":"integer"}},{"description":"La zona informada (A-6): `2` los clientes (el informe habitual), `3` el producto como alta y los clientes (el primer informe de la plataforma), `1` sólo el producto (el primer informe, sin clientes todavía). El alta del producto se admite una vez (B-5)","in":"query","name":"zone","schema":{"default":2,"enum":[1,2,3],"type":"integer"}},{"description":"ID emisor del envío (A-4), opcional","in":"query","name":"sender_id","schema":{"minimum":0,"type":"integer"}},{"description":"`true` en el primer informe de clientes: declara además, como altas con `FechaInicio` el primer día del período, los clientes que empezaron antes y siguen vigentes (C-2, p. 12)","in":"query","name":"first_report","schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"text/xml":{"schema":{"type":"string"}}},"description":"El informe firmado (`Declaracion`)","headers":{"Cache-Control":{"description":"`private, no-store`","schema":{"type":"string"}},"Content-Disposition":{"description":"`attachment; filename=\"Prov_RUC_AAAAMM_xx.xml\"` (formato p. 5)","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`nothing_to_declare`: el período no tiene altas ni bajas de clientes (16.4: no corresponde enviar el informe); `provider_not_configured`: sin certificado de la plataforma, sin RUC del proveedor, o `CFE_PROVIDER_RUC` distinto del RUC del sujeto del certificado (I02)"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_query`: `period` o `zone` mal formados; `provider_report_invalid`: lo armado no cumple el formato (por ejemplo, un período anterior a 202010 o el mes en curso, A-3)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"El informe de proveedores de software de un mes, firmado, para subirlo al portal de e-Factura (solo ADMIN; se audita)","tags":["administración"],"x-error-codes":["database_unavailable","forbidden","internal_error","invalid_environment","invalid_query","nothing_to_declare","overloaded","provider_not_configured","provider_report_invalid","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/rates":{"put":{"description":"Para un día que el BCU no publicó o el worker no cargó, o la UI de un año. Inserta o reemplaza (origen `MANUAL`); una carga posterior del BCU del mismo día la reemplaza, salvo la UI del 31/12, que el worker no cambia. Una cotización `UYI` del 31/12 en `rates` es la UI de ese año (si también viene en `ui_values`, vale esa). La UI admite hasta 6 decimales y las demás cotizaciones 8.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoadFiscalRates"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"rates_saved":{"type":"integer"},"ui_values_saved":{"type":"integer"}},"type":"object"}}},"description":"Guardados"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es ADMIN de plataforma"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Datos inválidos"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Carga a mano tipos de cambio fiscales o la UI (solo ADMIN de plataforma)","tags":["administración"],"x-error-codes":["database_unavailable","internal_error","invalid_body","invalid_cfe","invalid_environment","overloaded","payload_too_large","restore_pending","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/settings":{"get":{"description":"Lo que viene de variables de entorno: el ambiente de la DGI, el corte de prioridad de envío que aplicó el worker, el reporte automático, el correo entre empresas, la verificación pública y la seguridad. Sin secretos: sólo si están configurados.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminSettings"}}},"description":"Configuración"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"}},"security":[{"bearerAuth":[]}],"summary":"Configuración del despliegue, de sólo lectura (solo ADMIN)","tags":["administración"],"x-error-codes":["forbidden","internal_error","invalid_environment","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/staff":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/StaffMember"},"type":"array"}}},"description":"Equipo"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"}},"security":[{"bearerAuth":[]}],"summary":"Equipo de la plataforma con su rol","tags":["consola"],"x-error-codes":["forbidden","internal_error","invalid_environment","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"post":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffCreateRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffMember"}}},"description":"Creado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Email en uso"},"422":{"$ref":"#/components/responses/ReasonRequired"}},"security":[{"bearerAuth":[]}],"summary":"Alta de un miembro del equipo con su rol","tags":["consola"],"x-error-codes":["forbidden","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","reason_required","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/staff/me":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffMe"}}},"description":"Rol"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"}},"security":[{"bearerAuth":[]}],"summary":"Quién soy en el equipo: rol y rutas que abre","tags":["consola"],"x-error-codes":["forbidden","internal_error","invalid_environment","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/staff/{id}":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"patch":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffUpdateRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffMember"}}},"description":"Miembro"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Es el último ADMIN activo (`last_admin`)"},"422":{"$ref":"#/components/responses/ReasonRequired"}},"security":[{"bearerAuth":[]}],"summary":"Cambia el rol o desactiva (termina sus sesiones)","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_body","invalid_environment","last_admin","not_found","overloaded","payload_too_large","reason_required","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/submissions":{"get":{"description":"El worker los concilia solo (`CFE_WORKER_RECONCILE_UNKNOWN`, a los `CFE_WORKER_RECONCILE_AFTER_SECONDS` del envío): sus CFE salen en un sobre nuevo y la DGI contesta `E02` con la respuesta original por los que ya tenía.","parameters":[{"description":"`unknown` si se omite; `all` suma los conciliados en los últimos 7 días","in":"query","name":"reconciliation","required":false,"schema":{"enum":["unknown","all"],"type":"string"}},{"in":"query","name":"limit","required":false,"schema":{"maximum":500,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/UnknownOutcomeEnvelope"},"type":"array"}}},"description":"Los más nuevos primero"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"422":{"$ref":"#/components/responses/Unprocessable"}},"security":[{"bearerAuth":[]}],"summary":"Sobres de resultado desconocido, de todos los emisores (solo ADMIN)","tags":["administración"],"x-error-codes":["internal_error","invalid_environment","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/submissions/{id}/reconcile":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReconcileRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnknownOutcomeEnvelope"}}},"description":"Conciliado"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`not_unknown_outcome`: no espera conciliación"},"422":{"$ref":"#/components/responses/Unprocessable"}},"security":[{"bearerAuth":[]}],"summary":"Concilia a mano un sobre de resultado desconocido (solo ADMIN)","tags":["administración"],"x-error-codes":["bad_request","internal_error","invalid_body","invalid_cfe","invalid_environment","not_unknown_outcome","overloaded","payload_too_large","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/tenants":{"get":{"parameters":[{"description":"También los sandbox de los clientes (RUC `SB…`); sin él, sólo los clientes reales","in":"query","name":"include_sandbox","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/AdminTenant"},"type":"array"}}},"description":"Tenants"},"403":{"$ref":"#/components/responses/SessionRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Clientes con plan y consumo, sin los sandbox (solo ADMIN)","tags":["administración"],"x-error-codes":["database_unavailable","forbidden","internal_error","invalid_environment","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"post":{"description":"Valida todo (RUC, email, contraseña, límites) antes de escribir y crea el tenant y su primer OWNER en una sola transacción: si algo falla no queda nada y la misma solicitud se puede repetir. El tenant nace sin domicilio fiscal; el emisor lo carga en su perfil.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTenant"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedTenant"}}},"description":"Tenant creado"},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"RUC ya registrado (`tenant_exists`) o email tomado (`email_taken`)"},"422":{"$ref":"#/components/responses/Unprocessable"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Crea un tenant y, opcionalmente, su primer owner","tags":["administración"],"x-error-codes":["already_member","bad_request","database_unavailable","internal_error","invalid_body","invalid_cfe","invalid_environment","mail_not_sent","overloaded","payload_too_large","restore_pending","session_required","staff_role_required","tenant_exists","unauthorized","unknown_template","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/tenants/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminTenantDetail"}}},"description":"Tenant"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Un tenant con su perfil de emisor (solo ADMIN)","tags":["administración"],"x-error-codes":["bad_request","database_unavailable","internal_error","invalid_environment","not_found","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"patch":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"monthly_quota":{"type":"integer"},"name":{"type":"string"},"plan":{"type":"string"},"rate_limit_per_minute":{"type":"integer"},"reason":{"description":"Para el historial (opcional): la cuota y el límite por minuto son excepciones de la membresía, con quién y por qué","maxLength":2000,"type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminTenant"}}},"description":"Tenant actualizado"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Cambia plan, cuota o límite de un tenant","tags":["administración"],"x-error-codes":["bad_request","database_unavailable","internal_error","invalid_body","invalid_environment","not_found","overloaded","payload_too_large","restore_pending","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/activity":{"get":{"parameters":[{"description":"`change`, `report`, `rejection`, `envelope_rejected`, `expiry`, `limit_alert`, separados por coma","in":"query","name":"kinds","schema":{"type":"string"}},{"description":"`next` de la página anterior","in":"query","name":"before","schema":{"type":"string"}},{"description":"Hechos","in":"query","name":"limit","schema":{"default":50,"maximum":200,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientActivity"}}},"description":"Una página"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un tipo o el cursor no valen (`invalid_query`)"}},"security":[{"bearerAuth":[]}],"summary":"Actividad: historial y hechos importantes (rechazos, reportes, vencimientos, avisos)","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_environment","invalid_query","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}]},"/v1/admin/tenants/{id}/api":{"get":{"description":"Cada clave con su uso de 30 días, las últimas IP y `User-Agent`, si es de prueba o real y quién la creó; revocar es `POST /v1/admin/tenants/{id}/api-keys/revoke`.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiPanel"}}},"description":"Panel"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, su rol no alcanza (`staff_role_required`) o una clave (`session_required`)"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Pestaña API de un cliente: funciones, plan y precios, lo que se cobra, rango disponible, ciclo y claves","tags":["consola"],"x-error-codes":["bad_request","database_unavailable","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}]},"/v1/admin/tenants/{id}/api-keys":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ApiKey"},"type":"array"}}},"description":"Claves"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"}},"security":[{"bearerAuth":[]}],"summary":"Claves del cliente (nunca la clave)","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_environment","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}]},"/v1/admin/tenants/{id}/api-keys/revoke":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"post":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeysRevokeRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeysRevoked"}}},"description":"Revocadas"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"422":{"$ref":"#/components/responses/ReasonRequired"}},"security":[{"bearerAuth":[]}],"summary":"Revoca claves del cliente (rige en su próxima solicitud)","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_body","invalid_environment","keys_required","overloaded","payload_too_large","reason_required","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/api/billing-cycle":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"put":{"description":"ADMIN y BILLING. El ciclo en curso va hasta la próxima vez que llega el día nuevo: nunca queda un hueco ni un día contado dos veces. Queda en el historial (categoría `billing`).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiCycleRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiCycle"}}},"description":"El ciclo en curso"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, su rol no alcanza (`staff_role_required`) o una clave (`session_required`)"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un filtro o un campo que no se lee (`field` lo nombra)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Día del ciclo de facturación del cliente (1 a 28), con motivo","tags":["consola"],"x-error-codes":["bad_request","database_unavailable","forbidden","internal_error","invalid_body","invalid_environment","not_found","overloaded","payload_too_large","reason_required","restore_pending","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/api/cycles":{"get":{"parameters":[{"in":"query","name":"limit","schema":{"default":24,"maximum":500,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiCycles"}}},"description":"Ciclos"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, su rol no alcanza (`staff_role_required`) o una clave (`session_required`)"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Ciclo en curso y ciclos cerrados del cliente, lo más nuevo primero","tags":["consola"],"x-error-codes":["bad_request","database_unavailable","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}]},"/v1/admin/tenants/{id}/api/cycles/export":{"get":{"description":"ADMIN y BILLING.","parameters":[{"in":"query","name":"starts_on","schema":{"format":"date","type":"string"}}],"responses":{"200":{"content":{"text/csv":{"schema":{"type":"string"}}},"description":"CSV. En el formato de todos los CSV de la plataforma (docs/API.md, \"Formato de los CSV\"): UTF-8 con BOM, `;` entre celdas, CRLF, números con coma decimal y sin separador de miles, fechas `20/10/2026` e instantes `20/10/2026 14:05:09` en la hora de Uruguay; un texto que una planilla tomaría por fórmula lleva `'` delante."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, su rol no alcanza (`staff_role_required`) o una clave (`session_required`)"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un filtro o un campo que no se lee (`field` lo nombra)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Ciclos cerrados del cliente en CSV (o uno, con `starts_on`)","tags":["consola"],"x-error-codes":["bad_request","database_unavailable","forbidden","internal_error","invalid_environment","invalid_filter","not_found","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}]},"/v1/admin/tenants/{id}/api/pricing":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"put":{"description":"ADMIN y BILLING. Queda en el historial (`tenant_config_change`, categoría `pricing`).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiPricingRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiPricingChanged"}}},"description":"Precios"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, su rol no alcanza (`staff_role_required`) o una clave (`session_required`)"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un filtro o un campo que no se lee (`field` lo nombra)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Excepción de precios del cliente (sólo lo que cambia; null la quita), con motivo","tags":["consola"],"x-error-codes":["bad_request","database_unavailable","forbidden","internal_error","invalid_body","invalid_environment","not_found","overloaded","payload_too_large","reason_required","restore_pending","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/api/usage":{"get":{"description":"Hasta 400 días. La medición sale de contadores en la base escritos en lote por cada réplica; los comprobantes salen del libro.","parameters":[{"description":"Primer día (Uruguay); 29 días antes de `to` por defecto","in":"query","name":"from","schema":{"format":"date","type":"string"}},{"description":"Último día; hoy por defecto","in":"query","name":"to","schema":{"format":"date","type":"string"}},{"in":"query","name":"granularity","schema":{"enum":["day"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiUsageReport"}}},"description":"Uso"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, su rol no alcanza (`staff_role_required`) o una clave (`session_required`)"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un filtro o un campo que no se lee (`field` lo nombra)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Peticiones por día, clave y ruta, errores por código, p50/p95, comprobantes y límites alcanzados","tags":["consola"],"x-error-codes":["bad_request","database_unavailable","forbidden","internal_error","invalid_environment","invalid_filter","not_found","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}]},"/v1/admin/tenants/{id}/dgi-contacts":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/DgiContact"},"type":"array"}}},"description":"Actualizaciones"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"bearerAuth":[]}],"summary":"Actualizaciones de contactos en la DGI de un tenant, las más nuevas primero (solo ADMIN)","tags":["administración","intercambio"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_environment","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"post":{"description":"`EFACSOLACTUALIZARCONTACTO` (Servicios Web Externos DGI v1.9, p. 3-5) con el código 19 (URL del web service) o 20 (mail de contacto técnico), firmado con WS-Security con el certificado del tenant. `201` cuando la DGI respondió (`accepted` dice si lo tomó); cada llamada queda registrada. Una respuesta ambigua no se repite.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DgiContactRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DgiContact"}}},"description":"La DGI respondió"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Código o valor inválidos"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`dgi_unavailable`: la DGI no respondió (queda registrada como `FAILED`)"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`dgi_contact_unavailable`: falta `CFE_DGI_SOLICITUD_ENDPOINT`"}},"security":[{"bearerAuth":[]}],"summary":"Actualiza un contacto de un tenant en la DGI (solo ADMIN)","tags":["administración","intercambio"],"x-error-codes":["bad_request","dgi_contact_unavailable","dgi_unavailable","forbidden","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/features":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantFeatures"}}},"description":"Configuración"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma (o una clave: `session_required`)"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"bearerAuth":[]}],"summary":"La configuración de un cliente, con lo que dice la membresía y sus excepciones","tags":["administración"],"x-error-codes":["bad_request","internal_error","invalid_environment","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"put":{"description":"En una transacción: las excepciones de las funciones y, con `limits`, las de los límites de la membresía (como `PATCH /v1/admin/tenants/{id}/membership`, con el mismo rol), una fila del historial por clave que cambió (quién, cuándo, antes, después y por qué) y el evento `tenant.configuration_changed`. Si algo se rechaza no se guarda nada. Rige en la petición siguiente de la API de cliente en todas las réplicas (`cfe_invalidate`).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminTenantFeaturesRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminTenantFeatures"}}},"description":"Configuración, con lo que cambió"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma (o una clave: `session_required`); `limits` pide un rol que administre las membresías"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`tenant_offboarded`: con `limits`, el cliente está dado de baja"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`reason_required`, `unknown_feature`, `invalid_feature_value`, `unknown_template`, la moneda por defecto fuera de las permitidas, o un límite que no es válido (`invalid_cfe`, con `field` en `limits.`)"}},"security":[{"bearerAuth":[]}],"summary":"Enciende o apaga funciones de un cliente y cambia las excepciones de sus límites, con motivo, o le aplica una plantilla","tags":["administración"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","not_found","overloaded","payload_too_large","reason_required","session_required","staff_role_required","tenant_offboarded","unauthorized","unknown_template","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/history":{"get":{"parameters":[{"description":"Las filas anteriores a este id (`next`).","in":"query","name":"before","schema":{"type":"integer"}},{"in":"query","name":"limit","schema":{"default":50,"maximum":500,"type":"integer"}},{"description":"`feature`, `membership`... Varias separadas por coma (`membership,limit,account`).","in":"query","name":"category","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigHistory"}}},"description":"Historial, lo más nuevo primero"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma (o una clave: `session_required`)"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"bearerAuth":[]}],"summary":"Historial inmutable de la configuración, la membresía y las acciones del equipo","tags":["administración"],"x-error-codes":["bad_request","internal_error","invalid_environment","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}]},"/v1/admin/tenants/{id}/membership":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffMembership"}}},"description":"Membresía"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, o su rol no alcanza"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"La membresía de un cliente: de dónde sale cada valor y su consumo","tags":["membresías"],"x-error-codes":["bad_request","database_unavailable","forbidden","internal_error","invalid_environment","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"patch":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MembershipChangeRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffMembership"}}},"description":"Membresía"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, o su rol no alcanza"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Con la renovación automática encendida, el fin elegido ya se renovó una vez (`renewal_end_already_renewed`): vencería ese día. Elija otro fin o desactive la opción."},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un valor no válido, o falta el motivo; `renewal_period_too_long` si la renovación automática queda encendida con una vigencia de más de un año (ajuste «Desde» primero)."},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Excepciones a los límites, vigencia y renovación automática de un cliente","tags":["membresías"],"x-error-codes":["bad_request","database_unavailable","internal_error","invalid_body","invalid_cfe","invalid_environment","overloaded","payload_too_large","renewal_end_already_renewed","renewal_period_too_long","restore_pending","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"},"put":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MembershipAssignRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffMembership"}}},"description":"Membresía"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, o su rol no alcanza"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un valor no válido, o falta el motivo"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Cambia la membresía de un cliente, ahora o desde el período siguiente","tags":["membresías"],"x-error-codes":["bad_request","database_unavailable","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","restore_pending","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/membership/reactivate":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReasonRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffMembership"}}},"description":"Membresía"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, o su rol no alcanza"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un valor no válido, o falta el motivo"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Reactiva una cuenta suspendida o vencida","tags":["membresías"],"x-error-codes":["bad_request","database_unavailable","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","overloaded","payload_too_large","restore_pending","session_required","staff_role_required","tenant_offboarded","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/membership/renewals":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Las renovaciones anteriores a este id (`next`).","in":"query","name":"before","schema":{"type":"integer"}},{"in":"query","name":"limit","schema":{"default":20,"maximum":200,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MembershipRenewalPage"}}},"description":"Una página de renovaciones (`membership_renewal`)"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, o su rol no alcanza"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Las renovaciones automáticas de un cliente, de la más nueva a la más vieja","tags":["membresías"],"x-error-codes":["bad_request","database_unavailable","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/membership/suspend":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReasonRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffMembership"}}},"description":"Membresía"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, o su rol no alcanza"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un valor no válido, o falta el motivo"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Suspende: no emite, sigue consultando y recibiendo","tags":["membresías"],"x-error-codes":["bad_request","database_unavailable","internal_error","invalid_body","invalid_cfe","invalid_environment","overloaded","payload_too_large","restore_pending","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/membership/trial":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MembershipTrialRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffMembership"}}},"description":"Membresía"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, o su rol no alcanza"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La membresía está suspendida"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un valor no válido, o falta el motivo"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Extiende (o empieza) el período de prueba","tags":["membresías"],"x-error-codes":["bad_request","database_unavailable","internal_error","invalid_body","invalid_cfe","invalid_environment","overloaded","payload_too_large","restore_pending","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/notes":{"get":{"parameters":[{"description":"Con las borradas y las versiones anteriores","in":"query","name":"include_deleted","schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/StaffNote"},"type":"array"}}},"description":"Notas"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"}},"security":[{"bearerAuth":[]}],"summary":"Notas internas del equipo (el cliente nunca las ve)","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_environment","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"post":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffNote"}}},"description":"Nota"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Vacía o de más de 5000 caracteres (`invalid_note`)"}},"security":[{"bearerAuth":[]}],"summary":"Escribe una nota interna","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_body","invalid_environment","invalid_note","not_found","overloaded","payload_too_large","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/offboarding":{"delete":{"parameters":[{"description":"El motivo (obligatorio)","in":"query","name":"reason","schema":{"type":"string"}}],"responses":{"204":{"description":"Cancelada"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ReasonRequired"}},"security":[{"bearerAuth":[]}],"summary":"Cancela la baja: la membresía como estaba y el reporte automático otra vez","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_environment","not_found","overloaded","reason_required","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"post":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReasonRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Offboarding"}}},"description":"Baja"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Ya está dado de baja (`tenant_offboarded`)"},"422":{"$ref":"#/components/responses/ReasonRequired"}},"security":[{"bearerAuth":[]}],"summary":"Da de baja: deja de emitir ya, conserva los datos y termina los reportes pendientes","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_body","invalid_environment","not_found","overloaded","payload_too_large","reason_required","session_required","staff_role_required","tenant_offboarded","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/overview":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientOverview"}}},"description":"Ficha"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"bearerAuth":[]}],"summary":"Ficha del cliente: resumen, salud, certificado y CAE, DGI, usuarios y claves","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_environment","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}]},"/v1/admin/tenants/{id}/printing/logos/{logo_id}/image":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"in":"path","name":"logo_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"image/png":{"schema":{"contentMediaType":"image/png","type":"string"}}},"description":"El PNG"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"bearerAuth":[]}],"summary":"El PNG de un logo de un cliente","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_environment","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/printing/preview":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Por defecto, la vigente","in":"query","name":"version","required":false,"schema":{"minimum":0,"type":"integer"}},{"in":"query","name":"format","required":false,"schema":{"enum":["a4","80mm","57mm"],"type":"string"}},{"in":"query","name":"output","required":false,"schema":{"default":"pdf","enum":["pdf","pos"],"type":"string"}},{"in":"query","name":"encoding","required":false,"schema":{"enum":["json","escpos","text"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PosTicket"}},"application/octet-stream":{"schema":{"contentMediaType":"application/octet-stream","type":"string"}},"application/pdf":{"schema":{"format":"binary","type":"string"}},"text/plain":{"schema":{"type":"string"}}},"description":"El PDF o el ticket","headers":{"x-cfe-print-template-version":{"description":"La versión de la plantilla con que salió: un número (`0` es la de okCFE) o `draft` en una vista previa","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_format`, `invalid_output` o `invalid_encoding`"}},"security":[{"bearerAuth":[]}],"summary":"Una versión de la plantilla de un cliente sobre el comprobante de ejemplo","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_encoding","invalid_environment","invalid_format","invalid_output","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/printing/template":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrintTemplateVersion"}}},"description":"La vigente"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"bearerAuth":[]}],"summary":"La plantilla del impreso vigente de un cliente","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_environment","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/printing/template/versions":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"in":"query","name":"limit","required":false,"schema":{"default":20,"maximum":100,"minimum":1,"type":"integer"}},{"in":"query","name":"before","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrintTemplateVersionList"}}},"description":"Una página"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"bearerAuth":[]}],"summary":"Las versiones de la plantilla de un cliente","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_environment","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/printing/template/versions/{version}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"La versión; `0` es la de okCFE","in":"path","name":"version","required":true,"schema":{"minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrintTemplateVersion"}}},"description":"La versión"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"bearerAuth":[]}],"summary":"Una versión de la plantilla de un cliente","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_environment","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/reports":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"post":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffReportRequest"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffReportQueued"}}},"description":"En cola"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ReasonRequired"}},"security":[{"bearerAuth":[]}],"summary":"Pide el reporte diario de un día (lo envía el worker)","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_body","invalid_environment","not_found","overloaded","payload_too_large","reason_required","report_date_out_of_range","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/reports/{report_id}/dgi-state":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"in":"path","name":"report_id","required":true,"schema":{"format":"uuid","type":"string"}}],"post":{"description":"Preguntas frecuentes 9.7: después de \"Reporte Recibido\" (AR) la DGI controla el reporte contra los comprobantes y lo deja \"Reporte Procesado\" (`DR`) o \"Reporte en Gestión\" (`ER`); otro reporte de la fecha con la secuencia siguiente lo deja \"Reporte Reliquidado\" (`FR`). Sólo lo dicen el portal y el correo de la DGI: se registra aquí con lo que comunicó. Sólo un reporte recibido; uno reliquidado no cambia más. Queda en el estado del reporte, en su historial (el que ve el cliente) y en el historial del cliente.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffReportDgiStateRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"}}},"description":"El reporte con su estado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ReasonRequired"}},"security":[{"bearerAuth":[]}],"summary":"Registra el estado que la DGI le dio a un reporte recibido","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_body","invalid_environment","invalid_report_state","not_found","overloaded","payload_too_large","reason_required","report_not_received","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/sandbox":{"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxPurgeRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxPurge"}}},"description":"Purgado: el sandbox sigue, vacío, con sus claves"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`reason_required` o `confirmation_required`"}},"security":[{"bearerAuth":[]}],"summary":"Purga el sandbox del cliente (ADMIN y SUPPORT, con `confirm` y motivo)","tags":["consola"],"x-error-codes":["bad_request","confirmation_required","forbidden","internal_error","invalid_body","invalid_environment","not_found","overloaded","payload_too_large","reason_required","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"},"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxOverview"}}},"description":"El sandbox"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"bearerAuth":[]}],"summary":"El sandbox del cliente","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_environment","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/sandbox/keys":{"post":{"description":"El equipo nunca crea claves reales. Mismos límites que `POST /v1/api-keys` con `kind: test`.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxKeyRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKey"}}},"description":"Clave de prueba creada"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`staff_role_required`"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`sandbox_keys_limit`: el cliente ya tiene el máximo de claves de prueba activas de su membresía (`max_keys`, `limit: sandbox_keys`): de 1 a 3, y 3 sin valor en la membresía"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`reason_required`, `invalid_sandbox_outcome` o un nombre o permisos inválidos"}},"security":[{"bearerAuth":[]}],"summary":"Crea una clave de prueba para el cliente (ADMIN y SUPPORT, con motivo); el secreto se ve una vez","tags":["consola"],"x-error-codes":["bad_request","feature_disabled","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","invalid_sandbox_outcome","not_found","overloaded","payload_too_large","reason_required","sandbox_keys_limit","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/users":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/User"},"type":"array"}}},"description":"Usuarios"},"403":{"$ref":"#/components/responses/SessionRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Usuarios de un tenant (solo ADMIN)","tags":["administración"],"x-error-codes":["bad_request","database_unavailable","internal_error","invalid_environment","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"post":{"description":"`role` es `OWNER` (por defecto) o `MEMBER`: `ADMIN` responde `422` con `field: role` y un valor desconocido `400 invalid_body` con `field: role`. Como en el portal, es una invitación: la persona elige su contraseña desde el enlace, que la respuesta trae sólo sin correo configurado.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUser"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamInvitationSent"}}},"description":"Invitación enviada"},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Tenant inexistente"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Ya es parte del equipo (`already_member`) o la membresía no admite más usuarios (`limit_reached`)"},"422":{"$ref":"#/components/responses/Unprocessable"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El correo no salió (`mail_not_sent`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Invita a una persona al equipo de un tenant (solo ADMIN)","tags":["administración"],"x-error-codes":["already_member","bad_request","database_unavailable","internal_error","invalid_body","invalid_cfe","invalid_environment","limit_reached","mail_not_sent","overloaded","payload_too_large","restore_pending","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/tenants/{id}/view-as":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"post":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ViewAsRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ViewAsStarted"}}},"description":"Sesión"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ReasonRequired"}},"security":[{"bearerAuth":[]}],"summary":"Abre una sesión de ver como el cliente, en producción o en pruebas: sólo lectura, con vencimiento y auditada","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_body","invalid_environment","invalid_minutes","not_found","overloaded","payload_too_large","reason_required","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/usage":{"get":{"parameters":[{"in":"query","name":"period","schema":{"examples":["2026-10"],"type":"string"}},{"in":"query","name":"format","schema":{"enum":["json","csv"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageExport"}},"text/csv":{"schema":{"type":"string"}}},"description":"Consumo (JSON, o CSV con `format=csv` o `Accept: text/csv`; el CSV, en el formato de todos los CSV de la plataforma: docs/API.md, \"Formato de los CSV\")"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`period` no es AAAA-MM"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No es personal de la plataforma, o su rol no alcanza"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Consumo del período para facturar (JSON o CSV)","tags":["membresías"],"x-error-codes":["database_unavailable","forbidden","internal_error","invalid_environment","overloaded","restore_pending","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/users/{id}":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"patch":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsoleUserUpdateRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsoleTenantUser"}}},"description":"Usuario"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Dejaría al cliente sin dueño activo (`last_owner`)"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Falta el motivo (`reason_required`), o se quiso cambiar el rol de un usuario de prueba, que trabaja sólo en Pruebas y lo conserva (`test_user_role_fixed`, con `field: \"role\"`)"},"429":{"$ref":"#/components/responses/LimitReached"}},"security":[{"bearerAuth":[]}],"summary":"Desactiva, activa o cambia el rol de un usuario de un cliente","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","last_owner","limit_reached","not_found","overloaded","payload_too_large","reason_required","session_required","staff_role_required","test_user_role_fixed","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/users/{id}/invitation":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"post":{"requestBody":{"content":{"application/json":{"schema":{"properties":{"reason":{"maxLength":2000,"type":"string"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLinkSent"}}},"description":"Enviada"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Ya entró (`already_signed_in`), desactivado (`user_inactive`) o sin correo para SUPPORT (`mail_not_configured`)"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El correo no salió (`mail_not_sent`)"}},"security":[{"bearerAuth":[]}],"summary":"Reenvía la invitación (un enlace nuevo de 7 días por correo)","tags":["consola"],"x-error-codes":["already_signed_in","bad_request","forbidden","internal_error","invalid_body","invalid_environment","mail_not_configured","not_found","overloaded","payload_too_large","session_required","staff_role_required","unauthorized","unsupported_media_type"],"x-surface":"staff"}},"/v1/admin/users/{id}/password-link":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"post":{"description":"El mismo restablecimiento (la contraseña deja de servir, terminan las sesiones), pero el enlace (24 horas) no se manda: la respuesta lo muestra esta única vez (`link`) para entregárselo a la persona. Es un acto propio, con su motivo en el historial y su línea en la auditoría del equipo.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReasonRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLinkSent"}}},"description":"Generado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Desactivado (`user_inactive`)"},"422":{"$ref":"#/components/responses/ReasonRequired"}},"security":[{"bearerAuth":[]}],"summary":"Genera un enlace de un solo uso para restablecer la contraseña (solo ADMIN)","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_body","invalid_environment","not_found","overloaded","payload_too_large","reason_required","session_required","staff_role_required","unauthorized","unsupported_media_type","user_inactive"],"x-surface":"staff"}},"/v1/admin/users/{id}/password-reset":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"post":{"description":"El enlace va sólo por correo al usuario y nunca vuelve en la respuesta. Sin correo configurado, `409 mail_not_configured` y no cambia nada: un ADMIN puede generar un enlace de un solo uso con `POST /v1/admin/users/{id}/password-link`.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReasonRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLinkSent"}}},"description":"Enviado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Desactivado (`user_inactive`) o sin correo configurado (`mail_not_configured`)"},"422":{"$ref":"#/components/responses/ReasonRequired"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El correo no salió (`mail_not_sent`)"}},"security":[{"bearerAuth":[]}],"summary":"Restablece la contraseña: deja de servir, terminan las sesiones y un enlace de 24 horas llega por correo para elegir otra","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_body","invalid_environment","mail_not_configured","mail_not_sent","not_found","overloaded","payload_too_large","reason_required","session_required","staff_role_required","unauthorized","unsupported_media_type","user_inactive"],"x-surface":"staff"}},"/v1/admin/view-sessions":{"get":{"parameters":[{"description":"De un cliente","in":"query","name":"tenant_id","schema":{"format":"uuid","type":"string"}},{"description":"De un miembro","in":"query","name":"staff_id","schema":{"format":"uuid","type":"string"}},{"description":"Sólo las abiertas (o las cerradas)","in":"query","name":"active","schema":{"type":"boolean"}},{"description":"Filas","in":"query","name":"limit","schema":{"default":50,"maximum":500,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ViewSession"},"type":"array"}}},"description":"Sesiones"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"}},"security":[{"bearerAuth":[]}],"summary":"Sesiones de ver como el cliente, con cuántas solicitudes hizo cada una","tags":["consola"],"x-error-codes":["forbidden","internal_error","invalid_environment","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"}},"/v1/admin/view-sessions/{id}":{"delete":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ViewSession"}}},"description":"Sesión"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/StaffRoleRequired"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"bearerAuth":[]}],"summary":"Termina una sesión de ver como el cliente (la propia, o un ADMIN cualquiera)","tags":["consola"],"x-error-codes":["bad_request","forbidden","internal_error","invalid_environment","not_found","overloaded","session_required","staff_role_required","unauthorized"],"x-surface":"staff"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}]},"/v1/annulments":{"get":{"description":"Los más recientes primero (hasta 1000). Con `date`, solo los del reporte diario de esa fecha (el día de `annulled_at` en Uruguay).","parameters":[{"description":"`YYYY-MM-DD`","in":"query","name":"date","required":false,"schema":{"format":"date","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/Annulment"},"type":"array"}}},"description":"Anulaciones"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"422":{"$ref":"#/components/responses/Unprocessable"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Números anulados por la empresa","tags":["numeración"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"post":{"description":"Para un número de un rango autorizado que no llegó a ser un CFE (extraviado, salteado, o el anulado del set de pruebas). Lo consume de su rango en la misma transacción: si es el próximo libre, `next_number` avanza; si está más adelante, la numeración lo saltea cuando llegue a él, sin dejar huecos. El reporte diario de su fecha lo cuenta en C26 y C28 y lo lista en `RngDocsAnulados`.\n\nUn CFE ya firmado no se anula así: se corrige con una nota de crédito (`409 number_emitted`). Los CFC de contingencia no se anulan (`422 contingency_not_annullable`).\n\nIdempotente: anular de nuevo el mismo número devuelve `200` con el registro original (se ignora el motivo nuevo). Queda la auditoría: quién, cuándo y por qué. Solo OWNER (o clave de API).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnnulmentRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Annulment"}}},"description":"Ya estaba anulado: el registro original"},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Annulment"}}},"description":"Número anulado"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Falta el motivo o supera 500 caracteres (`bad_request`, `field` = `reason`)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`number_emitted`: el número es un CFE firmado (corregir con nota de crédito); `number_used`: ya fue consumido"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`number_not_in_range` (`field` = `NroCFE`): ningún rango cargado de ese tipo y serie lo contiene; `contingency_not_annullable` (`field` = `TipoCFE`); `invalid_cfe`: tipo o serie inválidos"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Anula un número de CAE que nunca se usó","tags":["numeración"],"x-error-codes":["account_suspended","bad_request","contingency_not_annullable","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","number_emitted","number_not_in_range","overloaded","payload_too_large","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"emit","x-surface":"client"}},"/v1/api-keys":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ApiKey"},"type":"array"}}},"description":"Claves"},"403":{"$ref":"#/components/responses/SessionRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Claves del ambiente de la sesión: las de producción, o las de prueba para un usuario de prueba","tags":["usuarios"],"x-error-codes":["account_suspended","database_unavailable","forbidden","internal_error","invalid_environment","overloaded","restore_pending","session_required","unauthorized"],"x-surface":"portal"},"post":{"requestBody":{"content":{"application/json":{"schema":{"properties":{"kind":{"description":"Optativo: el ambiente de la sesión lo decide. Un usuario de producción crea claves de producción (`live`); un usuario de prueba, claves de prueba (`test`, `cfe_test_…`, y el sandbox de la cuenta con la primera), hasta las que permite la membresía (`sandbox_keys`, de 1 a 3; sin valor propio, 3; `409 sandbox_keys_limit`), que no cuentan en las claves de la membresía. El otro valor es `400 invalid_environment`.","enum":["live","test"],"type":"string"},"name":{"maxLength":80,"type":"string"},"sandbox_outcome":{"description":"Sólo con `kind: test`: la respuesta por defecto de la DGI simulada (los valores de `Cfe-Sandbox-Outcome`: `accepted`, `rejected:<E01-E15>`, `delay:<1-120>`, `timeout`; no hay `observed`: la DGI sólo observa comprobantes de contingencia, que el sandbox no lleva). Mal escrito, `422 invalid_sandbox_outcome`; en una clave real, `422` con `field: sandbox_outcome`.","type":["string","null"]},"scopes":{"description":"Optativo: los permisos de la clave dentro de la API de cliente. Ausente o `null`, todos. Una lista vacía es `422` (`field: scopes`); un valor desconocido, `400 invalid_body`","items":{"$ref":"#/components/schemas/Scope"},"minItems":1,"type":["array","null"]}},"required":["name"],"type":"object"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKey"}}},"description":"Clave creada"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Rol insuficiente, o `membership_required`: una clave de producción (`kind: live`) pide una membresía en prueba o activa (sin plan, vencida o suspendida, `state` dice cuál: `NONE`, `EXPIRED`, `SUSPENDED`); las de prueba se crean igual"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`sandbox_keys_limit`: una clave de prueba (`kind: test`) y la cuenta ya tiene el máximo de claves de prueba activas de su membresía (`max_keys`, `limit: sandbox_keys`): de 1 a 3, y 3 sin valor en la membresía"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`limit_reached`: la membresía no permite más claves de producción activas (`limit`, `used`, `max`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Crea una clave (el texto plano se devuelve una sola vez)","tags":["usuarios"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","invalid_sandbox_outcome","limit_reached","membership_required","overloaded","payload_too_large","restore_pending","sandbox_keys_limit","session_required","unauthorized","unsupported_media_type"],"x-surface":"portal"}},"/v1/api-keys/{id}":{"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Revocada"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Rol insuficiente"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Revoca una clave del ambiente de la sesión (la del otro ambiente no existe: 404)","tags":["usuarios"],"x-error-codes":["account_suspended","bad_request","database_unavailable","internal_error","invalid_environment","not_found","overloaded","restore_pending","session_required","unauthorized"],"x-surface":"portal"}},"/v1/api-keys/{id}/reveal":{"post":{"description":"La clave completa (`api_key`), otra vez, para copiarla: a un `OWNER` de la cuenta las claves reales y a un usuario de prueba las de prueba, con su sesión y su propia contraseña (`password`). Un `MEMBER` recibe `403 forbidden`, una clave de API `403 session_required` y el equipo de la plataforma nunca la ve (\"ver como el cliente\" es de sólo lectura: `403 view_only`). La clave de otra cuenta, la del otro ambiente o una que no existe, es `404 not_found` antes que nada. Cinco intentos por minuto por usuario, con la contraseña correcta o no (`429 rate_limited`, con `Retry-After`); una contraseña equivocada es `401 invalid_credentials`. Cada vez queda en el historial de la cuenta (`api_key.revealed`: quién y qué clave, nunca la clave) y avisa el evento `api_key.revealed` a los destinos y webhooks que lo eligieron. Las claves se guardan cifradas con la clave maestra (`CFE_MASTER_KEY`), como los certificados; una creada antes de la migración 105 no tiene copia (`409 api_key_not_revealable`) y una revocada la olvidó (`409 api_key_revoked`). La respuesta lleva `Cache-Control: no-store`.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyRevealRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKey"}}},"description":"La clave, con `api_key`"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_credentials`: la contraseña no es la del usuario; `unauthorized`: sin sesión"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sólo `OWNER` con sesión: `forbidden`, `session_required` (una clave de API) o `view_only` (\"ver como el cliente\")"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La clave no es de la cuenta, o no existe"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`api_key_not_revealable`: la clave se creó antes y no se puede volver a ver (cree una nueva); `api_key_revoked`: la clave está revocada"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`rate_limited`: más de cinco intentos en el minuto; `Retry-After` y `retry_after_seconds`"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`key_storage_unavailable`: la clave maestra no está disponible ahora (`Retry-After`); también `database_unavailable`"}},"security":[{"bearerAuth":[]}],"summary":"Muestra de nuevo una clave","tags":["usuarios"],"x-error-codes":["account_suspended","api_key_not_revealable","api_key_revoked","bad_request","database_unavailable","forbidden","internal_error","invalid_body","invalid_credentials","invalid_environment","key_storage_unavailable","not_found","overloaded","payload_too_large","rate_limited","restore_pending","session_required","unauthorized","unsupported_media_type","view_only"],"x-surface":"portal"}},"/v1/assistant":{"get":{"description":"Si el asistente está disponible para la persona de la sesión, por qué no, sus límites y lo que la empresa usó este mes. Solo en el portal: nunca con una clave de API.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantStatus"}}},"description":"Estado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sin sesión de una persona de la empresa (`session_required`, `forbidden`), desde \"ver como el cliente\" (`view_only`) o con la cuenta suspendida (`account_suspended`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Estado del asistente","tags":["asistente"],"x-error-codes":["account_suspended","database_unavailable","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","session_required","unauthorized","view_only","view_session_invalid"],"x-surface":"portal"}},"/v1/assistant/conversations":{"get":{"description":"Las conversaciones de la persona de la sesión, la más reciente primero. `before` es el `next_before` de la página anterior.","parameters":[{"in":"query","name":"limit","schema":{"default":20,"maximum":50,"minimum":1,"type":"integer"}},{"in":"query","name":"before","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantConversationList"}}},"description":"Conversaciones"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sin sesión de una persona de la empresa (`session_required`, `forbidden`), desde \"ver como el cliente\" (`view_only`) o con la cuenta suspendida (`account_suspended`)"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`before` no es una conversación de la persona (`assistant_conversation_not_found`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Conversaciones de la persona","tags":["asistente"],"x-error-codes":["account_suspended","assistant_conversation_not_found","bad_request","database_unavailable","forbidden","internal_error","invalid_body","invalid_environment","overloaded","restore_pending","sandbox_not_available","session_required","unauthorized","view_only","view_session_invalid"],"x-surface":"portal"},"post":{"description":"Una conversación nueva y vacía de la persona de la sesión.","responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantConversation"}}},"description":"Creada","headers":{"Location":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sin sesión de una persona de la empresa (`session_required`, `forbidden`), desde \"ver como el cliente\" (`view_only`), con el asistente fuera del plan o apagado (`feature_disabled`), con la cuenta suspendida (`account_suspended`) o en Pruebas (`Cfe-Environment: sandbox`): el asistente prepara órdenes reales y sólo trabaja en producción (`sandbox_not_available`)"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El asistente no está en esta instalación (`assistant_unavailable`, `reason: not_configured`)"}},"security":[{"bearerAuth":[]}],"summary":"Empieza una conversación","tags":["asistente"],"x-error-codes":["account_suspended","assistant_unavailable","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","rate_limited","restore_pending","sandbox_not_available","session_required","unauthorized","view_only","view_session_invalid"],"x-surface":"portal"}},"/v1/assistant/conversations/{id}":{"delete":{"description":"La borra con sus mensajes. Las órdenes que preparó quedan: son de la empresa.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Borrada"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sin sesión de una persona de la empresa (`session_required`, `forbidden`), desde \"ver como el cliente\" (`view_only`), con la cuenta suspendida (`account_suspended`) o en Pruebas (`sandbox_not_available`)"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe o es de otra persona (`assistant_conversation_not_found`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Borra una conversación","tags":["asistente"],"x-error-codes":["account_suspended","assistant_conversation_not_found","bad_request","database_unavailable","forbidden","internal_error","invalid_body","invalid_environment","overloaded","restore_pending","sandbox_not_available","session_required","unauthorized","view_only","view_session_invalid"],"x-surface":"portal"},"get":{"description":"La conversación y lo que el portal muestra de cada mensaje: el texto, la actividad de las herramientas y las órdenes.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantConversationDetail"}}},"description":"Conversación"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sin sesión de una persona de la empresa (`session_required`, `forbidden`), desde \"ver como el cliente\" (`view_only`) o con la cuenta suspendida (`account_suspended`)"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe o es de otra persona (`assistant_conversation_not_found`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Lee una conversación","tags":["asistente"],"x-error-codes":["account_suspended","assistant_conversation_not_found","bad_request","database_unavailable","forbidden","internal_error","invalid_body","invalid_environment","overloaded","restore_pending","session_required","unauthorized","view_only","view_session_invalid"],"x-surface":"portal"},"patch":{"description":"El nombre que la lista muestra: una línea de hasta 80 caracteres (los espacios de más se quitan). Sin nombre, la conversación lleva la primera línea de su primer mensaje respondido.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantConversationRename"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantConversation"}}},"description":"Conversación con su nombre nuevo"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sin sesión de una persona de la empresa (`session_required`, `forbidden`), desde \"ver como el cliente\" (`view_only`), con la cuenta suspendida (`account_suspended`) o en Pruebas (`sandbox_not_available`)"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe o es de otra persona (`assistant_conversation_not_found`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Cambia el nombre de una conversación","tags":["asistente"],"x-error-codes":["account_suspended","assistant_conversation_not_found","bad_request","database_unavailable","forbidden","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","restore_pending","sandbox_not_available","session_required","unauthorized","unsupported_media_type","view_only","view_session_invalid"],"x-surface":"portal"}},"/v1/assistant/conversations/{id}/messages":{"post":{"description":"Una vez admitido, la respuesta es `text/event-stream` (`200`). Cada evento es `event: <nombre>` y `data: <JSON>`; cada 15 segundos llega un comentario `: ping`.\n\n- `turn` `{conversation_id}`: primero.\n- `activity` `{tool, skill, label, state}`: una herramienta que empieza (`running`) y cómo terminó (`done`, `error`, `not_allowed`). `skill` es la habilidad a la que pertenece (`ordenes`, `comprobantes`, `clientes`, `productos`, `reportes`, `emisiones`, `cuenta`, `configuracion`, `envios`, `errores`, `pendientes`, `cae`, `borradores`; `null` para `decline` o una herramienta que no existe, que se muestra como `unknown`). `label` es el texto para la persona.\n- `card` `{card}`: lo que encontró una herramienta, armado por el servidor con los datos (nunca por el modelo) para mostrarlo al lado de la respuesta: un comprobante, una orden, un cliente, una tabla o una lista de datos (`AssistantCard`). Llegan antes del texto que los comenta, a lo sumo 12 por mensaje.\n- `text` `{delta}`: un trozo del texto ya revisado.\n- `order` `{order}`: una orden que se preparó o se corrigió, como la devuelve `GET /v1/orders/{id}`. Nunca se emite: la persona la revisa y la factura desde el portal.\n- `error` `{code, detail, retry_after}`: el proveedor no respondió (`assistant_unavailable`) o falló algo interno (`internal_error`).\n- `done` `{outcome, usage, cost_micro_usd, calls, orders}`: último. `outcome` es `answered`, `refused` (fuera de tema, uso general, algo fuera de okCFE, otra empresa, una acción que no hace, intento de cambiar las reglas o respuesta retenida: el texto es fijo) `failed` o `stopped` (la persona la detuvo con `POST .../stop`).\n\nAntes del flujo, cada rechazo es un problema con su código: `422 assistant_message_invalid` (vacío o más largo que `limits.max_message_chars`), `404 assistant_conversation_not_found`, `409 assistant_conversation_full` (topes de turnos o de tokens: empiece otra), `429 assistant_rate_limited` (mensajes por minuto de la persona, con `Retry-After`), `429 limit_reached` (`assistant_messages_per_month` o `assistant_tokens_per_month` de la empresa), `503 assistant_overloaded` (demasiadas respuestas en curso, con `Retry-After`), `409 assistant_busy` (otra respuesta de esta conversación en curso).","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantMessageRequest"}}},"required":true},"responses":{"200":{"content":{"text/event-stream":{"schema":{"type":"string"}}},"description":"Eventos de la respuesta"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sin sesión de una persona de la empresa (`session_required`, `forbidden`), desde \"ver como el cliente\" (`view_only`), con el asistente fuera del plan o apagado (`feature_disabled`), con la cuenta suspendida (`account_suspended`) o en Pruebas (`Cfe-Environment: sandbox`): el asistente prepara órdenes reales y sólo trabaja en producción (`sandbox_not_available`)"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe o es de otra persona (`assistant_conversation_not_found`)"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Conversación llena (`assistant_conversation_full`) u otra respuesta en curso (`assistant_busy`, con `Retry-After`)"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Mensaje vacío o demasiado largo (`assistant_message_invalid`)"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Mensajes por minuto de la persona (`assistant_rate_limited`, con `Retry-After`) o tope del mes de la empresa (`limit_reached`)"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El asistente no está en esta instalación (`assistant_unavailable`) o tiene demasiadas respuestas en curso (`assistant_overloaded`, con `Retry-After`)"}},"security":[{"bearerAuth":[]}],"summary":"Envía un mensaje al asistente","tags":["asistente"],"x-error-codes":["account_suspended","assistant_busy","assistant_conversation_full","assistant_conversation_not_found","assistant_message_invalid","assistant_overloaded","assistant_rate_limited","assistant_unavailable","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","limit_reached","overloaded","payload_too_large","restore_pending","sandbox_not_available","session_required","unauthorized","unsupported_media_type","view_only","view_session_invalid"],"x-surface":"portal"}},"/v1/assistant/conversations/{id}/reports/{report_id}/download":{"get":{"description":"Un reporte que el asistente mostró en una tabla con más filas de las que se ven (`download.path` de su tarjeta), entero: la API lo vuelve a generar con los mismos parámetros (`parameters`), sin pasar por el modelo, y lo envía a medida que lo genera. En el formato de todos los CSV de la plataforma, para una planilla de Uruguay (docs/API.md, \"Formato de los CSV\"): UTF-8 con BOM, `;` entre celdas, fechas `20/10/2026`, meses `10/2026` e importes con coma decimal y sin separador de miles; los totales van al final. Hasta 100.000 filas (la tarjeta avisa si el reporte tiene más) y 30 segundos; una descarga por vez por persona y 6 por minuto. Sólo la persona de la conversación, en Producción, con los meses que hoy deja consultar la membresía. Un reporte cortado a la mitad termina el cuerpo con un error, nunca como un archivo completo.","parameters":[{"description":"La conversación","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"El reporte (`download.report_id` de la tarjeta)","in":"path","name":"report_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"text/csv":{"schema":{"type":"string"}}},"description":"El reporte en CSV, con `Content-Disposition: attachment` y su nombre (`ventas-2026-10-01-al-2026-10-22.csv`)"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sin sesión de una persona de la empresa (`session_required`, `forbidden`), sin permiso para leer comprobantes (`forbidden`), desde \"ver como el cliente\" (`view_only`), con la cuenta suspendida (`account_suspended`) o en Pruebas (`sandbox_not_available`)"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El reporte no existe, es de otra conversación o de otra persona (`assistant_report_not_found`)"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Ya hay una descarga de la persona en curso (`assistant_report_busy`, con `Retry-After`)"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El reporte no se pudo generar en el tiempo máximo (`assistant_report_too_large`): se pide uno más corto o con un filtro"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Más de 6 descargas en el minuto (`assistant_report_rate_limited`, con `limit` y `Retry-After`)","headers":{"Retry-After":{"schema":{"type":"integer"}}}},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La réplica tiene todas sus descargas en curso (`assistant_overloaded`, `Retry-After: 5`) o la base de datos no responde"}},"security":[{"bearerAuth":[]}],"summary":"Descarga un reporte del asistente en CSV","tags":["asistente"],"x-error-codes":["account_suspended","assistant_overloaded","assistant_report_busy","assistant_report_not_found","assistant_report_rate_limited","assistant_report_too_large","bad_request","database_unavailable","forbidden","internal_error","invalid_body","invalid_environment","overloaded","restore_pending","sandbox_not_available","session_required","unauthorized","view_only","view_session_invalid"],"x-surface":"portal"}},"/v1/assistant/conversations/{id}/stop":{"post":{"description":"Pide que termine la respuesta que el asistente está preparando en esta conversación, en el nodo en que corra. Termina en su próximo paso (antes de la próxima consulta al modelo o de la próxima herramienta): el flujo de `POST .../messages` cierra con `done` `{outcome: stopped}`, lo que ya mostró queda en la conversación (las órdenes que preparó, también) y nunca se vuelve a enviar al modelo. `202` si había una en curso; `204` si no había ninguna.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"202":{"description":"Se pidió detenerla"},"204":{"description":"No había ninguna en curso"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sin sesión de una persona de la empresa (`session_required`, `forbidden`), desde \"ver como el cliente\" (`view_only`), con la cuenta suspendida (`account_suspended`) o en Pruebas (`sandbox_not_available`)"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe o es de otra persona (`assistant_conversation_not_found`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Detiene la respuesta en curso","tags":["asistente"],"x-error-codes":["account_suspended","assistant_conversation_not_found","bad_request","database_unavailable","forbidden","internal_error","invalid_body","invalid_environment","overloaded","restore_pending","sandbox_not_available","session_required","unauthorized","view_only","view_session_invalid"],"x-surface":"portal"}},"/v1/auth/invitation":{"post":{"description":"Sirve también para el enlace de una invitación al equipo (`POST /v1/users`): crea el usuario con esa contraseña. Si el correo ya tiene un usuario en la plataforma, `409 email_unavailable` (sólo lo sabe quien tiene el enlace, dueño de esa dirección); si la membresía no admite más usuarios, `409 limit_reached`.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationAcceptRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationAccepted"}}},"description":"Lista"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El correo ya tiene un usuario (`email_unavailable`) o la membresía no admite más usuarios (`limit_reached`)"},"410":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El enlace no existe, ya se usó, venció o lo reemplazó otro (`invitation_invalid`)"},"422":{"$ref":"#/components/responses/Unprocessable"}},"security":[],"summary":"Usa el enlace de una invitación o de un restablecimiento: elige la contraseña (una vez)","tags":["autenticación"],"x-error-codes":["email_unavailable","internal_error","invalid_body","invalid_cfe","invalid_environment","invitation_invalid","limit_reached","overloaded","payload_too_large","session_required","unauthorized","unsupported_media_type"],"x-surface":"portal"}},"/v1/auth/login":{"post":{"description":"La respuesta trae el access token (Bearer, 15 min) y setea `cfe_refresh` HttpOnly. Un fallo de credenciales responde 401 `invalid_credentials` sin revelar si el email existe. Limitado por dirección y por email (intentos por minuto): al superarlo responde `429 rate_limited` con `Retry-After`.","requestBody":{"content":{"application/json":{"schema":{"properties":{"email":{"format":"email","type":"string"},"password":{"minLength":12,"type":"string"}},"required":["email","password"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}},"description":"Sesión"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Credenciales inválidas"},"403":{"$ref":"#/components/responses/SessionRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[],"summary":"Inicia sesión y emite un access token + cookie de refresh","tags":["autenticación"],"x-error-codes":["database_unavailable","internal_error","invalid_body","invalid_credentials","invalid_environment","overloaded","payload_too_large","rate_limited","restore_pending","session_required","unauthorized","unsupported_media_type"],"x-surface":"portal"}},"/v1/auth/logout":{"post":{"responses":{"204":{"description":"Sesión cerrada"},"403":{"$ref":"#/components/responses/SessionRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[],"summary":"Cierra la sesión y limpia la cookie","tags":["autenticación"],"x-error-codes":["database_unavailable","internal_error","invalid_environment","overloaded","restore_pending","session_required","unauthorized"],"x-surface":"portal"}},"/v1/auth/me":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}},"description":"Sesión"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sin sesión"},"403":{"$ref":"#/components/responses/SessionRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Usuario, tenant y permisos de la sesión","tags":["autenticación"],"x-error-codes":["database_unavailable","internal_error","invalid_environment","overloaded","restore_pending","session_required","unauthorized"],"x-surface":"portal"}},"/v1/auth/password":{"post":{"requestBody":{"content":{"application/json":{"schema":{"properties":{"current_password":{"type":"string"},"new_password":{"minLength":12,"type":"string"}},"required":["current_password","new_password"],"type":"object"}}},"required":true},"responses":{"204":{"description":"Contraseña cambiada"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Credenciales inválidas"},"403":{"$ref":"#/components/responses/SessionRequired"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Contraseña demasiado corta"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Cambia la contraseña y revoca las otras sesiones","tags":["autenticación"],"x-error-codes":["database_unavailable","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","restore_pending","session_required","unauthorized","unsupported_media_type","view_only"],"x-surface":"portal"}},"/v1/auth/refresh":{"post":{"description":"Usa la cookie HttpOnly. El token presentado se revoca: reusar uno viejo devuelve 401 `session_expired`.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}},"description":"Sesión"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sesión vencida o revocada"},"403":{"$ref":"#/components/responses/SessionRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[],"summary":"Rota el refresh token y emite un access token nuevo","tags":["autenticación"],"x-error-codes":["database_unavailable","internal_error","invalid_environment","overloaded","restore_pending","session_expired","session_required","unauthorized"],"x-surface":"portal"}},"/v1/cae-ranges":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/CaeRange"},"type":"array"}}},"description":"Rangos con disponibilidad"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Rangos de CAE del tenant","tags":["numeración"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"post":{"description":"Idempotente. Nunca rebobina números ya consumidos: volver a declarar un CAE lo extiende. Solo OWNER (o clave de API). Un rango nuevo lleva serie de `A` a `ZZ` y, con `authorized_on`, un vencimiento de a lo sumo `FA` + 24 meses (uno anterior, con `special_expiry`): si no, `422` con el campo (`Serie`, `FVD`). Un `expires_on` ya vencido también es `422` (`invalid_cfe`, campo `FchVenc`), como el archivo vencido por `POST /v1/cae-ranges/xml` (campo `FVD`).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaeRangeRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaeRange"}}},"description":"Rango cargado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"El rol no alcanza (`forbidden`): la operación es solo para OWNER También `feature_disabled` (la configuración del cliente lo apaga)."},"422":{"$ref":"#/components/responses/Unprocessable"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Carga o extiende un rango de CAE","tags":["numeración"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","limit_reached","overloaded","payload_too_large","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"settings","x-surface":"client"}},"/v1/cae-ranges/xml":{"post":{"description":"El cuerpo es el XML del CAE tal como lo entrega DGI. Antes de guardar nada se verifica la firma (con el certificado de DGI si está configurado), que `RucE` sea el del tenant (E09), que `TA` sea E, que `FA` no sea futura y que `FVD` no esté vencida ni pase de 24 meses (E07). Guarda el CAE especial (`CAEEspecial`, `CausalCAEEsp`), `RucE`, `FA` y el archivo. Idempotente como `POST /v1/cae-ranges`. Solo OWNER (o clave de API).","requestBody":{"content":{"application/xml":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaeRange"}}},"description":"Rango cargado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"El rol no alcanza (`forbidden`): la operación es solo para OWNER También `feature_disabled` (la configuración del cliente lo apaga)."},"422":{"$ref":"#/components/responses/Unprocessable"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Carga el archivo de CAE firmado por DGI","tags":["numeración"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","overloaded","payload_too_large","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"settings","x-surface":"client"}},"/v1/catalog/cfe-types":{"get":{"description":"Para cada tipo (y su variante de contingencia), cada campo del JSON de `POST /v1/invoices` por su ruta (`lines[].quantity`): si es obligatorio, optativo o no va (`presence`), su largo, sus enteros y decimales, sus valores, su tope de filas, sus fechas y las condiciones que lo cambian (`conditions`). Se genera preguntándole al mismo validador que corre la emisión, así que un campo obligatorio acá es uno sin el que la emisión se rechaza. `tenant: fills`: la API lo completa desde el perfil del emisor; `tenant: must_match`: tiene que ser el del emisor.","parameters":[{"description":"Sólo ese tipo.","in":"query","name":"code","schema":{"type":"integer"}},{"description":"`es` (por defecto) o `en`: el idioma de las etiquetas.","in":"header","name":"Accept-Language","schema":{"type":"string"}},{"description":"El `ETag` de una respuesta anterior: `304` si no cambió.","in":"header","name":"If-None-Match","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CatalogCfeTypes"}}},"description":"Catálogo","headers":{"Cache-Control":{"description":"`private, no-cache`: revalide en cada uso con `If-None-Match` (un `304` mientras no cambie), así un cambio de la configuración del cliente se ve en la petición siguiente. `Vary: Accept-Language, Authorization, X-API-Key, X-CFE-View-As, Cfe-Environment`.","schema":{"type":"string"}},"ETag":{"description":"Hash del cuerpo, versionado con la API y el servicio (`\"v1-…\"`). Envíelo en `If-None-Match` para revalidar.","schema":{"type":"string"}}}},"304":{"description":"Lo que el cliente ya tiene (`If-None-Match`)","headers":{"Cache-Control":{"description":"`private, no-cache`: revalide en cada uso con `If-None-Match` (un `304` mientras no cambie), así un cambio de la configuración del cliente se ve en la petición siguiente. `Vary: Accept-Language, Authorization, X-API-Key, X-CFE-View-As, Cfe-Environment`.","schema":{"type":"string"}},"ETag":{"description":"Hash del cuerpo, versionado con la API y el servicio (`\"v1-…\"`). Envíelo en `If-None-Match` para revalidar.","schema":{"type":"string"}}}},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sin credenciales"},"403":{"$ref":"#/components/responses/ScopeRequired"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`code` no es un tipo de CFE"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]},{"apiKey":[]}],"summary":"Reglas de cada tipo de CFE","tags":["catálogo"],"x-error-codes":["account_suspended","code","database_unavailable","feature_disabled","forbidden","internal_error","invalid_cfe","invalid_environment","invalid_sandbox_outcome","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/catalog/codes":{"get":{"description":"Los códigos que toma el JSON de entrada, con su valor y su nombre: indicadores de facturación, tipos de documento (con sus países, su largo y su dígito verificador), países y monedas de la DGI, tipos de código de ítem, la Tabla C de retenciones, modalidades de venta, vías de transporte, tipos de traslado, CAE especial y los demás.","parameters":[{"description":"`es` (por defecto) o `en`: el idioma de las etiquetas.","in":"header","name":"Accept-Language","schema":{"type":"string"}},{"description":"El `ETag` de una respuesta anterior: `304` si no cambió.","in":"header","name":"If-None-Match","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CatalogCodes"}}},"description":"Catálogo","headers":{"Cache-Control":{"description":"`private, no-cache`: revalide en cada uso con `If-None-Match` (un `304` mientras no cambie), así un cambio de la configuración del cliente se ve en la petición siguiente. `Vary: Accept-Language, Authorization, X-API-Key, X-CFE-View-As, Cfe-Environment`.","schema":{"type":"string"}},"ETag":{"description":"Hash del cuerpo, versionado con la API y el servicio (`\"v1-…\"`). Envíelo en `If-None-Match` para revalidar.","schema":{"type":"string"}}}},"304":{"description":"Lo que el cliente ya tiene (`If-None-Match`)","headers":{"Cache-Control":{"description":"`private, no-cache`: revalide en cada uso con `If-None-Match` (un `304` mientras no cambie), así un cambio de la configuración del cliente se ve en la petición siguiente. `Vary: Accept-Language, Authorization, X-API-Key, X-CFE-View-As, Cfe-Environment`.","schema":{"type":"string"}},"ETag":{"description":"Hash del cuerpo, versionado con la API y el servicio (`\"v1-…\"`). Envíelo en `If-None-Match` para revalidar.","schema":{"type":"string"}}}},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sin credenciales"},"403":{"$ref":"#/components/responses/ScopeRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]},{"apiKey":[]}],"summary":"Tablas de códigos","tags":["catálogo"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","invalid_sandbox_outcome","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/catalog/vat-rates":{"get":{"description":"Lo que paga cada indicador de facturación en la fecha (sección 4-B del formato): la tasa básica y la mínima vigentes y a qué total va cada indicador.","parameters":[{"description":"Por defecto, hoy en Uruguay.","in":"query","name":"date","schema":{"format":"date","type":"string"}},{"description":"`es` (por defecto) o `en`: el idioma de las etiquetas.","in":"header","name":"Accept-Language","schema":{"type":"string"}},{"description":"El `ETag` de una respuesta anterior: `304` si no cambió.","in":"header","name":"If-None-Match","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VatRateTable"}}},"description":"Catálogo","headers":{"Cache-Control":{"description":"`private, no-cache`: revalide en cada uso con `If-None-Match` (un `304` mientras no cambie), así un cambio de la configuración del cliente se ve en la petición siguiente. `Vary: Accept-Language, Authorization, X-API-Key, X-CFE-View-As, Cfe-Environment`.","schema":{"type":"string"}},"ETag":{"description":"Hash del cuerpo, versionado con la API y el servicio (`\"v1-…\"`). Envíelo en `If-None-Match` para revalidar.","schema":{"type":"string"}}}},"304":{"description":"Lo que el cliente ya tiene (`If-None-Match`)","headers":{"Cache-Control":{"description":"`private, no-cache`: revalide en cada uso con `If-None-Match` (un `304` mientras no cambie), así un cambio de la configuración del cliente se ve en la petición siguiente. `Vary: Accept-Language, Authorization, X-API-Key, X-CFE-View-As, Cfe-Environment`.","schema":{"type":"string"}},"ETag":{"description":"Hash del cuerpo, versionado con la API y el servicio (`\"v1-…\"`). Envíelo en `If-None-Match` para revalidar.","schema":{"type":"string"}}}},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sin credenciales"},"403":{"$ref":"#/components/responses/ScopeRequired"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Fecha inválida o anterior al régimen (`field`: `date`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]},{"apiKey":[]}],"summary":"Tasas de IVA de una fecha","tags":["catálogo"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_cfe","invalid_environment","invalid_sandbox_outcome","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/contingency-annulments":{"post":{"description":"Un papel nunca cargado (roto, perdido) o uno que la DGI observó. No uno que la DGI todavía no respondió (`409 paper_in_flight`) ni uno que recibió (`409 paper_received`: es válido, se corrige con nota de crédito). No va nada a la DGI: el reporte diario no informa CFC anulados (Formato Reporte v13.2, C28). Idempotente. Solo OWNER (o clave de API).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContingencyAnnulmentRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContingencyDocument"}}},"description":"Ya estaba anulado"},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContingencyDocument"}}},"description":"Papel anulado"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Falta el motivo o supera 500 caracteres"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`paper_in_flight`, `paper_received`"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_cfe` (`field` = `TipoCFE` si no es 2xx; `NroCFE` si ningún rango lo incluye)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Anula un papel de contingencia","tags":["numeración"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","overloaded","paper_received","payload_too_large","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"emit","x-surface":"client"}},"/v1/contingency-documents":{"get":{"parameters":[{"in":"query","name":"cfe_type","schema":{"type":"integer"}},{"in":"query","name":"status","schema":{"enum":["PENDING","RECEIVED","OBSERVED","REJECTED","ANNULLED"],"type":"string"}},{"in":"query","name":"limit","schema":{"default":100,"maximum":500,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"count":{"type":"integer"},"documents":{"items":{"$ref":"#/components/schemas/ContingencyDocument"},"type":"array"}},"type":"object"}}},"description":"Por tipo, serie y número"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Papeles de contingencia","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"post":{"description":"Formato Sobre v05, p. 4: los CFC se envían a la DGI \"posteriormente a la entrega del documento al cliente, cuando se haya solucionado la contingencia\" y \"no debe enviarlo al receptor. El comprobante valido fiscalmente es el documento papel\".\n\nEl número tiene que estar en un rango de contingencia (constancia del tipo 2xx) de la serie, vigente en la fecha del papel (la DGI no observa un CFC por la fecha de firma: no hay C07, MR p. 18 y 24), y no estar usado. Se firma ahora con esa fecha y sale en el próximo sobre a la DGI; nunca al receptor. Un rango con papeles cargados no se numera en línea. Idempotente por número.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContingencyLoadRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContingencyLoaded"}}},"description":"Papel cargado, con su emisión"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required`: la clave de API no tiene el permiso (`x-scope`) de la ruta. `errors[0].params` trae `required` (el que pide) y `granted` (los que tiene). También `forbidden` si el rol de la sesión no alcanza. También `feature_disabled` (la configuración del cliente lo apaga)."},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`number_taken`: el número ya está usado; `idempotency_key_reused`: otro cuerpo para un número ya cargado"},"413":{"$ref":"#/components/responses/EmissionTooLarge"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_cfe` (`field` = `TipoCFE` si no es 2xx, `FchEmis` sin fecha o con fecha futura); `no_range_for_number`; `cae_expired_for_number`; un documento que no valida trae `errors[]`, con las rutas bajo `invoice` (`invoice.lines[0].unit_price`), y `number`/`series` del papel con la suya"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Carga un comprobante de contingencia (CFC) emitido en papel","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","database_unavailable","external_id_taken","feature_disabled","forbidden","idempotency_key_reused","internal_error","invalid_body","invalid_cfe","invalid_environment","invalid_external_id","no_range_for_number","overloaded","payload_too_large","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"emit","x-surface":"client"}},"/v1/contingency-documents/{id}":{"get":{"parameters":[{"description":"Id del papel de contingencia","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContingencyDocument"}}},"description":"El papel"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Un papel de contingencia","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/contingency-documents/{id}/correction":{"post":{"description":"MR p. 9: los CFC \"no se rechazan, sino que se devuelven observados para su corrección, debiendo el emisor volver a informarlo corregido, salvo que el comprobante papel sea anulado\". El cuerpo es el documento corregido; sin `issue_date` conserva la fecha del papel. Mismo número; el observado queda reemplazado (fuera de C30) y el corregido sale en el próximo sobre. Si la DGI observó la constancia (C03, C13) el corregido sale de otro rango que incluya el número. Idempotente. Llega el webhook `contingency.correction_required` cuando la DGI observa un CFC.\n\nEl binario de la adenda (zona J-C2) del comprobante reemplazado va también con el nuevo si el cuerpo no trae `adenda_attachment`; con otro, va ese, y con `\"adenda_attachment\": null`, ninguno.","parameters":[{"description":"Id del papel de contingencia","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContingencyLoaded"}}},"description":"Corregido, con su emisión"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required`: la clave de API no tiene el permiso (`x-scope`) de la ruta. `errors[0].params` trae `required` (el que pide) y `granted` (los que tiene). También `forbidden` si el rol de la sesión no alcanza. También `feature_disabled` (la configuración del cliente lo apaga)."},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`not_observed`: la DGI no lo observó; `paper_annulled`: el papel está anulado; `idempotency_key_reused`"},"413":{"$ref":"#/components/responses/EmissionTooLarge"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_cfe`; `cae_does_not_authorize`; `cae_expired_for_number`; un documento que no valida trae `errors[]` con la ruta JSON de cada error"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Informa de nuevo corregido un CFC observado (CE)","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","cae_does_not_authorize","database_unavailable","external_id_taken","feature_disabled","forbidden","idempotency_key_reused","internal_error","invalid_body","invalid_cfe","invalid_environment","invalid_external_id","not_found","not_observed","overloaded","paper_annulled","payload_too_large","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"emit","x-surface":"client"}},"/v1/contingency-ranges":{"get":{"description":"Por rango de contingencia, los números por debajo del más alto registrado que no están cargados ni anulados: el emisor los carga o los anula. El reporte diario no informa números de CFC (Formato Reporte v13.2, C41-C46: \"No se incluyen los CFC\").","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"ranges":{"items":{"$ref":"#/components/schemas/ContingencyRange"},"type":"array"}},"type":"object"}}},"description":"Rangos"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Rangos de contingencia y sus huecos","tags":["numeración"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/counterparty-certificates":{"get":{"parameters":[{"in":"query","name":"source","required":false,"schema":{"enum":["RECEPTION","ANSWER"],"type":"string"}},{"in":"query","name":"trust","required":false,"schema":{"enum":["VALID","UNTRUSTED","REVOKED"],"type":"string"}},{"in":"query","name":"limit","required":false,"schema":{"default":200,"maximum":1000,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/CounterpartyCertificateEntry"},"type":"array"}}},"description":"Un elemento por sobre o respuesta"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"422":{"$ref":"#/components/responses/Unprocessable"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]},{"apiKey":[]}],"summary":"Certificados de las otras empresas: cadena y revocación de los sobres recibidos y de las respuestas, los más recientes primero","tags":["intercambio"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_cfe","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/dgi-exchanges/{id}":{"get":{"description":"Lo mismo que ve la consola, sin el token.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DgiExchangeDetail"}}},"description":"La llamada","headers":{"Cache-Control":{"description":"`private, no-store`","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/SessionRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Una llamada a la DGI del tenant, lo enviado y lo recibido lado a lado (solo sesión)","tags":["entrega"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","internal_error","invalid_environment","not_found","overloaded","restore_pending","session_required","unauthorized"],"x-surface":"portal"}},"/v1/dgi-exchanges/{id}/request":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"text/xml":{"schema":{"type":"string"}}},"description":"El mensaje SOAP enviado","headers":{"Cache-Control":{"description":"`private, no-store`","schema":{"type":"string"}},"Content-Disposition":{"description":"`attachment; filename=\"dgi-exchange-{id}-request.xml\"` (o `-response`)","schema":{"type":"string"}},"x-xml-sha256":{"description":"SHA-256 del cuerpo, tal como viajó","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/SessionRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Lo que se envió a la DGI, byte por byte (solo sesión)","tags":["entrega"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","internal_error","invalid_environment","not_found","overloaded","restore_pending","session_required","unauthorized"],"x-surface":"portal"}},"/v1/dgi-exchanges/{id}/response":{"get":{"description":"`404` también cuando no volvió nada.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"text/xml":{"schema":{"type":"string"}}},"description":"La respuesta de la DGI","headers":{"Cache-Control":{"description":"`private, no-store`","schema":{"type":"string"}},"Content-Disposition":{"description":"`attachment; filename=\"dgi-exchange-{id}-request.xml\"` (o `-response`)","schema":{"type":"string"}},"x-xml-sha256":{"description":"SHA-256 del cuerpo, tal como viajó","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/SessionRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Lo que respondió la DGI, byte por byte (solo sesión)","tags":["entrega"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","internal_error","invalid_environment","not_found","overloaded","restore_pending","session_required","unauthorized"],"x-surface":"portal"}},"/v1/emissions":{"get":{"description":"Las más nuevas primero: fecha de emisión, tipo, serie y número, todo descendente. Para paginar, envíe en `after` el `next_cursor` de la página anterior: cuesta lo mismo a cualquier profundidad y no se corre cuando entran emisiones nuevas. `offset` sigue funcionando pero está deprecado. `total` cuenta hasta 10.000 coincidencias; si hay más, vale 10.000 y `total_capped` es `true`. Cada solicitud cuenta como 3 en el límite por minuto del plan.","parameters":[{"in":"query","name":"date","schema":{"format":"date","type":"string"}},{"description":"Estado de entrega, sin importar mayúsculas. Vacío es sin filtro; otro valor responde 400.","in":"query","name":"status","schema":{"enum":["PENDING","ACCEPTED","REJECTED","CANCELLED"],"type":"string"}},{"in":"query","name":"cfe_type","schema":{"type":"integer"}},{"in":"query","name":"limit","schema":{"default":50,"maximum":200,"type":"integer"}},{"description":"El `next_cursor` de la página anterior, tal cual. Opaco: no se arma a mano.","in":"query","name":"after","schema":{"type":"string"}},{"deprecated":true,"description":"Deprecado: usá `after`. No se combina con `after`.","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"El número de pedido de la tienda: la emisión que lo tiene (a lo sumo una). Vacío es sin filtro.","in":"query","name":"external_id","schema":{"maxLength":128,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceList"}}},"description":"Página de emisiones"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Emisiones con filtros y paginación","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","invalid_sandbox_outcome","overloaded","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/envelopes":{"post":{"description":"Reintenta primero los sobres que nunca salieron, y tras enviar intenta reconciliar la respuesta. Un fallo ambiguo no se reenvía: queda para reconciliación. Toma uno de los lugares hacia la DGI del despliegue y sus tokens (el ritmo global que comparten los workers).","requestBody":{"content":{"application/json":{"schema":{"properties":{"invoice_ids":{"description":"Si se omite, envía todo lo pendiente","items":{"format":"uuid","type":"string"},"type":"array"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Delivery"}}},"description":"Resultado del envío"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Delivery"}}},"description":"La DGI todavía no contestó dentro de lo que la petición puede esperar (`CFE_REQUEST_TIMEOUT_SECONDS` menos 2 s): los sobres en camino, con `acknowledged: false`. El envío sigue en segundo plano y su resultado se registra igual; consúltelo en `GET /v1/submissions/{id}`"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No se envió nada. `delivery_busy`: otro emisor de sobres (el worker u otra solicitud) está enviando un sobre de este emisor y no terminó en 15 s; `delivery_waiting`: un sobre anterior espera su reenvío y uno nuevo llegaría a la DGI antes que él (el orden de `Idemisor` se respeta); `envelope_conflict`: otro emisor tomó estos comprobantes; `certificate_missing` / `certificate_expired`: el emisor no tiene con qué firmar el sobre."},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`dgi_busy`: todos los sobres que la DGI acepta a la vez están en vuelo (el ritmo es uno solo para los workers y la API, `CFE_DGI_ENVELOPES_IN_FLIGHT`); el worker envía estos comprobantes sin intervención, o vuelva a intentarlo después de `Retry-After`. `certificate_unavailable`: la clave del certificado del emisor no se puede abrir ahora (vault). Vuelva a intentarlo después de `Retry-After` segundos. `database_unavailable`: la base no contesta por un momento (failover); `restore_pending`: numeración detenida después de un restore. Siempre con `Retry-After`.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"summary":"Envía los CFE pendientes en un sobre","tags":["entrega"],"x-error-codes":["account_suspended","certificate_expired","certificate_missing","certificate_unavailable","database_unavailable","delivery_busy","delivery_waiting","dgi_busy","envelope_conflict","feature_disabled","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","overloaded","payload_too_large","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"emit","x-surface":"client"}},"/v1/events":{"get":{"description":"Los mismos eventos que entregan los webhooks, con el mismo `payload`, haya webhook configurado o no. En el orden en que se confirmaron: un evento que se confirma después de otro ya leído nunca queda atrás del cursor (una transacción abierta demora el feed mientras dura, no pierde eventos). Se guardan 30 días (`retention_days`), los mismos que el outbox guarda una entrega: un conector parado tanto como puede estarlo un webhook encuentra lo que se perdió. Un cursor más viejo que eso es `410 cursor_expired`: concilie con `GET /v1/invoices` y comience uno nuevo sin `since`. Cuenta como 3 en el límite por minuto.","parameters":[{"description":"El `next_cursor` de la página anterior, tal cual; sin él, desde el evento más viejo que se guarda","in":"query","name":"since","schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"default":100,"maximum":500,"minimum":1,"type":"integer"}},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventsPage"}}},"description":"Una página del feed"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`bad_request`: `since` no es un cursor del feed"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"410":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`cursor_expired`: el cursor es más viejo que la retención (`retention_days`); pueden faltar eventos"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Los eventos de los webhooks, como feed con cursor","tags":["cuenta"],"x-error-codes":["account_suspended","bad_request","cursor_expired","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","invalid_sandbox_outcome","overloaded","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/exchange/addresses":{"delete":{"parameters":[{"in":"query","name":"ruc","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Borrada"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Olvida la dirección de una empresa (solo OWNER)","tags":["intercambio"],"x-error-codes":["account_suspended","bad_request","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"emit","x-surface":"client"},"get":{"parameters":[{"description":"Sólo las aprendidas de un correo que todavía no se confirmaron","in":"query","name":"unconfirmed","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ExchangeAddress"},"type":"array"}}},"description":"Direcciones"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"}},"summary":"Direcciones de intercambio que conoce el tenant","tags":["intercambio"],"x-error-codes":["account_suspended","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"put":{"description":"Gana sobre la publicada por la DGI y sobre la aprendida de un correo recibido, confirmada o no.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeAddressRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeAddress"}}},"description":"Guardada"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"RUC o dirección inválidos"}},"summary":"Fija la dirección de intercambio de una empresa (solo OWNER)","tags":["intercambio"],"x-error-codes":["account_suspended","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"emit","x-surface":"client"}},"/v1/exchange/addresses/confirm":{"post":{"description":"Una dirección `INBOUND` confirmada vale como la del tenant: gana sobre la del directorio de la DGI. El cuerpo repite la dirección revisada.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeAddressConfirm"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeAddress"}}},"description":"Confirmada"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`address_changed` (la dirección ya no es esa) o `address_not_learned` (la cargó el tenant)"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"RUC o dirección inválidos"}},"summary":"Confirma una dirección aprendida de un correo (solo OWNER)","tags":["intercambio"],"x-error-codes":["account_suspended","address_changed","address_not_learned","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","not_found","overloaded","payload_too_large","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"emit","x-surface":"client"}},"/v1/exchange/discarded-envelopes":{"get":{"description":"No se respondieron y el archivo no se guardó: se conserva el hash, el remitente, el RUC que dice la carátula y los motivos, hasta `CFE_MAIL_DISCARD_RETENTION_DAYS`. Para recibirlo, pedir al emisor que lo reenvíe o subirlo con `POST /v1/received-envelopes`.","parameters":[{"in":"query","name":"limit","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/DiscardedEnvelope"},"type":"array"}}},"description":"Registros, el más reciente primero"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"}},"summary":"Sobres recibidos por correo que no prueban su emisor","tags":["intercambio"],"x-error-codes":["account_suspended","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/exchange/messages":{"get":{"parameters":[{"in":"query","name":"kind","required":false,"schema":{"type":"string"}},{"in":"query","name":"status","required":false,"schema":{"type":"string"}},{"in":"query","name":"recipient_ruc","required":false,"schema":{"type":"string"}},{"in":"query","name":"invoice_id","required":false,"schema":{"format":"uuid","type":"string"}},{"in":"query","name":"received_envelope_id","required":false,"schema":{"format":"uuid","type":"string"}},{"in":"query","name":"limit","required":false,"schema":{"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ExchangeMessage"},"type":"array"}}},"description":"Mensajes"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"}},"summary":"Mensajes a otras empresas, los más nuevos primero","tags":["intercambio"],"x-error-codes":["account_suspended","bad_request","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/exchange/messages/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeMessage"}}},"description":"Mensaje"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Un mensaje, con las respuestas que llegaron","tags":["intercambio"],"x-error-codes":["account_suspended","bad_request","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/exchange/messages/{id}/retry":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"email":{"description":"Otra dirección","format":"email","type":"string"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeMessage"}}},"description":"Encolado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`message_not_failed`"}},"summary":"Vuelve a encolar un mensaje FAILED, con los mismos bytes (solo OWNER)","tags":["intercambio"],"x-error-codes":["account_suspended","bad_request","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","message_not_failed","not_found","overloaded","payload_too_large","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"emit","x-surface":"client"}},"/v1/exchange/messages/{id}/xml":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/xml":{"schema":{"type":"string"}}},"description":"El XML","headers":{"content-disposition":{"description":"`attachment; filename=\"…\"`","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"El archivo tal como salió (o saldrá); 404 hasta el primer intento","tags":["intercambio"],"x-error-codes":["account_suspended","bad_request","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/exchange/settings":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeSettings"}}},"description":"Configuración"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"}},"summary":"Configuración del intercambio del tenant","tags":["intercambio"],"x-error-codes":["account_suspended","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"put":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeSettings"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeSettings"}}},"description":"Guardada"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"summary":"Activa o desactiva el envío automático al receptor (solo OWNER)","tags":["intercambio"],"x-error-codes":["account_suspended","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"settings","x-surface":"client"}},"/v1/inbound/email":{"post":{"description":"Ruta de la plataforma, autenticada con `CFE_MAIL_INBOUND_SECRET`. El cuerpo es el mensaje crudo (`message/rfc822`) o un `multipart/form-data` con el mensaje crudo en el campo `email` (SendGrid) o `body-mime` (Mailgun), hasta 12 MB. Cada XML adjunto va al tenant al que está dirigido por su carátula: un `EnvioCFE_entreEmpresas` se recibe como un upload (`channel` `EMAIL`) y sus dos respuestas se encolan sólo si el sobre prueba a su emisor (sus CFE verifican con un certificado que lleva el RUC de la carátula), a la dirección conocida de ese RUC o, sin ella, al remitente cuando el servidor de correo avala su `From` (`Authentication-Results` de `CFE_MAIL_AUTHSERV_ID`), con un límite diario por RUC y por dominio (`answers` dice qué pasó); un `ACKSobre`/`ACKCFE` se asocia al sobre nuestro que responde (`IDEmisor`); una `CFEs_Anulados_x_RechazoDGI` marca las copias. Todo es idempotente por contenido: `5xx` solo cuando conviene que el proveedor lo reintente.","parameters":[{"description":"El secreto, para proveedores que solo llaman a una URL","in":"query","name":"token","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"message/rfc822":{"schema":{"type":"string"}},"multipart/form-data":{"schema":{"properties":{"body-mime":{"type":"string"},"email":{"type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboundMailResult"}}},"description":"Resultado por archivo"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Más de 12 MB"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`inbound_mail_disabled`: falta `CFE_MAIL_INBOUND_SECRET`; `database_unavailable`"}},"security":[{"inboundSecret":[]}],"summary":"Correo de otra empresa, como lo entrega el proveedor de correo","tags":["intercambio"],"x-error-codes":["bad_request","database_unavailable","inbound_mail_disabled","internal_error","invalid_body","overloaded","payload_too_large","unauthorized","unsupported_media_type"],"x-surface":"public"}},"/v1/insights/catalog":{"get":{"description":"Cada informe con su título y su descripción en español, sus parámetros (con sus opciones y su valor por defecto), sus columnas con su tipo, el gráfico que lo dibuja y los límites. El portal, el CSV y el asistente leen este mismo catálogo.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightCatalog"}}},"description":"El catálogo"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La clave no tiene el permiso `read` (`scope_required`) o la configuración del cliente apaga los informes (`feature_disabled`, `feature: \"insights.enabled\"`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"El catálogo de informes","tags":["informes"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/insights/query":{"post":{"description":"Una página de un informe armado (`definition`): sus filas, `page` con el total (exacto si es agrupado o tiene hasta 10.000 filas; si no, «más de 10.000») y `next_cursor` si hay más. Agrupado, la página es por posición; una lista de filas, por clave si el orden lo permite (`page.kind`). Mismos límites que los informes del catálogo: el período más largo de su forma, 10 segundos por consulta y pocos informes a la vez por cuenta. Cuenta como una lista en el límite de pedidos.","parameters":[{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightQueryRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightBuiltAnswer"}}},"description":"La página"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La definición no vale (`insight_invalid_definition`): `errors[]` trae cada problema con su `path` (`definition.columns[2].field`), su `code` (`unknown_field`, `operator_not_applicable`, `mixed_currencies`...) y su explicación en español; o un período más largo que el de su forma (`insight_period_too_long`, con `max_days` y `suggested_groups`), o un cursor de otra consulta (`insight_invalid_cursor`)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La clave no tiene el permiso `read` (`scope_required`) o la configuración del cliente apaga los informes (`feature_disabled`, `feature: \"insights.enabled\"`)"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El informe tardó más de 10 segundos en calcularse (`insight_too_costly`): se acorta el período o se agrega un filtro"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Demasiados pedidos (`rate_limited`) o demasiados informes calculándose a la vez para la cuenta o para el servicio (`insight_busy`, con `scope` `tenant` o `replica`, `max` y `Retry-After`): se reintenta a los segundos que dice","headers":{"Retry-After":{"description":"Segundos a esperar","schema":{"type":"integer"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Corre un informe armado","tags":["informes"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","insight_busy","insight_invalid_cursor","insight_invalid_definition","insight_invalid_parameter","insight_period_too_long","insight_too_costly","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"read","x-surface":"client"}},"/v1/insights/query/csv":{"post":{"description":"Todas las filas de un informe armado: UTF-8 con BOM, `;` entre celdas, CRLF, fechas `24/10/2026`, meses `10/2026`, trimestres `T4/2026` e importes con coma decimal y sin separador de miles; la moneda va en el encabezado de cada importe. Se transmite mientras se lee, con todas las filas del pedido (sin páginas) hasta 200.000: con más, `400 insight_export_too_large` pide dividir el período. Un archivo cortado a la mitad termina con un error, nunca como si estuviera completo.","parameters":[{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightQueryCsvRequest"}}},"required":true},"responses":{"200":{"content":{"text/csv":{"schema":{"type":"string"}}},"description":"El CSV","headers":{"Content-Disposition":{"description":"`attachment` con el nombre del archivo","schema":{"type":"string"}},"X-Rows-Total":{"description":"Cuántas filas tiene el archivo","schema":{"type":"integer"}}}},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La definición no vale (`insight_invalid_definition`): `errors[]` trae cada problema con su `path` (`definition.columns[2].field`), su `code` (`unknown_field`, `operator_not_applicable`, `mixed_currencies`...) y su explicación en español; o un período más largo que el de su forma (`insight_period_too_long`, con `max_days` y `suggested_groups`), o un cursor de otra consulta (`insight_invalid_cursor`)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La clave no tiene el permiso `read` (`scope_required`) o la configuración del cliente apaga los informes (`feature_disabled`, `feature: \"insights.enabled\"`)"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El informe tardó más de 10 segundos en calcularse (`insight_too_costly`): se acorta el período o se agrega un filtro"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Demasiados pedidos (`rate_limited`) o demasiados informes calculándose a la vez para la cuenta o para el servicio (`insight_busy`, con `scope` `tenant` o `replica`, `max` y `Retry-After`): se reintenta a los segundos que dice","headers":{"Retry-After":{"description":"Segundos a esperar","schema":{"type":"integer"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Un informe armado en CSV","tags":["informes"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","insight_busy","insight_export_too_large","insight_invalid_cursor","insight_invalid_definition","insight_invalid_parameter","insight_period_too_long","insight_too_costly","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"read","x-surface":"client"}},"/v1/insights/saved":{"get":{"description":"Los informes propios que quien pregunta ve: los del equipo y los suyos privados, del más reciente al más antiguo (hasta 200 por cuenta).","parameters":[{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"count":{"type":"integer"},"max":{"type":"integer"},"saved":{"items":{"$ref":"#/components/schemas/InsightSaved"},"type":"array"}},"type":"object"}}},"description":"Los informes guardados"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La clave no tiene el permiso `read` (`scope_required`) o la configuración del cliente apaga los informes (`feature_disabled`, `feature: \"insights.enabled\"`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Los informes guardados","tags":["informes"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"post":{"description":"Guarda una definición con su nombre (una vez por cuenta), su descripción y si la ve el equipo (`shared`) o sólo quien la arma. La definición se valida como en `POST /v1/insights/query`; sus errores llevan el `path` desde `definition`.","parameters":[{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightSavedRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightSaved"}}},"description":"El informe guardado"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un nombre, una descripción o una definición que no valen (`insight_invalid_parameter`, `insight_invalid_definition` con `errors[]`)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La clave no tiene el permiso `settings` (`scope_required`), la configuración del cliente apaga los informes (`feature_disabled`) o el informe guardado lo armó otra persona y no es suyo cambiarlo (`insight_saved_forbidden`)"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Ya hay un informe con ese nombre (`insight_name_taken`) o la cuenta ya tiene 200 (`insight_saved_limit`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Guarda un informe armado","tags":["informes"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","insight_invalid_definition","insight_invalid_parameter","insight_name_taken","insight_saved_limit","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"settings","x-surface":"client"}},"/v1/insights/saved/{id}":{"delete":{"description":"Lo borra quien lo armó; uno del equipo, también quien administra la cuenta.","parameters":[{"description":"El `id` del informe guardado (`GET /v1/insights/saved`).","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"204":{"description":"Borrado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La clave no tiene el permiso `settings` (`scope_required`), la configuración del cliente apaga los informes (`feature_disabled`) o el informe guardado lo armó otra persona y no es suyo cambiarlo (`insight_saved_forbidden`)"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No hay un informe guardado con ese `id` que quien pregunta pueda ver (`insight_saved_not_found`): uno privado de otra persona o de otra cuenta responde lo mismo que uno que no existe"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Borra un informe guardado","tags":["informes"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","insight_saved_forbidden","insight_saved_not_found","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"settings","x-surface":"client"},"get":{"description":"El informe guardado con su definición, quién lo armó y si quien pregunta lo puede cambiar (`editable`).","parameters":[{"description":"El `id` del informe guardado (`GET /v1/insights/saved`).","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightSaved"}}},"description":"El informe guardado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La clave no tiene el permiso `read` (`scope_required`) o la configuración del cliente apaga los informes (`feature_disabled`, `feature: \"insights.enabled\"`)"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No hay un informe guardado con ese `id` que quien pregunta pueda ver (`insight_saved_not_found`): uno privado de otra persona o de otra cuenta responde lo mismo que uno que no existe"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Un informe guardado","tags":["informes"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","insight_saved_not_found","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"patch":{"description":"Cambia lo que venga de `name`, `description`, `definition` y `shared`. Lo cambia quien lo armó; uno del equipo, también quien administra la cuenta (que no lo hace privado).","parameters":[{"description":"El `id` del informe guardado (`GET /v1/insights/saved`).","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightSavedPatch"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightSaved"}}},"description":"El informe guardado"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un miembro que no vale (`insight_invalid_parameter`, `insight_invalid_definition`)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La clave no tiene el permiso `settings` (`scope_required`), la configuración del cliente apaga los informes (`feature_disabled`) o el informe guardado lo armó otra persona y no es suyo cambiarlo (`insight_saved_forbidden`)"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No hay un informe guardado con ese `id` que quien pregunta pueda ver (`insight_saved_not_found`): uno privado de otra persona o de otra cuenta responde lo mismo que uno que no existe"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Ya hay un informe con ese nombre (`insight_name_taken`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Cambia un informe guardado","tags":["informes"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","insight_invalid_definition","insight_invalid_parameter","insight_name_taken","insight_saved_forbidden","insight_saved_not_found","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"settings","x-surface":"client"}},"/v1/insights/saved/{id}/csv":{"get":{"description":"Todas las filas del informe guardado, con su período o el que se pida: UTF-8 con BOM, `;` entre celdas, CRLF, fechas `24/10/2026`, meses `10/2026`, trimestres `T4/2026` e importes con coma decimal y sin separador de miles; la moneda va en el encabezado de cada importe. Se transmite mientras se lee, con todas las filas del pedido (sin páginas) hasta 200.000: con más, `400 insight_export_too_large` pide dividir el período. Un archivo cortado a la mitad termina con un error, nunca como si estuviera completo.","parameters":[{"description":"El `id` del informe guardado (`GET /v1/insights/saved`).","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Otro período que el guardado, por su nombre","in":"query","name":"period","schema":{"enum":["today","yesterday","last_7_days","last_30_days","last_90_days","this_month","last_month","this_quarter","last_quarter","this_year","last_year","last_12_months","custom"],"type":"string"}},{"description":"Otro período: desde, con `to`","in":"query","name":"from","schema":{"format":"date","type":"string"}},{"description":"Otro período: hasta, con `from`","in":"query","name":"to","schema":{"format":"date","type":"string"}},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"text/csv":{"schema":{"type":"string"}}},"description":"El CSV","headers":{"Content-Disposition":{"description":"`attachment` con el nombre del archivo","schema":{"type":"string"}},"X-Rows-Total":{"description":"Cuántas filas tiene el archivo","schema":{"type":"integer"}}}},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La definición no vale (`insight_invalid_definition`): `errors[]` trae cada problema con su `path` (`definition.columns[2].field`), su `code` (`unknown_field`, `operator_not_applicable`, `mixed_currencies`...) y su explicación en español; o un período más largo que el de su forma (`insight_period_too_long`, con `max_days` y `suggested_groups`), o un cursor de otra consulta (`insight_invalid_cursor`)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La clave no tiene el permiso `read` (`scope_required`) o la configuración del cliente apaga los informes (`feature_disabled`, `feature: \"insights.enabled\"`)"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No hay un informe guardado con ese `id` que quien pregunta pueda ver (`insight_saved_not_found`): uno privado de otra persona o de otra cuenta responde lo mismo que uno que no existe"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El informe tardó más de 10 segundos en calcularse (`insight_too_costly`): se acorta el período o se agrega un filtro"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Demasiados pedidos (`rate_limited`) o demasiados informes calculándose a la vez para la cuenta o para el servicio (`insight_busy`, con `scope` `tenant` o `replica`, `max` y `Retry-After`): se reintenta a los segundos que dice","headers":{"Retry-After":{"description":"Segundos a esperar","schema":{"type":"integer"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Un informe guardado en CSV","tags":["informes"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","insight_busy","insight_export_too_large","insight_invalid_cursor","insight_invalid_definition","insight_invalid_parameter","insight_period_too_long","insight_saved_not_found","insight_too_costly","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"read","x-surface":"client"}},"/v1/insights/saved/{id}/run":{"get":{"description":"Una página del informe guardado, con su período o el que se pida; como `POST /v1/insights/query`, y `saved` con el informe.","parameters":[{"description":"El `id` del informe guardado (`GET /v1/insights/saved`).","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"description":"Otro período que el guardado, por su nombre","in":"query","name":"period","schema":{"enum":["today","yesterday","last_7_days","last_30_days","last_90_days","this_month","last_month","this_quarter","last_quarter","this_year","last_year","last_12_months","custom"],"type":"string"}},{"description":"Otro período: desde, con `to`","in":"query","name":"from","schema":{"format":"date","type":"string"}},{"description":"Otro período: hasta, con `from`","in":"query","name":"to","schema":{"format":"date","type":"string"}},{"description":"Las filas de la página: 50 si no se indica, hasta 500.","in":"query","name":"page_size","schema":{"default":50,"maximum":500,"minimum":1,"type":"integer"}},{"description":"El `page.next_cursor` de la página anterior, tal cual: opaco, sellado y atado a la cuenta y a la misma consulta (otro informe, otros parámetros u otra cuenta: `insight_invalid_cursor`).","in":"query","name":"cursor","schema":{"maxLength":2000,"type":"string"}},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightBuiltAnswer"}}},"description":"La página"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La definición no vale (`insight_invalid_definition`): `errors[]` trae cada problema con su `path` (`definition.columns[2].field`), su `code` (`unknown_field`, `operator_not_applicable`, `mixed_currencies`...) y su explicación en español; o un período más largo que el de su forma (`insight_period_too_long`, con `max_days` y `suggested_groups`), o un cursor de otra consulta (`insight_invalid_cursor`)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La clave no tiene el permiso `read` (`scope_required`) o la configuración del cliente apaga los informes (`feature_disabled`, `feature: \"insights.enabled\"`)"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No hay un informe guardado con ese `id` que quien pregunta pueda ver (`insight_saved_not_found`): uno privado de otra persona o de otra cuenta responde lo mismo que uno que no existe"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El informe tardó más de 10 segundos en calcularse (`insight_too_costly`): se acorta el período o se agrega un filtro"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Demasiados pedidos (`rate_limited`) o demasiados informes calculándose a la vez para la cuenta o para el servicio (`insight_busy`, con `scope` `tenant` o `replica`, `max` y `Retry-After`): se reintenta a los segundos que dice","headers":{"Retry-After":{"description":"Segundos a esperar","schema":{"type":"integer"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Corre un informe guardado","tags":["informes"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","insight_busy","insight_invalid_cursor","insight_invalid_definition","insight_invalid_parameter","insight_period_too_long","insight_saved_not_found","insight_too_costly","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"read","x-surface":"client"}},"/v1/insights/sources":{"get":{"description":"Lo que un informe propio puede leer: cada fuente (comprobantes emitidos, sus líneas, clientes, comprobantes recibidos) con sus campos (dimensión o medida, tipo, nombre en español, moneda, si se lee del pedido), los operadores y las funciones de cada uno, los agrupamientos de fechas y los límites. Es la misma lista que valida `POST /v1/insights/query`.","parameters":[{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightSources"}}},"description":"Las fuentes"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La clave no tiene el permiso `read` (`scope_required`) o la configuración del cliente apaga los informes (`feature_disabled`, `feature: \"insights.enabled\"`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Las fuentes del armador de informes","tags":["informes"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/insights/{insight}":{"get":{"description":"Una página del informe con los parámetros pedidos: sus filas (`page_size`, 50 si no se indica, hasta 500), `page` con dónde está (`first_row`, `last_row`), el total (`total`, exacto) y `next_cursor` si hay más; la cifra principal (`headline`) es del informe entero, sus columnas y su gráfico. Nunca se corta: las filas siguientes se piden con `cursor`. Sólo los datos del cliente; en el portal, desde el primer día que deja consultar la membresía (`meta.clipped`). Los importes van como texto con dos decimales. Cuenta como una lista en el límite de pedidos.","parameters":[{"description":"El `id` del informe en el catálogo (`GET /v1/insights/catalog`), como `sales_by_period` o `top_clients`.","in":"path","name":"insight","required":true,"schema":{"pattern":"^[a-z_]{1,40}$","type":"string"}},{"description":"El período por su nombre, en días de Uruguay; `custom` (o sólo `from` y `to`) toma las fechas. Sin él, el del informe (`parameters[].default`).","in":"query","name":"period","schema":{"enum":["today","yesterday","last_7_days","last_30_days","last_90_days","this_month","last_month","this_quarter","last_quarter","this_year","last_year","last_12_months","custom"],"type":"string"}},{"description":"Desde, `AAAA-MM-DD`, incluido. El período más largo depende de la forma del informe: agrupado por día 400 días, por semana 3 años, por mes, trimestre o año 10 años; lo que lee los receptores o las líneas, 3 años (`limits` del catálogo).","in":"query","name":"from","schema":{"format":"date","type":"string"}},{"description":"Hasta, `AAAA-MM-DD`, incluido.","in":"query","name":"to","schema":{"format":"date","type":"string"}},{"description":"Cómo se agrupan las filas, entre las opciones del informe (`day`, `week`, `month`, `quarter`, `year`, `weekday`, `hour`, `key`, `route`, `channel`, `event`).","in":"query","name":"group","schema":{"type":"string"}},{"description":"Sólo los comprobantes en esa moneda (código ISO). Sin ella, todo en pesos, cada comprobante a su tipo de cambio.","in":"query","name":"currency","schema":{"pattern":"^[A-Za-z]{3}$","type":"string"}},{"description":"Sólo un tipo de comprobante (101 e-Ticket, 111 e-Factura...).","in":"query","name":"cfe_type","schema":{"maximum":299,"minimum":101,"type":"integer"}},{"description":"Por qué se ordena un ranking, entre las opciones del informe (`amount`, `count`, `quantity`).","in":"query","name":"by","schema":{"type":"string"}},{"description":"Sólo las primeras filas de un ranking. Sin él, todas, en páginas.","in":"query","name":"limit","schema":{"maximum":10000,"minimum":1,"type":"integer"}},{"description":"El importe mínimo de un comprobante (`amount_ranges`).","in":"query","name":"min","schema":{"pattern":"^[0-9]+([.,][0-9]+)?$","type":"string"}},{"description":"El importe máximo de un comprobante (`amount_ranges`).","in":"query","name":"max","schema":{"pattern":"^[0-9]+([.,][0-9]+)?$","type":"string"}},{"description":"Las filas de la página: 50 si no se indica, hasta 500.","in":"query","name":"page_size","schema":{"default":50,"maximum":500,"minimum":1,"type":"integer"}},{"description":"El `page.next_cursor` de la página anterior, tal cual: opaco, sellado y atado a la cuenta y a la misma consulta (otro informe, otros parámetros u otra cuenta: `insight_invalid_cursor`).","in":"query","name":"cursor","schema":{"maxLength":2000,"type":"string"}},{"description":"`previous`: agrega `comparison`, el mismo informe en el período anterior de igual largo (sólo su cifra principal y las secundarias, sin filas). Corre después del informe, uno a la vez: nunca ocupa dos lugares del límite de informes simultáneos. Otro valor: `400 insight_invalid_parameter`.","in":"query","name":"compare","schema":{"enum":["previous"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightAnswer"}}},"description":"El informe"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un parámetro que el informe no toma o que no vale (`insight_invalid_parameter`, con `field`), un cursor que no es de esta consulta (`insight_invalid_cursor`), un período más largo que el del informe (`insight_period_too_long`, `field: \"from\"`, con `max_days`, `days` y `suggested_groups`: las agrupaciones que sí lo abarcan)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La clave no tiene el permiso `read` (`scope_required`) o la configuración del cliente apaga los informes (`feature_disabled`, `feature: \"insights.enabled\"`)"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No hay un informe con ese `id` (`insight_not_found`)"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El informe tardó más de 10 segundos en calcularse (`insight_too_costly`): se acorta el período o se filtra por moneda o tipo"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Demasiados pedidos (`rate_limited`) o demasiados informes calculándose a la vez para la cuenta o para el servicio (`insight_busy`, con `scope` `tenant` o `replica`, `max` y `Retry-After`): se reintenta a los segundos que dice","headers":{"Retry-After":{"description":"Segundos a esperar","schema":{"type":"integer"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Un informe","tags":["informes"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","insight_busy","insight_invalid_cursor","insight_invalid_parameter","insight_not_found","insight_period_too_long","insight_too_costly","internal_error","invalid_environment","overloaded","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/insights/{insight}/csv":{"get":{"description":"Todas las filas de `GET /v1/insights/{insight}` con los mismos parámetros (`meta.csv_path` es su enlace), para una planilla de Uruguay: UTF-8 con BOM, `;` entre celdas, CRLF, fechas `24/10/2026`, meses `10/2026`, trimestres `T4/2026` e importes con coma decimal y sin separador de miles; la moneda va en el encabezado de cada importe. Se transmite mientras se lee, con todas las filas del pedido (sin páginas) hasta 200.000: con más, `400 insight_export_too_large` pide dividir el período. Un archivo cortado a la mitad termina con un error, nunca como si estuviera completo.","parameters":[{"description":"El `id` del informe en el catálogo (`GET /v1/insights/catalog`), como `sales_by_period` o `top_clients`.","in":"path","name":"insight","required":true,"schema":{"pattern":"^[a-z_]{1,40}$","type":"string"}},{"description":"El período por su nombre, en días de Uruguay; `custom` (o sólo `from` y `to`) toma las fechas. Sin él, el del informe (`parameters[].default`).","in":"query","name":"period","schema":{"enum":["today","yesterday","last_7_days","last_30_days","last_90_days","this_month","last_month","this_quarter","last_quarter","this_year","last_year","last_12_months","custom"],"type":"string"}},{"description":"Desde, `AAAA-MM-DD`, incluido. El período más largo depende de la forma del informe: agrupado por día 400 días, por semana 3 años, por mes, trimestre o año 10 años; lo que lee los receptores o las líneas, 3 años (`limits` del catálogo).","in":"query","name":"from","schema":{"format":"date","type":"string"}},{"description":"Hasta, `AAAA-MM-DD`, incluido.","in":"query","name":"to","schema":{"format":"date","type":"string"}},{"description":"Cómo se agrupan las filas, entre las opciones del informe (`day`, `week`, `month`, `quarter`, `year`, `weekday`, `hour`, `key`, `route`, `channel`, `event`).","in":"query","name":"group","schema":{"type":"string"}},{"description":"Sólo los comprobantes en esa moneda (código ISO). Sin ella, todo en pesos, cada comprobante a su tipo de cambio.","in":"query","name":"currency","schema":{"pattern":"^[A-Za-z]{3}$","type":"string"}},{"description":"Sólo un tipo de comprobante (101 e-Ticket, 111 e-Factura...).","in":"query","name":"cfe_type","schema":{"maximum":299,"minimum":101,"type":"integer"}},{"description":"Por qué se ordena un ranking, entre las opciones del informe (`amount`, `count`, `quantity`).","in":"query","name":"by","schema":{"type":"string"}},{"description":"Sólo las primeras filas de un ranking. Sin él, todas, en páginas.","in":"query","name":"limit","schema":{"maximum":10000,"minimum":1,"type":"integer"}},{"description":"El importe mínimo de un comprobante (`amount_ranges`).","in":"query","name":"min","schema":{"pattern":"^[0-9]+([.,][0-9]+)?$","type":"string"}},{"description":"El importe máximo de un comprobante (`amount_ranges`).","in":"query","name":"max","schema":{"pattern":"^[0-9]+([.,][0-9]+)?$","type":"string"}}],"responses":{"200":{"content":{"text/csv":{"schema":{"type":"string"}}},"description":"El CSV","headers":{"Content-Disposition":{"description":"`attachment` con el nombre del archivo","schema":{"type":"string"}},"X-Rows-Total":{"description":"Cuántas filas tiene el archivo","schema":{"type":"integer"}}}},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un parámetro que el informe no toma o que no vale (`insight_invalid_parameter`, con `field`), un cursor que no es de esta consulta (`insight_invalid_cursor`), un período más largo que el del informe (`insight_period_too_long`, `field: \"from\"`, con `max_days`, `days` y `suggested_groups`: las agrupaciones que sí lo abarcan), o un CSV de más de 200.000 filas (`insight_export_too_large`, con `max_rows` y `rows`)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La clave no tiene el permiso `read` (`scope_required`) o la configuración del cliente apaga los informes (`feature_disabled`, `feature: \"insights.enabled\"`)"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No hay un informe con ese `id` (`insight_not_found`)"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El informe tardó más de 10 segundos en calcularse (`insight_too_costly`): se acorta el período o se filtra por moneda o tipo"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Demasiados pedidos (`rate_limited`) o demasiados informes calculándose a la vez para la cuenta o para el servicio (`insight_busy`, con `scope` `tenant` o `replica`, `max` y `Retry-After`): se reintenta a los segundos que dice","headers":{"Retry-After":{"description":"Segundos a esperar","schema":{"type":"integer"}}}},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Un informe en CSV","tags":["informes"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","insight_busy","insight_export_too_large","insight_invalid_cursor","insight_invalid_parameter","insight_not_found","insight_period_too_long","insight_too_costly","internal_error","invalid_environment","overloaded","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/insights/{insight}/duplicate":{"post":{"description":"Guarda como informe propio la definición del armador que responde el informe (con los parámetros de la consulta: período, agrupación, moneda, tipo), para cambiarle columnas, filtros y orden. Los informes que el armador no expresa (una comparación de dos períodos, una proyección, tramos de importes, la numeración, el uso de la plataforma) quedan predefinidos: `422 insight_not_editable` con el motivo (`reason`, también en `not_editable_reason` del catálogo).","parameters":[{"description":"El `id` del informe en el catálogo (`GET /v1/insights/catalog`), como `sales_by_period` o `top_clients`.","in":"path","name":"insight","required":true,"schema":{"pattern":"^[a-z_]{1,40}$","type":"string"}},{"description":"El período por su nombre, en días de Uruguay; `custom` (o sólo `from` y `to`) toma las fechas. Sin él, el del informe (`parameters[].default`).","in":"query","name":"period","schema":{"enum":["today","yesterday","last_7_days","last_30_days","last_90_days","this_month","last_month","this_quarter","last_quarter","this_year","last_year","last_12_months","custom"],"type":"string"}},{"description":"Desde, `AAAA-MM-DD`, incluido. El período más largo depende de la forma del informe: agrupado por día 400 días, por semana 3 años, por mes, trimestre o año 10 años; lo que lee los receptores o las líneas, 3 años (`limits` del catálogo).","in":"query","name":"from","schema":{"format":"date","type":"string"}},{"description":"Hasta, `AAAA-MM-DD`, incluido.","in":"query","name":"to","schema":{"format":"date","type":"string"}},{"description":"Cómo se agrupan las filas, entre las opciones del informe (`day`, `week`, `month`, `quarter`, `year`, `weekday`, `hour`, `key`, `route`, `channel`, `event`).","in":"query","name":"group","schema":{"type":"string"}},{"description":"Sólo los comprobantes en esa moneda (código ISO). Sin ella, todo en pesos, cada comprobante a su tipo de cambio.","in":"query","name":"currency","schema":{"pattern":"^[A-Za-z]{3}$","type":"string"}},{"description":"Sólo un tipo de comprobante (101 e-Ticket, 111 e-Factura...).","in":"query","name":"cfe_type","schema":{"maximum":299,"minimum":101,"type":"integer"}},{"description":"Por qué se ordena un ranking, entre las opciones del informe (`amount`, `count`, `quantity`).","in":"query","name":"by","schema":{"type":"string"}},{"description":"Sólo las primeras filas de un ranking. Sin él, todas, en páginas.","in":"query","name":"limit","schema":{"maximum":10000,"minimum":1,"type":"integer"}},{"description":"El importe mínimo de un comprobante (`amount_ranges`).","in":"query","name":"min","schema":{"pattern":"^[0-9]+([.,][0-9]+)?$","type":"string"}},{"description":"El importe máximo de un comprobante (`amount_ranges`).","in":"query","name":"max","schema":{"pattern":"^[0-9]+([.,][0-9]+)?$","type":"string"}},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightDuplicateRequest"}}},"required":false},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightSaved"}}},"description":"El informe guardado"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Un parámetro o un nombre que no valen (`insight_invalid_parameter`, `insight_period_too_long`)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La clave no tiene el permiso `settings` (`scope_required`), la configuración del cliente apaga los informes (`feature_disabled`) o el informe guardado lo armó otra persona y no es suyo cambiarlo (`insight_saved_forbidden`)"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No hay un informe con ese `id` (`insight_not_found`)"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Ya hay un informe con ese nombre (`insight_name_taken`) o la cuenta ya tiene 200 (`insight_saved_limit`)"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El informe queda predefinido (`insight_not_editable`, con `reason`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Duplica un informe del catálogo como informe propio","tags":["informes"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","insight_invalid_definition","insight_invalid_parameter","insight_name_taken","insight_not_editable","insight_not_found","insight_period_too_long","insight_saved_limit","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"settings","x-surface":"client"}},"/v1/invoices":{"get":{"description":"La misma lista que `GET /v1/emissions`, con los mismos filtros, la misma paginación y el mismo costo. `?external_id=` busca el CFE de un pedido de la tienda. Las más nuevas primero: fecha de emisión, tipo, serie y número, todo descendente. Para paginar, envíe en `after` el `next_cursor` de la página anterior: cuesta lo mismo a cualquier profundidad y no se corre cuando entran emisiones nuevas. `offset` sigue funcionando pero está deprecado. `total` cuenta hasta 10.000 coincidencias; si hay más, vale 10.000 y `total_capped` es `true`. Cada solicitud cuenta como 3 en el límite por minuto del plan.","parameters":[{"in":"query","name":"date","schema":{"format":"date","type":"string"}},{"description":"Estado de entrega, sin importar mayúsculas. Vacío es sin filtro; otro valor responde 400.","in":"query","name":"status","schema":{"enum":["PENDING","ACCEPTED","REJECTED","CANCELLED"],"type":"string"}},{"in":"query","name":"cfe_type","schema":{"type":"integer"}},{"in":"query","name":"limit","schema":{"default":50,"maximum":200,"type":"integer"}},{"description":"El `next_cursor` de la página anterior, tal cual. Opaco: no se arma a mano.","in":"query","name":"after","schema":{"type":"string"}},{"deprecated":true,"description":"Deprecado: usá `after`. No se combina con `after`.","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"El número de pedido de la tienda: la emisión que lo tiene (a lo sumo una). Vacío es sin filtro.","in":"query","name":"external_id","schema":{"maxLength":128,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceList"}}},"description":"Página de emisiones"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Emisiones con filtros y paginación (también por `external_id`)","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","invalid_sandbox_outcome","overloaded","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"post":{"description":"Reserva el número de CAE, firma y persiste en una sola transacción. Con `Idempotency-Key` un reintento devuelve la respuesta original en lugar de emitir otro comprobante.","parameters":[{"in":"header","name":"Idempotency-Key","required":false,"schema":{"maxLength":128,"type":"string"}},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}},{"$ref":"#/components/parameters/SandboxOutcome"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Invoice"}}},"description":"CFE emitido","headers":{"Location":{"description":"Ruta del CFE creado","schema":{"type":"string"}},"x-request-id":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required`: la clave de API no tiene el permiso (`x-scope`) de la ruta. `errors[0].params` trae `required` (el que pide) y `granted` (los que tiene). También `forbidden` si el rol de la sesión no alcanza. También `feature_disabled` (la configuración del cliente lo apaga)."},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Conflicto de estado: sin numeración (`no_numbering`), idempotencia, o el emisor no puede firmar: `certificate_missing` (no subió su certificado y la plataforma no permite el de respaldo), `certificate_expired`, `certificate_not_yet_valid`, `certificate_revoked` (la CA lo revocó; la DGI respondería `S03`), `certificate_ruc_mismatch` (el certificado no es del RUC del emisor; `S02`). Ningún número se consume. `external_id_taken`: otra emisión de la cuenta tiene ese `external_id`; trae `invoice_id`."},"413":{"$ref":"#/components/responses/EmissionTooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La réplica está al límite (`overloaded`): de pedidos en curso, de firmas simultáneas, o la espera de una conexión o de un bloqueo pasó su tope. No se reservó ningún número: vuelva a intentarlo después de `Retry-After` segundos, con la misma `Idempotency-Key`. `certificate_unavailable`: la clave del certificado del emisor no se puede abrir ahora (vault); también con `Retry-After`. `database_unavailable`: la base no contesta por un momento (failover); `restore_pending`: numeración detenida después de un restore. Siempre con `Retry-After`. `dgi_encryption_unavailable`: el CFE pide la zona K cifrada (`fiscal_complement.encrypted`) y el servicio no tiene el certificado público de la DGI de su ambiente (o venció); no se reservó número: emítalo sin cifrar o configure `CFE_DGI_ENCRYPTION_CERTIFICATE_PATH`.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"summary":"Emite, firma y guarda un CFE","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","certificate_expired","certificate_missing","certificate_not_yet_valid","certificate_revoked","certificate_ruc_mismatch","certificate_unavailable","contingency_range_on_paper","database_unavailable","dgi_encryption_unavailable","external_id_required","external_id_taken","feature_disabled","forbidden","idempotency_key_reused","internal_error","invalid_body","invalid_cfe","invalid_environment","invalid_external_id","invalid_sandbox_outcome","limit_reached","membership_expired","membership_required","no_numbering","overloaded","payload_too_large","quota_exceeded","rate_limited","request_in_progress","restore_pending","rule_violation","sandbox_full","sandbox_not_available","scope_required","unauthorized","unsupported","unsupported_media_type","view_only"],"x-scope":"emit","x-surface":"client"}},"/v1/invoices/preview":{"post":{"description":"Mismo cuerpo, misma completitud con el perfil del emisor y mismas validaciones que `POST /v1/invoices` (incluida la existencia de las referencias). No reserva número de CAE, no toma la `Idempotency-Key`, no cuenta para la cuota ni el consumo y no guarda nada. Cuenta para el límite por minuto. Cualquier rol del tenant, con token o clave de API. Un `external_id` que ya tiene otra emisión vuelve como aviso (`warnings[]`, `external_id_taken`).","parameters":[{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}},{"$ref":"#/components/parameters/SandboxOutcome"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoicePreview"}}},"description":"Totales y líneas del CFE que se emitiría"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required`: la clave de API no tiene el permiso (`x-scope`) de la ruta. `errors[0].params` trae `required` (el que pide) y `granted` (los que tiene). También `forbidden` si el rol de la sesión no alcanza. También `feature_disabled` (la configuración del cliente lo apaga)."},"413":{"$ref":"#/components/responses/EmissionTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Calcula el CFE sin emitirlo","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","database_unavailable","dgi_encryption_unavailable","external_id_required","feature_disabled","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","invalid_external_id","invalid_sandbox_outcome","limit_reached","overloaded","payload_too_large","rate_limited","restore_pending","rule_violation","sandbox_not_available","scope_required","unauthorized","unsupported","unsupported_media_type"],"x-scope":"emit","x-surface":"client"}},"/v1/invoices/{id}":{"get":{"parameters":[{"$ref":"#/components/parameters/InvoiceId"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Invoice"}}},"description":"El CFE"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Consulta un CFE","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","invalid_sandbox_outcome","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/invoices/{id}/adenda-attachment":{"get":{"description":"Los bytes como los adjuntó el emisor, sin interpretar: siempre `application/octet-stream`, como descarga (`Content-Disposition: attachment` con el nombre saneado) y con `X-Content-Type-Options: nosniff`. El tipo declarado está en `adenda_attachment` de `GET /v1/invoices/{id}`.","parameters":[{"$ref":"#/components/parameters/InvoiceId"}],"responses":{"200":{"content":{"application/octet-stream":{"schema":{"format":"binary","type":"string"}}},"description":"El archivo","headers":{"content-disposition":{"description":"`attachment; filename=\"<nombre>\"`, o `adjunto-<serie>-<número>.bin` sin nombre","schema":{"type":"string"}},"x-cfe-recipient-delivery":{"description":"Si ya puede entregarse al receptor (Formato Sobre v05, p. 4)","schema":{"enum":["allowed","wait_for_dgi","never","void"],"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"El binario de la adenda (zona J-C2)","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/invoices/{id}/annulment-notice":{"get":{"description":"`CFEs_Anulados_x_RechazoDGI` (MR 3.4) con el CFE, motivo `RD`, firmado ahora con el certificado del tenant. Va al receptor electrónico, nunca a la DGI. Válido contra `CFEs_Anulados_x_RechazoDGI.xsd`.","parameters":[{"$ref":"#/components/parameters/InvoiceId"},{"description":"RUC del receptor electrónico. Por defecto, el del receptor del CFE.","in":"query","name":"rut_receptor","required":false,"schema":{"pattern":"^[0-9]{12}$","type":"string"}}],"responses":{"200":{"content":{"application/xml":{"schema":{"type":"string"}}},"description":"`CFEs_Anulados_x_RechazoDGI`","headers":{"content-disposition":{"description":"`attachment; filename=\"Rech_<RUC>_<IDComunicacion>.xml\"`","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`cfe_not_rejected`: la DGI no rechazó el CFE; o sin certificado para firmar"},"422":{"$ref":"#/components/responses/Unprocessable"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Comunicación de anulación al receptor de un CFE que la DGI rechazó","tags":["recepción"],"x-error-codes":["account_suspended","bad_request","cfe_not_rejected","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/invoices/{id}/company-delivery":{"post":{"description":"El CFE va primero a la DGI (Formato Sobre v05, p. 4: «previo al envío del comprobante al receptor electrónico»): `409 cfe_not_at_dgi_yet` hasta que la DGI recibió su sobre (`AS`), y `409 cfe_not_deliverable` si la DGI lo rechazó o es de contingencia. Sin `email` usa la dirección de intercambio del receptor; sin ninguna, `422 recipient_address_unknown`. El sobre se arma en el primer intento y queda fijo (`Idemisor` = tipo y número, como la descarga).","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyDeliveryRequest"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeMessage"}}},"description":"Ya estaba encolado para ese receptor"},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeMessage"}}},"description":"Encolado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`cfe_not_at_dgi_yet`, `cfe_not_deliverable`"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`recipient_address_unknown`, `invalid_cfe` (`rut_receptor`, `email`)"}},"summary":"Encola el sobre del CFE a su receptor electrónico por correo","tags":["intercambio"],"x-error-codes":["account_suspended","bad_request","cfe_not_at_dgi_yet","cfe_not_deliverable","feature_disabled","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","not_found","overloaded","payload_too_large","recipient_address_unknown","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"emit","x-surface":"client"}},"/v1/invoices/{id}/company-envelope":{"get":{"description":"El sobre que el emisor envía al receptor electrónico (Formato Sobre v05, p. 5): la misma carátula que el sobre a la DGI y el CFE firmado, byte por byte, dentro de `CFE_Adenda` seguido de su adenda. El sobre a la DGI lleva el mismo CFE sin la adenda. Se arma en cada solicitud y no se guarda: la misma solicitud devuelve los mismos bytes.","parameters":[{"$ref":"#/components/parameters/InvoiceId"},{"description":"`RutReceptor` de la carátula. Por defecto, el RUC del receptor del CFE; obligatorio si el CFE no tiene receptor con RUT (secreto profesional). Se acepta el RUT de la DGI (219999830019) para la prueba de certificación con adenda.","in":"query","name":"rut_receptor","required":false,"schema":{"pattern":"^[0-9]{12}$","type":"string"}},{"description":"`Idemisor` de la carátula. Por defecto, el código del tipo seguido del número en 7 dígitos (`1110000042`).","in":"query","name":"idemisor","required":false,"schema":{"maximum":9999999999,"minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/xml":{"schema":{"type":"string"}}},"description":"Sobre `EnvioCFE_entreEmpresas`, válido contra `EnvioCFE_entreEmpresas.xsd`","headers":{"content-disposition":{"description":"`attachment; filename=\"Sob_<RUC>_<AAAAMMDD>_<Idemisor>.xml\"`","schema":{"type":"string"}},"x-cfe-recipient-delivery":{"description":"Si ya puede entregarse al receptor (Formato Sobre v05, p. 4): `wait_for_dgi` mientras la DGI no recibió el sobre de una e-Factura, sus notas, e-Resguardo, e-Remito o e-Ticket sobre 5.000 UI; `never` para un CFC; `void` si la DGI lo rechazó o se reemplazó","schema":{"enum":["allowed","wait_for_dgi","never","void"],"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`cfe_not_deliverable`: un CFC (no se envía al receptor, Formato Sobre v05 p. 4) o un CFE rechazado"},"422":{"$ref":"#/components/responses/Unprocessable"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Sobre entre empresas (EnvioCFE_entreEmpresas) del CFE, con su adenda","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","cfe_not_deliverable","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","not_found","overloaded","restore_pending","rule_violation","sandbox_not_available","scope_required","unauthorized","unsupported"],"x-scope":"read","x-surface":"client"}},"/v1/invoices/{id}/pdf":{"get":{"description":"En A4 por defecto, o en rollo térmico de 80 o 57 mm (`format`), que sigue el orden alternativo de la p. 80 (emisor, comprobante, receptor, cuerpo, pie) con todos los elementos obligatorios, el QR de 22 a 30 mm y los recuadros mínimos. La leyenda del e-Ticket nombra el sitio del emisor o la página pública de la plataforma (`GET /v1/tenant/publication`). Sale con la plantilla del emisor (`/v1/printing/template`), la versión con que se imprimió por primera vez (`x-cfe-print-template-version`).","parameters":[{"$ref":"#/components/parameters/InvoiceId"},{"$ref":"#/components/parameters/PaperFormat"}],"responses":{"200":{"content":{"application/pdf":{"schema":{"format":"binary","type":"string"}}},"description":"Archivo PDF","headers":{"x-cfe-print-template-version":{"description":"La versión de la plantilla con que salió: un número (`0` es la de okCFE) o `draft` en una vista previa","schema":{"type":"string"}},"x-cfe-recipient-delivery":{"description":"Si ya puede entregarse al receptor (Formato Sobre v05, p. 4): `wait_for_dgi` mientras la DGI no recibió el sobre de una e-Factura, sus notas, e-Resguardo, e-Remito o e-Ticket sobre 5.000 UI; `never` para un CFC; `void` si la DGI lo rechazó o se reemplazó","schema":{"enum":["allowed","wait_for_dgi","never","void"],"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required`: la clave de API no tiene el permiso (`x-scope`) de la ruta. `errors[0].params` trae `required` (el que pide) y `granted` (los que tiene). También `forbidden` si el rol de la sesión no alcanza. También `feature_disabled` (la configuración del cliente lo apaga)."},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Comprobante en PDF con QR y sello","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","invalid_format","invalid_sandbox_outcome","issuer_since_missing","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized","verification_site_missing"],"x-scope":"read","x-surface":"client"}},"/v1/invoices/{id}/pdf-link":{"delete":{"description":"Ningún link de ese CFE funciona hasta pedir uno nuevo con `POST`. El PDF sigue disponible con credenciales (`GET /v1/invoices/{id}/pdf`).","parameters":[{"$ref":"#/components/parameters/InvoiceId"},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PdfLink"}}},"description":"El link como queda"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Revoca el link al PDF","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","invalid_sandbox_outcome","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"emit","x-surface":"client"},"post":{"description":"Emite un link nuevo (`pdf_url`) y revoca el anterior: el token anterior deja de funcionar. Para volver a habilitar un link revocado.","parameters":[{"$ref":"#/components/parameters/InvoiceId"},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PdfLink"}}},"description":"El link como queda"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Un link nuevo al PDF","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","invalid_sandbox_outcome","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"emit","x-surface":"client"}},"/v1/invoices/{id}/pos":{"get":{"description":"Los bloques `text`, `line`, `columns`, `money`, `qr`, `image`, `feed` y `cut` del formato `cfe-pos/1` (JSON Schema en `GET /v1/schemas/cfe-pos-1.json`), con los anchos ya calculados para `columns`: la aplicación POS sólo recorre los bloques. Lo mismo en bytes ESC/POS (`encoding=escpos`) o en texto plano (`encoding=text`). El rollo es papel térmico: admite e-Tickets y sus notas, salvo que el cliente publique todos sus CFE (422 `thermal_paper_not_admitted`). `403 feature_disabled` con `printing.pos_ticket` apagado o sin el rollo en `printing.formats`. Sale con la plantilla del emisor (`/v1/printing/template`), la versión con que se imprimió por primera vez (`x-cfe-print-template-version`).","parameters":[{"$ref":"#/components/parameters/InvoiceId"},{"$ref":"#/components/parameters/PosColumns"},{"$ref":"#/components/parameters/PosEncoding"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PosTicket"}},"application/octet-stream":{"schema":{"contentMediaType":"application/octet-stream","type":"string"}},"text/plain":{"schema":{"type":"string"}}},"description":"El ticket, armado del mismo modelo que el impreso con todo lo obligatorio del rollo (Formato CFE v25.2, p. 79-86). `x-cfe-pos-format` dice el formato; con `escpos`, `x-cfe-pos-code-page` dice la tabla (`PC850`).","headers":{"x-cfe-pos-code-page":{"description":"La página de códigos de los bytes ESC/POS (`ESC t 2`), sólo con `encoding=escpos`","schema":{"const":"PC850","type":"string"}},"x-cfe-pos-format":{"description":"El formato del ticket","schema":{"const":"cfe-pos/1","type":"string"}},"x-cfe-print-template-version":{"description":"La versión de la plantilla con que salió: un número (`0` es la de okCFE) o `draft` en una vista previa","schema":{"type":"string"}},"x-cfe-recipient-delivery":{"description":"Si ya puede entregarse al receptor (Formato Sobre v05, p. 4): `wait_for_dgi` mientras la DGI no recibió el sobre de una e-Factura, sus notas, e-Resguardo, e-Remito o e-Ticket sobre 5.000 UI; `never` para un CFC; `void` si la DGI lo rechazó o se reemplazó","schema":{"enum":["allowed","wait_for_dgi","never","void"],"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required`: la clave de API no tiene el permiso (`x-scope`) de la ruta. `errors[0].params` trae `required` (el que pide) y `granted` (los que tiene). También `forbidden` si el rol de la sesión no alcanza. También `feature_disabled` (la configuración del cliente lo apaga)."},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Ticket para impresoras POS (cfe-pos/1, ESC/POS o texto)","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_columns","invalid_encoding","invalid_environment","invalid_sandbox_outcome","issuer_since_missing","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","thermal_paper_not_admitted","unauthorized","verification_site_missing"],"x-scope":"read","x-surface":"client"}},"/v1/invoices/{id}/print":{"get":{"description":"En A4 por defecto, o en rollo térmico de 80 o 57 mm (`format`), que sigue el orden alternativo de la p. 80 (emisor, comprobante, receptor, cuerpo, pie) con todos los elementos obligatorios, el QR de 22 a 30 mm y los recuadros mínimos. La leyenda del e-Ticket nombra el sitio del emisor o la página pública de la plataforma (`GET /v1/tenant/publication`). Sale con la plantilla del emisor (`/v1/printing/template`), la versión con que se imprimió por primera vez (`x-cfe-print-template-version`).","parameters":[{"$ref":"#/components/parameters/InvoiceId"},{"$ref":"#/components/parameters/PaperFormat"}],"responses":{"200":{"content":{"text/html":{"schema":{"type":"string"}}},"description":"HTML listo para imprimir","headers":{"x-cfe-print-template-version":{"description":"La versión de la plantilla con que salió: un número (`0` es la de okCFE) o `draft` en una vista previa","schema":{"type":"string"}},"x-cfe-recipient-delivery":{"description":"Si ya puede entregarse al receptor (Formato Sobre v05, p. 4): `wait_for_dgi` mientras la DGI no recibió el sobre de una e-Factura, sus notas, e-Resguardo, e-Remito o e-Ticket sobre 5.000 UI; `never` para un CFC; `void` si la DGI lo rechazó o se reemplazó","schema":{"enum":["allowed","wait_for_dgi","never","void"],"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required`: la clave de API no tiene el permiso (`x-scope`) de la ruta. `errors[0].params` trae `required` (el que pide) y `granted` (los que tiene). También `forbidden` si el rol de la sesión no alcanza. También `feature_disabled` (la configuración del cliente lo apaga)."},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Representación imprimible con QR y sello","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","invalid_sandbox_outcome","issuer_since_missing","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","thermal_paper_not_admitted","unauthorized","verification_site_missing"],"x-scope":"read","x-surface":"client"}},"/v1/invoices/{id}/refund":{"post":{"description":"Para integradores (Shopify, Magento): la devolución se pide por línea y cantidad (`lines`, por índice de la línea del CFE), por importe (`amounts`, a una tasa con `indicator` o `vat_rate`, o repartido en proporción entre las tasas del CFE) o por el envío (`shipping`: la línea con código `ENVIO`/`SHIPPING` en `INT1`/`INT2`, o un importe). Los importes van en los términos de precio del original (con IVA si `MntBruto` = 1).\n\nLa nota sale por el mismo camino que `POST /v1/invoices`: el tipo es el de nota de crédito del original (111 → 112, 101 → 102, 121 → 122, 141 → 142, 151 → 152, y los de contingencia y remitos no tienen), con la misma moneda, tipo de cambio, receptor, complemento fiscal y zona de exportación, y la referencia (F-C8 `MntCFEref`) al CFE.\n\nVarias devoluciones por CFE, topeadas por línea, por tasa y en total por lo que queda (acumulado con las demás notas de crédito que lo referencian). Una nota que la DGI rechaza libera su parte. Dos devoluciones del mismo CFE a la vez se serializan. Todo rechazo es antes de reservar número.\n\nIdempotente por `refund_id` dentro del CFE: el mismo cuerpo otra vez devuelve `200` con la misma nota; otro cuerpo con el mismo `refund_id` es `409 refund_id_reused`. El evento `invoice.emitted` de la nota trae `refund` con `refund_id`, `original_id` y `external_id`. Se apaga con la configuración `integration.refunds` (encendida por defecto).","parameters":[{"$ref":"#/components/parameters/InvoiceId"},{"$ref":"#/components/parameters/SandboxOutcome"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefundRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefundCreated"}}},"description":"El mismo `refund_id` con el mismo cuerpo: la nota que ya se emitió","headers":{"Location":{"schema":{"type":"string"}}}},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefundCreated"}}},"description":"Nota de crédito emitida","headers":{"Location":{"description":"Ruta de la nota (`/v1/invoices/{note_id}`)","schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required`, o `feature_disabled` (`integration.refunds` apagada, o la nota toca otra configuración apagada: su `path` empieza con `note.`)"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`refund_id_reused`: el `refund_id` ya se usó en este CFE con otro cuerpo. `refund_original_not_valid`: el CFE fue rechazado, anulado o reemplazado (`status`). También los conflictos de `POST /v1/invoices` (sin numeración, certificado). Ningún número se consume."},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_refund` (`errors[].code`: `refund_id_invalid`, `refund_reason_too_long`, `refund_quantity_invalid`, `refund_amount_invalid`, `refund_rate_not_in_invoice`, `refund_empty`, `refund_line_not_found`, `refund_line_not_refundable`, `refund_shipping_ambiguous`, `refund_shipping_not_found`). `refund_exceeds_remaining` (`refund_exceeds_line` con `params.remaining_quantity` y `remaining_amount`, `refund_exceeds_rate` y `refund_exceeds_total` con `params.remaining`). `refund_not_supported`: el tipo no tiene nota de crédito (`field` `TipoCFE`). Errores de la nota armada: `invalid_cfe` con rutas `note.…`. Antes de reservar número."},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Como en `POST /v1/invoices`: `overloaded`, `database_unavailable`, etc. Vuelva a intentarlo con el mismo `refund_id`.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"summary":"Devolución parcial o total: emite la nota de crédito del CFE","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","certificate_expired","certificate_missing","certificate_not_yet_valid","certificate_revoked","certificate_ruc_mismatch","certificate_unavailable","database_unavailable","dgi_encryption_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","invalid_refund","invalid_sandbox_outcome","limit_reached","membership_expired","membership_required","no_numbering","not_found","overloaded","payload_too_large","quota_exceeded","rate_limited","refund_exceeds_remaining","refund_id_reused","refund_not_supported","refund_original_not_valid","restore_pending","rule_violation","sandbox_full","sandbox_not_available","scope_required","unauthorized","unsupported","unsupported_media_type","view_only"],"x-scope":"emit","x-surface":"client"}},"/v1/invoices/{id}/refunds":{"get":{"description":"Cada devolución con su nota y si cuenta (`counts`: la nota está pendiente o aceptada; una rechazada o anulada no descuenta). Lo que queda por línea, por tasa y en total; el total descuenta también las notas de crédito emitidas por fuera de este recurso.","parameters":[{"$ref":"#/components/parameters/InvoiceId"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceRefunds"}}},"description":"Devoluciones"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Devoluciones de un CFE y lo que queda por devolver","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","invalid_sandbox_outcome","not_found","overloaded","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/invoices/{id}/reissue":{"post":{"description":"Mensaje de Respuesta v19, p. 9: todo CFE rechazado se anula, \"excepto cuando el motivo de rechazo es E02 ... y E09\". El cuerpo es el documento corregido, del mismo tipo. El número sale de un rango del tipo y la serie que lo incluye, no retirado y con un CAE distinto del que la DGI rechazó: el correcto, cargado después del equivocado (al cargarlo, el equivocado queda retirado). Sin uno, `422 cae_does_not_authorize`.\n\nEl rechazado queda como la DGI lo respondió, marcado `superseded_at`; el nuevo lo nombra en `supersedes`, sale en el próximo sobre y cuenta en el reporte diario (C26) cuando la DGI lo recibe; el rechazado no cuenta ni en C26 ni en C28.\n\nIdempotente: el mismo cuerpo devuelve la misma emisión; otro cuerpo, `409 idempotency_key_reused`.\n\nEl binario de la adenda (zona J-C2) del comprobante reemplazado va también con el nuevo si el cuerpo no trae `adenda_attachment`; con otro, va ese, y con `\"adenda_attachment\": null`, ninguno.","parameters":[{"$ref":"#/components/parameters/InvoiceId"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Invoice"}}},"description":"Emitido de nuevo, con su número"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required`: la clave de API no tiene el permiso (`x-scope`) de la ruta. `errors[0].params` trae `required` (el que pide) y `granted` (los que tiene). También `forbidden` si el rol de la sesión no alcanza. También `feature_disabled` (la configuración del cliente lo apaga)."},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`not_reissuable`: no es un CFE rechazado con E09; `idempotency_key_reused`: otro cuerpo para la misma reemisión; `already_replaced` / `number_taken`"},"413":{"$ref":"#/components/responses/EmissionTooLarge"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`cae_does_not_authorize` (`field` = `NroCFE`): sólo el CAE rechazado (o rangos retirados) incluye el número; `no_range_for_number`; `cae_expired_for_number`; `invalid_cfe` (`field` = `TipoCFE` si el tipo no es el del número); un documento que no valida trae `errors[]` con la ruta JSON de cada error"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Reemite con su serie y número un CFE rechazado con E09","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","cae_does_not_authorize","database_unavailable","external_id_taken","feature_disabled","forbidden","idempotency_key_reused","internal_error","invalid_body","invalid_cfe","invalid_environment","invalid_external_id","no_range_for_number","not_found","not_reissuable","overloaded","payload_too_large","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"emit","x-surface":"client"}},"/v1/invoices/{id}/send":{"post":{"description":"Manda el PDF de `GET /v1/invoices/{id}/pdf` (en su papel de siempre) a la dirección `email`, desde «<emisor> vía okCFE», con un texto fijo: el tipo, la serie y el número, la fecha, el total y el emisor. Sale en el momento por el correo de la plataforma: `200` cuando el servidor de correo lo tomó, `409 mail_not_configured` si la plataforma no tiene correo y `502 mail_not_sent` si el servidor no lo tomó. Sólo un comprobante que ya puede entregarse a su receptor (`409 cfe_not_at_dgi_yet`, `409 cfe_not_deliverable`, como `x-cfe-recipient-delivery`). Cada llamada pesa 5 pedidos del minuto, y una empresa envía hasta 60 por hora (`429 invoice_mail_rate_limited`). Un comprobante de Pruebas no se envía (`403 sandbox_not_available`).","parameters":[{"$ref":"#/components/parameters/InvoiceId"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceSendRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceSent"}}},"description":"Enviado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`mail_not_configured`, `cfe_not_at_dgi_yet`, `cfe_not_deliverable`"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_cfe` (`email`), `issuer_since_missing`, `verification_site_missing`"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`rate_limited` (el minuto) o `invoice_mail_rate_limited` (la hora)","headers":{"Retry-After":{"schema":{"type":"integer"}}}},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`mail_not_sent`: el servidor de correo no lo tomó"}},"summary":"Envía el PDF del comprobante por correo","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","cfe_not_at_dgi_yet","cfe_not_deliverable","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","invalid_format","invoice_mail_rate_limited","issuer_since_missing","mail_not_configured","mail_not_sent","not_found","overloaded","payload_too_large","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type","verification_site_missing"],"x-scope":"emit","x-surface":"client"}},"/v1/invoices/{id}/xml":{"get":{"parameters":[{"$ref":"#/components/parameters/InvoiceId"}],"responses":{"200":{"content":{"application/xml":{"schema":{"type":"string"}}},"description":"CFE firmado","headers":{"x-cfe-recipient-delivery":{"description":"Si ya puede entregarse al receptor (Formato Sobre v05, p. 4): `wait_for_dgi` mientras la DGI no recibió el sobre de una e-Factura, sus notas, e-Resguardo, e-Remito o e-Ticket sobre 5.000 UI; `never` para un CFC; `void` si la DGI lo rechazó o se reemplazó","schema":{"enum":["allowed","wait_for_dgi","never","void"],"type":"string"}},"x-xml-sha256":{"description":"SHA-256 del cuerpo, para verificar que es lo firmado","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"XML firmado, byte por byte","tags":["emisión"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","invalid_sandbox_outcome","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/meta":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"build":{"properties":{"api_version":{"type":"string"},"cfe_format":{"type":"string"},"service_version":{"type":"string"},"xsd_version":{"type":"string"}},"type":"object"},"dgi_encryption":{"description":"Certificado público de la DGI con el que se cifra la zona K (`fiscal_complement.encrypted`). `null`: en este ambiente la zona K sólo se puede emitir en claro.","properties":{"not_after":{"format":"date-time","type":"string"},"subject":{"type":"string"}},"type":["object","null"]},"dgi_environment":{"type":"string"},"limits":{"description":"Los topes que un cliente controla antes de mandar, tomados de las constantes de `cfe-core` y de la API.","properties":{"adenda_attachment_bytes":{"type":"integer"},"adenda_attachment_name_chars":{"type":"integer"},"adenda_chars":{"type":"integer"},"adenda_distribution_lines":{"type":"integer"},"annulment_reason_chars":{"type":"integer"},"api_key_name_chars":{"description":"Caracteres del nombre de una clave de API","type":"integer"},"body_bytes":{"type":"integer"},"dgi_contact_value_chars":{"description":"Caracteres del valor de una solicitud de contacto ante la DGI","type":"integer"},"emission_body_bytes":{"type":"integer"},"envelope_bytes":{"type":"integer"},"envelope_documents":{"type":"integer"},"field_lengths":{"additionalProperties":{"type":"integer"},"description":"El largo máximo de cada campo cuyo tope es el mismo en todos los tipos que lo toman; los demás, en `GET /v1/catalog/cfe-types`.","type":"object"},"global_adjustments":{"type":"integer"},"item_codes":{"type":"integer"},"lines":{"type":"integer"},"lines_e_ticket":{"type":"integer"},"payment_means":{"type":"integer"},"reception_rules":{"description":"Lo que toma `PUT /v1/reception-rules` además de la espera. Los decimales van como texto, como los toma la ruta.","properties":{"amount_factor_decimals":{"type":"integer"},"amount_factor_max":{"type":"string"},"amount_factor_min":{"type":"string"},"amount_min_history_default":{"description":"`amount_min_history` mientras el emisor no lo cambia","type":"integer"},"amount_min_history_max":{"type":"integer"},"amount_min_history_min":{"type":"integer"},"exchange_rate_tolerance_decimals":{"type":"integer"},"exchange_rate_tolerance_max":{"description":"Porcentaje mayor que 0 y de hasta este valor","type":"string"}},"type":"object"},"reference_wait_minutes_max":{"type":"integer"},"references":{"type":"integer"},"rejection_cause_detail_chars":{"description":"Caracteres del detalle de un motivo","type":"integer"},"rejection_causes_per_document":{"description":"Motivos por CFE en un rechazo comercial","type":"integer"},"rejection_documents":{"description":"CFE de un rechazo comercial (`POST /v1/received-envelopes/{id}/rejections`)","type":"integer"},"report_first_date":{"description":"`date` de `POST /v1/reports`: desde este día (A-C3) hasta hoy en Uruguay","format":"date","type":"string"},"report_max_wait_minutes":{"description":"`max_wait_minutes` del reporte automático (`PUT /v1/report-schedule`): de 0 a este valor","type":"integer"},"report_sequence_max":{"description":"`sequence` de `POST /v1/reports`: de 1 a este valor","type":"integer"},"special_cae_cause_max":{"description":"`special_cause` de un rango CAE cargado a mano: de 1 a este valor","type":"integer"},"special_norm_chars":{"description":"Caracteres de `special_norm` de un rango de CAE especial de exonerado","type":"integer"},"sub_adjustments":{"type":"integer"},"subtotals":{"type":"integer"},"upload_bytes":{"type":"integer"},"upload_file_name_chars":{"type":"integer"},"verification_site_chars":{"description":"Caracteres de `verification_site` del perfil del emisor","type":"integer"},"webhook_secret_min_bytes":{"description":"Largo mínimo, en bytes, del secreto de un webhook elegido por el emisor","type":"integer"},"withholdings":{"type":"integer"},"withholdings_per_line":{"type":"integer"}},"type":"object"},"supported_cfe_types":{"items":{"type":"integer"},"type":"array"}},"type":"object"}}},"description":"Metadatos"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[],"summary":"Versiones y tipos soportados","tags":["operación"],"x-error-codes":["database_unavailable","internal_error","overloaded","restore_pending"],"x-surface":"public"}},"/v1/notices":{"get":{"description":"Lo que le pasó a la cuenta (los mismos hechos que se reparten a los destinos de los avisos), del más nuevo al más viejo, haya o no destinos: cada uno con su título, su detalle, su `severity` y si esta persona ya lo leyó, y `unread`, cuántos le quedan sin leer. Por cursor: `next_cursor` va en `before`. En Pruebas, `403 sandbox_not_available`: los avisos son de la cuenta real.","parameters":[{"in":"query","name":"limit","required":false,"schema":{"default":10,"maximum":50,"minimum":1,"type":"integer"}},{"description":"El `next_cursor` de la página anterior","in":"query","name":"before","required":false,"schema":{"type":"string"}},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoticesPage"}}},"description":"Una página de avisos"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`bad_request`: `before` no es un cursor válido"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Una clave (`session_required`) o una sesión de Pruebas (`sandbox_not_available`)"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Los avisos de la cuenta para la campana de la barra (sesión, Producción)","tags":["avisos"],"x-error-codes":["account_suspended","bad_request","database_unavailable","internal_error","invalid_environment","overloaded","rate_limited","restore_pending","sandbox_not_available","session_required","unauthorized"],"x-surface":"portal"}},"/v1/notices/read":{"put":{"description":"Mueve la marca de lectura de esta persona hasta `up_to`, el `id` opaco (`ntc_…`) de un aviso de `GET /v1/notices`. La marca nunca vuelve atrás ni pasa del aviso más nuevo de la cuenta. Una vista del equipo de la plataforma no marca nada (`403 view_only`).","parameters":[{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoticesReadRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoticesRead"}}},"description":"La marca y cuántos quedan sin leer"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`bad_request`: `up_to` no es el `id` de un aviso (un número no lo es)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Una clave (`session_required`), una sesión de Pruebas (`sandbox_not_available`) o una vista del equipo (`view_only`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Marca leídos los avisos hasta uno (sesión, Producción)","tags":["avisos"],"x-error-codes":["account_suspended","bad_request","database_unavailable","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","restore_pending","sandbox_not_available","session_required","unauthorized","unsupported_media_type","view_only"],"x-surface":"portal"}},"/v1/notifications/destinations":{"get":{"description":"Los destinos de la empresa (correo, WhatsApp, Telegram, Slack, Teams), del más viejo al más nuevo, con sus avisos.","parameters":[{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationDestinationList"}}},"description":"Los destinos"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Los destinos de avisos","tags":["avisos"],"x-error-codes":["account_suspended","database_unavailable","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"post":{"description":"Un destino nuevo, pendiente hasta verificarlo: nada se le envía antes. Recibe los eventos de `events`, como un webhook (sin `events`, los `default_events` del catálogo). El código de 6 dígitos sale ahora a la dirección (WhatsApp, correo, Slack, Teams) y se escribe en `POST .../verify`; el correo trae además un enlace de confirmación. Telegram no lleva dirección: la respuesta trae `verification.link`, que se abre desde el chat que recibirá los avisos. El mismo número o chat puede estar en varias empresas, verificado en cada una. Cualquier usuario agrega destinos propios; `OWNER` (o una clave con `settings`) los da a otro usuario. La cantidad la limita la membresía (`429 limit_reached`, `limit: notification_destinations`); los códigos, por destino, empresa y dirección (`429 verification_rate_limited`).","parameters":[{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationDestinationCreate"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationDestination"}}},"description":"El destino creado, con `verification`","headers":{"Location":{"description":"`/v1/notifications/destinations/{id}`","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required` o `forbidden` (el rol o la clave no alcanzan). `feature_disabled`: el canal (`notifications.channels`, `path: channel`) o un evento pedido (`notifications.triggers`, `path: events` o `events[i]`) que la membresía no incluye."},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`destination_exists`: la empresa ya tiene un destino con esa dirección (`destination_id`)"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_notification`: el cuerpo no es válido; `field` dice cuál (`channel`, `name`, `address`, `owner_user_id`, `events`; con `event`, el evento que no existe o que sólo recibe un webhook). `channel_not_available`: okCFE no tiene ese canal configurado. `webhook_url_not_allowed`: la URL de Slack o Teams apunta a una dirección no pública."},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`limit_reached` (la membresía) o `verification_rate_limited` (demasiados códigos; `Retry-After` y `retry_after_seconds`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Agrega un destino de avisos","tags":["avisos"],"x-error-codes":["account_suspended","channel_not_available","database_unavailable","destination_exists","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","invalid_notification","limit_reached","overloaded","payload_too_large","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type","verification_rate_limited","webhook_url_not_allowed"],"x-scope":"settings","x-surface":"client"}},"/v1/notifications/destinations/{id}":{"delete":{"description":"Con sus avisos y su historial. Lo gestiona `OWNER` (o una clave de API con `settings`) o el usuario dueño del destino; otro usuario recibe `403 forbidden`.","parameters":[{"$ref":"#/components/parameters/NotificationDestinationId"},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"204":{"description":"Eliminado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Elimina un destino de avisos","tags":["avisos"],"x-error-codes":["account_suspended","bad_request","database_unavailable","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"settings","x-surface":"client"},"get":{"description":"El destino, con sus avisos.","parameters":[{"$ref":"#/components/parameters/NotificationDestinationId"},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationDestination"}}},"description":"El destino"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Un destino de avisos","tags":["avisos"],"x-error-codes":["account_suspended","bad_request","database_unavailable","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"patch":{"description":"Su nombre, sus eventos (`events`, como un webhook: lo pendiente de un evento que deja de recibir se descarta), pausarlo (`enabled: false`: lo que pase mientras tanto no se le envía y lo pendiente espera) o reanudarlo (lo pendiente sale), y su usuario dueño. Uno dado de baja o revocado no se reanuda: necesita una verificación nueva (`409 verification_required`). Lo gestiona `OWNER` (o una clave de API con `settings`) o el usuario dueño del destino; otro usuario recibe `403 forbidden`.","parameters":[{"$ref":"#/components/parameters/NotificationDestinationId"},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationDestinationUpdate"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationDestination"}}},"description":"El destino"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required` o `forbidden` (el rol o la clave no alcanzan). `feature_disabled`: reanudar un destino de un canal que la membresía no incluye (`notifications.channels`) o pedir un evento que no incluye (`notifications.triggers`, `path: events` o `events[i]`)."},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`verification_required`: el destino no está confirmado"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_notification`: `name`, `events` u `owner_user_id`"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Cambia un destino de avisos","tags":["avisos"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","invalid_notification","not_found","overloaded","payload_too_large","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type","verification_required"],"x-scope":"settings","x-surface":"client"}},"/v1/notifications/destinations/{id}/history/{notification_id}/retry":{"post":{"description":"Un mensaje nuevo del mismo aviso (el mismo `trigger` y `facts`), pendiente para ahora, enlazado con el original: el nuevo lleva `retry_of` y el original `retried_by` (el más reciente). Sólo un mensaje que terminó, enviado o muerto (`409 delivery_not_ended`: el que sigue en curso se reintenta solo), de un destino confirmado y activo (`409 destination_not_active`, con `state`). Un código de confirmación no se repite (`409 not_retryable`): se pide uno nuevo con `POST /v1/notifications/destinations/{id}/verification`; tampoco «Destino de avisos confirmado», que se envía una sola vez al confirmarlo. Un doble clic no lo duplica: mientras el nuevo no termina, la misma petición responde `200` con él en lugar de `202`. Veinte por minuto por cliente, entre webhooks y avisos (`429 rate_limited`, con `Retry-After`). Lo gestiona `OWNER` (o una clave de API con `settings`) o el usuario dueño del destino; otro usuario recibe `403 forbidden`. No está en Pruebas (`sandbox_not_available`).","parameters":[{"$ref":"#/components/parameters/NotificationDestinationId"},{"description":"El `id` del mensaje, como en `GET /v1/notifications/history` (opaco, `ntf_…`). Un número no es un id: `404`.","in":"path","name":"notification_id","required":true,"schema":{"pattern":"^ntf_[a-z2-7]{26}$","type":"string"}},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Notification"}}},"description":"El que ya se había vuelto a enviar y sigue en curso (un doble clic)"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Notification"}}},"description":"El mensaje nuevo, pendiente"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`delivery_not_ended`: el mensaje sigue en curso; `destination_not_active`: el destino está pausado o sin confirmar (`state`); `not_retryable`: un código de confirmación o «Destino de avisos confirmado»"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`rate_limited`: más de veinte en el minuto; `Retry-After` y `retry_after_seconds`"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Vuelve a enviar un aviso","tags":["avisos"],"x-error-codes":["account_suspended","bad_request","database_unavailable","delivery_not_ended","destination_not_active","forbidden","internal_error","invalid_environment","not_found","not_retryable","overloaded","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"settings","x-surface":"client"}},"/v1/notifications/destinations/{id}/test":{"post":{"description":"Un mensaje de prueba, ahora, con lo que contestó el canal, aunque el destino esté pausado o no haya elegido ningún evento, como la prueba de un webhook. Queda en el historial y no se reintenta. Sólo a un destino confirmado (`409 destination_not_active`), y una cada 10 segundos por destino (`429 test_rate_limited`, con `Retry-After`): cada prueba sale por las cuentas de la plataforma. Lo gestiona `OWNER` (o una clave de API con `settings`) o el usuario dueño del destino; otro usuario recibe `403 forbidden`.","parameters":[{"$ref":"#/components/parameters/NotificationDestinationId"},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationTestResult"}}},"description":"Lo que contestó el canal"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`destination_not_active`: el destino no está confirmado (pendiente, dado de baja o revocado)"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`test_rate_limited`: ya se envió una prueba a este destino hace menos de 10 segundos; `Retry-After` y `retry_after_seconds`"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Envía un mensaje de prueba","tags":["avisos"],"x-error-codes":["account_suspended","bad_request","database_unavailable","destination_not_active","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","test_rate_limited","unauthorized"],"x-scope":"settings","x-surface":"client"}},"/v1/notifications/destinations/{id}/verification":{"post":{"description":"Un código nuevo (o un enlace nuevo de Telegram); el anterior deja de valer. También así vuelve un destino dado de baja o revocado. Hasta un código por minuto y 5 por hora por destino, 30 por hora por empresa y 10 por día por dirección entre todas las empresas. Lo gestiona `OWNER` (o una clave de API con `settings`) o el usuario dueño del destino; otro usuario recibe `403 forbidden`.","parameters":[{"$ref":"#/components/parameters/NotificationDestinationId"},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationDestination"}}},"description":"El destino, con `verification`"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required` o `forbidden` (el rol o la clave no alcanzan). `feature_disabled`: un canal que la membresía no incluye (`notifications.channels`)."},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`already_verified`: el destino ya está confirmado"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`channel_not_available`: okCFE ya no tiene ese canal configurado"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`verification_rate_limited`: `Retry-After` y `retry_after_seconds`"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Pide un código o enlace nuevo","tags":["avisos"],"x-error-codes":["account_suspended","already_verified","bad_request","channel_not_available","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized","verification_rate_limited"],"x-scope":"settings","x-surface":"client"}},"/v1/notifications/destinations/{id}/verify":{"post":{"description":"El código que llegó a la dirección. Bien escrito, el destino queda activo y le llega una confirmación que nombra a la empresa y su RUT. Mal escrito, cuenta uno de sus 5 intentos (`attempts_left`). Lo gestiona `OWNER` (o una clave de API con `settings`) o el usuario dueño del destino; otro usuario recibe `403 forbidden`.","parameters":[{"$ref":"#/components/parameters/NotificationDestinationId"},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationVerifyRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationDestination"}}},"description":"El destino, activo"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required` o `forbidden` (el rol o la clave no alcanzan). `feature_disabled`: un canal que la membresía no incluye (`notifications.channels`)."},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`already_verified`: el destino ya está confirmado"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`verification_failed`: el código no es correcto (`attempts_left`); `verification_expired`: venció o se pidió otro; `verification_locked`: se agotaron los intentos; `invalid_notification`: Telegram se confirma con el enlace"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Confirma un destino con su código","tags":["avisos"],"x-error-codes":["account_suspended","already_verified","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","invalid_notification","not_found","overloaded","payload_too_large","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type","verification_expired","verification_failed","verification_locked"],"x-scope":"settings","x-surface":"client"}},"/v1/notifications/email/confirm":{"get":{"description":"La página que abre el enlace del correo de confirmación, con un botón. Abrirla no confirma nada: los filtros de correo también abren los enlaces.","parameters":[{"in":"query","name":"token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"text/html":{"schema":{"type":"string"}}},"description":"La página"},"410":{"content":{"text/html":{"schema":{"type":"string"}}},"description":"El enlace no es válido"}},"security":[],"summary":"Página del enlace de confirmación del correo","tags":["avisos"],"x-error-codes":["database_unavailable","internal_error","overloaded"],"x-surface":"public"},"post":{"description":"El formulario de la página (`token=`): el correo queda activo y responde una página que nombra a la empresa. Un enlace vale 15 minutos y una sola vez (`409`), y uno más nuevo lo reemplaza (`410`).","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"properties":{"token":{"type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"text/html":{"schema":{"type":"string"}}},"description":"Confirmado"},"409":{"content":{"text/html":{"schema":{"type":"string"}}},"description":"El enlace ya se usó"},"410":{"content":{"text/html":{"schema":{"type":"string"}}},"description":"El enlace venció, se pidió un código más nuevo o no es válido"}},"security":[],"summary":"Confirma el correo","tags":["avisos"],"x-error-codes":["database_unavailable","internal_error","invalid_body","overloaded","payload_too_large","unsupported_media_type"],"x-surface":"public"}},"/v1/notifications/events":{"get":{"description":"Los canales (y si okCFE tiene cada uno configurado) y los eventos que un destino puede elegir, en el idioma del pedido: el mismo catálogo que `GET /v1/webhooks/events`. `reach` dice quién puede recibir cada uno: `all` (cualquier destino) o `webhook` (uno por comprobante u orden: sólo un webhook). `default_events` son los de un destino nuevo que no los elige. Los umbrales son de la cuenta: `GET /v1/notifications/thresholds`.","parameters":[{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationCatalog"}}},"description":"El catálogo"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Los eventos y los canales","tags":["avisos"],"x-error-codes":["account_suspended","database_unavailable","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/notifications/history":{"get":{"description":"Los mensajes de todos los destinos (o de `destination_id`), del más nuevo al más viejo, guardados 90 días, por cursor: `next_cursor` va en `before`.","parameters":[{"in":"query","name":"destination_id","required":false,"schema":{"format":"uuid","type":"string"}},{"in":"query","name":"trigger","required":false,"schema":{"type":"string"}},{"in":"query","name":"status","required":false,"schema":{"enum":["sent","pending","dead"],"type":"string"}},{"in":"query","name":"limit","required":false,"schema":{"default":50,"maximum":100,"minimum":1,"type":"integer"}},{"description":"El `next_cursor` de la página anterior","in":"query","name":"before","required":false,"schema":{"type":"string"}},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationHistoryPage"}}},"description":"Una página"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`bad_request`: `destination_id`, `status` o `before` no son válidos"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"El historial de avisos","tags":["avisos"],"x-error-codes":["account_suspended","bad_request","database_unavailable","forbidden","internal_error","invalid_environment","overloaded","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/notifications/telegram/webhook":{"post":{"description":"Con `CFE_TELEGRAM_WEBHOOK_SECRET` configurado, Telegram envía aquí lo que se escribe al bot, con el secreto en `X-Telegram-Bot-Api-Secret-Token` (`401` si no coincide). `/start <token>` vincula el chat con el destino del enlace; `/stop` da de baja el chat en todas las empresas. Sin el secreto responde `404` (el worker lee con `getUpdates`).","parameters":[{"in":"header","name":"X-Telegram-Bot-Api-Secret-Token","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object"}}},"required":true},"responses":{"200":{"description":"Recibido"},"401":{"$ref":"#/components/responses/Unauthorized"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`channel_not_available`: el canal no está configurado en esta instalación. `database_unavailable`: la base no contesta"}},"security":[],"summary":"Las actualizaciones del bot de Telegram","tags":["avisos"],"x-error-codes":["channel_not_available","database_unavailable","internal_error","invalid_body","overloaded","payload_too_large","unauthorized","unsupported_media_type"],"x-surface":"public"}},"/v1/notifications/thresholds":{"get":{"description":"Los umbrales de los eventos que los tienen (`cae.running_low`, `cae.expiring`, `certificate.expiring`): los mismos para todos los destinos de avisos, todos los webhooks y `GET /v1/events`. Una condición es un evento, con un `event_id`, sea cual sea la cantidad de destinos. `updated_at: null`: los del catálogo, sin cambios.","parameters":[{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationThresholdList"}}},"description":"Los umbrales"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Los umbrales de la cuenta","tags":["avisos"],"x-error-codes":["account_suspended","database_unavailable","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/notifications/thresholds/{event}":{"put":{"description":"Un umbral de la cuenta, para todos los destinos y webhooks, desde la próxima evaluación (cada pocos minutos). Lo que `settings` no nombra toma el valor del catálogo; `settings: null` vuelve al del catálogo. Sólo `OWNER` (o una clave de API con `settings`): otro usuario recibe `403 forbidden`.","parameters":[{"$ref":"#/components/parameters/NotificationThresholdEvent"},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationThresholdUpdate"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationThreshold"}}},"description":"El umbral"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_notification`: el evento no tiene umbral (`field: event`) o un valor está fuera de rango (`field: settings.<miembro>`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Cambia un umbral de la cuenta","tags":["avisos"],"x-error-codes":["account_suspended","bad_request","database_unavailable","forbidden","internal_error","invalid_body","invalid_environment","invalid_notification","overloaded","payload_too_large","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"settings","x-surface":"client"}},"/v1/notifications/whatsapp/webhook":{"get":{"description":"La comprobación de Meta al suscribir el webhook: con `hub.mode=subscribe` y `hub.verify_token` igual a `CFE_WHATSAPP_VERIFY_TOKEN` responde `hub.challenge`; si no, `403`. Sin WhatsApp configurado, `404`.","parameters":[{"in":"query","name":"hub.mode","required":false,"schema":{"type":"string"}},{"in":"query","name":"hub.verify_token","required":false,"schema":{"type":"string"}},{"in":"query","name":"hub.challenge","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"text/plain":{"schema":{"type":"string"}}},"description":"`hub.challenge`"},"403":{"$ref":"#/components/responses/Forbidden"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`channel_not_available`: el canal no está configurado en esta instalación. `database_unavailable`: la base no contesta"}},"security":[],"summary":"Verificación del webhook de WhatsApp","tags":["avisos"],"x-error-codes":["channel_not_available","database_unavailable","forbidden","internal_error","overloaded"],"x-surface":"public"},"post":{"description":"Lo que Meta envía, firmado con el secreto de la app en `X-Hub-Signature-256` (`401` si no verifica). `STOP`, `BAJA`, `DETENER`, `PARAR` o `CANCELAR` da de baja el número: en todas las empresas, o sólo la del aviso que responde. Siempre `200` una vez verificada la firma.","parameters":[{"in":"header","name":"X-Hub-Signature-256","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object"}}},"required":true},"responses":{"200":{"description":"Recibido"},"401":{"$ref":"#/components/responses/Unauthorized"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`channel_not_available`: el canal no está configurado en esta instalación. `database_unavailable`: la base no contesta"}},"security":[],"summary":"Los mensajes que recibe el número de WhatsApp","tags":["avisos"],"x-error-codes":["channel_not_available","database_unavailable","internal_error","invalid_body","overloaded","payload_too_large","unauthorized","unsupported_media_type"],"x-surface":"public"}},"/v1/openapi.json":{"get":{"responses":{"200":{"description":"Especificación OpenAPI"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[],"summary":"Este documento","tags":["operación"],"x-error-codes":["database_unavailable","internal_error","overloaded","restore_pending"],"x-surface":"public"}},"/v1/orders":{"get":{"description":"Las más nuevas primero, por cursor. Cuenta como una lista en el límite de pedidos.","parameters":[{"description":"Sin importar mayúsculas; `EXPIRED` incluye las abiertas vencidas que el barrido aún no escribió. Otro valor responde 400.","in":"query","name":"state","schema":{"$ref":"#/components/schemas/OrderState"}},{"description":"El número de pedido de la tienda.","in":"query","name":"external_id","schema":{"maxLength":128,"type":"string"}},{"description":"El número visible de la orden: `ORD-0000000012`, `ORD-12`, `ord 12` o `12` (con o sin los ceros, en mayúsculas o minúsculas; más de diez dígitos es `400`).","in":"query","name":"number","schema":{"type":"string"}},{"description":"El número de documento del receptor.","in":"query","name":"receiver_document","schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"default":50,"maximum":200,"type":"integer"}},{"description":"El `next_cursor` de la página anterior, tal cual.","in":"query","name":"after","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderList"}}},"description":"Una página de órdenes"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Lista las órdenes del emisor","tags":["órdenes"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","invalid_sandbox_outcome","overloaded","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"post":{"description":"El cuerpo es el de `POST /v1/invoices`. Corre toda la validación de la emisión (documento, configuración, perfil del emisor, certificado, numeración disponible, referencias, `external_id`) y guarda el pedido con lo resuelto (tipo, indicadores de `vat_rate`, moneda, emisor). No toma número de CAE, no cuenta en el cupo ni firma. Lo que cambia con el tiempo (cupo, vencimiento del CAE, del certificado o de la membresía) va en `warnings` y se controla de nuevo al facturar. Con `Idempotency-Key` un reintento devuelve la misma orden.","parameters":[{"in":"header","name":"Idempotency-Key","required":false,"schema":{"maxLength":128,"type":"string"}},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}},{"$ref":"#/components/parameters/SandboxOutcome"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}}},"description":"Orden creada (`OPEN`, versión 1)","headers":{"ETag":{"description":"La versión de la orden (`version`) entre comillas: la que acepta `If-Match`.","schema":{"examples":["\"3\""],"type":"string"}},"Location":{"description":"Ruta de la orden","schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required`: la clave de API no tiene el permiso (`x-scope`) de la ruta. `errors[0].params` trae `required` (el que pide) y `granted` (los que tiene). También `forbidden` si el rol de la sesión no alcanza. También `feature_disabled` (la configuración del cliente lo apaga)."},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Lo que respondería `POST /v1/invoices` antes de tomar número, con los mismos códigos: `no_numbering`, `certificate_*`, `external_id_taken` (otra orden abierta o facturada, o una emisión, tiene ese `external_id`; trae `order_id` y `order_number` o `invoice_id`), idempotencia. `too_many_open_orders`: el emisor llegó al tope de órdenes abiertas (`CFE_ORDER_MAX_OPEN`); trae `max`. Cancele o facture alguna."},"413":{"$ref":"#/components/responses/EmissionTooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La réplica está al límite (`overloaded`): de pedidos en curso, de firmas simultáneas, o la espera de una conexión o de un bloqueo pasó su tope. No se reservó ningún número: vuelva a intentarlo después de `Retry-After` segundos, con la misma `Idempotency-Key`. `certificate_unavailable`: la clave del certificado del emisor no se puede abrir ahora (vault); también con `Retry-After`. `database_unavailable`: la base no contesta por un momento (failover); `restore_pending`: numeración detenida después de un restore. Siempre con `Retry-After`. `dgi_encryption_unavailable`: el CFE pide la zona K cifrada (`fiscal_complement.encrypted`) y el servicio no tiene el certificado público de la DGI de su ambiente (o venció); no se reservó número: emítalo sin cifrar o configure `CFE_DGI_ENCRYPTION_CERTIFICATE_PATH`.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"summary":"Crea una orden: valida la factura sin emitirla","tags":["órdenes"],"x-error-codes":["account_suspended","bad_request","certificate_expired","certificate_missing","certificate_not_yet_valid","certificate_revoked","certificate_ruc_mismatch","certificate_unavailable","contingency_range_on_paper","database_unavailable","dgi_encryption_unavailable","external_id_required","external_id_taken","feature_disabled","forbidden","idempotency_key_reused","internal_error","invalid_body","invalid_cfe","invalid_environment","invalid_external_id","invalid_sandbox_outcome","limit_reached","membership_expired","membership_required","no_numbering","overloaded","payload_too_large","quota_exceeded","rate_limited","request_in_progress","restore_pending","rule_violation","sandbox_full","sandbox_not_available","scope_required","too_many_open_orders","unauthorized","unsupported","unsupported_media_type","view_only"],"x-scope":"emit","x-surface":"client"}},"/v1/orders/{id}":{"delete":{"description":"Libera su `external_id`. Cancelar una orden ya cancelada responde lo mismo (200).","parameters":[{"$ref":"#/components/parameters/OrderId"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}}},"description":"La orden cancelada","headers":{"ETag":{"description":"La versión de la orden (`version`) entre comillas: la que acepta `If-Match`.","schema":{"examples":["\"3\""],"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`order_not_found`"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`order_closed`: la orden no está `OPEN` (trae `state` e `invoice_id`). Una orden facturada o vencida no se cancela."},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Cancela una orden abierta","tags":["órdenes"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","invalid_sandbox_outcome","not_found","order_closed","order_not_found","overloaded","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"emit","x-surface":"client"},"get":{"parameters":[{"$ref":"#/components/parameters/OrderId"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}}},"description":"La orden, con el pedido tal como se recibió","headers":{"ETag":{"description":"La versión de la orden (`version`) entre comillas: la que acepta `If-Match`.","schema":{"examples":["\"3\""],"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`order_not_found`: no hay una orden con ese `id` en la cuenta."},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Consulta una orden","tags":["órdenes"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","invalid_sandbox_outcome","not_found","order_not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"put":{"description":"El cuerpo reemplaza al anterior entero (lo que no trae desaparece) y se valida como en la creación. La versión sube en uno, `last_error` se borra y `expires_at` se extiende (sin pasar `CFE_ORDER_MAX_AGE_DAYS` desde la creación). Con `If-Match` sólo si la orden sigue en esa versión.","parameters":[{"$ref":"#/components/parameters/OrderId"},{"description":"El `ETag` de la versión que se leyó; otra versión responde 409 `order_version_mismatch`. `*` o sin el encabezado: cualquiera.","in":"header","name":"If-Match","required":false,"schema":{"examples":["\"3\""],"type":"string"}},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}}},"description":"La orden reemplazada","headers":{"ETag":{"description":"La versión de la orden (`version`) entre comillas: la que acepta `If-Match`.","schema":{"examples":["\"3\""],"type":"string"}}}},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_body`, o `bad_request` con `If-Match` que no es una versión (`errors[0].field` = `If-Match`)."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required`: la clave de API no tiene el permiso (`x-scope`) de la ruta. `errors[0].params` trae `required` (el que pide) y `granted` (los que tiene). También `forbidden` si el rol de la sesión no alcanza. También `feature_disabled` (la configuración del cliente lo apaga)."},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`order_not_found`"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`order_closed`: la orden no está `OPEN` (trae `state` e `invoice_id`). `order_version_mismatch`: la orden ya no está en la versión de `If-Match`; trae `expected_version`, `version` y la orden actual (`order`). Lo que respondería `POST /v1/invoices` antes de tomar número, con los mismos códigos: `no_numbering`, `certificate_*`, `external_id_taken` (otra orden abierta o facturada, o una emisión, tiene ese `external_id`; trae `order_id` y `order_number` o `invoice_id`), idempotencia."},"413":{"$ref":"#/components/responses/EmissionTooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La réplica está al límite (`overloaded`): de pedidos en curso, de firmas simultáneas, o la espera de una conexión o de un bloqueo pasó su tope. No se reservó ningún número: vuelva a intentarlo después de `Retry-After` segundos, con la misma `Idempotency-Key`. `certificate_unavailable`: la clave del certificado del emisor no se puede abrir ahora (vault); también con `Retry-After`. `database_unavailable`: la base no contesta por un momento (failover); `restore_pending`: numeración detenida después de un restore. Siempre con `Retry-After`. `dgi_encryption_unavailable`: el CFE pide la zona K cifrada (`fiscal_complement.encrypted`) y el servicio no tiene el certificado público de la DGI de su ambiente (o venció); no se reservó número: emítalo sin cifrar o configure `CFE_DGI_ENCRYPTION_CERTIFICATE_PATH`.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"summary":"Reemplaza una orden abierta","tags":["órdenes"],"x-error-codes":["account_suspended","bad_request","certificate_expired","certificate_missing","certificate_not_yet_valid","certificate_revoked","certificate_ruc_mismatch","certificate_unavailable","contingency_range_on_paper","database_unavailable","dgi_encryption_unavailable","external_id_required","external_id_taken","feature_disabled","forbidden","idempotency_key_reused","internal_error","invalid_body","invalid_cfe","invalid_environment","invalid_external_id","invalid_sandbox_outcome","limit_reached","membership_expired","membership_required","no_numbering","order_closed","order_not_found","order_version_mismatch","overloaded","payload_too_large","quota_exceeded","rate_limited","request_in_progress","restore_pending","rule_violation","sandbox_full","sandbox_not_available","scope_required","unauthorized","unsupported","unsupported_media_type","view_only"],"x-scope":"emit","x-surface":"client"}},"/v1/orders/{id}/duplicate":{"post":{"description":"Copia el pedido tal como se recibió, de una orden en cualquier estado, y lo valida como una creación: número, `id` y versión nuevos. El `external_id` no se copia: va el del cuerpo, si viene.","parameters":[{"$ref":"#/components/parameters/OrderId"},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderDuplicateRequest"}}},"required":false},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}}},"description":"La orden nueva","headers":{"ETag":{"description":"La versión de la orden (`version`) entre comillas: la que acepta `If-Match`.","schema":{"examples":["\"3\""],"type":"string"}},"Location":{"description":"Ruta de la orden nueva","schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required`: la clave de API no tiene el permiso (`x-scope`) de la ruta. `errors[0].params` trae `required` (el que pide) y `granted` (los que tiene). También `forbidden` si el rol de la sesión no alcanza. También `feature_disabled` (la configuración del cliente lo apaga)."},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`order_not_found`"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Lo que respondería `POST /v1/invoices` antes de tomar número, con los mismos códigos: `no_numbering`, `certificate_*`, `external_id_taken` (otra orden abierta o facturada, o una emisión, tiene ese `external_id`; trae `order_id` y `order_number` o `invoice_id`), idempotencia. `too_many_open_orders`: el emisor llegó al tope de órdenes abiertas."},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La réplica está al límite (`overloaded`): de pedidos en curso, de firmas simultáneas, o la espera de una conexión o de un bloqueo pasó su tope. No se reservó ningún número: vuelva a intentarlo después de `Retry-After` segundos, con la misma `Idempotency-Key`. `certificate_unavailable`: la clave del certificado del emisor no se puede abrir ahora (vault); también con `Retry-After`. `database_unavailable`: la base no contesta por un momento (failover); `restore_pending`: numeración detenida después de un restore. Siempre con `Retry-After`. `dgi_encryption_unavailable`: el CFE pide la zona K cifrada (`fiscal_complement.encrypted`) y el servicio no tiene el certificado público de la DGI de su ambiente (o venció); no se reservó número: emítalo sin cifrar o configure `CFE_DGI_ENCRYPTION_CERTIFICATE_PATH`.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"summary":"Crea una orden nueva con el pedido de otra","tags":["órdenes"],"x-error-codes":["account_suspended","bad_request","certificate_expired","certificate_missing","certificate_not_yet_valid","certificate_revoked","certificate_ruc_mismatch","certificate_unavailable","contingency_range_on_paper","database_unavailable","dgi_encryption_unavailable","external_id_required","external_id_taken","feature_disabled","forbidden","idempotency_key_reused","internal_error","invalid_body","invalid_cfe","invalid_environment","invalid_external_id","invalid_sandbox_outcome","limit_reached","membership_expired","membership_required","no_numbering","order_not_found","overloaded","payload_too_large","quota_exceeded","rate_limited","request_in_progress","restore_pending","rule_violation","sandbox_full","sandbox_not_available","scope_required","too_many_open_orders","unauthorized","unsupported","unsupported_media_type","view_only"],"x-scope":"emit","x-surface":"client"}},"/v1/orders/{id}/execute":{"post":{"description":"Se llama cuando el pago se confirmó. Emite la factura de lo que la orden validó, por el mismo camino de `POST /v1/invoices` (numeración, cupo, firma, límites, sandbox), en una transacción que bloquea la orden primero, y la deja `EXECUTED` con su `invoice_id`. La fecha de emisión es la del día si la orden no la trae. Facturar una orden ya facturada responde 200 con la misma factura (también si llegan dos a la vez). Antes de emitir se prepara de nuevo el documento: si sus importes cambiaron responde 409 `order_totals_changed` y no emite. Cualquier otro rechazo de la emisión deja la orden `OPEN` con ese problema en `last_error`.","parameters":[{"$ref":"#/components/parameters/OrderId"},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}},{"$ref":"#/components/parameters/SandboxOutcome"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderExecuteRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderExecution"}}},"description":"La orden ya estaba facturada: la misma factura"},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderExecution"}}},"description":"Factura emitida","headers":{"ETag":{"description":"La versión de la orden (`version`) entre comillas: la que acepta `If-Match`.","schema":{"examples":["\"3\""],"type":"string"}},"Location":{"description":"Ruta del CFE emitido","schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required`: la clave de API no tiene el permiso (`x-scope`) de la ruta. `errors[0].params` trae `required` (el que pide) y `granted` (los que tiene). También `forbidden` si el rol de la sesión no alcanza. También `feature_disabled` (la configuración del cliente lo apaga)."},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`order_not_found`"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`order_closed`: la orden no está `OPEN` (trae `state` e `invoice_id`). `order_version_mismatch`: `version` no es la de la orden (trae la orden actual). `order_amount_mismatch`: `paid_amount` no es el `payable` de la orden (trae `payable`, `paid_amount` y `currency`). `order_totals_changed`: preparado hoy, el documento da otros importes (trae `previous` y `amounts`); revise la orden con `PUT`. Lo que respondería `POST /v1/invoices` antes de tomar número, con los mismos códigos: `no_numbering`, `certificate_*`, `external_id_taken` (otra orden abierta o facturada, o una emisión, tiene ese `external_id`; trae `order_id` y `order_number` o `invoice_id`), idempotencia."},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_paid_amount`, `invalid_payment_reference`, o lo que respondería `POST /v1/invoices` (`invalid_cfe`, `rule_violation`)."},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"La réplica está al límite (`overloaded`): de pedidos en curso, de firmas simultáneas, o la espera de una conexión o de un bloqueo pasó su tope. No se reservó ningún número: vuelva a intentarlo después de `Retry-After` segundos, con la misma `Idempotency-Key`. `certificate_unavailable`: la clave del certificado del emisor no se puede abrir ahora (vault); también con `Retry-After`. `database_unavailable`: la base no contesta por un momento (failover); `restore_pending`: numeración detenida después de un restore. Siempre con `Retry-After`. `dgi_encryption_unavailable`: el CFE pide la zona K cifrada (`fiscal_complement.encrypted`) y el servicio no tiene el certificado público de la DGI de su ambiente (o venció); no se reservó número: emítalo sin cifrar o configure `CFE_DGI_ENCRYPTION_CERTIFICATE_PATH`.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"summary":"Factura una orden: emite su CFE","tags":["órdenes"],"x-error-codes":["account_suspended","bad_request","certificate_expired","certificate_missing","certificate_not_yet_valid","certificate_revoked","certificate_ruc_mismatch","certificate_unavailable","contingency_range_on_paper","database_unavailable","dgi_encryption_unavailable","external_id_required","external_id_taken","feature_disabled","forbidden","idempotency_key_reused","internal_error","invalid_body","invalid_cfe","invalid_environment","invalid_external_id","invalid_paid_amount","invalid_payment_reference","invalid_sandbox_outcome","limit_reached","membership_expired","membership_required","no_numbering","order_amount_mismatch","order_closed","order_not_found","order_totals_changed","order_version_mismatch","overloaded","payload_too_large","quota_exceeded","rate_limited","request_in_progress","restore_pending","rule_violation","sandbox_full","sandbox_not_available","scope_required","unauthorized","unsupported","unsupported_media_type","view_only"],"x-scope":"emit","x-surface":"client"}},"/v1/printing/logos":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrintLogoList"}}},"description":"Los logos"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"}},"summary":"Los logos de la cuenta, del más nuevo al más viejo","tags":["impreso"],"x-error-codes":["account_suspended","forbidden","internal_error","invalid_environment","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"post":{"description":"El tipo lo deciden los primeros bytes. Se decodifica con topes (4096 px por lado, 16 MP, memoria acotada), se aplica la orientación EXIF, se apoya sobre blanco, se achica a 1200 × 600 como máximo y se guarda como PNG RGB sin metadatos. Un SVG se dibuja una vez, sin textos, imágenes ni archivos externos, y nunca se guarda como SVG; sólo con formas, degradés, recortes y máscaras (sin filtros, patrones, marcadores, `use`, imágenes ni scripts), hasta 32 niveles de anidamiento y 2000 elementos: lo demás es `invalid_image` con el motivo. Cada subida pesa 5 pedidos del límite por minuto. Se guardan hasta 10 logos sin usar: subir otro borra el más viejo sin usar.","requestBody":{"content":{"image/jpeg":{"schema":{"contentMediaType":"image/jpeg","type":"string"}},"image/png":{"schema":{"contentMediaType":"image/png","type":"string"}},"image/svg+xml":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrintLogo"}}},"description":"El mismo PNG ya estaba: ese logo"},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrintLogo"}}},"description":"El logo nuevo"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required`: la clave no tiene `settings`; `forbidden` si la sesión no es `OWNER`. También `feature_disabled` (`printing.logo`, `printing.custom_template`) con cada campo en `errors[].path`."},"413":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`logo_too_large`: más de 1 MiB (`max_bytes`)"},"415":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`unsupported_image`: no es PNG, JPEG ni SVG"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_image`, `image_too_large` (`max_side`, `max_pixels`) o `image_too_small` (`min_side`)"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Sube un logo: PNG, JPEG o SVG, hasta 1 MiB (OWNER)","tags":["impreso"],"x-error-codes":["account_suspended","feature_disabled","forbidden","image_too_large","image_too_small","internal_error","invalid_body","invalid_environment","invalid_image","logo_too_large","overloaded","payload_too_large","rate_limited","sandbox_not_available","scope_required","unauthorized","unsupported_image","unsupported_media_type"],"x-scope":"settings","x-surface":"client"}},"/v1/printing/logos/{id}":{"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":"Borrado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`logo_in_use`: una versión lo usa y las reimpresiones lo necesitan"}},"summary":"Borra un logo que ninguna versión usa (OWNER)","tags":["impreso"],"x-error-codes":["account_suspended","bad_request","forbidden","internal_error","invalid_environment","logo_in_use","not_found","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"settings","x-surface":"client"}},"/v1/printing/logos/{id}/image":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"image/png":{"schema":{"contentMediaType":"image/png","type":"string"}}},"description":"El PNG guardado; nunca cambia (`Cache-Control: immutable`)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"El PNG de un logo","tags":["impreso"],"x-error-codes":["account_suspended","bad_request","forbidden","internal_error","invalid_environment","not_found","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/printing/preview":{"post":{"description":"El borrador (o la vigente) sobre un comprobante de ejemplo con los datos del emisor (e-Factura en A4, e-Ticket en rollo, con la leyenda «COMPROBANTE DE EJEMPLO») o sobre uno real de la cuenta (`invoice_id`), en PDF o como el ticket POS. No crea versión ni registra la impresión. Pesa 5 solicitudes en la ventana de la cuenta. Lo que la configuración no permite no se niega aquí: `x-cfe-print-preview-gated` lo nombra.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrintPreviewRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PosTicket"}},"application/octet-stream":{"schema":{"contentMediaType":"application/octet-stream","type":"string"}},"application/pdf":{"schema":{"format":"binary","type":"string"}},"text/plain":{"schema":{"type":"string"}}},"description":"El PDF (`output=pdf`) o el ticket (`output=pos`, como `GET /v1/invoices/{id}/pos`)","headers":{"x-cfe-print-preview-gated":{"description":"Las funciones que el borrador usa y la cuenta no tiene, separadas por comas (`printing.logo`, `printing.custom_template`)","schema":{"type":"string"}},"x-cfe-print-template-version":{"description":"La versión de la plantilla con que salió: un número (`0` es la de okCFE) o `draft` en una vista previa","schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Los de la plantilla (como el `PUT`), `invalid_format` (`pos` con `a4`), `invalid_output`, `invalid_encoding` o `thermal_paper_not_admitted`"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Vista previa de una plantilla, sin guardar nada","tags":["impreso"],"x-error-codes":["accent_too_light","account_suspended","bad_request","forbidden","internal_error","invalid_body","invalid_characters","invalid_color","invalid_encoding","invalid_environment","invalid_format","invalid_output","not_found","overloaded","payload_too_large","rate_limited","sandbox_not_available","scope_required","text_too_long","thermal_paper_not_admitted","too_many_lines","unauthorized","unknown_logo","unsupported_media_type"],"x-scope":"read","x-surface":"client"}},"/v1/printing/template":{"get":{"description":"Con la de okCFE (`defaults`), lo que la configuración permite (`features`) y los topes (`limits`). Una cuenta que nunca guardó una tiene la versión `0`.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrintTemplateVersion"}}},"description":"La vigente"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"}},"summary":"La plantilla del impreso vigente","tags":["impreso"],"x-error-codes":["account_suspended","forbidden","internal_error","invalid_environment","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"put":{"description":"Cada versión es inmutable: cada comprobante se reimprime siempre con la versión con que se imprimió por primera vez. Lo que exige el *Formato CFE* (zonas 1 a 5, RUC, QR, código de seguridad, CAE, leyendas) no se puede expresar.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrintTemplateInput"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrintTemplateVersion"}}},"description":"Igual a la vigente: no se hizo versión (`unchanged`)"},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrintTemplateVersion"}}},"description":"La versión nueva, ya vigente"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"`scope_required`: la clave no tiene `settings`; `forbidden` si la sesión no es `OWNER`. También `feature_disabled` (`printing.logo`, `printing.custom_template`) con cada campo en `errors[].path`."},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`template_conflict`: `base_version` ya no es la vigente (`current_version`)"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_color`, `accent_too_light`, `text_too_long`, `too_many_lines`, `invalid_characters`, `invalid_format` (todos en `errors[]` con `path` y `params`), `unknown_logo` o `invalid_body`"}},"summary":"Guarda una versión nueva de la plantilla (OWNER)","tags":["impreso"],"x-error-codes":["accent_too_light","account_suspended","bad_request","feature_disabled","forbidden","internal_error","invalid_body","invalid_characters","invalid_color","invalid_environment","invalid_format","overloaded","payload_too_large","sandbox_not_available","scope_required","template_conflict","text_too_long","too_many_lines","unauthorized","unknown_logo","unsupported_media_type"],"x-scope":"settings","x-surface":"client"}},"/v1/printing/template/versions":{"get":{"parameters":[{"in":"query","name":"limit","required":false,"schema":{"default":20,"maximum":100,"minimum":1,"type":"integer"}},{"description":"Las anteriores a esta versión (`next_before`)","in":"query","name":"before","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrintTemplateVersionList"}}},"description":"Una página"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"}},"summary":"Las versiones de la plantilla, de la más nueva a la más vieja","tags":["impreso"],"x-error-codes":["account_suspended","bad_request","forbidden","internal_error","invalid_body","invalid_environment","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/printing/template/versions/{version}":{"get":{"parameters":[{"description":"La versión; `0` es la de okCFE","in":"path","name":"version","required":true,"schema":{"minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrintTemplateVersion"}}},"description":"La versión"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Una versión de la plantilla","tags":["impreso"],"x-error-codes":["account_suspended","bad_request","forbidden","internal_error","invalid_environment","not_found","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/public/cfe":{"get":{"description":"Sin autenticación. Busca el CFE por RUC, tipo, serie y número y lo devuelve sólo si coinciden también el código de seguridad y el monto, como la consulta de la DGI desde el QR. Sólo los tipos que el emisor publica (`publication`). Cualquier diferencia es 404, sin decir qué no coincidió, con las mismas consultas y nunca antes de `CFE_PUBLIC_MIN_RESPONSE_MS` más una parte al azar: ni el cuerpo ni el tiempo dicen si el RUC es cliente. Limitado por dirección y para todas las direcciones juntas (`CFE_PUBLIC_LIMIT_GLOBAL`).","parameters":[{"$ref":"#/components/parameters/PublicRuc"},{"$ref":"#/components/parameters/PublicType"},{"$ref":"#/components/parameters/PublicSeries"},{"$ref":"#/components/parameters/PublicNumber"},{"$ref":"#/components/parameters/PublicCode"},{"$ref":"#/components/parameters/PublicAmount"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicVerification"}}},"description":"Comprobante verificado"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[],"summary":"Verifica un CFE publicado (JSON)","tags":["verificación pública"],"x-error-codes":["database_unavailable","internal_error","invalid_query","not_found","overloaded","rate_limited","restore_pending"],"x-surface":"public"}},"/v1/public/cfe/pdf":{"get":{"description":"Sin autenticación; mismos datos y reglas que `GET /v1/public/cfe`. Sale con la plantilla del emisor (`/v1/printing/template`), la versión con que se imprimió por primera vez (`x-cfe-print-template-version`).","parameters":[{"$ref":"#/components/parameters/PublicRuc"},{"$ref":"#/components/parameters/PublicType"},{"$ref":"#/components/parameters/PublicSeries"},{"$ref":"#/components/parameters/PublicNumber"},{"$ref":"#/components/parameters/PublicCode"},{"$ref":"#/components/parameters/PublicAmount"},{"$ref":"#/components/parameters/PaperFormat"}],"responses":{"200":{"content":{"application/pdf":{"schema":{"format":"binary","type":"string"}}},"description":"Archivo PDF","headers":{"x-cfe-print-template-version":{"description":"La versión de la plantilla con que salió: un número (`0` es la de okCFE) o `draft` en una vista previa","schema":{"type":"string"}}}},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`cfe_not_at_dgi_yet`: va primero a la DGI (e-Factura y sus notas, e-Resguardo, e-Remito, e-Ticket sobre 5.000 UI) y la DGI todavía no recibió su sobre; `cfe_not_deliverable`: un CFC, o un CFE rechazado o reemplazado"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[],"summary":"Representación impresa de un CFE publicado (PDF)","tags":["verificación pública"],"x-error-codes":["cfe_not_at_dgi_yet","cfe_not_deliverable","database_unavailable","internal_error","invalid_query","issuer_since_missing","not_found","overloaded","rate_limited","restore_pending","verification_site_missing"],"x-surface":"public"}},"/v1/public/cfe/print":{"get":{"description":"Sin autenticación; mismos datos y reglas que `GET /v1/public/cfe`. Permite al receptor volver a imprimir el comprobante (*Formato CFE*, p. 79). Sale con la plantilla del emisor (`/v1/printing/template`), la versión con que se imprimió por primera vez (`x-cfe-print-template-version`).","parameters":[{"$ref":"#/components/parameters/PublicRuc"},{"$ref":"#/components/parameters/PublicType"},{"$ref":"#/components/parameters/PublicSeries"},{"$ref":"#/components/parameters/PublicNumber"},{"$ref":"#/components/parameters/PublicCode"},{"$ref":"#/components/parameters/PublicAmount"},{"$ref":"#/components/parameters/PaperFormat"}],"responses":{"200":{"content":{"text/html":{"schema":{"type":"string"}}},"description":"HTML listo para imprimir","headers":{"x-cfe-print-template-version":{"description":"La versión de la plantilla con que salió: un número (`0` es la de okCFE) o `draft` en una vista previa","schema":{"type":"string"}}}},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`cfe_not_at_dgi_yet`: va primero a la DGI (e-Factura y sus notas, e-Resguardo, e-Remito, e-Ticket sobre 5.000 UI) y la DGI todavía no recibió su sobre; `cfe_not_deliverable`: un CFC, o un CFE rechazado o reemplazado"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[],"summary":"Representación impresa de un CFE publicado (HTML)","tags":["verificación pública"],"x-error-codes":["cfe_not_at_dgi_yet","cfe_not_deliverable","database_unavailable","internal_error","invalid_query","issuer_since_missing","not_found","overloaded","rate_limited","restore_pending","verification_site_missing"],"x-surface":"public"}},"/v1/public/pdf/{token}":{"get":{"description":"Sin autenticación: el token es la credencial, firmado por la API con el CFE y su generación, sin datos de la cuenta. Respeta la publicación de la cuenta (`printing.public_verification`): sólo los tipos que publica, nunca un CFC. Revocado o con una generación vieja es `404`, lo mismo que un token que no existe. Mismo límite por dirección que la verificación pública. `Cache-Control: private, no-store`, `Referrer-Policy: no-referrer`, `X-Robots-Tag: noindex`.","parameters":[{"in":"path","name":"token","required":true,"schema":{"maxLength":64,"type":"string"}},{"$ref":"#/components/parameters/PaperFormat"}],"responses":{"200":{"content":{"application/pdf":{"schema":{"format":"binary","type":"string"}}},"description":"Archivo PDF"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`bad_request`: el token está mal formado"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`cfe_not_at_dgi_yet`: va primero a la DGI y todavía no recibió su sobre; `cfe_not_deliverable`: rechazado o reemplazado"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[],"summary":"El PDF de un CFE por su link estable","tags":["verificación pública"],"x-error-codes":["bad_request","cfe_not_at_dgi_yet","cfe_not_deliverable","database_unavailable","internal_error","issuer_since_missing","not_found","overloaded","rate_limited","restore_pending","verification_site_missing"],"x-surface":"public"}},"/v1/public/verify":{"get":{"description":"Sin autenticación. Es la dirección que imprime el e-Ticket de un emisor sin sitio propio. Sin datos muestra el formulario (RUC, tipo, serie, número, código de seguridad y monto); con ellos, el resultado y los enlaces al comprobante. Cualquier dato que no coincida da el mismo mensaje que un RUC o un número inexistente; la página responde 200 con el mensaje, salvo el límite (429). Limitado por dirección (`CFE_PUBLIC_LIMIT_PER_IP` por minuto) y para todas juntas (`CFE_PUBLIC_LIMIT_GLOBAL`); una consulta no responde antes de `CFE_PUBLIC_MIN_RESPONSE_MS` más una parte al azar; las respuestas llevan `Cache-Control: no-store`, `Referrer-Policy: no-referrer` y `X-Robots-Tag: noindex`.","parameters":[{"description":"RUC del emisor (12 dígitos, con dígito verificador).","in":"query","name":"ruc","required":false,"schema":{"pattern":"^[0-9]{12}$","type":"string"}},{"description":"Tipo de CFE (Tabla A), por ejemplo 101.","in":"query","name":"type","required":false,"schema":{"type":"integer"}},{"description":"Serie del comprobante.","in":"query","name":"series","required":false,"schema":{"maxLength":2,"type":"string"}},{"description":"Número del comprobante.","in":"query","name":"number","required":false,"schema":{"maximum":9999999,"minimum":1,"type":"integer"}},{"description":"Código de seguridad: los 6 caracteres impresos debajo del QR (o el código completo).","in":"query","name":"code","required":false,"schema":{"minLength":6,"type":"string"}},{"description":"Monto total del comprobante, el del QR (A-C130 en el e-Ticket). Acepta `1234.50`, `1234,50` y `1.234,50`.","in":"query","name":"amount","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"text/html":{"schema":{"type":"string"}}},"description":"Formulario, o el resultado de la consulta: el comprobante encontrado o el motivo por el que no (ningún comprobante publicado coincide, o algún dato es inválido)"},"302":{"description":"Con `CFE_VERIFICATION_PAGE`: la página de verificación de la landing, con la misma consulta (`Location`). No busca nada.","headers":{"Location":{"schema":{"format":"uri","type":"string"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[],"summary":"Página de verificación de e-Tickets para el consumidor","tags":["verificación pública"],"x-error-codes":["database_unavailable","internal_error","overloaded","rate_limited","restore_pending"],"x-surface":"public"}},"/v1/rates":{"get":{"description":"Los que usan el reporte diario (Formato Reporte 1.B: comprador billete del cierre del día anterior a la operación, o del último día hábil) y el tope de 5.000 UI de los e-Ticket. El worker los carga del web service del BCU cada pocas horas. Por defecto los últimos 31 días; a lo sumo 400.","parameters":[{"in":"query","name":"currency","schema":{"type":"string"}},{"in":"query","name":"from","schema":{"format":"date","type":"string"}},{"in":"query","name":"to","schema":{"format":"date","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FiscalRates"}}},"description":"Cotizaciones"},"401":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Sin credenciales"},"403":{"$ref":"#/components/responses/ScopeRequired"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Rango inválido"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]},{"apiKey":[]}],"summary":"Tipos de cambio fiscales del BCU y valor de la UI","tags":["cuenta"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","invalid_sandbox_outcome","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/received-annulments":{"post":{"description":"El emisor avisa que la DGI rechazó CFE que ya había mandado (MR 3.4). Se valida la forma, que esté dirigida al tenant y la firma con el certificado de su `KeyInfo` (el único, o el firmante con su cadena); ese certificado no puede estar revocado ni, con `CFE_PKI_COUNTERPARTY_UNTRUSTED=enforce`, ser de una CA no acreditada, y si no trae RUC tiene que ser el de un sobre aceptado de ese emisor. Las copias aceptadas que nombra quedan con `annulled_at`. Los mismos bytes otra vez devuelven `200`.","requestBody":{"content":{"application/xml":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReceivedAnnulment"}}},"description":"Ya se había recibido"},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReceivedAnnulment"}}},"description":"Recibida"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"413":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Más de 3 MB"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`annulment_notice_invalid`: mal formada, para otro receptor, con firma inválida o con un certificado que no prueba al emisor"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Recibe una comunicación de anulación (CFEs_Anulados_x_RechazoDGI)","tags":["recepción"],"x-error-codes":["account_suspended","annulment_notice_invalid","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"receive","x-surface":"client"}},"/v1/received-documents":{"get":{"description":"Los CFE de los sobres `AS`, los más recientes primero. `from`/`to` filtran por fecha de emisión.","parameters":[{"description":"RUC del emisor que los mandó","in":"query","name":"issuer_ruc","required":false,"schema":{"pattern":"^[0-9]{12}$","type":"string"}},{"in":"query","name":"state","required":false,"schema":{"enum":["AE","BE"],"type":"string"}},{"description":"Emitidos desde (`YYYY-MM-DD`, inclusive)","in":"query","name":"from","required":false,"schema":{"format":"date","type":"string"}},{"description":"Emitidos hasta (`YYYY-MM-DD`, inclusive)","in":"query","name":"to","required":false,"schema":{"format":"date","type":"string"}},{"in":"query","name":"limit","required":false,"schema":{"default":200,"maximum":1000,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ReceivedDocument"},"type":"array"}}},"description":"CFE recibidos"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"422":{"$ref":"#/components/responses/Unprocessable"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"CFE recibidos","tags":["recepción"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/received-documents/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReceivedDocument"}}},"description":"CFE recibido"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Un CFE recibido, con su adenda","tags":["recepción"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/received-documents/{id}/xml":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/xml":{"schema":{"type":"string"}}},"description":"CFE firmado","headers":{"content-disposition":{"description":"`attachment; filename=\"CFE_<RUC>_<tipo>_<serie><número>.xml\"`","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"El CFE firmado, tal como lo firmó su emisor","tags":["recepción"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/received-envelopes":{"get":{"description":"Los más recientes primero, sin sus CFE.","parameters":[{"description":"RUC del emisor que los mandó","in":"query","name":"issuer_ruc","required":false,"schema":{"pattern":"^[0-9]{12}$","type":"string"}},{"in":"query","name":"state","required":false,"schema":{"enum":["AS","BS"],"type":"string"}},{"description":"Recibidos desde (`YYYY-MM-DD`, inclusive)","in":"query","name":"from","required":false,"schema":{"format":"date","type":"string"}},{"description":"Recibidos hasta (`YYYY-MM-DD`, inclusive)","in":"query","name":"to","required":false,"schema":{"format":"date","type":"string"}},{"in":"query","name":"limit","required":false,"schema":{"default":200,"maximum":1000,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/Reception"},"type":"array"}}},"description":"Recepciones"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"422":{"$ref":"#/components/responses/Unprocessable"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Sobres recibidos","tags":["recepción"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"post":{"description":"Desde la vigencia de su autorización todo emisor es receptor electrónico de los CFE a su nombre (Instructivo v11, p. 13 y 16). El cuerpo es el `EnvioCFE_entreEmpresas` tal como llegó (hasta 3 MB; el sobre admite 2 MB y uno mayor se responde con `S07`).\n\nSe valida el sobre con los motivos que usa un receptor (tabla 4.2): `S01` formato, `S02` RUC del receptor, del emisor, del certificado o de los CFE, `S03` certificado ilegible o no vigente, `S04` formato de la carátula, `S05` cantidad, `S06` CFE firmado con otro certificado, `S07` tamaño y `S20` sobre ya recibido (mismo RUC e `Idemisor` que uno aceptado). Si el sobre es `AS`, cada CFE (tabla 4.3): `E02` ya recibido y aceptado (o repetido en el sobre; el detalle nombra la respuesta original), `E03` número fuera del CAE, `E04` firma inválida, `E05` formato, `E07` firmado después del vencimiento del CAE, `E10` tipo de cambio que falta o no tiene la forma de A-C111 (o de F-C10) y `E11` CAE especial que no corresponde con el CFE (G-C5, G-C6, `MntBruto`, `IndFact`). Contra lo recibido antes: `E03` y `E11` si el mismo CAE se vio en un CFE del mismo tipo y serie con otro rango, vencimiento o `CAEEspecial` (otro tipo o serie con el mismo `CAE_ID` no se compara); `E12` si una referencia nombra un CFE del emisor que no se recibió, que su emisor anuló, o cuya fecha, moneda, monto o tipo de cambio no son los recibidos; `E06` si el total supera el múltiplo del mayor aceptado del emisor que fijó el tenant. `E06` y `E12` se configuran en `PUT /v1/reception-rules`.\n\nLas dos respuestas (`ACKSobre` y, si es `AS`, `ACKCFE`) se firman con el certificado del tenant al recibir, se guardan y se descargan siempre iguales; se encolan por correo a la dirección de intercambio del emisor cuando se conoce (`send_answers`; ver `GET /v1/exchange/messages`). Los mismos bytes otra vez devuelven `200` con la recepción original. Un sobre rechazado entero también es una recepción (`201`, `state: BS`).","parameters":[{"description":"Nombre del archivo recibido (`NomArch` de las respuestas). También en `X-File-Name`.","in":"query","name":"file_name","required":false,"schema":{"maxLength":40,"type":"string"}},{"description":"Encolar las dos respuestas a la dirección de intercambio del emisor, si se conoce (`GET /v1/exchange/messages?received_envelope_id=`)","in":"query","name":"send_answers","required":false,"schema":{"default":true,"type":"boolean"}}],"requestBody":{"content":{"application/xml":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Reception"}}},"description":"Los mismos bytes ya se habían recibido: la recepción original"},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Reception"}}},"description":"Recibido y respondido"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`certificate_missing`, `certificate_expired`, `certificate_not_yet_valid`: sin certificado para firmar las respuestas (no se guarda nada); `reception_conflict`: reintentar"},"413":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Más de 3 MB"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`envelope_unaddressable`: el sobre no indica a qué RUC emisor responder; no se guarda"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`certificate_unavailable`: el certificado no se puede abrir ahora `database_unavailable`: la base no contesta por un momento (failover); `restore_pending`: numeración detenida después de un restore. Siempre con `Retry-After`.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"summary":"Recibe un sobre de otro emisor y lo responde","tags":["recepción"],"x-error-codes":["account_suspended","bad_request","certificate_expired","certificate_missing","certificate_not_yet_valid","certificate_unavailable","database_unavailable","envelope_unaddressable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","limit_reached","overloaded","payload_too_large","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"receive","x-surface":"client"}},"/v1/received-envelopes/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Reception"}}},"description":"Recepción"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Una recepción con sus CFE","tags":["recepción"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/received-envelopes/{id}/documents-ack":{"get":{"description":"`AE` o `BE` (con hasta 10 motivos) por cada CFE de un sobre `AS`. Válido contra `ACKCFE_Partes.xsd`. Un sobre `BS` no tiene (`404`), ni uno cuyo `ACKCFE` espera los CFE que referencian sus notas (`documents_answer_due_at`).","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/xml":{"schema":{"type":"string"}}},"description":"`ACKCFE`","headers":{"content-disposition":{"description":"`attachment; filename=\"ME_<IDRespuesta>_Sob_<RUC>_<AAAAMMDD>_<Idemisor>.xml\"`","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Respuesta por comprobante (ACKCFE) firmada","tags":["recepción"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/received-envelopes/{id}/envelope-ack":{"get":{"description":"`AS` con `ParamConsulta`, o `BS` con los motivos. Válido contra `ACKSobre.xsd`, firmado con el certificado del tenant, que viaja en `KeyInfo`.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/xml":{"schema":{"type":"string"}}},"description":"`ACKSobre`","headers":{"content-disposition":{"description":"`attachment; filename=\"M_<IDRespuesta>_Sob_<RUC>_<AAAAMMDD>_<Idemisor>.xml\"`","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Acuse del sobre (ACKSobre) firmado","tags":["recepción"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/received-envelopes/{id}/rejections":{"post":{"description":"Un `ACKCFE` posterior, firmado con el certificado del tenant, con `BE` y los motivos de cada CFE nombrado (MR p. 8: la respuesta por comprobante «puede ser generado en múltiples mensajes»; tabla 4.3: `E02`-`E07`, `E10`-`E12` y los comerciales `E20`-`E60`). Solo CFE aceptados al recibirlos (`AE`), una vez cada uno y nunca uno que su emisor ya anuló. El CFE sigue siendo válido para la DGI: se corrige con una nota de crédito. Se encola al emisor si se conoce su dirección.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommercialRejectionRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommercialRejection"}}},"description":"Rechazo firmado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`cfe_not_rejectable`: rechazado al recibirlo, ya rechazado o anulado por su emisor; `answer_pending`: el `ACKCFE` de la recepción todavía espera los CFE que referencian sus notas; `certificate_missing`"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_cfe`: un código que un receptor no usa, un CFE de otra recepción, sin motivos"}},"summary":"Rechazo comercial de CFE recibidos","tags":["recepción","intercambio"],"x-error-codes":["account_suspended","answer_pending","bad_request","certificate_missing","cfe_not_rejectable","feature_disabled","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","not_found","overloaded","payload_too_large","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"receive","x-surface":"client"}},"/v1/received-envelopes/{id}/xml":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/xml":{"schema":{"type":"string"}}},"description":"Los bytes recibidos","headers":{"content-disposition":{"description":"`attachment; filename=\"<NomArch>\"`","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"El sobre tal como se recibió","tags":["recepción"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/received-rejections/{id}/xml":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/xml":{"schema":{"type":"string"}}},"description":"El XML","headers":{"content-disposition":{"description":"`attachment; filename=\"…\"`","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"El ACKCFE firmado de un rechazo comercial","tags":["recepción","intercambio"],"x-error-codes":["account_suspended","bad_request","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/reception-rules":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReceptionRules"}}},"description":"Reglas de la recepción"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"}},"summary":"Qué rechaza sola la recepción (E06, E10 contra el BCU, E12)","tags":["recepción"],"x-error-codes":["account_suspended","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"put":{"description":"Vale para los sobres que se reciban desde ese momento.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReceptionRules"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReceptionRules"}}},"description":"Reglas de la recepción"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"}},"summary":"Cambia qué rechaza sola la recepción (OWNER o clave de API)","tags":["recepción"],"x-error-codes":["account_suspended","bad_request","feature_disabled","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","overloaded","payload_too_large","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"receive","x-surface":"client"}},"/v1/reports":{"get":{"description":"Los más recientes primero. Con `date`, solo los de esa fecha de resumen (las correcciones incluidas).","parameters":[{"description":"`YYYY-MM-DD`","in":"query","name":"date","required":false,"schema":{"format":"date","type":"string"}},{"description":"Hasta 200; 50 por defecto","in":"query","name":"limit","required":false,"schema":{"maximum":200,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/Report"},"type":"array"}}},"description":"Reportes"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"422":{"$ref":"#/components/responses/Unprocessable"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Reportes diarios","tags":["entrega"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","invalid_sandbox_outcome","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"post":{"description":"Encola el reporte de una fecha y responde `202` con el reporte para consultar en `GET /v1/reports/{id}` (cabecera `Location`); el worker lo arma, lo firma y lo envía. Con `wait: true` responde `200` cuando la DGI contestó (o `202` si todavía no puede terminar).\n\nIncluye los CFE firmados ese día (fecha de `TmstFirma`, hora de Uruguay) y los números anulados ese día. Los CFE sin respuesta de la DGI no son emitidos todavía: el reporte los espera (`WAITING`); con `force` o pasado `max_wait_minutes` sale sin ellos y lo dice en `pending` y `warnings`. Un día sin comprobantes también se reporta (`records: 0`).\n\nSi el reporte de esa fecha ya está en camino, devuelve ese mismo. La secuencia no se repite: la DGI recibe una sola por fecha y una corrección va con la siguiente.","requestBody":{"content":{"application/json":{"schema":{"properties":{"date":{"description":"Por defecto, ayer. Entre 2011-10-01 y hoy (R06)","format":"date","type":"string"},"force":{"default":false,"description":"Enviar aunque haya CFE de ese día sin respuesta de la DGI (quedan fuera)","type":"boolean"},"max_wait_minutes":{"description":"Esperar a esos CFE a lo sumo este tiempo y después enviar sin ellos. Sin este campo ni `force`, espera a que la DGI conteste todos","minimum":0,"type":"integer"},"sequence":{"description":"Por defecto, la siguiente al último reporte de ese día que la DGI recibió (`AR`)","maximum":99,"minimum":1,"type":"integer"},"wait":{"default":false,"description":"Responder con la respuesta de la DGI (`200`) en lugar de al encolar (`202`)","type":"boolean"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"}}},"description":"Con `wait`: la DGI contestó (`RECEIVED` o `REJECTED`), o no se pudo enviar (`FAILED`)"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"}}},"description":"Reporte encolado o en camino; con `wait`, también cuando no hay un lugar libre hacia la DGI en 5 s: el worker lo envía","headers":{"Location":{"description":"`/v1/reports/{id}`","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`sequence_used`: la DGI ya recibió esa secuencia de esa fecha; `report_in_progress`: el reporte de esa fecha ya está en camino con otra secuencia; el emisor no puede firmar (`certificate_missing`, `certificate_expired`)"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Fecha fuera de rango (`report_date_out_of_range`, `field` = `FechaResumen`), secuencia fuera de 1-99 (`sequence_out_of_range`, `field` = `SecEnvio`) o fecha inválida"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Encola el reporte diario","tags":["entrega"],"x-error-codes":["account_suspended","certificate_expired","certificate_missing","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","report_date_out_of_range","restore_pending","sandbox_not_available","scope_required","sequence_out_of_range","sequence_used","unauthorized","unsupported_media_type"],"x-scope":"reports","x-surface":"client"}},"/v1/reports/schedule":{"get":{"description":"Sin configurar, está apagado (`enabled: false`).","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportSchedule"}}},"description":"Programación"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Reporte diario automático","tags":["entrega"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"put":{"description":"Cada día, desde `send_at` (hora de Uruguay), el worker encola el reporte del día anterior si la DGI todavía no recibió uno. Espera a los CFE sin respuesta hasta `max_wait_minutes` después del fin del día; después sale sin ellos y, cuando la DGI los contesta, envía la corrección (secuencia + 1). Solo OWNER (o clave de API).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportScheduleRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportSchedule"}}},"description":"Programación guardada"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_time` (`send_at` no es HH:MM) o `invalid_wait` (`max_wait_minutes` fuera de 0-10080)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Prende o apaga el reporte diario automático","tags":["entrega"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","invalid_time","overloaded","payload_too_large","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"reports","x-surface":"client"}},"/v1/reports/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"}}},"description":"Reporte"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Un reporte diario","tags":["entrega"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","invalid_sandbox_outcome","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/reports/{id}/dgi-exchanges":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DgiExchangePage"}}},"description":"Las llamadas (`next_cursor` siempre null; hasta 200)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/SessionRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Las llamadas a la DGI de un reporte diario del tenant, las más viejas primero (solo sesión)","tags":["entrega"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","internal_error","invalid_environment","not_found","overloaded","restore_pending","session_required","unauthorized"],"x-surface":"portal"}},"/v1/reports/{id}/events":{"get":{"description":"Eventos del reporte y de su fecha, del más viejo al más nuevo: un `R05` que adelantó la secuencia, una reliquidación, el piso que fijó un restore, \"Reporte Procesado\".","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ReportEvent"},"type":"array"}}},"description":"Eventos"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Historia de la secuencia y del contenido de un reporte","tags":["entrega"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/reports/{id}/processed":{"post":{"description":"Registra que el portal de la DGI muestra el reporte como \"Reporte Procesado\" (Instructivo v11 p. 8: Consulta / Envíos Realizados / Procesar Reporte). La DGI no publica un servicio web que lo devuelva, por eso lo registra el operador. Sólo un reporte recibido (`AR`) que no quedó reliquidado (`409 report_not_received` si no); repetirlo conserva el primer registro. Un reporte en \"Reporte en Gestión\" (`ER`, Preguntas frecuentes 9.7) se termina desde la consola de okCFE, con la comunicación de la DGI: aquí responde `409 report_in_management`. Sólo el dueño.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportProcessedRequest"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"}}},"description":"Reporte"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Registrar \"Reporte Procesado\"","tags":["entrega"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","not_found","overloaded","payload_too_large","report_in_management","report_not_received","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"reports","x-surface":"client"}},"/v1/reports/{id}/xml":{"get":{"description":"Se guarda antes de enviarlo y se reenvía byte por byte. `404` mientras no está armado.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/xml":{"schema":{"type":"string"}}},"description":"Reporte firmado","headers":{"x-xml-sha256":{"description":"SHA-256 del cuerpo","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Reporte firmado, tal como se envió","tags":["entrega"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/sandbox":{"delete":{"description":"`confirm` es el RUC de la cuenta. Las claves de prueba siguen y la numeración vuelve a 1.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxPurgeRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxPurge"}}},"description":"Purgado: el sandbox sigue, vacío, con sus claves"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Una clave (`session_required`) o un usuario que no es dueño (`forbidden`)"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`confirmation_required`: falta `confirm` o no es el RUC de la cuenta"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Purga el sandbox: borra todos sus comprobantes, eventos, envíos, devoluciones y numeración, sin tocar nada real","tags":["cuenta"],"x-error-codes":["account_suspended","confirmation_required","database_unavailable","forbidden","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","restore_pending","session_required","unauthorized","unsupported_media_type","view_only"],"x-surface":"portal"},"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxOverview"}}},"description":"El sandbox"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Una clave (`session_required`) o un usuario que no es dueño (`forbidden`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"El sandbox de la cuenta: claves de prueba, comprobantes, numeración (sesión de un dueño)","tags":["cuenta"],"x-error-codes":["account_suspended","database_unavailable","forbidden","internal_error","invalid_environment","overloaded","restore_pending","session_required","unauthorized"],"x-surface":"portal"}},"/v1/schemas/cfe-pos-1.json":{"get":{"responses":{"200":{"content":{"application/schema+json":{"schema":{"type":"object"}}},"description":"El schema (draft 2020-12) con que se valida el JSON de `GET /v1/invoices/{id}/pos`"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[],"summary":"JSON Schema del ticket POS cfe-pos/1","tags":["operación"],"x-error-codes":["database_unavailable","internal_error","overloaded","restore_pending"],"x-surface":"public"}},"/v1/submissions":{"get":{"description":"Cada solicitud cuenta como 3 en el límite por minuto del plan.","parameters":[{"in":"query","name":"limit","schema":{"default":50,"maximum":200,"type":"integer"}},{"in":"query","name":"offset","schema":{"default":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/Submission"},"type":"array"}}},"description":"Envíos recientes"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Sobres y reportes enviados","tags":["entrega"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","invalid_sandbox_outcome","overloaded","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/submissions/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionDetail"}}},"description":"Envío y resultados"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Detalle de un envío con el resultado por documento","tags":["entrega"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","invalid_sandbox_outcome","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/submissions/{id}/dgi-exchanges":{"get":{"description":"Envío, reintentos y consultas del estado. Solo lectura; una clave de API recibe `403`.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DgiExchangePage"}}},"description":"Las llamadas (`next_cursor` siempre null; hasta 200)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/SessionRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Las llamadas a la DGI de un sobre del tenant, las más viejas primero (solo sesión)","tags":["entrega"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","internal_error","invalid_environment","not_found","overloaded","restore_pending","session_required","unauthorized"],"x-surface":"portal"}},"/v1/tenant":{"get":{"description":"Lo que la emisión completa en `Emisor` cuando la solicitud no lo trae. La sucursal (`CdgDGISucur`), la ciudad y el departamento nunca se suponen: sin ellos la emisión responde 422 nombrando el campo (`missing` dice cuáles faltan).","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantProfile"}}},"description":"Perfil"},"403":{"$ref":"#/components/responses/ScopeRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]},{"apiKey":[]}],"summary":"Perfil del emisor (domicilio, sucursales, datos de `Emisor` y del impreso)","tags":["usuarios"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized","view_session_invalid"],"x-scope":"read","x-surface":"client"},"patch":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTenantProfile"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantProfile"}}},"description":"Perfil actualizado"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Rol insuficiente"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Datos inválidos"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Actualiza el perfil del emisor (solo OWNER)","tags":["usuarios"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","limit_reached","overloaded","payload_too_large","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type","view_only"],"x-scope":"settings","x-surface":"client"}},"/v1/tenant/certificate":{"get":{"description":"Cualquier usuario del tenant o una API key. Solo metadatos: la clave privada nunca sale de la plataforma.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CertificateStatus"}}},"description":"Estado del certificado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]},{"apiKey":[]}],"summary":"Certificado de firma del emisor: estado, vencimiento e historial","tags":["usuarios"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"put":{"description":"El certificado nuevo pasa a ser el activo y el anterior queda en el historial: los CFE firmados con él antes de la rotación se envían en sobres con ese mismo certificado (`S06`). La clave privada se guarda cifrada (AES-256-GCM, con la clave de datos envuelta por la clave maestra). Subir el mismo certificado otra vez responde 200 sin cambiar nada. Una API key no puede: responde 403. Antes de guardarlo se verifica su cadena hasta las CA acreditadas de PKI Uruguay y su revocación (CRL de la CA, u OCSP); el resultado vuelve en `chain` y `revocation`. El RUC se lee del `serialNumber` del subject (`RUC` + 12 dígitos, política de Persona Jurídica de la UCE).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CertificateUpload"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CertificateStatus"}}},"description":"Era el mismo certificado activo; nada cambió"},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CertificateStatus"}}},"description":"Certificado nuevo activo"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El certificado no sirve para este emisor. `code`: `invalid_certificate` (ilegible o falta un campo), `certificate_password` (contraseña del PKCS#12 incorrecta), `certificate_without_integrity` (el PKCS#12 no tiene MAC de integridad), `certificate_key_mismatch` (la clave no es la del certificado), `certificate_key_type` (no es RSA), `certificate_key_size` (una clave RSA de menos de 2048 o más de 8192 bits), `certificate_signature_algorithm` (su autoridad lo firmó con SHA-1, MD2 o MD5, que la DGI no acepta desde el 01/01/2018: Preguntas frecuentes 4.15), `certificate_without_ruc`, `certificate_ruc_mismatch` (el RUC del subject no es el del emisor; la DGI respondería `S02`), `certificate_expired`, `certificate_not_yet_valid`, `certificate_untrusted` (no encadena a una CA acreditada de PKI Uruguay; solo con `CFE_PKI_TENANT_CHAIN=enforce`, el valor por defecto en producción; `chain_code` dice por qué, con los códigos de `chain.code`), `certificate_revoked` (la CRL o el OCSP de su CA lo da por revocado; la DGI respondería `S03`)"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`certificate_storage_unavailable`: falta CFE_MASTER_KEY o el vault no responde `database_unavailable`: la base no contesta por un momento (failover); `restore_pending`: numeración detenida después de un restore. Siempre con `Retry-After`.","headers":{"Retry-After":{"schema":{"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"Sube o rota el certificado de firma (solo OWNER del portal)","tags":["usuarios"],"x-error-codes":["account_suspended","bad_request","certificate_expired","certificate_key_mismatch","certificate_key_size","certificate_key_type","certificate_not_yet_valid","certificate_password","certificate_revoked","certificate_ruc_mismatch","certificate_signature_algorithm","certificate_untrusted","certificate_without_integrity","certificate_without_ruc","code","database_unavailable","forbidden","internal_error","invalid_body","invalid_certificate","invalid_environment","overloaded","payload_too_large","restore_pending","sandbox_not_available","session_required","unauthorized","unsupported_media_type"],"x-surface":"portal"}},"/v1/tenant/dgi-contacts":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/DgiContact"},"type":"array"}}},"description":"Actualizaciones"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"}},"summary":"Actualizaciones de contactos en la DGI, las más nuevas primero","tags":["intercambio"],"x-error-codes":["account_suspended","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"post":{"description":"`EFACSOLACTUALIZARCONTACTO` (Servicios Web Externos DGI v1.9, p. 3-5) con el código 19 (URL del web service) o 20 (mail de contacto técnico), firmado con WS-Security con el certificado del tenant. `201` cuando la DGI respondió (`accepted` dice si lo tomó); cada llamada queda registrada. Una respuesta ambigua no se repite.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DgiContactRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DgiContact"}}},"description":"La DGI respondió"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Código o valor inválidos"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`dgi_unavailable`: la DGI no respondió (queda registrada como `FAILED`)"},"503":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`dgi_contact_unavailable`: falta `CFE_DGI_SOLICITUD_ENDPOINT`"}},"summary":"Actualiza un contacto del emisor en la DGI (ws_efacsolicitud) (solo OWNER)","tags":["intercambio"],"x-error-codes":["account_suspended","dgi_contact_unavailable","dgi_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","overloaded","payload_too_large","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"settings","x-surface":"client"}},"/v1/tenant/features":{"get":{"description":"Cada función de la configuración (`features[]`) con el valor que rige, su valor por defecto y de dónde sale (`default`, `membership` u `override`). Un cambio de la consola rige en la petición siguiente en todas las réplicas y avisa `tenant.configuration_changed`.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantFeatures"}}},"description":"Configuración"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"}},"summary":"Qué tiene habilitado el cliente: cada función con su valor y de dónde sale","tags":["configuración"],"x-error-codes":["account_suspended","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"patch":{"description":"Sólo las funciones con `editable_by: owner` (formatos de impresión, verificación pública, envío automático, rechazo comercial automático, reporte diario automático). Las demás dan `403 feature_staff_only` en `errors[]`.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantFeaturesRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantFeatures"}}},"description":"Configuración, con lo que cambió"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`forbidden` (MEMBER), `feature_staff_only` o `scope_required`"},"422":{"$ref":"#/components/responses/Unprocessable"}},"summary":"Cambia las preferencias del cliente (OWNER o clave con `settings`)","tags":["configuración"],"x-error-codes":["account_suspended","feature_disabled","feature_staff_only","forbidden","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","sandbox_not_available","scope_required","unauthorized","unsupported_media_type"],"x-scope":"settings","x-surface":"client"}},"/v1/tenant/publication":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Publication"}}},"description":"Publicación"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"}},"summary":"Publicación web de los CFE y sitio que imprime el e-Ticket","tags":["usuarios"],"x-error-codes":["account_suspended","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"put":{"requestBody":{"content":{"application/json":{"schema":{"properties":{"publication":{"enum":["e_tickets","all","none"],"type":"string"}},"required":["publication"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Publication"}}},"description":"Publicación"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"}},"summary":"Elige qué CFE publica la página pública (OWNER)","tags":["usuarios"],"x-error-codes":["account_suspended","bad_request","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","overloaded","payload_too_large","sandbox_not_available","scope_required","unauthorized","unsupported_media_type","verification_site_required"],"x-scope":"settings","x-surface":"client"}},"/v1/tenant/readiness":{"get":{"description":"Certificado (presente, válido, días que le quedan), CAE por tipo y serie (presente, números que quedan, vencimiento), sucursal por defecto, tipos habilitados por la configuración y estado y topes de la membresía. Cada chequeo trae un `code` estable y un mensaje en el idioma de la solicitud. No reserva ni escribe nada: la emisión decide igual. Para mostrar al instalar un conector y antes de empezar a emitir.","parameters":[{"description":"Días hacia adelante que cuentan como \"por vencer\" (certificado y CAE); 30 por defecto, de 1 a 365","in":"query","name":"days","schema":{"default":30,"maximum":365,"minimum":1,"type":"integer"}},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantReadiness"}}},"description":"El estado de la cuenta"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Si la cuenta puede emitir, chequeo por chequeo","tags":["cuenta"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/test-users":{"get":{"description":"Un usuario de prueba entra siempre al ambiente de pruebas de la cuenta y ve sólo lo de pruebas; los demás, siempre la cuenta real. Hasta 3 por cuenta (`max_users`). No están en `GET /v1/users` ni cuentan en los usuarios de la membresía.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestUsers"}}},"description":"Los usuarios de prueba"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Una clave (`session_required`), un usuario que no es dueño (`forbidden`) o un usuario de prueba (`sandbox_not_available`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Usuarios de prueba de la cuenta (sesión del dueño, en producción)","tags":["usuarios"],"x-error-codes":["account_suspended","database_unavailable","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","session_required","unauthorized"],"x-surface":"portal"},"post":{"description":"Con el primero se crea el ambiente de pruebas de la cuenta, como con la primera clave de prueba. Funciona con la membresía vencida o sin membresía; no con la cuenta suspendida.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTestUser"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestUser"}}},"description":"Usuario de prueba creado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Una clave (`session_required`), un usuario que no es dueño (`forbidden`) o un usuario de prueba (`sandbox_not_available`)"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`test_users_limit`: la cuenta ya tiene 3 (`max_users`); `email_taken`: el correo ya es de un usuario"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Correo, nombre o contraseña inválidos"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Crea un usuario de prueba: entra siempre al ambiente de pruebas","tags":["usuarios"],"x-error-codes":["account_suspended","database_unavailable","email_taken","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","overloaded","payload_too_large","restore_pending","sandbox_not_available","session_required","test_users_limit","unauthorized","unsupported_media_type","view_only"],"x-surface":"portal"}},"/v1/test-users/{id}":{"delete":{"description":"Las claves de prueba que creó se revocan con él; las de otro usuario de prueba o del equipo siguen.","responses":{"204":{"description":"Eliminado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Una clave (`session_required`), un usuario que no es dueño (`forbidden`) o un usuario de prueba (`sandbox_not_available`)"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Elimina un usuario de prueba y cierra sus sesiones","tags":["usuarios"],"x-error-codes":["account_suspended","bad_request","database_unavailable","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","session_required","unauthorized","view_only"],"x-surface":"portal"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}]},"/v1/test-users/{id}/password":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"post":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestUserPassword"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestUser"}}},"description":"Contraseña cambiada"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Una clave (`session_required`), un usuario que no es dueño (`forbidden`) o un usuario de prueba (`sandbox_not_available`)"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Contraseña inválida"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Le da una contraseña nueva a un usuario de prueba y cierra sus sesiones","tags":["usuarios"],"x-error-codes":["account_suspended","bad_request","database_unavailable","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","not_found","overloaded","payload_too_large","restore_pending","sandbox_not_available","session_required","unauthorized","unsupported_media_type","view_only"],"x-surface":"portal"}},"/v1/usage":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usage"}}},"description":"Consumo"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Plan y consumo del mes","tags":["cuenta"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/users":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/User"},"type":"array"}}},"description":"Usuarios"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Rol insuficiente"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Usuarios del tenant (solo OWNER)","tags":["usuarios"],"x-error-codes":["account_suspended","database_unavailable","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","session_required","unauthorized"],"x-surface":"portal"},"post":{"description":"Crea una invitación pendiente y le manda a la persona un enlace de un solo uso (7 días) para elegir su contraseña y sumarse. La respuesta es la misma exista o no ese correo en otra empresa de la plataforma: sólo quien sigue el enlace lo sabe, al aceptar (`409 email_unavailable`). Sin correo configurado, la respuesta trae el enlace (`link`) esta única vez. Una invitación anterior a la misma persona queda sin efecto. Las invitaciones pendientes cuentan para los usuarios de la membresía (`409 limit_reached`).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUser"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamInvitationSent"}}},"description":"Invitación enviada"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Rol insuficiente"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Ya es parte del equipo (`already_member`) o la membresía no admite más usuarios (`limit_reached`)"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Datos inválidos"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El correo no salió (`mail_not_sent`): no se creó nada"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Invita a una persona al equipo (solo OWNER)","tags":["usuarios"],"x-error-codes":["account_suspended","already_member","database_unavailable","forbidden","internal_error","invalid_body","invalid_cfe","invalid_environment","limit_reached","mail_not_sent","overloaded","payload_too_large","restore_pending","sandbox_not_available","session_required","unauthorized","unsupported_media_type"],"x-surface":"portal"}},"/v1/users/invitations":{"get":{"description":"Las pendientes y las vencidas (para reenviarlas), las más nuevas primero. Nunca traen el enlace.","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/TeamInvitation"},"type":"array"}}},"description":"Invitaciones"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Rol insuficiente"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Invitaciones al equipo sin aceptar (solo OWNER)","tags":["usuarios"],"x-error-codes":["account_suspended","database_unavailable","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","session_required","unauthorized"],"x-surface":"portal"}},"/v1/users/invitations/{id}":{"delete":{"description":"El enlace deja de servir.","responses":{"204":{"description":"Revocada"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Rol insuficiente"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Revoca una invitación (solo OWNER)","tags":["usuarios"],"x-error-codes":["account_suspended","database_unavailable","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","session_required","unauthorized"],"x-surface":"portal"},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}]},"/v1/users/invitations/{id}/resend":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"post":{"description":"Un enlace nuevo por 7 días más; el anterior deja de servir. Sin correo configurado, la respuesta trae el enlace esta única vez.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamInvitationSent"}}},"description":"Reenviada"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Rol insuficiente"},"404":{"$ref":"#/components/responses/NotFound"},"502":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"El correo no salió (`mail_not_sent`)"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Reenvía una invitación (solo OWNER)","tags":["usuarios"],"x-error-codes":["account_suspended","database_unavailable","forbidden","internal_error","invalid_environment","limit_reached","mail_not_sent","not_found","overloaded","restore_pending","sandbox_not_available","session_required","unauthorized"],"x-surface":"portal"}},"/v1/users/{id}":{"patch":{"description":"Nunca deja al tenant sin un OWNER activo. Un MEMBER siempre se puede editar; solo se rechaza (`409 last_owner`) dejar al tenant sin OWNER activo o que un usuario se degrade o desactive a sí mismo.","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"active":{"type":"boolean"},"role":{"enum":["OWNER","MEMBER"],"type":"string"}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}},"description":"Usuario actualizado"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Rol insuficiente"},"404":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No existe"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Último owner"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"bearerAuth":[]}],"summary":"Activa/desactiva o cambia el rol de un usuario","tags":["usuarios"],"x-error-codes":["account_suspended","bad_request","database_unavailable","internal_error","invalid_body","invalid_environment","last_owner","not_found","overloaded","payload_too_large","restore_pending","sandbox_not_available","session_required","unauthorized","unsupported_media_type"],"x-surface":"portal"}},"/v1/webhooks":{"get":{"description":"Los destinos de la cuenta, del más viejo al más nuevo, sin sus secretos.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookList"}}},"description":"Los destinos"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Los destinos de webhook","tags":["webhooks"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"post":{"description":"Un destino nuevo, con su URL, sus eventos (`[\"*\"]`, o sin `events`: todos, también los que se agreguen después) y su secreto. Sin `secret` el servicio genera uno y **lo devuelve sólo en esta respuesta**; con `secret` (16 a 256 caracteres) usa ese y no lo repite. La URL debe ser HTTPS a una dirección pública: loopback, privadas, link-local y metadata se rechazan con `422 webhook_url_not_allowed`, al registrar y otra vez al entregar. La cantidad de destinos la limita la membresía (`429 limit_reached`, `limit: webhook_destinations`). Solo `OWNER` (o una clave de API con `settings`): un `MEMBER` recibe `403 forbidden`. También `feature_disabled` (la configuración del cliente apaga los webhooks).","parameters":[{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreate"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDestination"}}},"description":"El destino creado; `secret` si se generó","headers":{"Location":{"description":"`/v1/webhooks/{id}`","schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"Solo `OWNER` (o una clave de API con `settings`): un `MEMBER` recibe `403 forbidden`. También `feature_disabled`: la configuración del cliente apaga los webhooks, o un evento de `events` no está entre los que incluye la membresía (`integration.webhook_events`, `path: events[i]`). Sin `events` (o con `[\"*\"]`) el destino recibe los que la membresía incluye."},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_webhook`: el cuerpo no es válido; `field` dice cuál (`url`, `events`, `name`, `secret`). Un evento que no existe trae `event`. `webhook_url_not_allowed`: la URL apunta a una dirección no pública (loopback, privada, link-local, metadata)."},"429":{"$ref":"#/components/responses/LimitReached"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Crea un destino de webhook","tags":["webhooks"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","invalid_webhook","limit_reached","overloaded","payload_too_large","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type","webhook_url_not_allowed"],"x-scope":"settings","x-surface":"client"}},"/v1/webhooks/events":{"get":{"description":"Cada evento que un destino puede elegir, con su grupo, su título y lo que significa, en el idioma de `Accept-Language`: el mismo catálogo que eligen los destinos de avisos (`GET /v1/notifications/events`). Un webhook puede elegir cualquiera; `reach: webhook` marca los que sólo recibe un webhook. Los umbrales son de la cuenta (`GET /v1/notifications/thresholds`). `all` (`*`) los elige todos, también los que se agreguen después; `test_event` es el evento de prueba (`POST /v1/webhooks/{id}/test`), que no se elige.","parameters":[{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEventCatalog"}}},"description":"El catálogo"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"El catálogo de eventos","tags":["webhooks"],"x-error-codes":["account_suspended","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/webhooks/{id}":{"delete":{"description":"El destino, su secreto, sus eventos pendientes y su historial. Para pausar las entregas sin perderlos, `PATCH` con `\"enabled\": false`. Solo `OWNER` (o una clave de API con `settings`): un `MEMBER` recibe `403 forbidden`. También `feature_disabled` (la configuración del cliente apaga los webhooks).","parameters":[{"$ref":"#/components/parameters/WebhookId"}],"responses":{"204":{"description":"Eliminado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Elimina un destino de webhook","tags":["webhooks"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"settings","x-surface":"client"},"get":{"parameters":[{"$ref":"#/components/parameters/WebhookId"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDestination"}}},"description":"El destino, sin su secreto"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Consulta un destino de webhook","tags":["webhooks"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"},"patch":{"description":"Cambia lo que trae el cuerpo; lo demás queda igual. `\"name\": null` quita el nombre. Con `\"enabled\": false` las entregas se pausan: los eventos pendientes se guardan (hasta 30 días desde que se generaron) y salen al volver a habilitarlo; los eventos de mientras está apagado no se encolan para ese destino. Una URL nueva, o habilitarlo de nuevo, empieza su salud de cero. Con `events` sin un evento que ya estaba pendiente, ese evento no se entrega. Solo `OWNER` (o una clave de API con `settings`): un `MEMBER` recibe `403 forbidden`. También `feature_disabled` (la configuración del cliente apaga los webhooks).","parameters":[{"$ref":"#/components/parameters/WebhookId"},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookUpdate"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDestination"}}},"description":"El destino modificado"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"Solo `OWNER` (o una clave de API con `settings`): un `MEMBER` recibe `403 forbidden`. También `feature_disabled`: la configuración del cliente apaga los webhooks, o un evento de `events` no está entre los que incluye la membresía (`integration.webhook_events`, `path: events[i]`). Sin `events` (o con `[\"*\"]`) el destino recibe los que la membresía incluye."},"404":{"$ref":"#/components/responses/NotFound"},"422":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`invalid_webhook`: el cuerpo no es válido; `field` dice cuál (`url`, `events`, `name`, `secret`). Un evento que no existe trae `event`. `webhook_url_not_allowed`: la URL apunta a una dirección no pública (loopback, privada, link-local, metadata)."},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Modifica un destino de webhook","tags":["webhooks"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_body","invalid_environment","invalid_webhook","not_found","overloaded","payload_too_large","restore_pending","sandbox_not_available","scope_required","unauthorized","unsupported_media_type","webhook_url_not_allowed"],"x-scope":"settings","x-surface":"client"}},"/v1/webhooks/{id}/deliveries":{"get":{"description":"Las entregas del destino, de la más nueva a la más vieja, por cursor: `next_cursor` va en `before`. Se guardan 30 días. Cuenta como 3 en el límite por minuto.","parameters":[{"$ref":"#/components/parameters/WebhookId"},{"description":"`delivered`, `pending` (sin entregar todavía: espera, reintento o pausa) o `dead`; otro valor responde 400.","in":"query","name":"status","schema":{"enum":["delivered","pending","dead"],"type":"string"}},{"in":"query","name":"limit","schema":{"default":50,"maximum":100,"minimum":1,"type":"integer"}},{"description":"El `next_cursor` de la página anterior, tal cual.","in":"query","name":"before","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveriesPage"}}},"description":"Una página del historial"},"400":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`bad_request`: `status` o `before` no son válidos"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ScopeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"El historial de entregas de un destino","tags":["webhooks"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"read","x-surface":"client"}},"/v1/webhooks/{id}/deliveries/{delivery_id}/retry":{"post":{"description":"Una entrega nueva del mismo evento (el mismo `event`, `payload` y `event_id`, con su propio `id`), pendiente para ahora, enlazada con la original: la nueva lleva `retry_of` y la original `retried_by` (la más reciente). Sólo una entrega que terminó, entregada o muerta (`409 delivery_not_ended`: la que sigue en curso se reintenta sola), de un destino activo (`409 destination_disabled`) que todavía recibe el evento (`409 event_not_chosen`; el evento de prueba siempre). Un doble clic no la duplica: mientras la nueva no termina, la misma petición responde `200` con ella en lugar de `202`. Veinte por minuto por cliente, entre webhooks y avisos (`429 rate_limited`, con `Retry-After`). Solo `OWNER` (o una clave de API con `settings`): un `MEMBER` recibe `403 forbidden`. También `feature_disabled` (la configuración del cliente apaga los webhooks). No está en Pruebas (`sandbox_not_available`).","parameters":[{"$ref":"#/components/parameters/WebhookId"},{"description":"El `id` de la entrega, como en `GET /v1/webhooks/{id}/deliveries` (opaco, `dlv_…`). Un número no es un id: `404`.","in":"path","name":"delivery_id","required":true,"schema":{"pattern":"^dlv_[a-z2-7]{26}$","type":"string"}},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDelivery"}}},"description":"La que ya se había vuelto a enviar y sigue en curso (un doble clic)"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDelivery"}}},"description":"La entrega nueva, pendiente"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"Solo `OWNER` (o una clave de API con `settings`): un `MEMBER` recibe `403 forbidden`. También `feature_disabled` (la configuración del cliente apaga los webhooks)."},"404":{"$ref":"#/components/responses/NotFound"},"409":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`delivery_not_ended`: la entrega sigue en curso; `destination_disabled`: el destino está pausado; `event_not_chosen`: el destino ya no recibe ese evento"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`rate_limited`: más de veinte en el minuto; `Retry-After` y `retry_after_seconds`"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Vuelve a enviar una entrega","tags":["webhooks"],"x-error-codes":["account_suspended","bad_request","database_unavailable","delivery_not_ended","destination_disabled","event_not_chosen","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","rate_limited","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"settings","x-surface":"client"}},"/v1/webhooks/{id}/rotate-secret":{"post":{"description":"Reemplaza el secreto y lo devuelve **sólo en esta respuesta**. Las entregas firmadas desde ahora usan el nuevo, también los reintentos de eventos anteriores: mientras se cambia en el receptor, verifique con los dos. Solo `OWNER` (o una clave de API con `settings`): un `MEMBER` recibe `403 forbidden`. También `feature_disabled` (la configuración del cliente apaga los webhooks).","parameters":[{"$ref":"#/components/parameters/WebhookId"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDestination"}}},"description":"El destino, con `secret`"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Genera un secreto nuevo para un destino","tags":["webhooks"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","unauthorized"],"x-scope":"settings","x-surface":"client"}},"/v1/webhooks/{id}/test":{"post":{"description":"Envía `webhook.test` ahora, firmado como cualquier entrega, aunque el destino no lo haya elegido o esté apagado, y responde lo que contestó el receptor (en 10 segundos como máximo). La entrega queda en el historial ya cerrada: no se reintenta y no cuenta para la salud del destino. Una cada 10 segundos por destino (`429 test_rate_limited`, con `Retry-After`), como la de un destino de avisos. Solo `OWNER` (o una clave de API con `settings`): un `MEMBER` recibe `403 forbidden`. También `feature_disabled` (la configuración del cliente apaga los webhooks).","parameters":[{"$ref":"#/components/parameters/WebhookId"},{"in":"header","name":"Accept-Language","required":false,"schema":{"enum":["es","en"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTestResult"}}},"description":"Lo que contestó el receptor"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/FeatureDisabledProblem"}}},"description":"Solo `OWNER` (o una clave de API con `settings`): un `MEMBER` recibe `403 forbidden`. También `feature_disabled` (la configuración del cliente apaga los webhooks)."},"404":{"$ref":"#/components/responses/NotFound"},"429":{"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"`test_rate_limited`: ya se envió una prueba a este destino hace menos de 10 segundos; `Retry-After` y `retry_after_seconds`"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Envía el evento de prueba a un destino","tags":["webhooks"],"x-error-codes":["account_suspended","bad_request","database_unavailable","feature_disabled","forbidden","internal_error","invalid_environment","not_found","overloaded","restore_pending","sandbox_not_available","scope_required","test_rate_limited","unauthorized"],"x-scope":"settings","x-surface":"client"}},"/v1/ws_efactura_intercambio":{"post":{"description":"El servicio que el Estándar de intercambio v1.3 de la DGI pide a cada emisor (`https://[url_recepcion]/ws_efactura_intercambio`), con sus cuatro métodos: `Sobre` (un `EnvioCFE_entreEmpresas`), `RespuestaSobre` (un `ACKSobre`), `RespuestaCFEs` (un `ACKCFE`) y `NotificacionAnulacionCFE` (una `CFEs_Anulados_x_RechazoDGI`). SOAP 1.1: el XML va en `Datain/xmlData`, firmado con WS-Security por el certificado de la empresa que llama (persona jurídica, con su RUC; no revocado y, con `CFE_PKI_COUNTERPARTY_UNTRUSTED=enforce`, de una CA acreditada), y el contenido debe ser de ese RUC. La respuesta es `Dataout/xmlData` con un documento `Respuestas`: código x000 recibido, x001 rechazado con el motivo en `detalle`, x002 error del receptor, intente luego (1000-1002 para `Sobre`, 2000-2002, 3000-3002 y 4000-4002). Cada archivo sigue el mismo camino que uno recibido por correo (`channel` `WS`); las respuestas a un sobre se envían por correo a la dirección conocida del RUC emisor. La DGI no publicó el WSDL de este servicio: los nombres de los elementos y el perfil de WS-Security son los supuestos de docs/PROTOCOL.md. Una llamada que no es del servicio es un SOAP Fault con 400; una sin firma válida o de un certificado sin RUC, un SOAP Fault con 401. Un archivo dirigido a un RUC que no es una empresa de la plataforma, o a una que no recibe por este servicio, recibe el mismo x001 (`el receptor no recibe comprobantes por este servicio`): el servicio no dice quién es cliente ni cómo recibe cada uno. Límites (Estándar de intercambio v1.3, §8): una llamada de más de 4 MB recibe un SOAP Fault con 413 antes de leerse, y más de `CFE_EXCHANGE_WS_CALLS_PER_IP_MINUTE` llamadas por minuto desde una dirección (300 por defecto) o `CFE_EXCHANGE_WS_CALLS_PER_RUC_MINUTE` del mismo RUC de certificado (120), un SOAP Fault con 429 y `Retry-After`.","parameters":[{"description":"Opcional: termina en el nombre del método cuando el elemento del Body no lo dice","in":"header","name":"SOAPAction","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"text/xml":{"example":"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:dgi=\"http://dgi.gub.uy\"><soapenv:Header><wsse:Security>…</wsse:Security></soapenv:Header><soapenv:Body wsu:Id=\"Body\"><dgi:ws_efactura_intercambio.Sobre><dgi:Datain><dgi:xmlData>&lt;EnvioCFE_entreEmpresas …&gt;</dgi:xmlData></dgi:Datain></dgi:ws_efactura_intercambio.Sobre></soapenv:Body></soapenv:Envelope>","schema":{"type":"string"}}},"required":true},"responses":{"200":{"content":{"text/xml":{"example":"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><dgi:ws_efactura_intercambio.SobreResponse xmlns:dgi=\"http://dgi.gub.uy\"><dgi:Dataout><dgi:xmlData>&lt;Respuestas xmlns=\"http://cfe.dgi.gub.uy\"&gt;&lt;Respuesta&gt;&lt;codigo&gt;1000&lt;/codigo&gt;&lt;descripcion&gt;Sobre Recibido.&lt;/descripcion&gt;&lt;/Respuesta&gt;&lt;/Respuestas&gt;</dgi:xmlData></dgi:Dataout></dgi:ws_efactura_intercambio.SobreResponse></soap:Body></soap:Envelope>","schema":{"type":"string"}}},"description":"`<método>Response/Dataout/xmlData` con el documento `Respuestas` (código, descripción y detalle)"},"400":{"content":{"text/xml":{"schema":{"type":"string"}}},"description":"SOAP Fault: la llamada no es uno de los cuatro métodos o no trae `Datain/xmlData`"},"401":{"content":{"text/xml":{"schema":{"type":"string"}}},"description":"SOAP Fault: sin WS-Security, la firma no verifica con su certificado, o el certificado no trae RUC o está revocado"},"413":{"content":{"text/xml":{"schema":{"type":"string"}}},"description":"SOAP Fault: la llamada supera los 4 MB (un sobre de hasta 2 MB escapado dentro de `xmlData`, con su sobre SOAP y su firma)"},"429":{"content":{"text/xml":{"schema":{"type":"string"}}},"description":"SOAP Fault: demasiadas llamadas en el minuto desde la misma dirección o del mismo RUC de certificado; reintente después de `Retry-After` segundos","headers":{"Retry-After":{"schema":{"type":"integer"}}}},"503":{"content":{"text/xml":{"schema":{"type":"string"}}},"description":"SOAP Fault: el receptor no puede contar las llamadas ahora (`Intente luego`)"}},"security":[],"summary":"Servicio web de intercambio entre empresas (ws_efactura_intercambio)","tags":["intercambio"],"x-error-codes":["internal_error","invalid_body","overloaded","payload_too_large","unsupported_media_type"],"x-surface":"public"}}},"security":[{"apiKey":[]},{"bearer":[]}],"servers":[{"description":"Desarrollo","url":"http://localhost:8080"}],"tags":[{"description":"CFE emitidos y firmados","name":"emisión"},{"description":"Una factura validada ahora y emitida cuando se confirma el pago: `POST /v1/orders` valida como una emisión y no toma número ni cupo; `POST /v1/orders/{id}/execute` la emite.","name":"órdenes"},{"description":"Sobres enviados a la DGI y sus respuestas","name":"entrega"},{"description":"Rangos de CAE","name":"numeración"},{"description":"Configuración y consumo del tenant","name":"cuenta"},{"description":"Destinos de webhook: cada uno con su URL, su secreto, los eventos que elige (o todos) y sus reintentos; un evento de prueba y el historial de entregas. El cuerpo de cada entrega es `{\"id\", \"event\", \"payload\", \"event_id\", \"sandbox\"}`, firmado en `x-cfe-signature` con el secreto del destino.","name":"webhooks"},{"description":"Salud y metadatos del servicio","name":"operación"},{"description":"Sesiones del portal (Bearer + cookie de refresh)","name":"autenticación"},{"description":"Usuarios y claves de API del tenant","name":"usuarios"},{"description":"Personal de la plataforma","name":"administración"},{"description":"Rol de receptor electrónico: sobres `EnvioCFE_entreEmpresas` que mandan otros emisores, sus acuses firmados (`ACKSobre`, `ACKCFE`) y las comunicaciones de anulación `CFEs_Anulados_x_RechazoDGI` (Formato Mensaje de Respuesta v19, 3.2 a 3.4).","name":"recepción"},{"description":"Intercambio entre empresas por correo electrónico (Formato Mensaje de Respuesta v19, p. 9: todo emisor debe poder «recibir y enviar información por e-mail»): el sobre `EnvioCFE_entreEmpresas` al receptor electrónico una vez que la DGI lo recibió (Formato Sobre v05, p. 4), los acuses `ACKSobre` y `ACKCFE` en los dos sentidos, el rechazo comercial y la comunicación `CFEs_Anulados_x_RechazoDGI` (3.4). También `ws_efacsolicitud` (contactos del emisor en la DGI).","name":"intercambio"},{"description":"Consulta sin autenticación de los CFE que la plataforma publica por el emisor (e-Tickets por defecto).","name":"verificación pública"},{"description":"Lo que toma cada tipo de CFE, las tablas de códigos y las tasas de IVA, generados desde las reglas de `cfe-core`: la web y un integrador leen lo mismo.","name":"catálogo"},{"description":"Catálogo de membresías, la membresía de cada cliente, sus excepciones, avisos y el consumo para facturar (consola)","name":"membresías"},{"description":"Panel de gestión de clientes: roles del equipo de la plataforma, lista y ficha de cada cliente con su salud, acciones (baja, reporte de un día, ver como el cliente), usuarios y claves, notas internas y auditoría.","name":"consola"},{"description":"La plantilla del comprobante impreso (PDF, rollo y ticket POS): versiones inmutables, logos y vista previa. Lo que exige el *Formato CFE v25.2* (p. 79-86) no se puede cambiar.","name":"impreso"},{"description":"Avisos por correo, WhatsApp, Telegram, Slack y Teams: cuando quedan pocos CAE o vencen, cuando vence el certificado, cuando la DGI rechaza u observa algo, cuando llegan comprobantes de un proveedor y con los límites de la membresía. Cada destino se verifica antes de usarlo, cada aviso se activa por separado y cada mensaje nombra a la empresa y su RUT.","name":"avisos"},{"description":"El asistente del portal (Claude Haiku 5.5 de Anthropic): prepara órdenes de facturación conversando, nunca emite. Solo con la sesión de una persona de la empresa, nunca con una clave de API; no está en los SDK.","name":"asistente"},{"description":"Informes sobre los datos del cliente (ventas, clientes, productos, órdenes, la DGI, la numeración y el uso): un catálogo predefinido y un armador para los propios (fuente, columnas, filtros, agrupación y orden), guardados para el equipo o para uno. Cada uno en páginas y en CSV, con límites de período por su forma. No es el reporte diario a la DGI (`/v1/reports`).","name":"informes"}],"x-surfaces":{"client":"API de cliente: clave de API (con el permiso de `x-scope`) o sesión","portal":"API del portal: sólo sesión de usuario","public":"Sin credencial del emisor","staff":"Consola de la plataforma: sólo sesión del personal"}}