{"version":"2026-10-20.5","base_url":"/api/v1","precios":{"moneda":"MXN","iva_incluido":false,"modo":"cantidad_completa","compra_minima":50,"compra_maxima":100000,"escalonado":[{"desde":1,"hasta":99,"precio_mxn":0.95},{"desde":100,"hasta":499,"precio_mxn":0.9},{"desde":500,"hasta":null,"precio_mxn":0.8}],"paquetes":[{"code":"PACK_50","credits":50,"precio_mxn":47.5},{"code":"PACK_100","credits":100,"precio_mxn":90.0},{"code":"PACK_500","credits":500,"precio_mxn":400.0}],"regla_tarifa":"Sin suscripción aplica el precio por volumen sobre la cantidad completa. Con plan activo aplica la tarifa del plan a cualquier cantidad. Los folios se compran siempre por separado de la renta.","iva_tasa":0.16,"planes":[{"plan":"free","nombre":"Gratis","mensual_mxn":0,"anual_mxn":0,"precio_por_timbre_mxn":null},{"plan":"starter","nombre":"Starter","mensual_mxn":99,"anual_mxn":1188,"precio_por_timbre_mxn":0.75},{"plan":"pro","nombre":"Pro","mensual_mxn":199,"anual_mxn":2388,"precio_por_timbre_mxn":0.65},{"plan":"enterprise","nombre":"Enterprise","mensual_mxn":399,"anual_mxn":4788,"precio_por_timbre_mxn":0.6}]},"errores":[{"http":400,"code":"PAC_ERROR","titulo":"El PAC rechazó el comprobante","significado":"El comprobante no se timbró. El PAC devolvió una incidencia, por ejemplo CFDI40144 cuando el nombre fiscal no coincide con la constancia del SAT.","cfdi_generado":false,"folios_consumidos":0,"retriable":true,"retry_with_same_idempotency_key":true,"accion":"Corregir los datos y reintentar. El cargo de folios se reembolsa automáticamente.","ejemplo":{"detail":{"code":"PAC_ERROR","message":"El PAC rechazó el timbrado: CFDI40144 - El nombre del emisor no coincide"}}},{"http":400,"code":"BUILD_OR_SIGN","titulo":"Error al construir o sellar el CFDI","significado":"El payload no pudo convertirse en un CFDI válido, o el sellado con el CSD falló. No se llegó al PAC.","cfdi_generado":false,"folios_consumidos":0,"retriable":true,"retry_with_same_idempotency_key":true,"accion":"Revisar catálogos, importes y vigencia del CSD.","ejemplo":{"detail":{"code":"BUILD_OR_SIGN","message":"Error al construir/sellar el CFDI: ..."}}},{"http":402,"code":"INSUFFICIENT_CREDITS","titulo":"Sin folios disponibles","significado":"No hay saldo para timbrar. Nunca ocurre en sandbox.","cfdi_generado":false,"folios_consumidos":0,"retriable":false,"retry_with_same_idempotency_key":false,"accion":"Comprar folios y reintentar.","ejemplo":{"detail":{"code":"INSUFFICIENT_CREDITS","message":"Saldo de créditos insuficiente"}}},{"http":401,"code":"UNAUTHORIZED","titulo":"Credencial ausente o inválida","significado":"El token o la API Key no son válidos.","cfdi_generado":false,"folios_consumidos":0,"retriable":false,"retry_with_same_idempotency_key":false,"accion":"Reautenticar.","ejemplo":{"detail":"Not authenticated"}},{"http":403,"code":"SUBSCRIPTION_REQUIRED","titulo":"Suscripción inactiva","significado":"La API Key requiere una suscripción activa para uso servidor a servidor.","cfdi_generado":false,"folios_consumidos":0,"retriable":false,"retry_with_same_idempotency_key":false,"accion":"Activar o renovar la suscripción.","ejemplo":{"detail":"Se requiere una suscripción activa"}},{"http":422,"code":"VALIDATION_ERROR","titulo":"Payload inválido","significado":"Falta un campo obligatorio o un tipo es incorrecto. Lo valida el esquema antes de construir el CFDI.","cfdi_generado":false,"folios_consumidos":0,"retriable":true,"retry_with_same_idempotency_key":true,"accion":"Corregir el payload según el detalle por campo.","ejemplo":{"detail":[{"loc":["body","conceptos",0,"clave_prod_serv"],"msg":"Field required","type":"missing"}]}},{"http":429,"code":"RATE_LIMITED","titulo":"Límite de peticiones excedido","significado":"Se superó el límite por minuto.","cfdi_generado":false,"folios_consumidos":0,"retriable":true,"retry_with_same_idempotency_key":true,"accion":"Esperar los segundos de la cabecera Retry-After y reintentar con la misma Idempotency-Key.","ejemplo":{"detail":"Rate limit exceeded. 30 per 1 minute","code":"RATE_LIMITED","retriable":true,"retry_with_same_idempotency_key":true}},{"http":500,"code":"INTERNAL_ERROR","titulo":"Error interno","significado":"Falla inesperada de nuestro lado. IMPORTANTE: el comprobante PUEDE haberse timbrado. No asumas que no existe.","cfdi_generado":"indeterminado","folios_consumidos":"indeterminado","retriable":true,"retry_with_same_idempotency_key":true,"accion":"Reintentar con la MISMA Idempotency-Key. Si el CFDI ya existía recibirás 200 con el comprobante original y sin cobro nuevo. Nunca reintentes con una llave nueva: eso sí duplicaría el comprobante. Reporta el request_id a soporte.","ejemplo":{"detail":"Internal Server Error","code":"INTERNAL_ERROR","request_id":"9f2c1a7b4e8d4c1fa0b3c5d6e7f80912","retriable":true,"retry_with_same_idempotency_key":true}}],"idempotencia":{"header":"Idempotency-Key","obligatorio":false,"recomendado":true,"formato":"UUID v4, uno por comprobante lógico","alcance":"por tenant","regla_de_oro":"Una factura, una llave. Ante cualquier error reintenta con la MISMA llave; nunca generes una nueva para el mismo comprobante.","al_reintentar_con_la_misma_llave":{"si_ya_se_timbro":{"http":200,"cuerpo":"El comprobante original, con el mismo uuid","vuelve_a_cobrar":false,"devuelve_409":false},"si_habia_fallado":{"http":200,"cuerpo":"Se intenta timbrar de nuevo","vuelve_a_cobrar":"solo si el timbrado tiene éxito","registro":"Se reutiliza el mismo registro del historial (mismo id e idempotency_key)."}},"conciliacion":{"error_http":"El detalle del error incluye `timbre_id` del intento registrado.","respuesta_de_timbrado":"Incluye `idempotency_key` junto al `id` del timbre.","historial":"GET /timbrado/timbres/buscar?idempotency_key=<llave> devuelve el intento de esa llave.","creditos":"Un intento rechazado por el PAC genera un cargo y su reembolso, ambos con `reference` = id del timbre; el neto es cero."},"verificado":"2026-07-31, tres intentos con la misma llave devolvieron el mismo uuid"},"descuentos_e_impuestos":{"descripcion":"Un concepto con descuento e IVA 0%. La base del impuesto se calcula después del descuento.","formato_de_importes":{"regla":"`descuento` se normaliza a EXACTAMENTE los decimales de la moneda (MXN/USD/EUR: 2). 3227.5 se emite como 3227.50 y el Descuento del comprobante como 6748.40.","ruido_de_punto_flotante":"3227.5000000000005 se corrige a 3227.50.","mas_decimales_que_la_moneda":"3227.505 se rechaza (400, BUILD_OR_SIGN) antes de llamar al PAC y sin cobrar; envía el importe ya redondeado.","recomendacion":"Calcula los descuentos con decimales (no con float) y envíalos redondeados.","redondeo_de_impuestos":"El `importe` explícito de un impuesto (traslado/retención) se redondea a los decimales de la moneda con la regla del SAT: desde .5 se sube (293.645 -> 293.65). Antes se usaba redondeo 'al par' (293.645 -> 293.64). Si omites `importe`, Lite lo calcula; para conservar a la perfección una cifra ya emitida, envíala explícita.","simulacion_vs_produccion":"El sandbox y producción construyen el XML con el mismo código (mismos redondeos); el sandbox solo simula la respuesta del PAC, por lo que no valida las reglas del PAC."},"cliente_extranjero":{"campos":"receptor.residencia_fiscal (c_Pais alfa-3, nunca MEX) y receptor.num_reg_id_trib (requiere residencia_fiscal)","formato_num_reg_id_trib":{"USA":"[0-9]{9} (9 dígitos, sin guiones)","CAN":"[0-9]{9} (9 dígitos, sin guiones)","resto":"sin formato publicado por el SAT: 1 a 40 caracteres","fuente":"catCFDI_V_4_20261015, hoja c_Pais; consulta por país en GET /catalogos/pais (extra.formato_num_reg_id_trib)"},"ejemplo":{"moneda":"USD","tipo_cambio":17.25,"receptor":{"rfc":"XEXX010101000","nombre":"ACME INC","domicilio_fiscal_receptor":"<igual a lugar_expedicion>","regimen_fiscal_receptor":"616","uso_cfdi":"S01","residencia_fiscal":"USA","num_reg_id_trib":"123456789"}},"reglas":{"CFDI40151/CFDI40154":"residencia_fiscal y num_reg_id_trib solo con el RFC XEXX010101000","CFDI40153":"num_reg_id_trib requiere residencia_fiscal; con XEXX y Comercio Exterior, residencia_fiscal es obligatoria","CFDI40156":"num_reg_id_trib cumple el formato del país","CFDI40149":"RFC genérico (XAXX/XEXX): domicilio_fiscal_receptor = lugar_expedicion","CFDI40159":"RFC genérico: regimen_fiscal_receptor = 616","CFDI40115/40116/40114/40117":"tipo_cambio: obligatorio si la moneda no es MXN/XXX; no con XXX; con MXN solo 1; máx. 6 decimales","validacion":"422 (esquema) o 400 BUILD_OR_SIGN (cálculo) antes de llamar al PAC y sin cobrar"},"customer_id":"Los clientes guardan residencia_fiscal y num_reg_id_trib (POST/PUT /customers); un receptor inline prevalece. Con RFC genérico, Lite fija domicilio = lugar_expedicion y régimen 616.","sandbox":"Aplica las mismas reglas que producción; no verifica que el Tax ID exista realmente."},"comercio_exterior":{"regla_sat":"exportacion '02' EXIGE el complemento comercio_exterior (CFDI40122/CCE104); con '01' o '03' no debe existir (CFDI40222/CCE105).","campo":"comercio_exterior (en el cuerpo de POST /timbrado/timbrar) -> complemento ComercioExterior 2.0; tipos I, E, T","fuente_de_reglas":"Matriz_de_Errores_CCE_v2.0 y EstandarComercioExterior_v20 del SAT (CCE101-CCE172), aplicadas sobre el XML antes del PAC y sin cobrar; cada error trae el código de la regla","campos":["clave_de_pedimento (A1)","incoterm (obligatorio)","certificado_origen 0|1 (+num_certificado_origen solo si es 1)","numero_exportador_confiable (solo destino en la Unión Europea)","motivo_traslado (T)","tipo_cambio_usd (USD: se toma de tipo_cambio)","total_usd (def.: suma de valor_dolares)","emisor {curp, domicilio} (obligatorio con CURP si el emisor es persona física)","receptor_domicilio (obligatorio con receptor XEXX010101000)","propietarios[] (T con motivo 05)","destinatarios[]","mercancias[]: no_identificacion (= concepto; todos los conceptos lo llevan), fraccion_arancelaria, cantidad_aduana, unidad_aduana, valor_unitario_aduana, valor_dolares, descripciones_especificas"],"formato_domicilio":{"MEX":"estado = clave c_Estado; el CP debe existir y corresponder al estado/municipio/localidad","USA_CAN":"estado = clave c_Estado; CP con el formato publicado por el SAT","otros":"texto libre"},"catalogos":["/catalogos/cce-incoterm","/catalogos/cce-clave-pedimento","/catalogos/cce-unidad-aduana","/catalogos/cce-motivo-traslado","/catalogos/cce-fraccion-arancelaria?q=","/catalogos/pais"],"coherencia":"sin informacion_global ni impuestos_locales (CCE106/CCE115); ingreso: receptor no XAXX (CCE107); traslado: receptor = emisor y objeto_imp 01 (CCE108/CCE110)","xsd":"El XML se valida contra el XSD oficial del SAT (cfdv40 + ComercioExterior20) en cada petición con este complemento.","no_valida_lite":["tipo_cambio_usd = tipo de cambio oficial del DOF (CCE121)","existencia real del Tax ID (CCE131/CCE135 en línea)","vigencia de la fracción y unidad = UMT de la fracción (CCE161/162/167)","fracción de muestras 9801000100 (CCE163/164)","complemento Leyendas Fiscales (no implementado)"],"sandbox":"local_simulation no ejecuta las reglas del PAC; sí aplica las de Lite.","guia":"docs/API.md §4.1-septies"},"cfdi_relacionados":{"campo":"cfdi_relacionados (en el cuerpo de POST /timbrado/timbrar)","esquema":"[{ tipo_relacion: '01'..'09', uuid: '<UUID>' | uuids: ['<UUID>', ...] }]","ejemplo_sustitucion":{"cfdi_relacionados":[{"tipo_relacion":"04","uuid":"<UUID del CFDI que se sustituye>"}]},"resultado":"Genera el nodo cfdi:CfdiRelacionados TipoRelacion='04' con un cfdi:CfdiRelacionado por UUID.","validacion":"tipo_relacion inválido o UUID mal formado responde 422. Máximo 10 grupos.","nota":"Los campos que Lite no reconoce se ignoran sin error; verifica en el XML devuelto que el nodo exista."},"entrada":{"cantidad":1,"valor_unitario":3313.8,"descuento":926.66,"objeto_imp":"02","traslados":[{"impuesto":"002","tipo_factor":"Tasa","tasa_o_cuota":"0.000000"}]},"salida_esperada":{"Concepto@Importe":"3313.80","Concepto@Descuento":"926.66","Traslado@Base":"2387.14","Traslado@Importe":"0.00","Comprobante@SubTotal":"3313.80","Comprobante@Descuento":"926.66","Comprobante@Total":"2387.14"},"variantes_verificadas":[{"caso":"IVA 16%","tasa_o_cuota":"0.160000","base":"2387.14","importe":"381.94","total":"2769.08"},{"caso":"IVA 0%","tasa_o_cuota":"0.000000","base":"2387.14","importe":"0.00","total":"2387.14"},{"caso":"IEPS 8% + IVA 16%","base":"2387.14","importe":"190.97 + 381.94","total":"2960.05"},{"caso":"IVA 16% + retención ISR 1.25% + retención IVA 10.6667%","base":"2387.14","trasladados":"381.94","retenidos":"284.47","total":"2484.61"},{"caso":"Exento","tipo_factor":"Exento","base":"2387.14","importe":null,"total":"2387.14"},{"caso":"No objeto de impuesto","objeto_imp":"01","importe":null,"total":"2387.14"},{"caso":"Cuota fija","tipo_factor":"Cuota","nota":"El importe depende de la unidad gravada y no puede derivarse: enviar `importe` explícito."}]},"sandbox":{"campo":"sandbox","tipo":"boolean","default":false,"endpoints":["/timbrado/timbrar","/timbrado/nomina","/timbrado/pago","/timbrado/retencion","/timbrado/batch (por ítem)"],"verificacion_previa":"GET /timbrado/entorno?emisor_rfc=<rfc>","campo_a_mostrar":"effective_environment","folios_en_sandbox":0,"prefijo_uuid_simulado":"5A4DB0C5","rfc_que_fuerzan_sandbox":["AAA010101AAA","CACX7605101P8","EKU9003173C9","EWE1709045U0","KAHO641101B39","LAN7008173R5","MAG041126GT8","URE180429TM6","XIA190128J61"]},"cancelacion":{"endpoint":"POST /timbrado/cancelar","cuerpo":{"emisor_rfc":"RFC del emisor (obligatorio)","uuid":"UUID del CFDI a cancelar (obligatorio)","motivo":"01 | 02 | 03 | 04 (obligatorio)","folio_sustitucion":"UUID del CFDI sustituto. Obligatorio con motivo 01; se ignora con 02, 03 y 04."},"validacion":"Mismas reglas en sandbox y producción; un cuerpo inválido responde 422 antes de contactar al PAC.","idempotency_key":"No se usa. La cancelación es idempotente por naturaleza: repetir la solicitud sobre un CFDI ya cancelado devuelve 200 con el mismo estado, sin cobro adicional ni nueva llamada al PAC.","respuesta_exitosa":{"http":200,"cuerpo":"El timbre (mismo esquema que /timbrado/timbrar). Léelo así:","cancelado":"status = 'canceled': el SAT confirmó la cancelación.","pendiente":"status = 'stamped' y cancel_status = 'pending': la solicitud fue aceptada pero el CFDI SIGUE VIGENTE hasta que el SAT la confirme (p. ej. el receptor debe aceptar, o el SAT aún no la refleja). Se confirma sola: Lite consulta al SAT cada 5 minutos y, al confirmarse, el status pasa a 'canceled' y se emite el webhook timbre.cancelled. Repetir POST /cancelar consulta el estatus sin enviar otra solicitud.","rechazada_o_sin_efecto":"status = 'stamped' y cancel_status = 'rejected' (el receptor la rechazó) o 'not_applied' (el SAT no la reflejó tras 2 horas): puedes volver a solicitarla.","consulta":"GET /timbrado/timbres/buscar?cancel_status=pending lista las solicitudes en curso."},"errores":{"422":"motivo fuera de 01-04, o motivo 01 sin UUID sustituto válido.","400 NOT_FOUND":"El uuid no existe para este tenant.","400 NO_XML":"No se encuentra el XML del CFDI a cancelar.","400 CANCEL_ERROR":"El PAC/SAT rechazó la cancelación. `reason` indica la causa: SAT_203..SAT_212 (código del acuse del SAT: UUID inexistente o no aplicable, folio de sustitución inválido, etc.) o RECEIVER_REJECTED. En estos casos el CFDI no se cancela.","formato":"{ detail: { code, message, reason? } }"},"sandbox":"Un UUID de sandbox (prefijo 5A4DB0C5) se cancela por simulación local: no contacta al PAC ni al SAT y no cobra folios. Los CSD de prueba del SAT se pueden usar para probar cancelaciones.","costo_folios":0,"alcance":"Solo se pueden cancelar desde Lite los CFDI timbrados a través de Lite (responde 400 NOT_FOUND para un UUID que no está en tu historial). Un CFDI emitido por otro medio (p. ej. el portal del SAT) se cancela en ese medio. Para sustituir uno: emite el nuevo con cfdi_relacionados tipo 04 y cancela el original con motivo 01 indicando el UUID del nuevo.","verificacion":"Lite no da por cancelado un CFDI solo porque el PAC aceptó la solicitud: verifica el estatus real en el servicio oficial de consulta del SAT. (Cancelaciones de retenciones: se reportan según la respuesta del PAC.)"},"trazabilidad":{"header_respuesta":"X-Request-Id","presente_en":"todas las respuestas","uso":"citar este id al reportar un problema a soporte"},"folios":{"por_timbrado":1,"por_cancelacion":0,"en_sandbox":0,"reembolso_automatico":"sí, cuando el PAC rechaza el comprobante","texto_timbrado":"1 folio","texto_cancelacion":"Sin costo"},"pdf_con_marca":{"disponible":true,"plan_minimo":"pro","endpoint":"POST /timbrado/cfdi/{uuid}/pdf","listar_plantillas":"GET /timbrado/plantillas-pdf","afecta_xml":false,"comprobantes_soportados":["I","E"],"nota_comprobantes":"Solo facturas (tipo I/E). Nómina, pagos, traslados y retenciones usan GET /pdf (diseño SenHub); el POST responde 422 si no es factura.","campos":[{"campo":"template_id","tipo":"string","requerido":false,"nota":"Si se omite, se usa la plantilla default."},{"campo":"accent_color","tipo":"string","requerido":false,"nota":"Hexadecimal #RGB o #RRGGBB."},{"campo":"logo_base64","tipo":"string","requerido":false,"nota":"PNG/JPG en Base64, máx. 512 KB. No se aceptan URLs remotas."},{"campo":"notes","tipo":"string","requerido":false,"nota":"Notas comerciales; respeta saltos de línea \\n."},{"campo":"page_format","tipo":"string","requerido":false,"nota":"A4 (default) o Letter."}],"reglas":["Los campos de marca son opcionales e independientes.","Sin template_id: se usa la default y se omiten logo y color.","Con template_id sin logo_base64: la plantilla se renderiza sin logo.","Con template_id sin accent_color: se usa el color propio de la plantilla.","No se cachea; no altera el GET /pdf (diseño SenHub por defecto)."]},"historial":{"endpoint":"GET /timbrado/timbres/buscar","legacy":"GET /timbrado/timbres (array, solo limit; se mantiene por compatibilidad)","respuesta":"sobre { items, total, limit, offset, has_more, next_cursor }","paginacion":{"offset":"simple: offset += limit mientras has_more","cursor":"keyset: reenviar next_cursor; solo con orden por defecto"},"filtros":["status (draft|stamped|canceled|error)","tipo_comprobante (I|E|T|N|P)","rfc_emisor","rfc_receptor","serie","environment (sandbox|production)","date_field (created|stamped)","date_from / date_to (ISO-8601)","q (búsqueda parcial en uuid o folio)"],"orden":{"sort":["fecha","total","rfc_emisor"],"order":["asc","desc"],"default":"sort=fecha, order=desc"},"item_campos":["id","uuid","status","tipo_comprobante","rfc_emisor","rfc_receptor","serie","folio","total","subtotal","descuento","moneda","metodo_pago","forma_pago","uso_cfdi","credits_charged","sandbox","pac_environment","pac_provider","has_xml","has_pdf","error_code","error_message","created_at","stamped_at","canceled_at"]},"cfdi_detalle":{"detalle":{"endpoint":"GET /timbrado/cfdi/{uuid}/detalle","descripcion":"Conceptos e impuestos parseados del XML + estado en la plataforma.","campos":["version","serie","folio","fecha","tipo_comprobante","forma_pago","metodo_pago","moneda","tipo_cambio","subtotal","descuento","total","lugar_expedicion","exportacion","emisor","receptor","conceptos[]","impuestos","timbre_fiscal"],"nota":"No altera GET /timbrado/cfdi/{uuid} (resumen). 409 si no hay XML."},"saldo":{"endpoint":"GET /timbrado/cfdi/{uuid}/saldo","descripcion":"saldo = total − Σ ImpPagado de complementos de pago (REP) vigentes.","campos":["uuid","metodo_pago","moneda","total","pagado","saldo","liquidado","num_pagos","pagos[]"],"nota":"Relevante para PPD. Los pagos cancelados no reducen el saldo."}},"catalogos":{"fuente_de_verdad":"servidor","idempotencia":"client_ref (referencia externa del integrador, única por tenant).","products":{"crud":"GET/POST/PUT/DELETE /products","sync":"GET /products/sync?since=<iso> → { items, count, server_time, has_more }","bulk":"POST /products/bulk (upsert por client_ref, máx 500)","impuestos_default":["tasa_iva","tasa_ieps","ret_iva","ret_isr"]},"customers":{"crud":"GET/POST/PUT/DELETE /customers","sync":"GET /customers/sync?since=<iso> → { items, count, server_time, has_more }","bulk":"POST /customers/bulk (upsert por client_ref; adopta por RFC, máx 500)"},"reglas_sync":["POST con client_ref existente devuelve el registro (200), no duplica.","/sync incluye inactivos (borrados lógicos) para reflejar bajas.","Usar server_time de la respuesta como próximo since; paginar con has_more."]},"impuestos_locales":{"complemento":"ImpuestosLocales 1.0 (http://www.sat.gob.mx/implocal)","endpoint":"POST /timbrado/timbrar (campo opcional impuestos_locales)","casos":"ISH (hospedaje/hoteles), impuestos estatales (construcción), etc.","campo":{"impuestos_locales":{"traslados_locales":[{"imp_loc_trasladado":"str (ej. ISH)","tasa_de_traslado":"número % (ej. 3.0)","importe":"número"}],"retenciones_locales":[{"imp_loc_retenido":"str","tasa_de_retencion":"número %","importe":"número"}]}},"limite":"Máx 1 traslado local y 1 retención local por comprobante.","lectura":"GET /timbrado/cfdi/{uuid}/detalle -> campo impuestos_locales.","nota":"Los importes son explícitos (reglas estatales); las tasas van en porcentaje, no fracción."}}