{"openapi":"3.1.0","info":{"title":"Zenit API","version":"1.0.0","summary":"Recibos CFE, cotizaciones solares y enlaces de propuesta para integraciones (WhatsApp, CRM, automatizaciones).","description":"La API de Zenit conecta otras plataformas — un bot de WhatsApp, tu CRM, Make o n8n — con tu cuenta de Zenit: lee recibos CFE, cotiza con tus planes y precios, y comparte la propuesta con tu cliente.\n\n## Autenticación\nCrea una clave en Zenit (**Configuración → API**, solo administradores) y envíala en cada solicitud:\n\n`Authorization: Bearer zk_live_…`\n\nLa clave actúa como el usuario que la creó (su rol y permisos aplican) y solo se muestra una vez. Nunca la pongas en una URL ni en código del navegador.\n\n## Flujo para un bot de WhatsApp\n1. `POST /bill-readings` con el PDF o las fotos del recibo → **202** con `status: \"processing\"`.\n2. Espera el webhook `bill_reading.succeeded` o consulta `GET /bill-readings/{id}` cada ~5 s. Si tu plataforma puede esperar, envía `Prefer: wait=90` y recibirás la lectura terminada en la misma respuesta.\n3. `POST /quotations` con `bill_reading_id` → borrador con tus planes, el cliente y el recibo adjunto.\n4. (Opcional, permiso «Compartir propuestas») `POST /quotations/{id}/share` → enlace para enviar al cliente.\n\nUn recibo por solicitud (el PDF, o de 1 a 4 fotos de sus páginas). Varios recibos = varias solicitudes.\n\n## Reintentos seguros\nEnvía `Idempotency-Key` (p.ej. un UUID) en cada POST. Si reintentas con la misma clave obtienes la misma respuesta sin leer el recibo otra vez ni crear otro cliente. Las claves duran 24 h.\n\n## Errores\nSiempre `{ \"error\": { \"code\", \"message\", \"param?\", \"request_id\" } }`. Programa contra `code`; `message` está en español y puede mostrarse al usuario. Toda respuesta trae `X-Request-Id`.\n\n## Límites\n200 lecturas de recibo por organización en 24 horas y 10 en proceso a la vez (**429** con `Retry-After`). Las cotizaciones cuentan para el límite mensual de tu plan. Archivos de hasta 10 MB; el cuerpo de una solicitud, hasta 4 MB — para archivos más grandes envía una URL.\n\n## Webhooks\nConfigura una URL https en tu clave. Cada evento llega firmado: `Zenit-Signature: t=<unix>,v1=<HMAC-SHA256(secreto, \"t.cuerpo\")>`. Verifica la firma, rechaza marcas de tiempo de más de 5 minutos y descarta eventos repetidos por `id`. Respondemos con hasta 3 intentos; la fuente de verdad es `GET /bill-readings/{id}`.\n\n## Versiones\nEsta es la v1. Agregar campos, endpoints o códigos de error no cambia la versión — ignora los campos que no conozcas. Un cambio incompatible será `/api/v2`, anunciado con al menos 6 meses de anticipación y encabezados `Deprecation` y `Sunset`.","termsOfService":"https://zenitmaster.com/terminos","contact":{"name":"Soporte Zenit","url":"https://zenitmaster.com/desarrolladores"},"license":{"name":"Términos de servicio de Zenit","url":"https://zenitmaster.com/terminos"}},"servers":[{"url":"https://zenitmaster.com/api/v1","description":"Producción"}],"security":[{"apiKey":[]}],"tags":[{"name":"Recibos CFE","description":"Lectura de recibos con IA (PDF o fotos)"},{"name":"Cotizaciones","description":"Borradores con tus planes y precios, y enlaces para el cliente"},{"name":"Cuenta","description":"Qué puede hacer tu clave"}],"paths":{"/me":{"get":{"tags":["Cuenta"],"operationId":"getMe","summary":"Ver la clave y su organización","description":"La primera llamada del inicio rápido: confirma que la clave funciona y muestra el uso del día.","responses":{"200":{"description":"La clave","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"description":"Falta la clave, no es válida o fue revocada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"El plan no incluye la API o la suscripción no está activa","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bill-readings":{"post":{"tags":["Recibos CFE"],"operationId":"createBillReading","summary":"Leer un recibo CFE","description":"Recibe un recibo (el PDF, o de 1 a 4 fotos de sus páginas) y lo lee con el mismo motor que el cotizador de Zenit. Responde **202** de inmediato con la lectura en `processing`; la lectura termina en segundo plano (normalmente 5–60 s). Con `Prefer: wait=N` la respuesta espera hasta N segundos (máx. 120) y devuelve **201** con la lectura terminada si alcanza.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/Prefer"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"array","minItems":1,"maxItems":4,"items":{"type":"string","format":"binary"},"description":"El PDF del recibo o de 1 a 4 fotos (JPG, PNG, WebP). Repite el campo por cada archivo."},"reference":{"type":"string","maxLength":200,"description":"Tu identificador, p.ej. el chat de WhatsApp"}}}},"application/json":{"schema":{"$ref":"#/components/schemas/CreateBillReadingJson"},"example":{"files":[{"url":"https://media.example.com/recibo-frente.jpg"},{"url":"https://media.example.com/recibo-reverso.jpg"}],"reference":"whatsapp:5218100000000"}}}},"responses":{"201":{"description":"Lectura terminada (solo con `Prefer: wait`); revisa `status`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillReading"},"example":{"id":"5b0f0c4e-2f7a-4a52-9a43-0d3f6f1c2a11","object":"bill_reading","status":"succeeded","reference":"whatsapp:5218100000000","file_count":2,"created_at":"2026-10-15T17:02:11.000Z","completed_at":"2026-10-15T17:02:29.000Z","bill":{"holder_name":"CLIENTE DE PRUEBA","service_number":"000000000000","address":"CALLE DE PRUEBA 100, COL. CENTRO, MONTERREY, N.L. CP 64000","postal_code":"64000","state":"Nuevo León","tariff":"1C","billing_period":"08 JUN 26 - 06 AGO 26","amount_due":8700,"current_period":{"kwh":2000,"amount":6500},"history":[{"period":"06 ABR 26 al 08 JUN 26","kwh":1650,"amount":4980}],"iva_rate":0.16},"consumption":{"yearly_kwh":10200,"monthly_average_kwh":850,"yearly_spend":31800,"monthly_average_spend":2650,"current_bill_amount":6500,"basis":"history"},"sizing":{"system_kw":6.6,"panels":12,"yearly_production_kwh":10340,"coverage_percent":101,"losses_percent":20,"tariff_region":"noreste"},"warnings":[],"error":null}}}},"202":{"description":"Lectura en proceso; consulta `Location` o espera el webhook","headers":{"Location":{"schema":{"type":"string"},"description":"/api/v1/bill-readings/{id}"},"Retry-After":{"schema":{"type":"integer"},"description":"Segundos sugeridos antes de consultar"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillReading"}}}},"400":{"description":"Archivos faltantes, de más, demasiado grandes o en un formato no compatible","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Falta la clave, no es válida o fue revocada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Plan sin API, suscripción inactiva o permiso faltante","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Idempotency-Key reutilizada con otra solicitud, o aún en proceso","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"El cuerpo excede 4 MB; envía el archivo por URL"},"415":{"description":"Content-Type distinto de multipart/form-data o application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite diario o de lecturas simultáneas alcanzado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bill-readings/{id}":{"get":{"tags":["Recibos CFE"],"operationId":"getBillReading","summary":"Consultar una lectura","description":"Mientras `status` sea `processing`, vuelve a consultar en ~5 s. Una lectura `failed` trae `error.code` (p.ej. `unreadable_bill`: pide al cliente fotos más nítidas o el PDF). Revisa `warnings`: `history_missing` significa que falta la página del historial (el reverso).","parameters":[{"$ref":"#/components/parameters/ReadingId"}],"responses":{"200":{"description":"La lectura","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillReading"},"example":{"id":"5b0f0c4e-2f7a-4a52-9a43-0d3f6f1c2a11","object":"bill_reading","status":"succeeded","reference":"whatsapp:5218100000000","file_count":2,"created_at":"2026-10-15T17:02:11.000Z","completed_at":"2026-10-15T17:02:29.000Z","bill":{"holder_name":"CLIENTE DE PRUEBA","service_number":"000000000000","address":"CALLE DE PRUEBA 100, COL. CENTRO, MONTERREY, N.L. CP 64000","postal_code":"64000","state":"Nuevo León","tariff":"1C","billing_period":"08 JUN 26 - 06 AGO 26","amount_due":8700,"current_period":{"kwh":2000,"amount":6500},"history":[{"period":"06 ABR 26 al 08 JUN 26","kwh":1650,"amount":4980}],"iva_rate":0.16},"consumption":{"yearly_kwh":10200,"monthly_average_kwh":850,"yearly_spend":31800,"monthly_average_spend":2650,"current_bill_amount":6500,"basis":"history"},"sizing":{"system_kw":6.6,"panels":12,"yearly_production_kwh":10340,"coverage_percent":101,"losses_percent":20,"tariff_region":"noreste"},"warnings":[],"error":null}}}},"401":{"description":"Falta la clave, no es válida o fue revocada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe en tu organización","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/quotations":{"post":{"tags":["Cotizaciones"],"operationId":"createQuotation","summary":"Cotizar una lectura","description":"Crea un borrador de cotización a partir de una lectura terminada, con tus planes, catálogo y precios (los mismos que en Zenit), y adjunta el recibo. Crea el cliente con los datos del recibo y de `client`, salvo que envíes `client_id` — guarda `client.id` por chat para cotizar los siguientes recibos del mismo cliente. El borrador aparece en Zenit para que tu equipo lo revise.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateQuotation"},"example":{"bill_reading_id":"5b0f0c4e-2f7a-4a52-9a43-0d3f6f1c2a11","client":{"phone":"+5218100000000"},"lead_source":"Facebook"}}}},"responses":{"201":{"description":"Borrador creado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quotation"}}}},"400":{"description":"Cuerpo inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Límite mensual de cotizaciones, plan sin API o permiso faltante","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Lectura o cliente inexistente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"La lectura aún está en proceso o falló","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"No se pudo cotizar (p.ej. el plan indicado no existe)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/quotations/{id}":{"get":{"tags":["Cotizaciones"],"operationId":"getQuotation","summary":"Consultar una cotización","description":"Estado, totales, ahorro estimado, planes y enlace público (con sus vistas y si el cliente la aceptó).","parameters":[{"$ref":"#/components/parameters/QuotationId"}],"responses":{"200":{"description":"La cotización","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quotation"}}}},"404":{"description":"No existe o no es visible para el usuario de la clave","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/quotations/{id}/share":{"post":{"tags":["Cotizaciones"],"operationId":"shareQuotation","summary":"Compartir con el cliente","description":"Publica la propuesta en su enlace público (`share.url`) y devuelve también el PDF. Un borrador pasa a `sent`. Requiere una clave con el permiso «Compartir propuestas» (`quotations:share`), porque publica sin revisión humana. Repetir la llamada devuelve el mismo enlace.","parameters":[{"$ref":"#/components/parameters/QuotationId"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShareQuotation"}}}},"responses":{"200":{"description":"Cotización compartida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quotation"}}}},"403":{"description":"La clave no tiene el permiso «quotations:share»","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"La vista pedida no está disponible para esta cotización","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"webhooks":{"bill_reading.succeeded":{"post":{"operationId":"billReadingSucceeded","summary":"Lectura terminada","description":"Se envía a la URL de webhook de la clave que creó la lectura.","parameters":[{"$ref":"#/components/parameters/ZenitSignature"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"},"example":{"id":"evt_8a6e0f0e-3b9e-4d47-9a43-5a2f1f0d9c10","object":"event","type":"bill_reading.succeeded","created_at":"2026-10-15T17:02:29.000Z","data":{"object":{"id":"5b0f0c4e-2f7a-4a52-9a43-0d3f6f1c2a11","object":"bill_reading","status":"succeeded","reference":"whatsapp:5218100000000","file_count":2,"created_at":"2026-10-15T17:02:11.000Z","completed_at":"2026-10-15T17:02:29.000Z","bill":{"holder_name":"CLIENTE DE PRUEBA","service_number":"000000000000","address":"CALLE DE PRUEBA 100, COL. CENTRO, MONTERREY, N.L. CP 64000","postal_code":"64000","state":"Nuevo León","tariff":"1C","billing_period":"08 JUN 26 - 06 AGO 26","amount_due":8700,"current_period":{"kwh":2000,"amount":6500},"history":[{"period":"06 ABR 26 al 08 JUN 26","kwh":1650,"amount":4980}],"iva_rate":0.16},"consumption":{"yearly_kwh":10200,"monthly_average_kwh":850,"yearly_spend":31800,"monthly_average_spend":2650,"current_bill_amount":6500,"basis":"history"},"sizing":{"system_kw":6.6,"panels":12,"yearly_production_kwh":10340,"coverage_percent":101,"losses_percent":20,"tariff_region":"noreste"},"warnings":[],"error":null}}}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta se reintenta (hasta 3 intentos)."}}}},"bill_reading.failed":{"post":{"operationId":"billReadingFailed","summary":"Lectura fallida","description":"`data.object.error` explica por qué; normalmente basta pedir al cliente el PDF o fotos más nítidas.","parameters":[{"$ref":"#/components/parameters/ZenitSignature"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"2XX":{"description":"Recibido"}}}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"zk_live_…","description":"Clave de API de Configuración → API."}},"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Hace seguro reintentar: la misma clave con la misma solicitud devuelve la primera respuesta (24 h)."},"Prefer":{"name":"Prefer","in":"header","required":false,"schema":{"type":"string","example":"wait=90"},"description":"`wait=N` (máx. 120): espera hasta N segundos la lectura terminada antes de responder."},"ReadingId":{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"QuotationId":{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"ZenitSignature":{"name":"Zenit-Signature","in":"header","required":true,"schema":{"type":"string","example":"t=1760547749,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"description":"HMAC-SHA256 con el secreto del webhook sobre «t.cuerpo»."}},"schemas":{"Error":{"title":"Error","type":"object","properties":{"error":{"type":"object","properties":{"code":{"description":"Código estable, para programar contra él (p.ej. «daily_limit_reached»)","type":"string"},"message":{"description":"Explicación en español; puede mostrarse al usuario","type":"string"},"param":{"description":"Campo de la solicitud que causó el error, si aplica","type":"string"},"request_id":{"description":"Identificador de la solicitud; inclúyelo al pedir soporte","type":"string"}},"required":["code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false},"BillReading":{"title":"BillReading","type":"object","properties":{"id":{"description":"Identificador de la lectura","type":"string"},"object":{"type":"string","const":"bill_reading"},"status":{"description":"«processing» mientras se lee; luego «succeeded» o «failed»","type":"string","enum":["processing","succeeded","failed"]},"reference":{"anyOf":[{"type":"string"},{"type":"null"}]},"file_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"created_at":{"description":"Fecha y hora ISO 8601 (UTC)","type":"string"},"completed_at":{"anyOf":[{"description":"Fecha y hora ISO 8601 (UTC)","type":"string"},{"type":"null"}]},"bill":{"description":"Datos leídos del recibo (solo con status succeeded)","anyOf":[{"title":"Bill","type":"object","properties":{"holder_name":{"description":"Titular del servicio","anyOf":[{"type":"string"},{"type":"null"}]},"service_number":{"description":"Número de servicio (RPU)","anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}]},"state":{"anyOf":[{"type":"string"},{"type":"null"}]},"tariff":{"description":"Tarifa CFE (1, 1A–1F, DAC, PDBT, GDBT, GDMTO, GDMTH…)","anyOf":[{"type":"string"},{"type":"null"}]},"billing_period":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_due":{"description":"Total a pagar impreso, MXN","anyOf":[{"type":"number"},{"type":"null"}]},"current_period":{"type":"object","properties":{"kwh":{"anyOf":[{"type":"number"},{"type":"null"}]},"amount":{"description":"Facturación del periodo, MXN con IVA","anyOf":[{"type":"number"},{"type":"null"}]}},"required":["kwh","amount"],"additionalProperties":false},"history":{"description":"Historial de consumo impreso en el recibo","type":"array","items":{"type":"object","properties":{"period":{"description":"Periodo como lo imprime el recibo («04 DIC 24 al 03 FEB 25», «JUN 25»)","type":"string"},"kwh":{"type":"number"},"amount":{"description":"Importe del periodo, MXN con IVA","type":"number"}},"required":["period","kwh","amount"],"additionalProperties":false}},"iva_rate":{"description":"IVA del recibo como fracción: 0.16, o 0.08 en la región fronteriza","type":"number"}},"required":["holder_name","service_number","address","postal_code","state","tariff","billing_period","amount_due","current_period","history","iva_rate"],"additionalProperties":false},{"type":"null"}]},"consumption":{"anyOf":[{"title":"Consumption","type":"object","properties":{"yearly_kwh":{"type":"number"},"monthly_average_kwh":{"type":"number"},"yearly_spend":{"description":"Gasto anual estimado, MXN con IVA","type":"number"},"monthly_average_spend":{"type":"number"},"current_bill_amount":{"description":"Importe del recibo actual, MXN","type":"number"},"basis":{"description":"«history»: año leído del historial; «current_period»: estimado con el periodo actual (falta el historial)","type":"string","enum":["history","current_period"]}},"required":["yearly_kwh","monthly_average_kwh","yearly_spend","monthly_average_spend","current_bill_amount","basis"],"additionalProperties":false},{"type":"null"}]},"sizing":{"anyOf":[{"title":"Sizing","type":"object","properties":{"system_kw":{"description":"Potencia sugerida para cubrir el 100% del consumo, kWp","type":"number"},"panels":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"yearly_production_kwh":{"type":"number"},"coverage_percent":{"type":"number"},"losses_percent":{"description":"Pérdidas del sistema usadas (las predeterminadas de la organización)","type":"number"},"tariff_region":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["system_kw","panels","yearly_production_kwh","coverage_percent","losses_percent","tariff_region"],"additionalProperties":false},{"type":"null"}]},"warnings":{"description":"Datos que no se pudieron leer; p.ej. «history_missing» pide la foto del reverso","type":"array","items":{"title":"Warning","type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"error":{"description":"Por qué falló (solo con status failed)","anyOf":[{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false},{"type":"null"}]}},"required":["id","object","status","reference","file_count","created_at","completed_at","bill","consumption","sizing","warnings","error"],"additionalProperties":false},"CreateBillReadingJson":{"title":"CreateBillReadingJson","type":"object","properties":{"files":{"description":"Un recibo: el PDF, o de 1 a 4 fotos de sus páginas (frente y reverso). Varios recibos = varias solicitudes","minItems":1,"maxItems":4,"type":"array","items":{"title":"BillFileInput","type":"object","properties":{"url":{"description":"URL https del archivo (p.ej. el MediaUrl de Twilio). Zenit la descarga; máx. 10 MB","type":"string","maxLength":2048},"data":{"description":"Contenido del archivo en base64 (sin prefijo data:). Máx. 10 MB decodificado","type":"string"},"filename":{"description":"Nombre del archivo, solo informativo","type":"string","maxLength":200}}}},"reference":{"description":"Tu identificador (p.ej. el chat de WhatsApp). Se devuelve tal cual en la lectura y en los webhooks","type":"string","maxLength":200}},"required":["files"]},"Quotation":{"title":"Quotation","type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"quotation"},"number":{"description":"Folio, p.ej. COT-2026-123","type":"string"},"status":{"type":"string","enum":["draft","sent","accepted","rejected","expired"]},"created_at":{"description":"Fecha y hora ISO 8601 (UTC)","type":"string"},"valid_until":{"description":"Vigencia (fecha ISO)","anyOf":[{"type":"string"},{"type":"null"}]},"client":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","email","phone"],"additionalProperties":false},"service_type":{"anyOf":[{"type":"string","enum":["residencial","comercial","industrial","isla","bess"]},{"type":"null"}]},"plan":{"description":"Plan con el que se cotizó","anyOf":[{"type":"object","properties":{"name":{"type":"string"}},"required":["name"],"additionalProperties":false},{"type":"null"}]},"system":{"type":"object","properties":{"size_kw":{"type":"number"},"panels":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"yearly_production_kwh":{"type":"number"},"coverage_percent":{"type":"number"}},"required":["size_kw","panels","yearly_production_kwh","coverage_percent"],"additionalProperties":false},"totals":{"type":"object","properties":{"currency":{"type":"string","const":"MXN"},"subtotal":{"type":"number"},"discount_percent":{"type":"number"},"discount":{"type":"number"},"tax_percent":{"type":"number"},"tax":{"type":"number"},"total":{"type":"number"}},"required":["currency","subtotal","discount_percent","discount","tax_percent","tax","total"],"additionalProperties":false},"estimated_savings":{"anyOf":[{"type":"object","properties":{"yearly":{"description":"Ahorro del primer año, MXN","type":"number"},"payback_years":{"anyOf":[{"type":"number"},{"type":"null"}]},"twenty_five_years":{"description":"Ahorro acumulado a 25 años, MXN","type":"number"}},"required":["yearly","payback_years","twenty_five_years"],"additionalProperties":false},{"type":"null"}]},"plans":{"description":"La comparativa de planes adjunta (vacía si se cotizó con un solo plan)","type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"size_kw":{"type":"number"},"panels":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"price":{"description":"Precio total del plan, MXN con IVA","type":"number"},"selected":{"type":"boolean"}},"required":["name","size_kw","panels","price","selected"],"additionalProperties":false}},"share":{"type":"object","properties":{"enabled":{"type":"boolean"},"url":{"description":"Enlace público para el cliente (/q/…)","anyOf":[{"type":"string"},{"type":"null"}]},"pdf_url":{"anyOf":[{"type":"string"},{"type":"null"}]},"view_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"accepted_at":{"anyOf":[{"description":"Fecha y hora ISO 8601 (UTC)","type":"string"},{"type":"null"}]}},"required":["enabled","url","pdf_url","view_count","accepted_at"],"additionalProperties":false},"warnings":{"description":"Avisos al crear el borrador (en español)","type":"array","items":{"type":"string"}}},"required":["id","object","number","status","created_at","valid_until","client","service_type","plan","system","totals","estimated_savings","plans","share","warnings"],"additionalProperties":false},"CreateQuotation":{"title":"CreateQuotation","type":"object","properties":{"bill_reading_id":{"description":"Lectura de recibo con status «succeeded»","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"client_id":{"description":"Cliente existente. Sin él se crea uno nuevo con los datos de «client» y del recibo","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"client":{"type":"object","properties":{"name":{"description":"Por defecto, el titular del recibo","type":"string","minLength":1,"maxLength":200},"phone":{"description":"P.ej. el número de WhatsApp del cliente","type":"string","maxLength":30},"email":{"type":"string","maxLength":200,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"address":{"description":"Por defecto, la dirección del recibo","type":"string","maxLength":500}}},"plan":{"description":"Nombre o id de uno de tus planes de cotización. Por defecto, el plan de cotización rápida","type":"string","maxLength":120},"lead_source":{"description":"¿Cómo nos conoció el cliente?","type":"string","enum":["Facebook","Instagram","TikTok","Google","YouTube","Referido","Espectacular","Página Web","Otro"]},"notes":{"description":"Notas internas del borrador","type":"string","maxLength":2000}},"required":["bill_reading_id"]},"ShareQuotation":{"title":"ShareQuotation","type":"object","properties":{"view":{"description":"Qué muestra el enlace: el documento de cotización o la comparativa de planes. Por defecto, la comparativa si hay ≥2 planes","type":"string","enum":["quotation","comparison"]}}},"Me":{"title":"Me","type":"object","properties":{"object":{"type":"string","const":"api_key"},"key":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string"},"permissions":{"type":"array","items":{"type":"string"}},"webhook_url":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","prefix","permissions","webhook_url"],"additionalProperties":false},"organization":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"plan":{"type":"string"}},"required":["id","slug","name","plan"],"additionalProperties":false},"acting_user":{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"role":{"type":"string"}},"required":["id","name","role"],"additionalProperties":false},"limits":{"type":"object","properties":{"bill_readings_per_day":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"bill_readings_last_24h":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"bill_readings_in_flight":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"max_in_flight":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["bill_readings_per_day","bill_readings_last_24h","bill_readings_in_flight","max_in_flight"],"additionalProperties":false}},"required":["object","key","organization","acting_user","limits"],"additionalProperties":false},"WebhookEvent":{"title":"WebhookEvent","type":"object","properties":{"id":{"description":"evt_…; úsalo para descartar entregas repetidas","type":"string"},"object":{"type":"string","const":"event"},"type":{"type":"string","enum":["bill_reading.succeeded","bill_reading.failed"]},"created_at":{"description":"Fecha y hora ISO 8601 (UTC)","type":"string"},"data":{"type":"object","properties":{"object":{"title":"BillReading","type":"object","properties":{"id":{"description":"Identificador de la lectura","type":"string"},"object":{"type":"string","const":"bill_reading"},"status":{"description":"«processing» mientras se lee; luego «succeeded» o «failed»","type":"string","enum":["processing","succeeded","failed"]},"reference":{"anyOf":[{"type":"string"},{"type":"null"}]},"file_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"created_at":{"description":"Fecha y hora ISO 8601 (UTC)","type":"string"},"completed_at":{"anyOf":[{"description":"Fecha y hora ISO 8601 (UTC)","type":"string"},{"type":"null"}]},"bill":{"description":"Datos leídos del recibo (solo con status succeeded)","anyOf":[{"title":"Bill","type":"object","properties":{"holder_name":{"description":"Titular del servicio","anyOf":[{"type":"string"},{"type":"null"}]},"service_number":{"description":"Número de servicio (RPU)","anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}]},"state":{"anyOf":[{"type":"string"},{"type":"null"}]},"tariff":{"description":"Tarifa CFE (1, 1A–1F, DAC, PDBT, GDBT, GDMTO, GDMTH…)","anyOf":[{"type":"string"},{"type":"null"}]},"billing_period":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount_due":{"description":"Total a pagar impreso, MXN","anyOf":[{"type":"number"},{"type":"null"}]},"current_period":{"type":"object","properties":{"kwh":{"anyOf":[{"type":"number"},{"type":"null"}]},"amount":{"description":"Facturación del periodo, MXN con IVA","anyOf":[{"type":"number"},{"type":"null"}]}},"required":["kwh","amount"],"additionalProperties":false},"history":{"description":"Historial de consumo impreso en el recibo","type":"array","items":{"type":"object","properties":{"period":{"description":"Periodo como lo imprime el recibo («04 DIC 24 al 03 FEB 25», «JUN 25»)","type":"string"},"kwh":{"type":"number"},"amount":{"description":"Importe del periodo, MXN con IVA","type":"number"}},"required":["period","kwh","amount"],"additionalProperties":false}},"iva_rate":{"description":"IVA del recibo como fracción: 0.16, o 0.08 en la región fronteriza","type":"number"}},"required":["holder_name","service_number","address","postal_code","state","tariff","billing_period","amount_due","current_period","history","iva_rate"],"additionalProperties":false},{"type":"null"}]},"consumption":{"anyOf":[{"title":"Consumption","type":"object","properties":{"yearly_kwh":{"type":"number"},"monthly_average_kwh":{"type":"number"},"yearly_spend":{"description":"Gasto anual estimado, MXN con IVA","type":"number"},"monthly_average_spend":{"type":"number"},"current_bill_amount":{"description":"Importe del recibo actual, MXN","type":"number"},"basis":{"description":"«history»: año leído del historial; «current_period»: estimado con el periodo actual (falta el historial)","type":"string","enum":["history","current_period"]}},"required":["yearly_kwh","monthly_average_kwh","yearly_spend","monthly_average_spend","current_bill_amount","basis"],"additionalProperties":false},{"type":"null"}]},"sizing":{"anyOf":[{"title":"Sizing","type":"object","properties":{"system_kw":{"description":"Potencia sugerida para cubrir el 100% del consumo, kWp","type":"number"},"panels":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"yearly_production_kwh":{"type":"number"},"coverage_percent":{"type":"number"},"losses_percent":{"description":"Pérdidas del sistema usadas (las predeterminadas de la organización)","type":"number"},"tariff_region":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["system_kw","panels","yearly_production_kwh","coverage_percent","losses_percent","tariff_region"],"additionalProperties":false},{"type":"null"}]},"warnings":{"description":"Datos que no se pudieron leer; p.ej. «history_missing» pide la foto del reverso","type":"array","items":{"title":"Warning","type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"error":{"description":"Por qué falló (solo con status failed)","anyOf":[{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false},{"type":"null"}]}},"required":["id","object","status","reference","file_count","created_at","completed_at","bill","consumption","sizing","warnings","error"],"additionalProperties":false}},"required":["object"],"additionalProperties":false}},"required":["id","object","type","created_at","data"],"additionalProperties":false}}}}