En esta guía integrarás un flujo completo de autofactura CFDi usando QRwey!.
Al finalizar este Quickstart habrás logrado:
- Registrar una venta
- Generar una intención de autofactura mediante un código QR
- Resolver el QR desde la app de QRwey!
- Convertir la intención en un CFDi timbrado (XML)
- Obtener su representación impresa (PDF)
- Opcionalmente consultar el detalle de la transacción QR
Todo usando la API de QRwey!, sin portales complejos ni formularios innecesarios.
Antes de comenzar, este es el flujo que implementarás:
- Tu sistema registra una venta
- Usas el API de QRwey! para generar una intención de autofactura
- Se genera un código QR seguro y efímero
- El usuario escanea el QR desde la app de QRwey! y:
- El usuario valida la información
- Con un clic, QRwey! timbra el CFDi y genera el XML y PDF
- Dentro de la aplicación móvil puedes visualizar, compartir o enviar por correo el XML y PDF
Antes de iniciar, asegúrate de contar con:
- Una API Key válida de QRwey! modo developer para usar una SA y timbres de prueba
- Acceso al entorno de pruebas
- Un cliente HTTP (
curl, Postman, etc.) - La app de QRwey! que puedes descargar para iOS o para Android
- Configurar la app de QRwey! para que tenga al menos un RFC al cual facturar tu(s) prueba(s)
Todas las peticiones a la API de QRwey! requieren:
- Header
X-API-Key - Header
idempotency-keypara operaciones de escritura
Ejemplo base:
X-API-Key: TU_API_KEY_MODO_DEV
idempotency-key: uuid-unico
Content-Type: application/json⚠️ Importante
idempotency-keyevita operaciones duplicadas si ocurre un reintento por problemas de red por ejemplo
La especificación OpenAPI de QRwey! define estos servidores:
- Producción:
https://api.qrwey.com - Desarrollo/Pruebas:
https://api-dev.qrwey.com
En este Quickstart usaremos Desarrollo/Pruebas por default.
Cuando pases a producción, solo cambia el host a https://api.qrwey.com y no olvides cambiar TU_API_KEY productiva
Este endpoint crea una transacción y regresa el QR en 3 formatos:
qr_base64(imagen PNG en base64 para incrustar/impresión)qr_url(URL firmada para ver/descargar el PNG)qr_content(deep link que contienev,tym)
Consejo: usa un
expires_atrazonable (p.ej. 5 días o hasta fin de mes) para pruebas y operación.
curl -X POST "https://api-dev.qrwey.com/v1/qrs" \
-H "X-API-Key: TU_API_KEY" \
-H "X-TIME-ZONE: America/Mexico_City" \
-H "idempotency-key: 550e8400-e29b-41d4-a716-446655440000" \
-H "Content-Type: application/json" \
-d '{
"store_uid": "store_abc123",
"sale_id": "fcd68791-6a27-412f-a50f-8d47b7bc34d2",
"operation": "INVOICE",
"amount": 133.00,
"subtotal": 115.08,
"currency": "MXN",
"exchange_rate": 1.0,
"sat_payment_method": "PUE",
"sat_payment_form": "04",
"expires_at": "2026-01-03T23:59:59Z",
"type_of_receipt": "I",
"export_code": "01",
"related_cfdis": null,
"global_info": null,
"metadata": null,
"operation_data": [
{
"sku": "GAS87",
"description": "Gasolina Magna",
"quantity": 5.662,
"unit_price": 20.325,
"discount": 0.00,
"amount": 115.08,
"sat_unit_key": "LTR",
"sat_product_service_key": "15101515",
"sat_tax_object_key": "02",
"taxes": [
{
"type": "Traslado",
"tax": "002",
"factor": "Tasa",
"rate": "0.160000",
"taxable_base": 112.0,
"amount": 17.92
}
]
}
]
}'{
"qr_id": "tra_4aca0361cfcd41c097663db44008fbb9",
"store_uid": "store_abc123",
"sale_id": "fcd68791-6a27-412f-a50f-8d47b7bc34d2",
"idempotency_key": "550e8400-e29b-41d4-a716-446655440000",
"amount": 133.00,
"subtotal": 115.08,
"currency": "MXN",
"exchange_rate": 1.0,
"sat_payment_method": "PUE",
"sat_payment_form": "04",
"type_of_receipt": "I",
"export_code": "01",
"operation": "INVOICE",
"status": "PENDING",
"operation_data": [
{
"sku": "GAS87",
"description": "Gasolina Magna",
"quantity": 5.662,
"unit_price": 20.325,
"discount": 0.00,
"amount": 115.08,
"sat_unit_key": "LTR",
"sat_unit_desc": "Litro",
"sat_product_service_key": "15101515",
"sat_product_service_desc": "Gasolina premium mayor o igual a 91 octanos",
"sat_tax_object_key": "02",
"sat_tax_object_desc": "Sí objeto de impuesto",
"taxes": [
{
"type": "Traslado",
"tax": "002",
"factor": "Tasa",
"rate": "0.160000",
"taxable_base": 112.0,
"amount": 17.92
}
]
}
],
"metadata": null,
"qr_base64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
"qr_url": "https://api-dev.qrwey.com/qr.png?...",
"qr_content": "https://api-dev.qrwey.com/go?v=1&t=YWFh...&m=YmJi...",
"created_at": "2026-01-01T13:00:00Z",
"expires_at": "2026-01-03T23:59:59Z"
}- Guarda
qr_idcomo identificador de la transacción. - Guarda
qr_content(o el QR impreso/mostrado que lo contiene). qr_urles útil si quieres mostrar/descargar el PNG directamente.expires_atte indica hasta cuándo el QR será válido.
El usuario:
- Escanea el QR desde la app de QRwey!
- Revisa el detalle de la venta
- Confirma que la información fiscal es correcta
Este paso ocurre fuera de tu sistema y no requiere integración adicional.
Una vez confirmada la información por el usuario:
- QRwey! convierte la intención de factura a CFDi
- Se genera el XML timbrado
- Se genera la representación impresa (PDF)
Este proceso es gestionado completamente por QRwey! y dentro de la app móvil donde el usuario inclusive puede visualizar, compartir o enviar por correo dicho CFDi.
Opcionalmente, puedes consultar el detalle completo de la transacción usando el qr_id que obtuviste al generar el QR.
curl -X GET "https://api-dev.qrwey.com/v1/qrs/tra_4aca0361cfcd41c097663db44008fbb9" \
-H "X-API-Key: TU_API_KEY"{
"qr_id": "tra_4aca0361cfcd41c097663db44008fbb9",
"store_uid": "store_abc123",
"store_name": "PetroStation #45",
"sale_id": "fcd68791-6a27-412f-a50f-8d47b7bc34d2",
"idempotency_key": "550e8400-e29b-41d4-a716-446655440000",
"issuer_rfc": "EKU9003173C9",
"issuer_name": "ESCUELA KEMPER URGATE",
"amount": 133.00,
"subtotal": 115.08,
"currency": "MXN",
"exchange_rate": 1.0,
"sat_payment_form": "04",
"sat_payment_form_desc": "Tarjeta de crédito",
"sat_payment_method": "PUE",
"sat_payment_method_desc": "Pago en una sola exhibición",
"type_of_receipt": "I",
"type_of_receipt_desc": "Ingreso",
"export_code": "01",
"export_code_desc": "No aplica",
"operation": "INVOICE",
"status": "PENDING",
"operation_data": [
{
"sku": "GAS87",
"description": "Gasolina Magna",
"amount": 115.08,
"quantity": 5.662,
"discount": 0.00,
"sat_unit_key": "LTR",
"sat_unit_desc": "Litro",
"unit_price": 20.325,
"sat_product_service_key": "15101515",
"sat_product_service_desc": "Gasolina premium mayor o igual a 91 octanos",
"sat_tax_object_key": "02",
"sat_tax_object_desc": "Sí objeto de impuesto",
"taxes": [
{
"type": "Traslado",
"tax": "002",
"factor": "Tasa",
"rate": "0.160000",
"taxable_base": 112.0,
"amount": 17.92
}
]
}
],
"related_cfdis": null,
"global_info": null,
"metadata": null,
"invoice": null,
"customer": null,
"qr_base64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
"qr_url": "https://api-dev.qrwey.com/qr.png?...",
"qr_content": "https://api-dev.qrwey.com/go?v=1&t=YWFh...&m=YmJi...",
"created_at": "2026-01-01T13:00:00Z",
"updated_at": "2026-01-01T13:00:00Z",
"scanned_at": null,
"expires_at": "2026-01-03T23:59:59Z"
}Cuando el QR ya fue facturado, los campos
invoiceycustomercontendrán los datos de la factura generada y del cliente que se facturó.
Detalle completo: Obtener detalle de QR
- 400 Bad Request: validación (campos faltantes, tipos,
expires_aten el pasado) - 401 Unauthorized:
X-API-Keyinválida o ausente - 404 Not Found:
qr_idostore_uidno encontrado - 409 Conflict:
idempotency-keyduplicada con datos distintos - 422 Unprocessable Entity: error de negocio (tienda deshabilitada, CSD inválido, catálogo SAT incorrecto)
Para verificar si un QR expiró, consulta
GET /v1/qrs/{qrId}y revisa el campostatus: EXPIRED.
Guía recomendada: Manejo de errores
Antes de mover tu integración a https://api.qrwey.com, valida lo siguiente:
- API Key de producción configurada y almacenada en backend (no frontend)
- Generas un UUID por operación y reusas la misma
idempotency-keyen reintentos - Manejas explícitamente:
-
409 Conflict(idempotencia o duplicado) -
status: EXPIREDvíaGET /v1/qrs/{qrId}(QR expirado) -
422 Unprocessable Entity(reglas de negocio / configuración)
-
-
expires_atdefinido según tu operación (ventana realista según reglas del negocio) - Logs con
request_id,idempotency-keyy timestamps para depuración y soporte
Ahora que tienes un flujo básico funcionando:
- Aprende a manejar errores → Manejo de errores
- Controla reintentos → Idempotencia
- Entiende expiración y seguridad → Ciclo de vida del QR
- Consulta parámetros avanzados → Referencia del API