{
  "openapi": "3.1.1",
  "info": {
    "title": "miCFDI API",
    "description": "**miCFDI.com.mx, hecho por [MagicCode.com.mx](https://magiccode.com.mx).** API REST para emitir, consultar,\r\ndescargar y cancelar CFDI 4.0.\r\n\r\n## Autenticación\r\nEnvía tu llave en `Authorization: Bearer mcfdi_live_…` (producción) o `mcfdi_test_…` (pruebas: mismas\r\nvalidaciones y cálculos, **no timbra**, responde `estado: \"simulado\"`). Solo HTTPS.\r\n\r\n## Idempotencia\r\n`POST /v1/cfdi` exige `Idempotency-Key` (1 a 100 caracteres `A-Z a-z 0-9 _ - . :`, sin distinguir mayúsculas). Repite la misma llave\r\ncon el mismo cuerpo y obtendrás la misma respuesta con `Idempotent-Replayed: true`; nunca se timbra dos veces.\r\nSi el cuerpo cambia, responde `422 idempotency_key_reutilizada`. Si la petición falla antes de llegar al servicio\r\nde timbrado (validación, serie, saldo), la llave queda libre para reintentar.\r\n\r\n## Resultado de la emisión\r\n`201 timbrado`, `202 verificando` (el resultado fue incierto y se concilia solo: consulta\r\n`GET /v1/solicitudes/{id}` o espera el webhook) o `200 simulado` (llave de pruebas).\r\n\r\n## Fechas e importes\r\nFechas locales del centro de México, `yyyy-MM-ddTHH:mm:ss`. Importes con 2 decimales. Los errores son\r\n`application/problem+json` con `codigo` estable y, en validación, `errores` por campo.\r\n\r\n## Alcance de la v1\r\nTraslados de IVA (`002`, tasa 0.16, 0.08, 0.00 o exento) y de IEPS por tasa (`003`, tasas fijas de\r\nc_TasaOCuota; el IVA va sobre el valor más el IEPS), y retenciones de ISR e IVA; el factor `Cuota` y el IEPS\r\nretenido no se aceptan. Facturas en MXN o USD (`PPD` solo en MXN). Complemento de pago 2.0 en MXN con\r\nun pago por complemento y `monto` igual a la suma de los importes pagados.\r\n\r\n## Webhooks\r\nEventos `cfdi.timbrado`, `cfdi.verificando`, `cfdi.incierto`, `cfdi.cancelacion` y `webhook.prueba`. Cada\r\nwebhook pertenece al modo de la llave que lo creó: los de una llave `mcfdi_test_` solo reciben eventos de\r\npruebas y los de una `mcfdi_live_`, solo los reales (revisa también `modo` en el cuerpo). Llevan la\r\ncabecera `MiCFDI-Firma: t=<unix>,v1=<hex(HMAC-SHA256(secreto, t + \".\" + cuerpo))>`. Verifícala así (C#):\r\n\r\n```csharp\r\nstatic bool FirmaValida(string cabecera, string secreto, string cuerpo)\r\n{\r\n    string? t = null;\r\n    var firmas = new List<string>();\r\n    foreach (string parte in cabecera.Split(','))\r\n    {\r\n        string[] kv = parte.Trim().Split('=', 2);\r\n        if (kv.Length != 2) continue;\r\n        if (kv[0] == \"t\") t = kv[1];\r\n        else if (kv[0] == \"v1\") firmas.Add(kv[1]);\r\n    }\r\n    if (t is null || !long.TryParse(t, out long marca)) return false;\r\n    if (Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - marca) > 300) return false;   // 5 minutos\r\n    byte[] hmac = HMACSHA256.HashData(Encoding.UTF8.GetBytes(secreto), Encoding.UTF8.GetBytes(t + \".\" + cuerpo));\r\n    byte[] esperada = Encoding.ASCII.GetBytes(Convert.ToHexString(hmac).ToLowerInvariant());   // también en .NET 8\r\n    return firmas.Any(f => CryptographicOperations.FixedTimeEquals(esperada, Encoding.ASCII.GetBytes(f.ToLowerInvariant())));\r\n}\r\n```\r\nUsa el cuerpo **tal como llegó** (sin volver a serializarlo) y responde 2xx en menos de 10 s.",
    "contact": {
      "name": "MagicCode",
      "url": "https://magiccode.com.mx"
    },
    "version": "v1"
  },
  "servers": [
    {
      "url": "https://api.micfdi.com.mx",
      "description": "Producción"
    }
  ],
  "paths": {
    "/salud": {
      "get": {
        "tags": [
          "Salud"
        ],
        "summary": "El proceso está vivo",
        "operationId": "Salud",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/salud/lista": {
      "get": {
        "tags": [
          "Salud"
        ],
        "summary": "Revisa la base, el motor de timbrado y la carpeta de comprobantes",
        "description": "El resultado se guarda 10 s: es anónimo y cada revisión consulta la base, el motor y el disco.",
        "operationId": "SaludLista",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SaludLista"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SaludLista"
                }
              }
            }
          }
        }
      }
    },
    "/version": {
      "get": {
        "tags": [
          "Salud"
        ],
        "summary": "Versión, commit y fecha de compilación",
        "operationId": "Version",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InfoVersion"
                }
              }
            }
          }
        }
      }
    },
    "/chat/estado": {
      "get": {
        "tags": [
          "Chat"
        ],
        "summary": "Estado del chat de dudas de CFDI (para el widget del sitio)",
        "description": "Si el chat atiende, si responde con IA o con la búsqueda en la ayuda, el máximo de caracteres y el texto de privacidad.",
        "operationId": "ChatEstado",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EstadoChat"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        }
      }
    },
    "/chat/mensajes": {
      "post": {
        "tags": [
          "Chat"
        ],
        "summary": "Timbi responde una duda (chat público del sitio)",
        "description": "Sin llave. Con «Accept: text/event-stream» responde en flujo SSE (eventos delta, reemplazo, sugerir_soporte y fin); si no, JSON. No guarda el texto de la conversación: solo tokens, fecha e IP truncada. Información general, no asesoría fiscal.",
        "operationId": "ChatMensajes",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/SolicitudChat"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaChat"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "413": {
            "description": "Payload Too Large",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        }
      }
    },
    "/chat/tickets": {
      "post": {
        "tags": [
          "Chat"
        ],
        "summary": "Levanta un ticket de soporte desde el chat del sitio",
        "description": "Sin llave. Guarda el ticket con un folio (MC-000123), avisa a soporte@micfdi.com.mx y manda un acuse al correo del usuario. La conversación solo se guarda si incluirConversacion es verdadero, con RFC, CURP, correos, teléfonos y cuentas ocultos.",
        "operationId": "ChatTickets",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/SolicitudTicket"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaTicket"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "413": {
            "description": "Payload Too Large",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        }
      }
    },
    "/chat/panel/estado": {
      "get": {
        "tags": [
          "Chat del panel"
        ],
        "summary": "Estado de Timbi en el panel",
        "description": "Con la llave interna del panel. Si Timbi atiende con IA o con la búsqueda en la ayuda, el máximo de caracteres y el texto de privacidad.",
        "operationId": "ChatPanelEstado",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EstadoChat"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        }
      }
    },
    "/chat/panel/mensajes": {
      "post": {
        "tags": [
          "Chat del panel"
        ],
        "summary": "Timbi responde una duda dentro del panel (servidor a servidor)",
        "description": "Con X-MiCFDI-Panel, X-MiCFDI-Empresa y X-MiCFDI-Usuario. Mismo cuerpo que /chat/mensajes más «modulo» (la ruta del panel) y el mismo flujo SSE. La API agrega el contexto de la cuenta (plan, timbres, CSD, CFDI y borradores del mes, régimen) sin RFC, nombres, domicilios ni datos de clientes.",
        "operationId": "ChatPanelMensajes",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/SolicitudChatPanel"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaChat"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "413": {
            "description": "Payload Too Large",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        }
      }
    },
    "/chat/panel/tickets": {
      "post": {
        "tags": [
          "Chat del panel"
        ],
        "summary": "Levanta un ticket de soporte desde Timbi en el panel (servidor a servidor)",
        "description": "Con X-MiCFDI-Panel, X-MiCFDI-Empresa y X-MiCFDI-Usuario. Mismo cuerpo que /chat/tickets más «modulo»; nombre y correo son opcionales (el panel manda el correo del usuario de la sesión). La empresa sale del encabezado.",
        "operationId": "ChatPanelTickets",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/SolicitudTicketPanel"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaTicket"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "413": {
            "description": "Payload Too Large",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        }
      }
    },
    "/v1/emisor": {
      "get": {
        "tags": [
          "Emisor"
        ],
        "summary": "Datos del emisor de la llave",
        "description": "RFC, nombre, régimen fiscal, sucursales con su CSD, series por tipo de comprobante con el siguiente folio, y timbres disponibles (solo cuentan los timbres del proveedor actual y el plan ilimitado vigente).",
        "operationId": "ObtenerEmisor",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmisorVista"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/catalogos": {
      "get": {
        "tags": [
          "Catálogos"
        ],
        "summary": "Catálogos disponibles",
        "operationId": "ListarCatalogos",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListaCatalogos"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/catalogos/{nombre}": {
      "get": {
        "tags": [
          "Catálogos"
        ],
        "summary": "Contenido de un catálogo del SAT",
        "description": "usos-cfdi, formas-pago, metodos-pago, regimenes-fiscales, tipos-relacion, objetos-impuesto, exportaciones, monedas, periodicidades, meses y motivos-cancelacion. En productos-servicios y unidades se busca con ?q=texto (máximo 50).",
        "operationId": "ObtenerCatalogo",
        "parameters": [
          {
            "name": "nombre",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CatalogoVista"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/cfdi": {
      "post": {
        "tags": [
          "CFDI"
        ],
        "summary": "Emite un CFDI (factura, nota de crédito, honorarios o complemento de pago)",
        "description": "Requiere la cabecera Idempotency-Key. La API calcula importes e impuestos, valida contra los límites del servicio de timbrado y timbra. Responde 201 (timbrado), 202 (verificando: el resultado fue incierto y se concilia solo; consulta /v1/solicitudes/{id}) o 200 (simulado, con llave de pruebas). Repetir la misma llave con el mismo cuerpo devuelve la misma respuesta con Idempotent-Replayed: true. Un campo que la API no conoce (por ejemplo «descuentos» en vez de «descuento») no cambia el resultado: se avisa en la cabecera Warning y en el arreglo «avisos» de la respuesta (guía §9.1).",
        "operationId": "EmitirCfdi",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Llave única de la emisión (1 a 100 caracteres A-Z a-z 0-9 _ - . :; no distingue mayúsculas).",
            "required": true,
            "schema": {
              "maxLength": 100,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SolicitudEmision"
              },
              "example": {
                "tipo": "factura",
                "referencia": "venta-mostrador-2026-10-06",
                "formaPago": "04",
                "metodoPago": "PUE",
                "moneda": "MXN",
                "receptor": {
                  "rfc": "XAXX010101000",
                  "nombre": "PUBLICO EN GENERAL",
                  "regimenFiscal": "616",
                  "usoCfdi": "S01"
                },
                "informacionGlobal": {
                  "periodicidad": "01",
                  "meses": "10",
                  "anio": 2026
                },
                "conceptos": [
                  {
                    "claveProdServ": "01010101",
                    "claveUnidad": "ACT",
                    "unidad": "Actividad",
                    "descripcion": "Venta",
                    "cantidad": 1,
                    "valorUnitario": 0.86,
                    "objetoImp": "02",
                    "impuestos": {
                      "traslados": [
                        {
                          "impuesto": "002",
                          "tipoFactor": "Tasa",
                          "tasaOCuota": 0.16
                        }
                      ]
                    }
                  }
                ]
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "Idempotent-Replayed": {
                "description": "«true» si es la respuesta guardada de una petición anterior con la misma Idempotency-Key.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaEmision"
                },
                "example": {
                  "id": "0199b3f2-6c1e-7a40-9d1e-2f6b9c1d4e55",
                  "modo": "live",
                  "estado": "timbrado",
                  "tipo": "factura",
                  "referencia": "venta-mostrador-2026-10-06",
                  "uuid": "BE930CF9-1111-2222-3333-444455556666",
                  "serie": "A",
                  "folio": "123",
                  "fecha": "2026-10-06T11:59:55",
                  "fechaTimbrado": "2026-10-06T12:00:04",
                  "emisor": {
                    "rfc": "EKU9003173C9",
                    "nombre": "ESCUELA KEMPER URGATE"
                  },
                  "receptor": {
                    "rfc": "XAXX010101000",
                    "nombre": "PUBLICO EN GENERAL"
                  },
                  "moneda": "MXN",
                  "subtotal": 0.86,
                  "descuento": 0.00,
                  "impuestosTrasladados": 0.14,
                  "impuestosRetenidos": 0.00,
                  "total": 1.00,
                  "enlaces": {
                    "self": "https://api.micfdi.com.mx/v1/cfdi/BE930CF9-1111-2222-3333-444455556666",
                    "xml": "https://api.micfdi.com.mx/v1/cfdi/BE930CF9-1111-2222-3333-444455556666/xml",
                    "pdf": "https://api.micfdi.com.mx/v1/cfdi/BE930CF9-1111-2222-3333-444455556666/pdf"
                  }
                }
              }
            }
          },
          "202": {
            "description": "Accepted",
            "headers": {
              "Idempotent-Replayed": {
                "description": "«true» si es la respuesta guardada de una petición anterior con la misma Idempotency-Key.",
                "schema": {
                  "type": "string"
                }
              },
              "Location": {
                "description": "URL de GET /v1/solicitudes/{id} para seguir la verificación.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaEmision"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "headers": {
              "Idempotent-Replayed": {
                "description": "«true» si es la respuesta guardada de una petición anterior con la misma Idempotency-Key.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaEmision"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "402": {
            "description": "Payment Required",
            "headers": {
              "Idempotent-Replayed": {
                "description": "«true» si es la respuesta guardada de una petición anterior con la misma Idempotency-Key.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de repetir la petición con la misma Idempotency-Key.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "headers": {
              "Idempotent-Replayed": {
                "description": "«true» si es la respuesta guardada de una petición anterior con la misma Idempotency-Key.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar (con la misma Idempotency-Key al emitir).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      },
      "get": {
        "tags": [
          "CFDI"
        ],
        "summary": "Lista los CFDI del emisor (todos, no solo los emitidos por la API)",
        "description": "Filtros: desde y hasta (fecha de emisión, yyyy-MM-dd o yyyy-MM-ddTHH:mm:ss), rfcReceptor, referencia (solo los emitidos por la API), tipo, estado (vigente o cancelado, según la base), pagina (desde 1) y tamanio (1 a 100, 20 por omisión). Orden: más reciente primero.",
        "operationId": "ListarCfdi",
        "parameters": [
          {
            "name": "desde",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "hasta",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "rfcReceptor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "referencia",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tipo",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "estado",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "pagina",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tamanio",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultadoPaginadoOfCfdiResumen"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/cfdi/{uuid}": {
      "get": {
        "tags": [
          "CFDI"
        ],
        "summary": "Detalle de un CFDI",
        "description": "«cancelado» refleja la base del panel; el estado definitivo es GET /v1/cfdi/{uuid}/estatus-sat.",
        "operationId": "ObtenerCfdi",
        "parameters": [
          {
            "name": "uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaEmision"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/cfdi/{uuid}/xml": {
      "get": {
        "tags": [
          "CFDI"
        ],
        "summary": "XML timbrado",
        "operationId": "DescargarXml",
        "parameters": [
          {
            "name": "uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/Stream"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/cfdi/{uuid}/pdf": {
      "get": {
        "tags": [
          "CFDI"
        ],
        "summary": "PDF (si no existe se genera)",
        "operationId": "DescargarPdf",
        "parameters": [
          {
            "name": "uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/pdf": {
                "schema": {
                  "$ref": "#/components/schemas/Stream"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar (con la misma Idempotency-Key al emitir).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/cfdi/{uuid}/estatus-sat": {
      "get": {
        "tags": [
          "CFDI"
        ],
        "summary": "Estatus real del CFDI en el SAT",
        "operationId": "EstatusSat",
        "parameters": [
          {
            "name": "uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaEstatusSat"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar (con la misma Idempotency-Key al emitir).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/cfdi/{uuid}/cancelacion": {
      "post": {
        "tags": [
          "CFDI"
        ],
        "summary": "Cancela un CFDI",
        "description": "motivo 01 exige folioSustitucion (UUID vigente del mismo emisor). Responde con la solicitud (aceptada o rechazada, según el EstatusUUID del acuse y el SAT) y el estado real en el SAT (cancelado, en_proceso, vigente, rechazada o no_encontrado). aceptada dice que el SAT recibió la solicitud; el CFDI está cancelado cuando estado es cancelado. Si no se puede saber qué resolvió el SAT (acuse sin código que el SAT todavía no registra, o respuesta sin confirmar) responde 503 cancelacion_sin_confirmar sin webhook: consulta /estatus-sat antes de repetir. Si ya tenía una cancelación registrada responde 409 ya_cancelado con el estatus del SAT.",
        "operationId": "CancelarCfdi",
        "parameters": [
          {
            "name": "uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/SolicitudCancelacion"
                  }
                ]
              },
              "example": {
                "motivo": "01",
                "folioSustitucion": "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaCancelacion"
                },
                "example": {
                  "uuid": "BE930CF9-1111-2222-3333-444455556666",
                  "solicitud": "aceptada",
                  "estado": "en_proceso",
                  "esCancelable": "Cancelable con aceptación",
                  "estatusCancelacion": "En proceso",
                  "acuse": {
                    "estatusUuid": "201"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar (con la misma Idempotency-Key al emitir).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/cfdi/{uuid}/correo": {
      "post": {
        "tags": [
          "CFDI"
        ],
        "summary": "Envía el CFDI por correo (máximo 5 direcciones)",
        "operationId": "EnviarCorreo",
        "parameters": [
          {
            "name": "uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/SolicitudCorreo"
                  }
                ]
              },
              "example": {
                "para": [
                  "cliente@ejemplo.com"
                ],
                "copia": [
                  "contabilidad@ejemplo.com"
                ],
                "asunto": "Tu factura",
                "mensaje": "Gracias por tu compra."
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaCorreo"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar (con la misma Idempotency-Key al emitir).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/cfdi/{uuid}/envios": {
      "get": {
        "tags": [
          "CFDI"
        ],
        "summary": "A quién y cuándo se envió el CFDI por correo",
        "description": "Incluye los envíos desde el panel, la API y las facturas recurrentes, con su resultado y, si está disponible, el estado de entrega (entregado, rebotó…). Con una llave de pruebas regresa una lista vacía.",
        "operationId": "HistorialEnvios",
        "parameters": [
          {
            "name": "uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaEnvios"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar (con la misma Idempotency-Key al emitir).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/solicitudes/{id}": {
      "get": {
        "tags": [
          "Solicitudes"
        ],
        "summary": "Estado de una solicitud de emisión",
        "description": "Útil cuando la emisión respondió 202 (verificando): cambia a timbrado o incierto.",
        "operationId": "ObtenerSolicitud",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaEmision"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/webhooks": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Los webhooks activos de la integración en el modo de la llave.",
        "operationId": "ListarWebhooks",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListaWebhooks"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Crea un webhook (el secreto se muestra solo en esta respuesta)",
        "description": "El webhook pertenece al modo de la llave: con mcfdi_test_ recibe solo eventos de pruebas («modo»: «test») y con mcfdi_live_ solo los reales. Máximo 5 por integración en cada modo.",
        "operationId": "CrearWebhook",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/SolicitudWebhook"
                  }
                ]
              },
              "example": {
                "url": "https://ejemplo.com/webhooks/micfdi",
                "eventos": [
                  "cfdi.timbrado",
                  "cfdi.incierto",
                  "cfdi.cancelacion"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookVista"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/webhooks/{id}": {
      "delete": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Desactiva un webhook de la integración y el modo de la llave.",
        "operationId": "EliminarWebhook",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/webhooks/{id}/prueba": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Encola un webhook.prueba (uno por minuto por webhook).",
        "operationId": "ProbarWebhook",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaPrueba"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/listas-sat/{rfc}": {
      "get": {
        "tags": [
          "Listas del SAT"
        ],
        "summary": "Si un RFC aparece en las listas 69 o 69-B del SAT",
        "description": "Consulta los listados públicos del SAT (artículo 69-B: presuntos y definitivos; artículo 69: no localizados, créditos firmes, exigibles, cancelados y sentencias), que miCFDI descarga de los archivos oficiales. Solo informa: no bloquea ninguna emisión. Un Desvirtuado o una Sentencia favorable del 69-B no cuentan como riesgo.",
        "operationId": "ListasSat",
        "parameters": [
          {
            "name": "rfc",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListasSatVista"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/ia/estado": {
      "get": {
        "tags": [
          "IA"
        ],
        "summary": "Estado de la IA para la empresa de la llave",
        "description": "Indica si las funciones usarán el modelo o responderán con su respaldo sin IA (apagada, empresa no autorizada, límite diario…), y los límites de la empresa. Sirve para mostrar u ocultar las funciones en el panel.",
        "operationId": "EstadoIa",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EstadoIa"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/ia/claves-sat": {
      "post": {
        "tags": [
          "IA"
        ],
        "summary": "Sugiere ClaveProdServ y ClaveUnidad para una descripción",
        "description": "Hasta 5 claves de c_ClaveProdServ con confianza y razón, y la ClaveUnidad. Toda clave existe en el catálogo de la base (las que invente el modelo se descartan y se cuentan en «descartadas»). Sin IA: búsqueda por palabras en el catálogo.",
        "operationId": "IaClavesSat",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/SolicitudClavesSat"
                  }
                ]
              },
              "example": {
                "descripcion": "Consultoría en procesos contables, cobro por hora",
                "maximo": 3
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaIaOfResultadoClavesSat"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/ia/borrador": {
      "post": {
        "tags": [
          "IA"
        ],
        "summary": "Convierte texto libre en un borrador de CFDI (no timbra)",
        "description": "Devuelve un borrador con el formato del cuerpo de POST /v1/cfdi, los totales estimados, notas y dudas. Los RFC, CURP, correos y teléfonos se ocultan antes de mandar el texto al modelo y se regresan en la respuesta. Nunca timbra.",
        "operationId": "IaBorrador",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/SolicitudBorrador"
                  }
                ]
              },
              "example": {
                "texto": "Factura a público en general 3 horas de consultoría a 850 más IVA, pago en transferencia"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaIaOfResultadoBorrador"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/ia/explicar-error": {
      "post": {
        "tags": [
          "IA"
        ],
        "summary": "Explica un error del proveedor, del SAT o del motor",
        "description": "Explicación en lenguaje claro, causa probable y pasos para corregir. Sin IA: tabla de errores conocidos (validaciones CFDI 4.0, códigos del proveedor, códigos de cancelación 201-209, mensajes E1-E99 del motor y códigos de la API).",
        "operationId": "IaExplicarError",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/SolicitudExplicarError"
                  }
                ]
              },
              "example": {
                "codigo": "CFDI40145",
                "mensaje": "El campo Nombre del receptor, debe pertenecer al nombre asociado al RFC registrado en el campo Rfc del Receptor.",
                "contexto": "timbrado"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaIaOfResultadoExplicacion"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/ia/revisar": {
      "post": {
        "tags": [
          "IA"
        ],
        "summary": "Revisa un comprobante antes de timbrar",
        "description": "Recibe el comprobante sin RFC ni nombres. Las reglas de miCFDI (PPD con forma 99, uso CFDI y régimen, IVA, totales, público en general con información global, claves del catálogo…) deciden los errores; la IA solo agrega advertencias y sugerencias.",
        "operationId": "IaRevisar",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/ComprobanteRevision"
                  }
                ]
              },
              "example": {
                "tipo": "factura",
                "emisor": {
                  "regimenFiscal": "612",
                  "tipoPersona": "fisica"
                },
                "receptor": {
                  "tipoPersona": "moral",
                  "regimenFiscal": "601",
                  "usoCfdi": "G03"
                },
                "formaPago": "03",
                "metodoPago": "PPD",
                "moneda": "MXN",
                "conceptos": [
                  {
                    "claveProdServ": "80101500",
                    "claveUnidad": "E48",
                    "cantidad": 3,
                    "valorUnitario": 850,
                    "descuento": 0,
                    "objetoImp": "02",
                    "impuestos": {
                      "traslados": [
                        {
                          "impuesto": "002",
                          "tipoFactor": "Tasa",
                          "tasaOCuota": 0.16,
                          "importe": 408.00
                        }
                      ]
                    }
                  }
                ],
                "totales": {
                  "subtotal": 2550.00,
                  "descuento": 0,
                  "impuestosTrasladados": 408.00,
                  "impuestosRetenidos": 0,
                  "total": 2958.00
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaIaOfResultadoRevision"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/ia/ayuda": {
      "post": {
        "tags": [
          "IA"
        ],
        "summary": "Asistente de ayuda del panel de miCFDI",
        "description": "Responde con los artículos de ayuda de miCFDI y los cita. Sin IA: búsqueda por palabras en los artículos.",
        "operationId": "IaAyuda",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/SolicitudAyuda"
                  }
                ]
              },
              "example": {
                "pregunta": "¿Cómo cancelo una factura que hice con errores?",
                "pantalla": "/comprobantes"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaIaOfResultadoAyuda"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/ia/resumen": {
      "post": {
        "tags": [
          "IA"
        ],
        "summary": "Resumen ejecutivo del mes",
        "description": "Con las cifras agregadas del periodo (las manda el panel o las calcula la API desde la base: solo conteos e importes) redacta un resumen para el tablero o para el contador.",
        "operationId": "IaResumen",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/SolicitudResumen"
                  }
                ]
              },
              "example": {
                "anio": 2026,
                "mes": 9,
                "destinatario": "contador"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaIaOfResultadoResumen"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/ia/recordatorio": {
      "post": {
        "tags": [
          "IA"
        ],
        "summary": "Recordatorio de cobranza con marcadores",
        "description": "Devuelve la plantilla con {cliente}, {folio}, {saldo} y {vencimiento} y, si mandas «valores», el texto final: los valores se reemplazan en la API y nunca van al modelo.",
        "operationId": "IaRecordatorio",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/SolicitudRecordatorio"
                  }
                ]
              },
              "example": {
                "tono": "cordial",
                "diasVencidos": 5,
                "canal": "correo",
                "valores": {
                  "cliente": "Cliente Ejemplo",
                  "folio": "A-123",
                  "saldo": 1160.00,
                  "moneda": "MXN",
                  "vencimiento": "2026-10-07"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaIaOfResultadoRecordatorio"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/despacho/clientes": {
      "get": {
        "tags": [
          "Despacho"
        ],
        "summary": "Las empresas cliente del despacho",
        "description": "Cada cliente activo o pendiente con su estado, timbres, CSD (y su vencimiento) y las señales del tablero.",
        "operationId": "DespachoClientes",
        "responses": {
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar (con la misma Idempotency-Key al emitir).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Despacho"
        ],
        "summary": "Da de alta una empresa nueva como cliente del despacho",
        "description": "La empresa queda completa en miCFDI, activa, con la titularidad PENDIENTE: su dueño recibe una invitación por correo (14 días) para reclamarla. Los miembros del despacho reciben acceso de contador. Cuerpo: rfc, razonSocial, regimenFiscal (clave c_RegimenFiscal), codigoPostal, correoDueno, telefono (opcional), aceptaTerminos y declaraConsentimiento (las dos true), aceptarAvisos (opcional). Si el RFC ya es cliente de tu despacho (por ejemplo, al reintentar tras un timeout) responde 200 con ese cliente y repetido: true. Un RFC registrado por alguien más responde 409: pide acceso con POST /v1/despacho/clientes/solicitud.",
        "operationId": "DespachoAltaCliente",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonObject"
              },
              "example": {
                "rfc": "EKU9003173C9",
                "razonSocial": "ESCUELA KEMPER URGATE",
                "regimenFiscal": "601",
                "codigoPostal": "44100",
                "correoDueno": "duena@ejemplo.com",
                "telefono": "3312345678",
                "aceptaTerminos": true,
                "declaraConsentimiento": true
              }
            }
          },
          "required": true
        },
        "responses": {
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar (con la misma Idempotency-Key al emitir).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/despacho/clientes/{idEmpresa}": {
      "get": {
        "tags": [
          "Despacho"
        ],
        "summary": "El detalle de una empresa cliente",
        "operationId": "DespachoCliente",
        "parameters": [
          {
            "name": "idEmpresa",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar (con la misma Idempotency-Key al emitir).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/despacho/clientes/solicitud": {
      "post": {
        "tags": [
          "Despacho"
        ],
        "summary": "Pide acceso a una empresa que ya usa miCFDI",
        "description": "Cuerpo: rfc. La liga queda pendiente hasta que el dueño la apruebe en su panel (Equipo › Despachos contables). La respuesta es la misma exista o no el RFC.",
        "operationId": "DespachoSolicitudCliente",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonObject"
              },
              "example": {
                "rfc": "EKU9003173C9"
              }
            }
          },
          "required": true
        },
        "responses": {
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar (con la misma Idempotency-Key al emitir).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/despacho/clientes/{idEmpresa}/csd": {
      "post": {
        "tags": [
          "Despacho"
        ],
        "summary": "Carga el CSD de una empresa cliente",
        "description": "Cuerpo: cer y key (el contenido de los archivos .cer y .key en base64) y contrasena (la de la llave privada del sello, no la de la e.firma). Misma validación que el panel: que sea CSD y no e.firma, del RFC de la empresa, vigente, y que la llave abra con la contraseña; luego se registra en el PAC. Con avisos (por ejemplo, vence pronto) responde 422 con «avisos»: repite con aceptarAvisos: true. Necesita una liga con «puede configurar».",
        "operationId": "DespachoCsdCliente",
        "parameters": [
          {
            "name": "idEmpresa",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonObject"
              }
            }
          },
          "required": true
        },
        "responses": {
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar (con la misma Idempotency-Key al emitir).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/despacho/bolsa": {
      "get": {
        "tags": [
          "Despacho"
        ],
        "summary": "La bolsa de timbres del despacho y sus últimos movimientos",
        "operationId": "DespachoBolsa",
        "responses": {
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar (con la misma Idempotency-Key al emitir).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/despacho/bolsa/asignaciones": {
      "post": {
        "tags": [
          "Despacho"
        ],
        "summary": "Asigna timbres de la bolsa a una empresa cliente",
        "description": "Cuerpo: idEmpresa y timbres. Requiere Idempotency-Key: repetir la misma clave nunca asigna dos veces. Lo asignado ya no se puede quitar. Sin saldo suficiente responde 409.",
        "operationId": "DespachoAsignarTimbres",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Llave única de la asignación (1 a 100 caracteres A-Z a-z 0-9 _ - . :): repetirla nunca asigna dos veces.",
            "required": true,
            "schema": {
              "maxLength": 100,
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonObject"
              },
              "example": {
                "idEmpresa": 4921,
                "timbres": 50
              }
            }
          },
          "required": true
        },
        "responses": {
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar (con la misma Idempotency-Key al emitir).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/despacho/clientes/{idEmpresa}/llaves": {
      "post": {
        "tags": [
          "Despacho"
        ],
        "summary": "Crea una llave de API de una empresa cliente",
        "description": "Cuerpo: modo (live o test) y nombre (opcional, máximo 100). La llave se muestra UNA vez en la respuesta: guárdala. Con ella timbras, consultas y cancelas a nombre de esa empresa en /v1/cfdi. Misma regla que el CSD: cliente activo de tu despacho, alcance completo y «puede configurar». Hasta 4 llaves activas por empresa. Si la liga deja de estar activa o pierde «puede configurar», sus llaves se revocan solas. Con una llave de despacho de pruebas responde simulado: true y no crea nada.",
        "operationId": "DespachoCrearLlaveCliente",
        "parameters": [
          {
            "name": "idEmpresa",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonObject"
              }
            }
          },
          "required": true
        },
        "responses": {
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar (con la misma Idempotency-Key al emitir).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      },
      "get": {
        "tags": [
          "Despacho"
        ],
        "summary": "Las llaves que tu despacho creó para una empresa cliente",
        "description": "Solo sus datos (prefijo, modo, nombre, fechas y último uso), nunca la llave. Pide la liga activa.",
        "operationId": "DespachoLlavesCliente",
        "parameters": [
          {
            "name": "idEmpresa",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar (con la misma Idempotency-Key al emitir).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/despacho/clientes/{idEmpresa}/llaves/{prefijo}": {
      "delete": {
        "tags": [
          "Despacho"
        ],
        "summary": "Revoca una llave que tu despacho creó para una empresa cliente",
        "description": "Por su prefijo (los primeros 20 caracteres, como sale en la lista). Deja de valer en menos de un minuto.",
        "operationId": "DespachoRevocarLlaveCliente",
        "parameters": [
          {
            "name": "idEmpresa",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "prefijo",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar (con la misma Idempotency-Key al emitir).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/despacho/webhooks": {
      "get": {
        "tags": [
          "Despacho"
        ],
        "summary": "Los webhooks activos de la integración en el modo de la llave.",
        "operationId": "DespachoListarWebhooks",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListaWebhooks"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Despacho"
        ],
        "summary": "Registra un webhook del despacho (el secreto se muestra solo en esta respuesta)",
        "description": "Eventos: despacho.cliente.ligado, despacho.cliente.desligado, despacho.csd.por_vencer (30 días), despacho.csd.vencido, despacho.csd.suspendido (el SAT suspendió o revocó su CSD), despacho.timbres.por_agotarse (10 o menos, uno al mes por cliente), despacho.cancelacion.recibida (una vez por solicitud), despacho.cfdi.timbrado y despacho.cfdi.cancelacion (de las llaves de empresa que creó tu despacho) y webhook.prueba. Sin «eventos» se suscribe a todos. Ligado y desligado cuentan desde que registras tu primer webhook live. Los avisos de clientes llegan a los webhooks live; los despacho.cfdi.* en el modo de la llave de empresa que timbró. Misma firma (MiCFDI-Firma) y reintentos que /v1/webhooks.",
        "operationId": "DespachoCrearWebhook",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/SolicitudWebhook"
                  }
                ]
              },
              "example": {
                "url": "https://tu-plataforma.example.com/micfdi/avisos",
                "eventos": [
                  "despacho.cliente.ligado",
                  "despacho.csd.por_vencer",
                  "despacho.cfdi.timbrado"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookVista"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable Entity",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/despacho/webhooks/{id}": {
      "delete": {
        "tags": [
          "Despacho"
        ],
        "summary": "Desactiva un webhook de la integración y el modo de la llave.",
        "operationId": "DespachoEliminarWebhook",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    },
    "/v1/despacho/webhooks/{id}/prueba": {
      "post": {
        "tags": [
          "Despacho"
        ],
        "summary": "Encola un webhook.prueba (uno por minuto por webhook).",
        "operationId": "DespachoProbarWebhook",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaPrueba"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "headers": {
              "Retry-After": {
                "description": "Segundos que hay que esperar antes de reintentar.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemaApi"
                }
              }
            }
          }
        },
        "security": [
          {
            "llaveApi": [ ]
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "AcuseCancelacion": {
        "required": [
          "estatusUuid"
        ],
        "type": "object",
        "properties": {
          "estatusUuid": {
            "type": [
              "null",
              "string"
            ],
            "description": "201 aceptada, 202 ya cancelado; otro = rechazo."
          }
        },
        "description": "Acuse de cancelación."
      },
      "ArticuloCitado": {
        "required": [
          "id",
          "titulo",
          "pantalla"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Id del artículo (nombre del archivo en `docs/ayuda`)."
          },
          "titulo": {
            "type": "string",
            "description": "Título."
          },
          "pantalla": {
            "type": [
              "null",
              "string"
            ],
            "description": "Ruta del panel relacionada, si la hay."
          }
        },
        "description": "Artículo de la ayuda citado."
      },
      "CancelacionResumen": {
        "required": [
          "motivo",
          "fecha"
        ],
        "type": "object",
        "properties": {
          "motivo": {
            "type": [
              "null",
              "string"
            ]
          },
          "fecha": {
            "type": [
              "null",
              "string"
            ]
          }
        },
        "description": "Última cancelación registrada."
      },
      "CatalogoVista": {
        "required": [
          "catalogo",
          "datos"
        ],
        "type": "object",
        "properties": {
          "catalogo": {
            "type": "string",
            "description": "Nombre del catálogo."
          },
          "datos": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ElementoCatalogo"
            },
            "description": "Elementos (en búsquedas, máximo 50)."
          }
        },
        "description": "Contenido de un catálogo."
      },
      "CfdiResumen": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "description": "Folio fiscal."
          },
          "tipo": {
            "type": "string",
            "description": "Tipo público (o «otro» si no es de los que emite la API)."
          },
          "serie": {
            "type": [
              "null",
              "string"
            ],
            "description": "Serie."
          },
          "folio": {
            "type": [
              "null",
              "string"
            ],
            "description": "Folio."
          },
          "fecha": {
            "type": [
              "null",
              "string"
            ],
            "description": "Fecha de emisión."
          },
          "fechaTimbrado": {
            "type": [
              "null",
              "string"
            ],
            "description": "Fecha de timbrado."
          },
          "receptor": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Receptor.",
                "$ref": "#/components/schemas/ParteFiscal"
              }
            ]
          },
          "moneda": {
            "type": [
              "null",
              "string"
            ],
            "description": "Moneda."
          },
          "subtotal": {
            "type": "number",
            "description": "Subtotal.",
            "format": "double"
          },
          "total": {
            "type": "number",
            "description": "Total.",
            "format": "double"
          },
          "cancelado": {
            "type": "boolean",
            "description": "Según la base del panel."
          },
          "referencia": {
            "type": [
              "null",
              "string"
            ],
            "description": "Referencia del integrador, si se emitió por la API."
          },
          "enlaces": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Enlaces.",
                "$ref": "#/components/schemas/Enlaces"
              }
            ]
          }
        },
        "description": "Elemento del listado de CFDI."
      },
      "CifrasPeriodo": {
        "type": "object",
        "properties": {
          "anio": {
            "type": [
              "null",
              "integer"
            ],
            "description": "Año.",
            "format": "int32"
          },
          "mes": {
            "type": [
              "null",
              "integer"
            ],
            "description": "Mes (1 a 12).",
            "format": "int32"
          },
          "facturas": {
            "type": "integer",
            "description": "Facturas de ingreso vigentes (factura, honorarios, servicios parciales).",
            "format": "int32"
          },
          "facturadoMxn": {
            "type": "number",
            "description": "Total facturado en MXN (facturas vigentes en pesos).",
            "format": "double"
          },
          "facturasMonedaExtranjera": {
            "type": "integer",
            "description": "Facturas vigentes en moneda extranjera.",
            "format": "int32"
          },
          "facturadoMonedaExtranjera": {
            "type": "number",
            "description": "Total de esas facturas en su moneda (sin convertir).",
            "format": "double"
          },
          "notasCredito": {
            "type": "integer",
            "description": "Notas de crédito vigentes.",
            "format": "int32"
          },
          "notasCreditoMxn": {
            "type": "number",
            "description": "Total de notas de crédito en MXN.",
            "format": "double"
          },
          "pagos": {
            "type": "integer",
            "description": "Complementos de pago vigentes.",
            "format": "int32"
          },
          "cancelados": {
            "type": "integer",
            "description": "CFDI cancelados del periodo (según la base).",
            "format": "int32"
          },
          "canceladoMxn": {
            "type": "number",
            "description": "Total cancelado en MXN.",
            "format": "double"
          },
          "ivaTrasladadoMxn": {
            "type": "number",
            "description": "IVA trasladado de las facturas vigentes en MXN.",
            "format": "double"
          },
          "ivaRetenidoMxn": {
            "type": "number",
            "description": "IVA retenido de las facturas vigentes en MXN.",
            "format": "double"
          },
          "isrRetenidoMxn": {
            "type": "number",
            "description": "ISR retenido de las facturas vigentes en MXN.",
            "format": "double"
          },
          "facturasPpd": {
            "type": "integer",
            "description": "Facturas vigentes con método PPD.",
            "format": "int32"
          },
          "facturadoPpdMxn": {
            "type": "number",
            "description": "Total de las facturas PPD en MXN.",
            "format": "double"
          },
          "clientesDistintos": {
            "type": "integer",
            "description": "Clientes distintos facturados.",
            "format": "int32"
          },
          "facturadoMesAnteriorMxn": {
            "type": [
              "null",
              "number"
            ],
            "description": "Facturado en MXN del mes anterior (para comparar), si se conoce.",
            "format": "double"
          },
          "facturasMesAnterior": {
            "type": [
              "null",
              "integer"
            ],
            "description": "Facturas del mes anterior, si se conoce.",
            "format": "int32"
          },
          "timbresDisponibles": {
            "type": [
              "null",
              "integer"
            ],
            "description": "Timbres disponibles hoy, si se conoce.",
            "format": "int32"
          }
        },
        "description": "Cifras agregadas de un periodo: solo conteos e importes, sin RFC ni nombres."
      },
      "ComprobanteRevision": {
        "type": "object",
        "properties": {
          "tipo": {
            "type": [
              "null",
              "string"
            ],
            "description": "`factura` (por omisión), `nota_credito`, `honorarios` o `pago`."
          },
          "emisor": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Datos fiscales del emisor (sin RFC).",
                "$ref": "#/components/schemas/EmisorRevision"
              }
            ]
          },
          "receptor": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Datos fiscales del receptor (sin RFC ni nombre).",
                "$ref": "#/components/schemas/ReceptorRevision"
              }
            ]
          },
          "formaPago": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_FormaPago."
          },
          "metodoPago": {
            "type": [
              "null",
              "string"
            ],
            "description": "PUE o PPD."
          },
          "moneda": {
            "type": [
              "null",
              "string"
            ],
            "description": "MXN, USD…"
          },
          "tipoCambio": {
            "type": [
              "null",
              "number"
            ],
            "description": "Tipo de cambio (obligatorio en moneda distinta de MXN).",
            "format": "double"
          },
          "exportacion": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_Exportacion."
          },
          "informacionGlobal": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Información de la factura global, si la trae.",
                "$ref": "#/components/schemas/InformacionGlobalEntrada"
              }
            ]
          },
          "relacionados": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "CFDI relacionados (solo el tipo de relación y cuántos).",
                "$ref": "#/components/schemas/RelacionadosRevision"
              }
            ]
          },
          "conceptos": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/ConceptoRevision"
            },
            "description": "Conceptos (1 a 500)."
          },
          "totales": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Totales como los calculó el editor (opcional): se comparan con la suma de los conceptos.",
                "$ref": "#/components/schemas/TotalesBorrador"
              }
            ]
          }
        },
        "description": "Cuerpo de `POST /v1/ia/revisar`: el comprobante <b>sin RFC ni nombres</b> (solo claves, importes, régimen, uso,\r\nforma y método de pago e impuestos). El tipo de persona del receptor lo calcula quien llama a partir del RFC."
      },
      "ConceptoEntrada": {
        "type": "object",
        "properties": {
          "claveProdServ": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_ClaveProdServ (8 dígitos), por ejemplo `01010101` o `81112100` (`GET /v1/catalogos/productos-servicios?q=`)."
          },
          "claveUnidad": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_ClaveUnidad, por ejemplo `ACT`, `H87` o `E48` (`GET /v1/catalogos/unidades?q=`)."
          },
          "unidad": {
            "type": [
              "null",
              "string"
            ],
            "description": "Unidad (≤ 20), por ejemplo `Servicio`."
          },
          "noIdentificacion": {
            "type": [
              "null",
              "string"
            ],
            "description": "Número de identificación (≤ 50, opcional). El servicio de timbrado lo usa como código del catálogo de\r\nproductos del emisor y lo sobrescribe: se rechaza si ya existe en el catálogo del panel un producto con\r\nese código que no creó la API. Usa un prefijo propio."
          },
          "descripcion": {
            "type": [
              "null",
              "string"
            ],
            "description": "Descripción (1 a 1000, sin «|» ni saltos de línea)."
          },
          "cantidad": {
            "type": [
              "null",
              "number"
            ],
            "description": "Cantidad (&gt; 0, máximo 6 decimales).",
            "format": "double"
          },
          "valorUnitario": {
            "type": [
              "null",
              "number"
            ],
            "description": "Valor unitario sin impuestos (≥ 0, máximo 6 decimales).",
            "format": "double"
          },
          "descuento": {
            "type": [
              "null",
              "number"
            ],
            "description": "Descuento del concepto (≥ 0, ≤ importe, 2 decimales). Reduce la base de los impuestos.",
            "format": "double"
          },
          "objetoImp": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_ObjetoImp: `02` lleva impuestos; `01`, `03` y `04` no."
          },
          "impuestos": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Impuestos del concepto (la API calcula base e importe).",
                "$ref": "#/components/schemas/ImpuestosConceptoEntrada"
              }
            ]
          }
        },
        "description": "Concepto del CFDI."
      },
      "ConceptoRevision": {
        "type": "object",
        "properties": {
          "claveProdServ": {
            "type": [
              "null",
              "string"
            ],
            "description": "ClaveProdServ."
          },
          "claveUnidad": {
            "type": [
              "null",
              "string"
            ],
            "description": "ClaveUnidad."
          },
          "cantidad": {
            "type": "number",
            "description": "Cantidad.",
            "format": "double"
          },
          "valorUnitario": {
            "type": "number",
            "description": "Valor unitario.",
            "format": "double"
          },
          "descuento": {
            "type": "number",
            "description": "Descuento.",
            "format": "double"
          },
          "importe": {
            "type": [
              "null",
              "number"
            ],
            "description": "Importe como lo calculó el editor (opcional).",
            "format": "double"
          },
          "objetoImp": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_ObjetoImp."
          },
          "impuestos": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Impuestos del concepto.",
                "$ref": "#/components/schemas/ImpuestosRevision"
              }
            ]
          }
        },
        "description": "Concepto en la revisión (sin descripción)."
      },
      "DocumentoPagoEntrada": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": [
              "null",
              "string"
            ],
            "description": "UUID de la factura que se paga: si es del emisor, debe ser `PPD` y en `MXN`."
          },
          "numParcialidad": {
            "type": [
              "null",
              "integer"
            ],
            "description": "Número de parcialidad (1 a 999).",
            "format": "int32"
          },
          "saldoAnterior": {
            "type": [
              "null",
              "number"
            ],
            "description": "Saldo anterior (&gt; 0, 2 decimales).",
            "format": "double"
          },
          "importePagado": {
            "type": [
              "null",
              "number"
            ],
            "description": "Importe pagado (&gt; 0, 2 decimales, ≤ saldo anterior).",
            "format": "double"
          },
          "objetoImp": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_ObjetoImp del documento: `02` (predeterminado, lleva impuestos), `01` o `03`."
          },
          "impuestos": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Impuestos del documento.",
                "$ref": "#/components/schemas/ImpuestosDocumentoEntrada"
              }
            ]
          }
        },
        "description": "Documento relacionado de un pago."
      },
      "ElementoCatalogo": {
        "required": [
          "clave",
          "descripcion"
        ],
        "type": "object",
        "properties": {
          "clave": {
            "type": "string",
            "description": "Clave del SAT."
          },
          "descripcion": {
            "type": "string",
            "description": "Descripción."
          },
          "fisica": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Aplica a personas físicas (solo en usos de CFDI y regímenes fiscales)."
          },
          "moral": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Aplica a personas morales (solo en usos de CFDI y regímenes fiscales)."
          }
        },
        "description": "Elemento de un catálogo publicado."
      },
      "EmisorRevision": {
        "type": "object",
        "properties": {
          "regimenFiscal": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_RegimenFiscal del emisor."
          },
          "tipoPersona": {
            "type": [
              "null",
              "string"
            ],
            "description": "`fisica` o `moral`."
          }
        },
        "description": "Emisor en la revisión."
      },
      "EmisorVista": {
        "required": [
          "rfc",
          "nombre",
          "regimenFiscal",
          "modo",
          "seriePredeterminada",
          "sucursales",
          "series",
          "timbres"
        ],
        "type": "object",
        "properties": {
          "rfc": {
            "type": "string"
          },
          "nombre": {
            "type": "string"
          },
          "regimenFiscal": {
            "type": [
              "null",
              "string"
            ]
          },
          "modo": {
            "type": "string"
          },
          "seriePredeterminada": {
            "type": [
              "null",
              "string"
            ]
          },
          "sucursales": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SucursalVista"
            }
          },
          "series": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SerieVista"
            }
          },
          "timbres": {
            "$ref": "#/components/schemas/TimbresVista"
          }
        },
        "description": "Datos del emisor de la llave."
      },
      "Enlaces": {
        "type": "object",
        "properties": {
          "self": {
            "type": [
              "null",
              "string"
            ],
            "description": "El CFDI."
          },
          "xml": {
            "type": [
              "null",
              "string"
            ],
            "description": "XML timbrado."
          },
          "pdf": {
            "type": [
              "null",
              "string"
            ],
            "description": "PDF."
          },
          "solicitud": {
            "type": [
              "null",
              "string"
            ],
            "description": "Estado de la solicitud de emisión."
          }
        },
        "description": "Enlaces de un CFDI o de una solicitud."
      },
      "EnvioCfdi": {
        "required": [
          "fecha",
          "origen",
          "para",
          "copia",
          "asunto",
          "quien",
          "resultado",
          "error",
          "estado",
          "estadoFecha"
        ],
        "type": "object",
        "properties": {
          "fecha": {
            "type": "string",
            "format": "date-time"
          },
          "origen": {
            "type": "string"
          },
          "para": {
            "type": "string"
          },
          "copia": {
            "type": [
              "null",
              "string"
            ]
          },
          "asunto": {
            "type": [
              "null",
              "string"
            ]
          },
          "quien": {
            "type": [
              "null",
              "string"
            ]
          },
          "resultado": {
            "type": "string"
          },
          "error": {
            "type": [
              "null",
              "string"
            ]
          },
          "estado": {
            "type": [
              "null",
              "string"
            ]
          },
          "estadoFecha": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          }
        },
        "description": "Un envío por correo: origen panel, lote, api o recurrente; resultado enviado o error; estado de entrega de Brevo si lo hay."
      },
      "ErrorSolicitud": {
        "required": [
          "codigo",
          "mensaje"
        ],
        "type": "object",
        "properties": {
          "codigo": {
            "type": "string"
          },
          "mensaje": {
            "type": "string"
          }
        },
        "description": "Error de una solicitud rechazada."
      },
      "EstadoChat": {
        "required": [
          "habilitado",
          "conIa",
          "maxCaracteres",
          "privacidad"
        ],
        "type": "object",
        "properties": {
          "habilitado": {
            "type": "boolean",
            "description": "El chat atiende."
          },
          "conIa": {
            "type": "boolean",
            "description": "Responde el modelo (si no, la búsqueda en la ayuda)."
          },
          "maxCaracteres": {
            "type": "integer",
            "description": "Caracteres máximos por mensaje.",
            "format": "int32"
          },
          "privacidad": {
            "type": "string",
            "description": "Texto de privacidad que muestra el widget."
          }
        },
        "description": "Respuesta de `GET /chat/estado`."
      },
      "EstadoComponente": {
        "required": [
          "estado",
          "milisegundos"
        ],
        "type": "object",
        "properties": {
          "estado": {
            "type": "string",
            "description": "`ok` o `error`."
          },
          "milisegundos": {
            "type": "integer",
            "description": "Duración de la revisión.",
            "format": "int64"
          },
          "detalle": {
            "type": [
              "null",
              "string"
            ],
            "description": "Detalle sin secretos."
          }
        },
        "description": "Estado de un componente para `/salud/lista`."
      },
      "EstadoFuncionIa": {
        "required": [
          "nombre",
          "conIa"
        ],
        "type": "object",
        "properties": {
          "nombre": {
            "type": "string",
            "description": "Nombre de la función."
          },
          "conIa": {
            "type": "boolean",
            "description": "Verdadero si usará el modelo."
          }
        },
        "description": "Estado de una función."
      },
      "EstadoIa": {
        "required": [
          "habilitada",
          "motivo",
          "funciones",
          "peticionesPorMinuto",
          "tokensPorDia",
          "tokensUsadosHoy"
        ],
        "type": "object",
        "properties": {
          "habilitada": {
            "type": "boolean",
            "description": "Verdadero si las funciones usarán el modelo (si no, responden con el respaldo)."
          },
          "motivo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Por qué no está habilitada: `apagada`, `empresa_no_autorizada` o `empresa_desactivada`."
          },
          "funciones": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EstadoFuncionIa"
            },
            "description": "Funciones y si usan el modelo."
          },
          "peticionesPorMinuto": {
            "type": "integer",
            "description": "Límite de peticiones por minuto de la integración.",
            "format": "int32"
          },
          "tokensPorDia": {
            "type": "integer",
            "description": "Límite diario de tokens de la empresa (0 = sin tope).",
            "format": "int64"
          },
          "tokensUsadosHoy": {
            "type": "integer",
            "description": "Tokens usados hoy por la empresa.",
            "format": "int64"
          }
        },
        "description": "Estado de la IA para la empresa de la llave (`GET /v1/ia/estado`)."
      },
      "Hallazgo": {
        "required": [
          "nivel",
          "campo",
          "mensaje",
          "sugerencia",
          "regla",
          "origen"
        ],
        "type": "object",
        "properties": {
          "nivel": {
            "type": "string",
            "description": "`error`, `advertencia` o `sugerencia`."
          },
          "campo": {
            "type": "string",
            "description": "Campo del comprobante (por ejemplo `formaPago` o `conceptos[0].impuestos`)."
          },
          "mensaje": {
            "type": "string",
            "description": "Qué está mal o qué conviene revisar."
          },
          "sugerencia": {
            "type": [
              "null",
              "string"
            ],
            "description": "Cómo corregirlo."
          },
          "regla": {
            "type": [
              "null",
              "string"
            ],
            "description": "Id de la regla de miCFDI (R01…); null si lo encontró la IA."
          },
          "origen": {
            "type": "string",
            "description": "`regla` o `ia`."
          }
        },
        "description": "Hallazgo de la revisión."
      },
      "ImpuestoDocumentoEntrada": {
        "type": "object",
        "properties": {
          "impuesto": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_Impuesto: `002` (IVA) en traslados; `001` (ISR) o `002` (IVA) en retenciones."
          },
          "tipoFactor": {
            "type": [
              "null",
              "string"
            ],
            "description": "`Tasa` o `Exento`."
          },
          "tasaOCuota": {
            "type": [
              "null",
              "number"
            ],
            "description": "Tasa con máximo 6 decimales (no aplica con `Exento`).",
            "format": "double"
          },
          "base": {
            "type": [
              "null",
              "number"
            ],
            "description": "Base (opcional; obligatoria si el mismo impuesto viene con varias tasas).",
            "format": "double"
          },
          "importe": {
            "type": [
              "null",
              "number"
            ],
            "description": "Importe (opcional; si no viene, base × tasa).",
            "format": "double"
          }
        },
        "description": "Impuesto de un documento pagado. Si no vienen base e importe, la API los calcula (una sola tasa por impuesto)."
      },
      "ImpuestoEntrada": {
        "type": "object",
        "properties": {
          "impuesto": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_Impuesto: `002` (IVA) o `003` (IEPS por tasa) en traslados; `001` (ISR) o `002` (IVA) en retenciones."
          },
          "tipoFactor": {
            "type": [
              "null",
              "string"
            ],
            "description": "`Tasa` o `Exento` (exento solo en traslados de IVA)."
          },
          "tasaOCuota": {
            "type": [
              "null",
              "number"
            ],
            "description": "Tasa con máximo 6 decimales (no aplica con `Exento`), por ejemplo 0.16.",
            "format": "double"
          },
          "importe": {
            "type": [
              "null",
              "number"
            ],
            "description": "Importe del impuesto (opcional, 2 decimales; no aplica con `Exento`). Si no viene, la API calcula\r\nBase × Tasa redondeado. Si viene, se respeta cuando cae dentro de los límites del SAT (Anexo 20: Base ± 0.005\r\npor la tasa, truncado abajo y redondeado arriba); fuera de ellos, se rechaza. Sirve para cuadrar al centavo\r\nun total con IVA incluido (FIS-54).",
            "format": "double"
          }
        },
        "description": "Un impuesto de un concepto: la base la calcula la API; el importe también, salvo que lo mandes."
      },
      "ImpuestoRevision": {
        "type": "object",
        "properties": {
          "impuesto": {
            "type": [
              "null",
              "string"
            ],
            "description": "001 ISR, 002 IVA, 003 IEPS."
          },
          "tipoFactor": {
            "type": [
              "null",
              "string"
            ],
            "description": "Tasa, Cuota o Exento."
          },
          "tasaOCuota": {
            "type": [
              "null",
              "number"
            ],
            "description": "Tasa (por ejemplo 0.16).",
            "format": "double"
          },
          "base": {
            "type": [
              "null",
              "number"
            ],
            "description": "Base como la calculó el editor (opcional).",
            "format": "double"
          },
          "importe": {
            "type": [
              "null",
              "number"
            ],
            "description": "Importe como lo calculó el editor (opcional).",
            "format": "double"
          }
        },
        "description": "Impuesto en la revisión."
      },
      "ImpuestosConceptoEntrada": {
        "type": "object",
        "properties": {
          "traslados": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/ImpuestoEntrada"
            },
            "description": "Traslados: IVA (`002`) con `Tasa` 0.16, 0.08 o 0.00, o `Exento`; IEPS (`003`) con `Tasa` fija de c_TasaOCuota (0.265, 0.30, 0.53, 0.50, 1.60, 0.304, 0.25, 0.09, 0.08, 0.07, 0.06, 0.03 o 0.00), y entonces el IVA va sobre el valor más el IEPS. El factor `Cuota` no se acepta en la v1."
          },
          "retenciones": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/ImpuestoEntrada"
            },
            "description": "Retenciones: ISR (`001`) o IVA (`002`) con `Tasa` entre 0 y 1, por ejemplo 0.10 y 0.106667."
          }
        },
        "description": "Traslados y retenciones de un concepto."
      },
      "ImpuestosDocumentoEntrada": {
        "type": "object",
        "properties": {
          "traslados": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/ImpuestoDocumentoEntrada"
            },
            "description": "Traslados del documento: uno por combinación (impuesto, tipo de factor, tasa), por ejemplo IVA 0.16 y 0.00."
          },
          "retenciones": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/ImpuestoDocumentoEntrada"
            },
            "description": "Retenciones del documento."
          }
        },
        "description": "Traslados y retenciones de un documento pagado."
      },
      "ImpuestosRevision": {
        "type": "object",
        "properties": {
          "traslados": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/ImpuestoRevision"
            },
            "description": "Traslados."
          },
          "retenciones": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/ImpuestoRevision"
            },
            "description": "Retenciones."
          }
        },
        "description": "Impuestos de un concepto en la revisión."
      },
      "InformacionGlobalEntrada": {
        "type": "object",
        "properties": {
          "periodicidad": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_Periodicidad: `01` diario, `02` semanal, `03` quincenal, `04` mensual o `05` bimestral."
          },
          "meses": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_Meses: `01` a `12`; `13` a `18` con periodicidad bimestral."
          },
          "anio": {
            "type": [
              "null",
              "integer"
            ],
            "description": "Año (el actual o el anterior).",
            "format": "int32"
          }
        },
        "description": "Información de la factura global."
      },
      "InfoVersion": {
        "required": [
          "version",
          "commit",
          "fecha"
        ],
        "type": "object",
        "properties": {
          "version": {
            "type": "string"
          },
          "commit": {
            "type": [
              "null",
              "string"
            ]
          },
          "fecha": {
            "type": [
              "null",
              "string"
            ]
          }
        },
        "description": "Versión, commit y fecha de compilación embebidos en el ensamblado."
      },
      "JsonObject": {
        "type": "object"
      },
      "ListaCatalogos": {
        "required": [
          "catalogos"
        ],
        "type": "object",
        "properties": {
          "catalogos": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Nombres para `GET /v1/catalogos/{nombre}`."
          }
        },
        "description": "Catálogos disponibles."
      },
      "ListasSatVista": {
        "required": [
          "rfc",
          "enListas",
          "publicaciones"
        ],
        "type": "object",
        "properties": {
          "rfc": {
            "type": "string",
            "description": "El RFC consultado."
          },
          "enListas": {
            "type": "boolean",
            "description": "Si aparece en algún supuesto de riesgo. Un Desvirtuado o una Sentencia favorable del 69-B no cuentan."
          },
          "publicaciones": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicacionVista"
            },
            "description": "Dónde aparece."
          }
        },
        "description": "La respuesta."
      },
      "ListaWebhooks": {
        "required": [
          "datos"
        ],
        "type": "object",
        "properties": {
          "datos": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookVista"
            },
            "description": "Webhooks activos del modo de la llave (sin secreto)."
          }
        },
        "description": "Lista de webhooks."
      },
      "MensajeChatEntrada": {
        "type": "object",
        "properties": {
          "rol": {
            "type": [
              "null",
              "string"
            ],
            "description": "`usuario` o `asistente`."
          },
          "texto": {
            "type": [
              "null",
              "string"
            ],
            "description": "Texto del mensaje."
          },
          "firma": {
            "type": [
              "null",
              "string"
            ],
            "description": "Firma que dio la API a esa respuesta del asistente (solo en mensajes del asistente)."
          }
        },
        "description": "Un mensaje de la conversación tal como lo manda el navegador."
      },
      "PagoEntrada": {
        "type": "object",
        "properties": {
          "fechaPago": {
            "type": [
              "null",
              "string"
            ],
            "description": "Fecha del pago, `yyyy-MM-ddTHH:mm:ss` (hora del centro de México), no futura."
          },
          "formaPago": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_FormaPago del pago (por ejemplo `03`; `99` no aplica)."
          },
          "moneda": {
            "type": [
              "null",
              "string"
            ],
            "description": "Moneda del pago: solo `MXN`."
          },
          "monto": {
            "type": [
              "null",
              "number"
            ],
            "description": "Monto (&gt; 0, 2 decimales, ≤ 9,999,999.99): igual a la suma de los `importePagado` de sus documentos.",
            "format": "double"
          },
          "numeroOperacion": {
            "type": [
              "null",
              "string"
            ],
            "description": "Número de operación (≤ 50)."
          },
          "documentos": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/DocumentoPagoEntrada"
            },
            "description": "Documentos que se pagan (cada UUID una sola vez)."
          }
        },
        "description": "El pago del complemento de pago 2.0 (uno por complemento)."
      },
      "ParteFiscal": {
        "required": [
          "rfc",
          "nombre"
        ],
        "type": "object",
        "properties": {
          "rfc": {
            "type": [
              "null",
              "string"
            ]
          },
          "nombre": {
            "type": [
              "null",
              "string"
            ]
          }
        },
        "description": "RFC y nombre de una parte del CFDI."
      },
      "ProblemaApi": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "`https://api.micfdi.com.mx/errores/{codigo}`."
          },
          "title": {
            "type": "string",
            "description": "Título corto."
          },
          "status": {
            "type": "integer",
            "description": "Estado HTTP.",
            "format": "int32"
          },
          "detail": {
            "type": "string",
            "description": "Explicación para el integrador."
          },
          "codigo": {
            "type": "string",
            "description": "Código estable de la API."
          },
          "errores": {
            "type": [
              "null",
              "object"
            ],
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Errores por campo (validación)."
          },
          "solicitudId": {
            "type": [
              "null",
              "string"
            ],
            "description": "Id de la solicitud de emisión, cuando aplica.",
            "format": "uuid"
          }
        },
        "description": "Cuerpo de error `application/problem+json` (RFC 9457) con los campos propios de la API\r\n(especificación §3): `codigo`, `errores` y `solicitudId`."
      },
      "PublicacionVista": {
        "required": [
          "lista",
          "supuesto",
          "fecha",
          "oficio"
        ],
        "type": "object",
        "properties": {
          "lista": {
            "type": "string",
            "description": "69B o 69-NoLocalizados, 69-Firmes, 69-Exigibles, 69-Cancelados, 69-Sentencias."
          },
          "supuesto": {
            "type": "string",
            "description": "Presunto o Definitivo (69-B) o el supuesto del 69 como lo publica el SAT."
          },
          "fecha": {
            "type": [
              "null",
              "string"
            ],
            "description": "La publicación de ese supuesto (aaaa-mm-dd)."
          },
          "oficio": {
            "type": [
              "null",
              "string"
            ],
            "description": "El oficio global del SAT (solo 69-B)."
          }
        },
        "description": "Una publicación en la que aparece el RFC."
      },
      "ReceptorEntrada": {
        "type": "object",
        "properties": {
          "rfc": {
            "type": [
              "null",
              "string"
            ],
            "description": "RFC (12 caracteres persona moral, 13 persona física; `XAXX010101000` público en general)."
          },
          "nombre": {
            "type": [
              "null",
              "string"
            ],
            "description": "Nombre o razón social tal como está en la constancia del SAT, sin régimen societario (≤ 250). Se envía en mayúsculas."
          },
          "regimenFiscal": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_RegimenFiscal del receptor, por ejemplo `601`, `612`, `626` o `616` (obligatorio con `XAXX010101000`)."
          },
          "codigoPostal": {
            "type": [
              "null",
              "string"
            ],
            "description": "Código postal del domicilio fiscal (5 dígitos). Con RFC genérico es el de la sucursal: puede omitirse."
          },
          "usoCfdi": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_UsoCFDI, por ejemplo `G03`, `G01`, `D01` o `S01` (`P01` no es válido en 4.0; en `pago` es `CP01`)."
          },
          "correo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Correo del receptor (opcional, ≤ 250)."
          }
        },
        "description": "Receptor del CFDI."
      },
      "ReceptorRevision": {
        "type": "object",
        "properties": {
          "tipoPersona": {
            "type": [
              "null",
              "string"
            ],
            "description": "`fisica`, `moral`, `publico_general` (XAXX010101000) o `extranjero` (XEXX010101000)."
          },
          "regimenFiscal": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_RegimenFiscal del receptor."
          },
          "usoCfdi": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_UsoCFDI."
          },
          "codigoPostalIgualAlDeExpedicion": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Verdadero si el código postal del receptor es el del lugar de expedición (obligatorio con RFC genérico)."
          }
        },
        "description": "Receptor en la revisión."
      },
      "RelacionadosEntrada": {
        "type": "object",
        "properties": {
          "tipoRelacion": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_TipoRelacion: `01` a `07` (por ejemplo `01` nota de crédito, `04` sustitución)."
          },
          "uuids": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "type": "string"
            },
            "description": "UUID relacionados (1 a 100, sin repetir)."
          }
        },
        "description": "CFDI relacionados (un solo grupo, como admite el servicio de timbrado)."
      },
      "RelacionadosRevision": {
        "type": "object",
        "properties": {
          "tipoRelacion": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_TipoRelacion."
          },
          "cantidad": {
            "type": "integer",
            "description": "Cuántos UUID se relacionan.",
            "format": "int32"
          }
        },
        "description": "Relacionados en la revisión."
      },
      "RespuestaCancelacion": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "description": "UUID cancelado."
          },
          "solicitud": {
            "type": "string",
            "description": "`aceptada` (el SAT recibió la solicitud) o `rechazada`, según el EstatusUUID del acuse y el SAT."
          },
          "estado": {
            "type": [
              "null",
              "string"
            ],
            "description": "Estado real en el SAT: cancelado, en_proceso, vigente, rechazada o no_encontrado (null si el SAT no respondió)."
          },
          "esCancelable": {
            "type": [
              "null",
              "string"
            ],
            "description": "EsCancelable del SAT."
          },
          "estatusCancelacion": {
            "type": [
              "null",
              "string"
            ],
            "description": "EstatusCancelacion del SAT."
          },
          "acuse": {
            "description": "Datos del acuse.",
            "$ref": "#/components/schemas/AcuseCancelacion"
          },
          "mensaje": {
            "type": [
              "null",
              "string"
            ],
            "description": "Aviso adicional."
          },
          "simulado": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Verdadero en modo de pruebas."
          }
        },
        "description": "Respuesta de la cancelación (especificación §6)."
      },
      "RespuestaChat": {
        "required": [
          "respuesta",
          "origen",
          "aviso",
          "firma",
          "datosOcultos",
          "mensajesRestantes"
        ],
        "type": "object",
        "properties": {
          "respuesta": {
            "type": [
              "null",
              "string"
            ],
            "description": "Texto de la respuesta (con flujo, ya llegó en los eventos `delta`/`reemplazo`)."
          },
          "origen": {
            "type": "string",
            "description": "`ia` (respondió el modelo), `respaldo` (búsqueda en la ayuda, sin IA) o `guarda` (respuesta fija)."
          },
          "aviso": {
            "type": [
              "null",
              "string"
            ],
            "description": "Por qué se respondió sin IA, o que la respuesta se cortó; null si no hay nada que avisar."
          },
          "firma": {
            "type": "string",
            "description": "Firma de esta respuesta: el navegador la regresa con el historial."
          },
          "datosOcultos": {
            "type": "boolean",
            "description": "Verdadero si el mensaje traía RFC, CURP, correos, teléfonos o cuentas y se ocultaron."
          },
          "mensajesRestantes": {
            "type": "integer",
            "description": "Mensajes que le quedan hoy a esta sesión.",
            "format": "int32"
          },
          "sugerirSoporte": {
            "type": "boolean",
            "description": "Verdadero si conviene ofrecer «Hablar con soporte» (el modelo no pudo resolver, el caso necesita a una persona o\r\nel usuario lo pidió). Con flujo, además llega antes de `fin` el evento `sugerir_soporte`.",
            "default": false
          }
        },
        "description": "Respuesta de `POST /chat/mensajes` sin flujo (y datos del evento `fin` del flujo)."
      },
      "RespuestaCorreo": {
        "required": [
          "uuid",
          "estado",
          "para",
          "copia"
        ],
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "description": "CFDI enviado."
          },
          "estado": {
            "type": "string",
            "description": "`enviado` (el servicio de correo lo aceptó; no se confirma la entrega) o `simulado`."
          },
          "para": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Destinatarios."
          },
          "copia": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Copias."
          }
        },
        "description": "Respuesta de `POST /v1/cfdi/{uuid}/correo`."
      },
      "RespuestaEmision": {
        "type": "object",
        "properties": {
          "id": {
            "type": [
              "null",
              "string"
            ],
            "description": "Id de la solicitud de emisión (null si el CFDI no se emitió por la API).",
            "format": "uuid"
          },
          "modo": {
            "type": "string",
            "description": "`live` o `test`."
          },
          "estado": {
            "type": "string",
            "description": "`timbrado`, `verificando`, `simulado`, `incierto`, `rechazado` o `procesando`."
          },
          "tipo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Tipo público del comprobante."
          },
          "referencia": {
            "type": [
              "null",
              "string"
            ],
            "description": "Referencia del integrador."
          },
          "uuid": {
            "type": [
              "null",
              "string"
            ],
            "description": "Folio fiscal."
          },
          "serie": {
            "type": [
              "null",
              "string"
            ],
            "description": "Serie."
          },
          "folio": {
            "type": [
              "null",
              "string"
            ],
            "description": "Folio."
          },
          "fecha": {
            "type": [
              "null",
              "string"
            ],
            "description": "Fecha del CFDI, hora del centro de México."
          },
          "fechaTimbrado": {
            "type": [
              "null",
              "string"
            ],
            "description": "Fecha del timbrado."
          },
          "emisor": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Emisor.",
                "$ref": "#/components/schemas/ParteFiscal"
              }
            ]
          },
          "receptor": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Receptor.",
                "$ref": "#/components/schemas/ParteFiscal"
              }
            ]
          },
          "moneda": {
            "type": [
              "null",
              "string"
            ],
            "description": "Moneda."
          },
          "subtotal": {
            "type": "number",
            "description": "Subtotal.",
            "format": "double"
          },
          "descuento": {
            "type": "number",
            "description": "Descuento.",
            "format": "double"
          },
          "impuestosTrasladados": {
            "type": "number",
            "description": "Impuestos trasladados.",
            "format": "double"
          },
          "impuestosRetenidos": {
            "type": "number",
            "description": "Impuestos retenidos.",
            "format": "double"
          },
          "total": {
            "type": "number",
            "description": "Total.",
            "format": "double"
          },
          "enlaces": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Enlaces al recurso, al XML y al PDF.",
                "$ref": "#/components/schemas/Enlaces"
              }
            ]
          },
          "cancelado": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Solo en el detalle: según la base del panel. El dato definitivo es `/estatus-sat`."
          },
          "ultimaCancelacion": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Solo en el detalle, si existe.",
                "$ref": "#/components/schemas/CancelacionResumen"
              }
            ]
          },
          "error": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Solo en solicitudes rechazadas.",
                "$ref": "#/components/schemas/ErrorSolicitud"
              }
            ]
          }
        },
        "description": "Respuesta de la emisión y del detalle de un CFDI (especificación §4.3)."
      },
      "RespuestaEnvios": {
        "required": [
          "uuid",
          "envios"
        ],
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string"
          },
          "envios": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EnvioCfdi"
            }
          }
        },
        "description": "t55/env · Respuesta de `GET /v1/cfdi/{uuid}/envios`."
      },
      "RespuestaEstatusSat": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "description": "UUID consultado."
          },
          "estado": {
            "type": "string",
            "description": "vigente, cancelado, en_proceso, rechazada o no_encontrado."
          },
          "estadoSat": {
            "type": [
              "null",
              "string"
            ],
            "description": "Estado textual del SAT."
          },
          "esCancelable": {
            "type": [
              "null",
              "string"
            ],
            "description": "EsCancelable del SAT."
          },
          "estatusCancelacion": {
            "type": [
              "null",
              "string"
            ],
            "description": "EstatusCancelacion del SAT."
          },
          "codigoEstatus": {
            "type": [
              "null",
              "string"
            ],
            "description": "CodigoEstatus del SAT."
          },
          "validacionEfos": {
            "type": [
              "null",
              "string"
            ],
            "description": "ValidacionEFOS del SAT."
          },
          "consultado": {
            "type": "string",
            "description": "Momento de la consulta (hora del centro de México)."
          }
        },
        "description": "Respuesta de `GET /v1/cfdi/{uuid}/estatus-sat`."
      },
      "RespuestaIaOfResultadoAyuda": {
        "required": [
          "funcion",
          "origen",
          "modelo",
          "aviso",
          "resultado"
        ],
        "type": "object",
        "properties": {
          "funcion": {
            "type": "string",
            "description": "Función que respondió (`claves-sat`, `borrador`…)."
          },
          "origen": {
            "type": "string",
            "description": "`ia` (lo produjo el modelo y la API lo validó) o `respaldo` (cálculo determinista, sin IA)."
          },
          "modelo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Modelo que respondió (solo con origen `ia`)."
          },
          "aviso": {
            "type": [
              "null",
              "string"
            ],
            "description": "Por qué se usó el respaldo (IA apagada, límite diario, error…); null con origen `ia`."
          },
          "resultado": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Resultado de la función.",
                "$ref": "#/components/schemas/ResultadoAyuda"
              }
            ]
          }
        },
        "description": "Sobre común de las respuestas de `/v1/ia`."
      },
      "RespuestaIaOfResultadoBorrador": {
        "required": [
          "funcion",
          "origen",
          "modelo",
          "aviso",
          "resultado"
        ],
        "type": "object",
        "properties": {
          "funcion": {
            "type": "string",
            "description": "Función que respondió (`claves-sat`, `borrador`…)."
          },
          "origen": {
            "type": "string",
            "description": "`ia` (lo produjo el modelo y la API lo validó) o `respaldo` (cálculo determinista, sin IA)."
          },
          "modelo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Modelo que respondió (solo con origen `ia`)."
          },
          "aviso": {
            "type": [
              "null",
              "string"
            ],
            "description": "Por qué se usó el respaldo (IA apagada, límite diario, error…); null con origen `ia`."
          },
          "resultado": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Resultado de la función.",
                "$ref": "#/components/schemas/ResultadoBorrador"
              }
            ]
          }
        },
        "description": "Sobre común de las respuestas de `/v1/ia`."
      },
      "RespuestaIaOfResultadoClavesSat": {
        "required": [
          "funcion",
          "origen",
          "modelo",
          "aviso",
          "resultado"
        ],
        "type": "object",
        "properties": {
          "funcion": {
            "type": "string",
            "description": "Función que respondió (`claves-sat`, `borrador`…)."
          },
          "origen": {
            "type": "string",
            "description": "`ia` (lo produjo el modelo y la API lo validó) o `respaldo` (cálculo determinista, sin IA)."
          },
          "modelo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Modelo que respondió (solo con origen `ia`)."
          },
          "aviso": {
            "type": [
              "null",
              "string"
            ],
            "description": "Por qué se usó el respaldo (IA apagada, límite diario, error…); null con origen `ia`."
          },
          "resultado": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Resultado de la función.",
                "$ref": "#/components/schemas/ResultadoClavesSat"
              }
            ]
          }
        },
        "description": "Sobre común de las respuestas de `/v1/ia`."
      },
      "RespuestaIaOfResultadoExplicacion": {
        "required": [
          "funcion",
          "origen",
          "modelo",
          "aviso",
          "resultado"
        ],
        "type": "object",
        "properties": {
          "funcion": {
            "type": "string",
            "description": "Función que respondió (`claves-sat`, `borrador`…)."
          },
          "origen": {
            "type": "string",
            "description": "`ia` (lo produjo el modelo y la API lo validó) o `respaldo` (cálculo determinista, sin IA)."
          },
          "modelo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Modelo que respondió (solo con origen `ia`)."
          },
          "aviso": {
            "type": [
              "null",
              "string"
            ],
            "description": "Por qué se usó el respaldo (IA apagada, límite diario, error…); null con origen `ia`."
          },
          "resultado": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Resultado de la función.",
                "$ref": "#/components/schemas/ResultadoExplicacion"
              }
            ]
          }
        },
        "description": "Sobre común de las respuestas de `/v1/ia`."
      },
      "RespuestaIaOfResultadoRecordatorio": {
        "required": [
          "funcion",
          "origen",
          "modelo",
          "aviso",
          "resultado"
        ],
        "type": "object",
        "properties": {
          "funcion": {
            "type": "string",
            "description": "Función que respondió (`claves-sat`, `borrador`…)."
          },
          "origen": {
            "type": "string",
            "description": "`ia` (lo produjo el modelo y la API lo validó) o `respaldo` (cálculo determinista, sin IA)."
          },
          "modelo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Modelo que respondió (solo con origen `ia`)."
          },
          "aviso": {
            "type": [
              "null",
              "string"
            ],
            "description": "Por qué se usó el respaldo (IA apagada, límite diario, error…); null con origen `ia`."
          },
          "resultado": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Resultado de la función.",
                "$ref": "#/components/schemas/ResultadoRecordatorio"
              }
            ]
          }
        },
        "description": "Sobre común de las respuestas de `/v1/ia`."
      },
      "RespuestaIaOfResultadoResumen": {
        "required": [
          "funcion",
          "origen",
          "modelo",
          "aviso",
          "resultado"
        ],
        "type": "object",
        "properties": {
          "funcion": {
            "type": "string",
            "description": "Función que respondió (`claves-sat`, `borrador`…)."
          },
          "origen": {
            "type": "string",
            "description": "`ia` (lo produjo el modelo y la API lo validó) o `respaldo` (cálculo determinista, sin IA)."
          },
          "modelo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Modelo que respondió (solo con origen `ia`)."
          },
          "aviso": {
            "type": [
              "null",
              "string"
            ],
            "description": "Por qué se usó el respaldo (IA apagada, límite diario, error…); null con origen `ia`."
          },
          "resultado": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Resultado de la función.",
                "$ref": "#/components/schemas/ResultadoResumen"
              }
            ]
          }
        },
        "description": "Sobre común de las respuestas de `/v1/ia`."
      },
      "RespuestaIaOfResultadoRevision": {
        "required": [
          "funcion",
          "origen",
          "modelo",
          "aviso",
          "resultado"
        ],
        "type": "object",
        "properties": {
          "funcion": {
            "type": "string",
            "description": "Función que respondió (`claves-sat`, `borrador`…)."
          },
          "origen": {
            "type": "string",
            "description": "`ia` (lo produjo el modelo y la API lo validó) o `respaldo` (cálculo determinista, sin IA)."
          },
          "modelo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Modelo que respondió (solo con origen `ia`)."
          },
          "aviso": {
            "type": [
              "null",
              "string"
            ],
            "description": "Por qué se usó el respaldo (IA apagada, límite diario, error…); null con origen `ia`."
          },
          "resultado": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Resultado de la función.",
                "$ref": "#/components/schemas/ResultadoRevision"
              }
            ]
          }
        },
        "description": "Sobre común de las respuestas de `/v1/ia`."
      },
      "RespuestaPrueba": {
        "required": [
          "evento",
          "estado"
        ],
        "type": "object",
        "properties": {
          "evento": {
            "type": "integer",
            "description": "Id del evento (también llega en la cabecera `MiCFDI-Entrega`).",
            "format": "int64"
          },
          "estado": {
            "type": "string",
            "description": "Siempre `encolado`."
          }
        },
        "description": "Evento de prueba encolado."
      },
      "RespuestaTicket": {
        "required": [
          "folio",
          "correo"
        ],
        "type": "object",
        "properties": {
          "folio": {
            "type": "string",
            "description": "Folio legible (`MC-000123`)."
          },
          "correo": {
            "type": "string",
            "description": "Buzón de soporte (`soporte@micfdi.com.mx`)."
          }
        },
        "description": "Respuesta 200 de los tickets."
      },
      "ResultadoAyuda": {
        "required": [
          "respuesta",
          "pasos",
          "articulos",
          "encontrado"
        ],
        "type": "object",
        "properties": {
          "respuesta": {
            "type": "string",
            "description": "Respuesta en texto plano."
          },
          "pasos": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Pasos a seguir en el panel, en orden."
          },
          "articulos": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ArticuloCitado"
            },
            "description": "Artículos de la ayuda de miCFDI en los que se basa (siempre existen)."
          },
          "encontrado": {
            "type": "boolean",
            "description": "Falso si la ayuda no cubre la pregunta."
          }
        },
        "description": "Respuesta del asistente de ayuda."
      },
      "ResultadoBorrador": {
        "required": [
          "borrador",
          "totales",
          "notas",
          "dudas"
        ],
        "type": "object",
        "properties": {
          "borrador": {
            "description": "Mismo formato que el cuerpo de `POST /v1/cfdi`.",
            "$ref": "#/components/schemas/SolicitudEmision"
          },
          "totales": {
            "description": "Totales estimados con las reglas de cálculo de la API.",
            "$ref": "#/components/schemas/TotalesBorrador"
          },
          "notas": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Lo que se decidió o corrigió al armar el borrador."
          },
          "dudas": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Lo que falta o hay que confirmar antes de timbrar."
          }
        },
        "description": "Borrador para prellenar el editor. <b>No se timbra</b>: hay que revisarlo y emitirlo aparte."
      },
      "ResultadoClavesSat": {
        "required": [
          "sugerencias",
          "unidad",
          "descartadas"
        ],
        "type": "object",
        "properties": {
          "sugerencias": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SugerenciaClave"
            },
            "description": "Hasta 5 ClaveProdServ, de la más a la menos probable."
          },
          "unidad": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "ClaveUnidad sugerida (existe en c_ClaveUnidad).",
                "$ref": "#/components/schemas/SugerenciaUnidad"
              }
            ]
          },
          "descartadas": {
            "type": "integer",
            "description": "Claves que propuso el modelo y no existen en el catálogo (no se devuelven).",
            "format": "int32"
          }
        },
        "description": "Claves sugeridas. Toda clave existe en el catálogo c_ClaveProdServ de la base."
      },
      "ResultadoExplicacion": {
        "required": [
          "codigo",
          "reconocido",
          "titulo",
          "explicacion",
          "causaProbable",
          "pasos",
          "categoria"
        ],
        "type": "object",
        "properties": {
          "codigo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Código reconocido o extraído del mensaje."
          },
          "reconocido": {
            "type": "boolean",
            "description": "Verdadero si el error está en la tabla de errores conocidos de miCFDI."
          },
          "titulo": {
            "type": "string",
            "description": "Título corto."
          },
          "explicacion": {
            "type": "string",
            "description": "Qué significa, sin tecnicismos."
          },
          "causaProbable": {
            "type": "string",
            "description": "Causa más probable."
          },
          "pasos": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Qué hacer para corregirlo, en orden."
          },
          "categoria": {
            "type": "string",
            "description": "receptor, emisor, certificado, conceptos, impuestos, pago, folios, timbres, cancelacion, servicio u otro."
          },
          "campo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Dato del CFDI donde está el problema, como ruta del XML (por ejemplo `Receptor.Nombre` o\r\n`Concepto.ObjetoImp`); null si el error no es de un campo. Sale del catálogo de errores de miCFDI: si no se\r\nindica, se toma del código cuando el catálogo lo conoce sin ambigüedad."
          },
          "ayuda": {
            "type": [
              "null",
              "string"
            ],
            "description": "t54/err · Liga pública a la explicación del código en micfdi.com.mx/ayuda/errores (ErroresPublicos);\r\nnull si el código no se publica (los internos de miCFDI y los de la cuenta con el proveedor)."
          }
        },
        "description": "Explicación en lenguaje claro."
      },
      "ResultadoPaginadoOfCfdiResumen": {
        "required": [
          "pagina",
          "tamanio",
          "total",
          "datos"
        ],
        "type": "object",
        "properties": {
          "pagina": {
            "type": "integer",
            "description": "Número de página (desde 1).",
            "format": "int32"
          },
          "tamanio": {
            "type": "integer",
            "description": "Elementos por página.",
            "format": "int32"
          },
          "total": {
            "type": "integer",
            "description": "Total de elementos que cumplen el filtro.",
            "format": "int32"
          },
          "datos": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CfdiResumen"
            },
            "description": "Elementos de la página."
          }
        },
        "description": "Página de resultados."
      },
      "ResultadoRecordatorio": {
        "required": [
          "plantilla",
          "mensaje",
          "marcadores"
        ],
        "type": "object",
        "properties": {
          "plantilla": {
            "description": "Texto con los marcadores {cliente}, {folio}, {saldo} y {vencimiento}.",
            "$ref": "#/components/schemas/TextoRecordatorio"
          },
          "mensaje": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Texto final con los valores reemplazados (solo si vinieron `valores`).",
                "$ref": "#/components/schemas/TextoRecordatorio"
              }
            ]
          },
          "marcadores": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Marcadores que usa la plantilla."
          }
        },
        "description": "Recordatorio de cobranza."
      },
      "ResultadoResumen": {
        "required": [
          "titulo",
          "resumen",
          "puntos",
          "alertas",
          "paraElContador",
          "cifras"
        ],
        "type": "object",
        "properties": {
          "titulo": {
            "type": "string",
            "description": "Título (por ejemplo «Septiembre de 2026»)."
          },
          "resumen": {
            "type": "string",
            "description": "Párrafo corto."
          },
          "puntos": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Puntos clave."
          },
          "alertas": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Lo que requiere atención."
          },
          "paraElContador": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Lo que conviene mandarle al contador."
          },
          "cifras": {
            "description": "Las cifras con que se redactó.",
            "$ref": "#/components/schemas/CifrasPeriodo"
          }
        },
        "description": "Resumen ejecutivo del periodo."
      },
      "ResultadoRevision": {
        "required": [
          "apto",
          "errores",
          "advertencias",
          "sugerencias",
          "hallazgos"
        ],
        "type": "object",
        "properties": {
          "apto": {
            "type": "boolean",
            "description": "Verdadero si no hay hallazgos de nivel `error`."
          },
          "errores": {
            "type": "integer",
            "description": "Cuántos errores (impiden timbrar o el SAT lo rechazaría).",
            "format": "int32"
          },
          "advertencias": {
            "type": "integer",
            "description": "Cuántas advertencias (conviene revisar).",
            "format": "int32"
          },
          "sugerencias": {
            "type": "integer",
            "description": "Cuántas sugerencias.",
            "format": "int32"
          },
          "hallazgos": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Hallazgo"
            },
            "description": "Primero los de las reglas de miCFDI y luego los de la IA (que nunca son de nivel `error`)."
          }
        },
        "description": "Resultado de la revisión."
      },
      "SaludLista": {
        "required": [
          "estado",
          "componentes"
        ],
        "type": "object",
        "properties": {
          "estado": {
            "type": "string"
          },
          "componentes": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/EstadoComponente"
            }
          }
        },
        "description": "Respuesta de `/salud/lista`."
      },
      "SerieVista": {
        "required": [
          "tipo",
          "serie",
          "idSucursal",
          "siguienteFolio",
          "foliosRestantes",
          "duplicada"
        ],
        "type": "object",
        "properties": {
          "tipo": {
            "type": "string"
          },
          "serie": {
            "type": "string"
          },
          "idSucursal": {
            "type": "integer",
            "format": "int32"
          },
          "siguienteFolio": {
            "type": "integer",
            "format": "int32"
          },
          "foliosRestantes": {
            "type": "integer",
            "format": "int32"
          },
          "duplicada": {
            "type": "boolean"
          }
        },
        "description": "Serie disponible para un tipo."
      },
      "SolicitudAyuda": {
        "type": "object",
        "properties": {
          "pregunta": {
            "type": [
              "null",
              "string"
            ],
            "description": "Pregunta de uso del panel (3 a 500 caracteres)."
          },
          "pantalla": {
            "type": [
              "null",
              "string"
            ],
            "description": "Ruta del panel donde está el usuario (opcional, por ejemplo `/comprobantes/agregar`)."
          }
        },
        "description": "Cuerpo de `POST /v1/ia/ayuda`."
      },
      "SolicitudBorrador": {
        "type": "object",
        "properties": {
          "texto": {
            "type": [
              "null",
              "string"
            ],
            "description": "Lo que se quiere facturar, en texto libre (5 a 2000 caracteres), por ejemplo «factura a público en general 3 horas\r\nde consultoría a 850 más IVA, pago en transferencia». Los RFC, CURP, correos y teléfonos se ocultan antes de\r\nmandarlo al modelo."
          }
        },
        "description": "Cuerpo de `POST /v1/ia/borrador`."
      },
      "SolicitudCancelacion": {
        "type": "object",
        "properties": {
          "motivo": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_MotivoCancelacion: 01, 02, 03 o 04."
          },
          "folioSustitucion": {
            "type": [
              "null",
              "string"
            ],
            "description": "UUID que sustituye al cancelado (obligatorio con motivo 01; prohibido en otro caso)."
          }
        },
        "description": "Cuerpo de `POST /v1/cfdi/{uuid}/cancelacion`."
      },
      "SolicitudChat": {
        "type": "object",
        "properties": {
          "mensajes": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/MensajeChatEntrada"
            },
            "description": "La conversación, del mensaje más antiguo al más reciente; el último es la pregunta del visitante. Las\r\nrespuestas anteriores del asistente se mandan con la `firma` que dio la API (sin firma válida se ignoran)."
          },
          "sesion": {
            "type": [
              "null",
              "string"
            ],
            "description": "Id aleatorio de la sesión del navegador (16 a 64 letras, números, guion o guion bajo)."
          }
        },
        "description": "Cuerpo de `POST /chat/mensajes`."
      },
      "SolicitudChatPanel": {
        "type": "object",
        "properties": {
          "modulo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Ruta del panel donde está el usuario (por ejemplo `/comprobantes/agregar`); opcional."
          },
          "mensajes": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/MensajeChatEntrada"
            },
            "description": "La conversación, del mensaje más antiguo al más reciente; el último es la pregunta del visitante. Las\r\nrespuestas anteriores del asistente se mandan con la `firma` que dio la API (sin firma válida se ignoran)."
          },
          "sesion": {
            "type": [
              "null",
              "string"
            ],
            "description": "Id aleatorio de la sesión del navegador (16 a 64 letras, números, guion o guion bajo)."
          }
        },
        "description": "Cuerpo de `POST /chat/panel/mensajes`: el de `/chat/mensajes` más la pantalla del panel."
      },
      "SolicitudClavesSat": {
        "type": "object",
        "properties": {
          "descripcion": {
            "type": [
              "null",
              "string"
            ],
            "description": "Descripción del producto o servicio como la escribiría el usuario (3 a 500 caracteres)."
          },
          "maximo": {
            "type": [
              "null",
              "integer"
            ],
            "description": "Máximo de claves sugeridas (1 a 5; 5 por omisión).",
            "format": "int32"
          }
        },
        "description": "Cuerpo de `POST /v1/ia/claves-sat`."
      },
      "SolicitudCorreo": {
        "type": "object",
        "properties": {
          "para": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "type": "string"
            },
            "description": "Destinatarios."
          },
          "copia": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "type": "string"
            },
            "description": "Copias."
          },
          "asunto": {
            "type": [
              "null",
              "string"
            ],
            "description": "Asunto (≤ 150)."
          },
          "mensaje": {
            "type": [
              "null",
              "string"
            ],
            "description": "Mensaje (≤ 2000)."
          }
        },
        "description": "Cuerpo de `POST /v1/cfdi/{uuid}/correo`."
      },
      "SolicitudEmision": {
        "type": "object",
        "properties": {
          "tipo": {
            "type": [
              "null",
              "string"
            ],
            "description": "`factura`, `nota_credito`, `honorarios` o `pago`."
          },
          "serie": {
            "type": [
              "null",
              "string"
            ],
            "description": "Serie (1 a 10). Si no viene: la serie predeterminada de la integración (si aplica al tipo); si no, la única serie activa del tipo (`GET /v1/emisor`)."
          },
          "fecha": {
            "type": [
              "null",
              "string"
            ],
            "description": "Fecha del CFDI, `yyyy-MM-ddTHH:mm:ss` (hora del centro de México). Opcional: sin ella es la hora de la emisión. No\r\nfutura y dentro del límite técnico de timbrado (ver `ValidadorEmision.AtrasoMaximoFecha`). No aplica en `pago`."
          },
          "referencia": {
            "type": [
              "null",
              "string"
            ],
            "description": "Referencia del integrador (≤ 100). No sale en el CFDI; se guarda en la API y sirve para buscar (`GET /v1/cfdi?referencia=`)."
          },
          "comentario": {
            "type": [
              "null",
              "string"
            ],
            "description": "Comentario (≤ 1000). No va en el XML, pero el PDF lo imprime como «Comentario:»."
          },
          "formaPago": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_FormaPago, por ejemplo `01` efectivo, `03` transferencia, `04` tarjeta de crédito, `28` débito o `99` por definir (obligatoria con `PPD`). No aplica en `pago`."
          },
          "metodoPago": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_MetodoPago: `PUE` o `PPD` (`PPD` solo en `MXN`). No aplica en `pago`."
          },
          "moneda": {
            "type": [
              "null",
              "string"
            ],
            "description": "`MXN` (predeterminada) o `USD`. En `pago`, solo `MXN`."
          },
          "tipoCambio": {
            "type": [
              "null",
              "number"
            ],
            "description": "Tipo de cambio: obligatorio si la moneda es `USD` (&gt; 0, máximo 6 decimales); en `MXN` no se envía.",
            "format": "double"
          },
          "condicionesPago": {
            "type": [
              "null",
              "string"
            ],
            "description": "Condiciones de pago (≤ 150). No aplica en `pago`."
          },
          "exportacion": {
            "type": [
              "null",
              "string"
            ],
            "description": "c_Exportacion: `01` (predeterminada), `02` o `03`."
          },
          "receptor": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Receptor del CFDI.",
                "$ref": "#/components/schemas/ReceptorEntrada"
              }
            ]
          },
          "informacionGlobal": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Obligatoria en la factura global (receptor `XAXX010101000` con nombre `PUBLICO EN GENERAL`); prohibida en otro caso.",
                "$ref": "#/components/schemas/InformacionGlobalEntrada"
              }
            ]
          },
          "conceptos": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/ConceptoEntrada"
            },
            "description": "Conceptos (1 a 500; a una integración se le puede ampliar hasta 1,000). No aplica en `pago`: la API arma el concepto «Pago»."
          },
          "relacionados": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "CFDI relacionados (obligatorio en `nota_credito`).",
                "$ref": "#/components/schemas/RelacionadosEntrada"
              }
            ]
          },
          "pagos": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/PagoEntrada"
            },
            "description": "Pagos del complemento: exactamente uno, solo en el tipo `pago`."
          }
        },
        "description": "Cuerpo de `POST /v1/cfdi` (especificación §4.1). Todo es opcional en el modelo para que la validación explique qué falta."
      },
      "SolicitudExplicarError": {
        "type": "object",
        "properties": {
          "codigo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Código del proveedor, del SAT, del motor o de la API (por ejemplo CFDI40145, 205, E6 o sin_timbres)."
          },
          "mensaje": {
            "type": [
              "null",
              "string"
            ],
            "description": "Mensaje tal como llegó (≤ 2000). Los RFC y correos se ocultan antes de mandarlo al modelo."
          },
          "contexto": {
            "type": [
              "null",
              "string"
            ],
            "description": "`timbrado` (por omisión), `cancelacion` o `api`: desempata códigos que se repiten."
          }
        },
        "description": "Cuerpo de `POST /v1/ia/explicar-error`. Al menos uno de `codigo` o `mensaje`."
      },
      "SolicitudRecordatorio": {
        "type": "object",
        "properties": {
          "tono": {
            "type": [
              "null",
              "string"
            ],
            "description": "`cordial` (por omisión), `amable` o `firme`."
          },
          "diasVencidos": {
            "type": [
              "null",
              "integer"
            ],
            "description": "Días de atraso (negativo: faltan días para el vencimiento; 0: vence hoy).",
            "format": "int32"
          },
          "canal": {
            "type": [
              "null",
              "string"
            ],
            "description": "`correo` (por omisión) o `whatsapp`."
          },
          "valores": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Valores para reemplazar los marcadores (opcional). Se reemplazan en la API, fuera del modelo.",
                "$ref": "#/components/schemas/ValoresRecordatorio"
              }
            ]
          }
        },
        "description": "Cuerpo de `POST /v1/ia/recordatorio`. Los datos del cliente nunca van al modelo."
      },
      "SolicitudResumen": {
        "type": "object",
        "properties": {
          "anio": {
            "type": [
              "null",
              "integer"
            ],
            "description": "Año del periodo (si no vienen `cifras`, la API las calcula de la base).",
            "format": "int32"
          },
          "mes": {
            "type": [
              "null",
              "integer"
            ],
            "description": "Mes del periodo (1 a 12).",
            "format": "int32"
          },
          "destinatario": {
            "type": [
              "null",
              "string"
            ],
            "description": "`tablero` (por omisión) o `contador`."
          },
          "cifras": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Cifras agregadas del periodo (solo conteos e importes). Si no vienen, la API las calcula.",
                "$ref": "#/components/schemas/CifrasPeriodo"
              }
            ]
          }
        },
        "description": "Cuerpo de `POST /v1/ia/resumen`."
      },
      "SolicitudTicket": {
        "type": "object",
        "properties": {
          "nombre": {
            "type": [
              "null",
              "string"
            ],
            "description": "Nombre de contacto (obligatorio en el sitio, 2 a 100)."
          },
          "correo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Correo de contacto (obligatorio en el sitio; en el panel, el del usuario de la sesión)."
          },
          "asunto": {
            "type": [
              "null",
              "string"
            ],
            "description": "Asunto (3 a 150)."
          },
          "mensaje": {
            "type": [
              "null",
              "string"
            ],
            "description": "Mensaje para soporte (10 a 4,000)."
          },
          "incluirConversacion": {
            "type": "boolean",
            "description": "Verdadero si el usuario marcó adjuntar la conversación con Timbi."
          },
          "conversacion": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/MensajeChatEntrada"
            },
            "description": "La conversación (solo se guarda si bool SolicitudTicket.IncluirConversacion), con los datos personales ocultos."
          },
          "pagina": {
            "type": [
              "null",
              "string"
            ],
            "description": "Página del sitio desde la que escribe (opcional, hasta 300)."
          },
          "sitioWeb": {
            "type": [
              "null",
              "string"
            ],
            "description": "Trampa para robots: un campo oculto que una persona nunca llena. Si trae algo, no se guarda nada."
          }
        },
        "description": "Cuerpo de `POST /chat/tickets` (desde el sitio)."
      },
      "SolicitudTicketPanel": {
        "type": "object",
        "properties": {
          "modulo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Ruta del panel donde está el usuario (opcional)."
          },
          "nombre": {
            "type": [
              "null",
              "string"
            ],
            "description": "Nombre de contacto (obligatorio en el sitio, 2 a 100)."
          },
          "correo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Correo de contacto (obligatorio en el sitio; en el panel, el del usuario de la sesión)."
          },
          "asunto": {
            "type": [
              "null",
              "string"
            ],
            "description": "Asunto (3 a 150)."
          },
          "mensaje": {
            "type": [
              "null",
              "string"
            ],
            "description": "Mensaje para soporte (10 a 4,000)."
          },
          "incluirConversacion": {
            "type": "boolean",
            "description": "Verdadero si el usuario marcó adjuntar la conversación con Timbi."
          },
          "conversacion": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/MensajeChatEntrada"
            },
            "description": "La conversación (solo se guarda si bool SolicitudTicket.IncluirConversacion), con los datos personales ocultos."
          },
          "pagina": {
            "type": [
              "null",
              "string"
            ],
            "description": "Página del sitio desde la que escribe (opcional, hasta 300)."
          },
          "sitioWeb": {
            "type": [
              "null",
              "string"
            ],
            "description": "Trampa para robots: un campo oculto que una persona nunca llena. Si trae algo, no se guarda nada."
          }
        },
        "description": "Cuerpo de `POST /chat/panel/tickets`: el del sitio más la pantalla del panel."
      },
      "SolicitudWebhook": {
        "type": "object",
        "properties": {
          "url": {
            "type": [
              "null",
              "string"
            ],
            "description": "URL https:// del integrador."
          },
          "eventos": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "type": "string"
            },
            "description": "Eventos (todos si no viene)."
          }
        },
        "description": "Cuerpo de `POST /v1/webhooks`."
      },
      "Stream": {
        "type": "string",
        "format": "binary"
      },
      "SucursalVista": {
        "required": [
          "id",
          "nombre",
          "codigoPostal",
          "csdVigente",
          "venceCsd",
          "planIlimitado"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int32"
          },
          "nombre": {
            "type": "string"
          },
          "codigoPostal": {
            "type": [
              "null",
              "string"
            ]
          },
          "csdVigente": {
            "type": "boolean"
          },
          "venceCsd": {
            "type": [
              "null",
              "string"
            ]
          },
          "planIlimitado": {
            "type": "boolean"
          }
        },
        "description": "Sucursal del emisor."
      },
      "SugerenciaClave": {
        "required": [
          "clave",
          "descripcion",
          "confianza",
          "razon"
        ],
        "type": "object",
        "properties": {
          "clave": {
            "type": "string",
            "description": "Clave de 8 dígitos."
          },
          "descripcion": {
            "type": "string",
            "description": "Descripción oficial del catálogo."
          },
          "confianza": {
            "type": "number",
            "description": "De 0 a 1.",
            "format": "double"
          },
          "razon": {
            "type": "string",
            "description": "Por qué se sugiere (breve)."
          }
        },
        "description": "ClaveProdServ sugerida."
      },
      "SugerenciaUnidad": {
        "required": [
          "clave",
          "descripcion",
          "razon"
        ],
        "type": "object",
        "properties": {
          "clave": {
            "type": "string",
            "description": "Clave de c_ClaveUnidad (por ejemplo E48, H87, HUR, ACT)."
          },
          "descripcion": {
            "type": "string",
            "description": "Descripción oficial del catálogo."
          },
          "razon": {
            "type": "string",
            "description": "Por qué se sugiere (breve)."
          }
        },
        "description": "ClaveUnidad sugerida."
      },
      "TextoRecordatorio": {
        "required": [
          "asunto",
          "mensaje"
        ],
        "type": "object",
        "properties": {
          "asunto": {
            "type": [
              "null",
              "string"
            ]
          },
          "mensaje": {
            "type": "string"
          }
        },
        "description": "Asunto (solo en correo) y mensaje."
      },
      "TimbresVista": {
        "required": [
          "disponibles",
          "sucursalesConPlanIlimitado"
        ],
        "type": "object",
        "properties": {
          "disponibles": {
            "type": "integer",
            "format": "int32"
          },
          "sucursalesConPlanIlimitado": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32"
            }
          }
        },
        "description": "Saldo de timbres según la regla del motor (solo SW + plan ilimitado vigente; Pax no cuenta)."
      },
      "TotalesBorrador": {
        "required": [
          "subtotal",
          "descuento",
          "impuestosTrasladados",
          "impuestosRetenidos",
          "total"
        ],
        "type": "object",
        "properties": {
          "subtotal": {
            "type": "number",
            "format": "double"
          },
          "descuento": {
            "type": "number",
            "format": "double"
          },
          "impuestosTrasladados": {
            "type": "number",
            "format": "double"
          },
          "impuestosRetenidos": {
            "type": "number",
            "format": "double"
          },
          "total": {
            "type": "number",
            "format": "double"
          }
        },
        "description": "Totales estimados del borrador."
      },
      "ValoresRecordatorio": {
        "type": "object",
        "properties": {
          "cliente": {
            "type": [
              "null",
              "string"
            ],
            "description": "Nombre del cliente ({cliente})."
          },
          "folio": {
            "type": [
              "null",
              "string"
            ],
            "description": "Serie y folio ({folio})."
          },
          "saldo": {
            "type": [
              "null",
              "number"
            ],
            "description": "Saldo pendiente ({saldo}).",
            "format": "double"
          },
          "moneda": {
            "type": [
              "null",
              "string"
            ],
            "description": "Moneda del saldo (MXN por omisión)."
          },
          "vencimiento": {
            "type": [
              "null",
              "string"
            ],
            "description": "Fecha de vencimiento `yyyy-MM-dd` ({vencimiento})."
          }
        },
        "description": "Valores de los marcadores del recordatorio."
      },
      "WebhookVista": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Id.",
            "format": "int32"
          },
          "url": {
            "type": "string",
            "description": "URL."
          },
          "eventos": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Eventos suscritos."
          },
          "activo": {
            "type": "boolean",
            "description": "Activo."
          },
          "creado": {
            "type": "string",
            "description": "Alta."
          },
          "secreto": {
            "type": [
              "null",
              "string"
            ],
            "description": "Secreto: solo en la respuesta de creación."
          }
        },
        "description": "Un webhook tal como se muestra (sin secreto)."
      }
    },
    "securitySchemes": {
      "llaveApi": {
        "type": "http",
        "description": "Llave de API de la integración.",
        "scheme": "bearer",
        "bearerFormat": "mcfdi_live_… / mcfdi_test_…"
      }
    }
  },
  "tags": [
    {
      "name": "Salud"
    },
    {
      "name": "Chat"
    },
    {
      "name": "Chat del panel"
    },
    {
      "name": "Emisor"
    },
    {
      "name": "Catálogos"
    },
    {
      "name": "CFDI"
    },
    {
      "name": "Solicitudes"
    },
    {
      "name": "Webhooks"
    },
    {
      "name": "Listas del SAT"
    },
    {
      "name": "IA"
    },
    {
      "name": "Despacho"
    }
  ]
}