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 la intención de factura
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://clients.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://clients.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–15 minutos) para pruebas y operación.
curl -X POST "https://api-dev.qrwey.com/api/v1/qrs" \
-H "X-API-Key: TU_API_KEY" \
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-H "Content-Type: application/json" \
-d '{
"store": "PetroStation #45",
"issuer_rfc": "EKU9003173C9",
"amount": 133.00,
"subtotal": 115.08,
"currency": "MXN",
"sat_payment_method": "04",
"expires_at": "2025-12-29T23:59:59Z",
"operation": "INVOICE",
"operation_data": [
{
"sku": "GAS87",
"description": "Gasolina Magna",
"amount": 115.08,
"quantity": 5.662,
"sat_unit_key": "LTR",
"unit_price": 20.325,
"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_base64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
"qr_url": "https://api-dev.qrwey.com/qr.png?t=YWFh...&exp=1696200000&sig=YmJi...",
"qr_content": "https://api-dev.qrwey.com/go?v=1&t=YWFh...&m=YmJi...",
"created_at": "2025-09-11T18:25:43Z",
"expires_at": "2025-09-30T23:59:59Z"
}- 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! timbra el 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.
Cuando el usuario escanea el QR, la app móvil extrae de qr_content estos parámetros:
v(versión del formato; actualmente"1")t(token opaco Base64URL)m(firma HMAC truncada Base64URL)
Con esos valores, se consulta el endpoint de resolución.
Ejemplo de qr_content:
https://api-dev.qrwey.com/go?v=1&t=YWFh...&m=YmJi...De ahí obtienes:
v=1t=YWFh...m=YmJi...
curl -X GET "https://api-dev.qrwey.com/api/v1/qrs?v=1&t=YWFh...&m=YmJi..." \
-H "X-API-Key: TU_API_KEY"{
"id": "tra_4aca0361cfcd41c097663db44008fbb9",
"store": "PetroStation #45",
"issuer_rfc": "EKU9003173C9",
"issuer_name": "ESCUELA KEMPER URGATE",
"amount": 133.0,
"subtotal": 115.08,
"currency": "MXN",
"sat_payment_method": "04",
"sat_payment_method_desc": "Tarjeta de crédito",
"created_at": "2025-09-29T13:00:00Z",
"expires_at": "2025-09-30T23:59:59Z",
"operation": "INVOICE",
"operation_data": [
{
"sku": "GAS87",
"description": "Gasolina Magna",
"amount": 115.08,
"quantity": 30,
"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
}
]
}
]
}- 400 Bad Request: validación (campos faltantes, tipos, firma inválida,
expires_aten el pasado) - 401 Unauthorized:
X-API-Keyinválida o ausente - 404 Not Found: token no encontrado (revocado o purgado)
- 409 Conflict: token ya consumido (si la política es de un solo uso)
- 410 Gone: QR expirado
- 422 Unprocessable Entity: error de negocio (ej.
issuer_rfcno configurado)
Guía recomendada: Manejo de errores
Antes de mover tu integración a https://clients.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(token consumido) -
410 Gone(QR expirado) -
422 Unprocessable Entity(reglas de negocio / configuración)
-
-
expires_atdefinido según tu operación (ventana realista: 5–30 minutos típicamente) - No confías en datos del QR sin resolverlos vía API (validación server-side)
- Logs con
codeymessagepara 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