Skip to content

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.


Flujo general

Antes de comenzar, este es el flujo que implementarás:

  1. Tu sistema registra una venta
  2. Usas el API de QRwey! para generar una intención de autofactura
  3. Se genera un código QR seguro y efímero
  4. 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

Requisitos previos

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)

Autenticación

Todas las peticiones a la API de QRwey! requieren:

  • Header X-API-Key
  • Header idempotency-key para operaciones de escritura

Ejemplo base:

X-API-Key: TU_API_KEY_MODO_DEV
idempotency-key: uuid-unico
Content-Type: application/json

⚠️ Importante idempotency-key evita operaciones duplicadas si ocurre un reintento por problemas de red por ejemplo


Base URL (servidores)

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


Paso 1: Generar un Código QR (POST /v1/qrs)

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 contiene v, t y m)

Request de ejemplo (DEV)

Consejo: usa un expires_at razonable (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
          }
        ]
      }
    ]
  }'

Respuesta esperada (201)

{
  "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"
}

¿Qué debes guardar?

  • Guarda qr_id como identificador de la transacción.
  • Guarda qr_content (o el QR impreso/mostrado que lo contiene).
  • qr_url es útil si quieres mostrar/descargar el PNG directamente.
  • expires_at te indica hasta cuándo el QR será válido.

Paso 2: El usuario escanea el QR

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.


Paso 3: Timbrado del CFDi

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.


Paso 4: Consultar el detalle de la transacción QR (GET /v1/qrs/{qrId})

Opcionalmente, puedes consultar el detalle completo de la transacción usando el qr_id que obtuviste al generar el QR.

Request de ejemplo (DEV)

curl -X GET "https://api-dev.qrwey.com/v1/qrs/tra_4aca0361cfcd41c097663db44008fbb9" \
  -H "X-API-Key: TU_API_KEY"

Respuesta esperada (200)

{
  "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 invoice y customer contendrán los datos de la factura generada y del cliente que se facturó.

Detalle completo: Obtener detalle de QR


Errores comunes y qué hacer

  • 400 Bad Request: validación (campos faltantes, tipos, expires_at en el pasado)
  • 401 Unauthorized: X-API-Key inválida o ausente
  • 404 Not Found: qr_id o store_uid no encontrado
  • 409 Conflict: idempotency-key duplicada 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 campo status: EXPIRED.

Guía recomendada: Manejo de errores


Checklist para pasar a Producción

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-key en reintentos
  • Manejas explícitamente:
    • 409 Conflict (idempotencia o duplicado)
    • status: EXPIRED vía GET /v1/qrs/{qrId} (QR expirado)
    • 422 Unprocessable Entity (reglas de negocio / configuración)
  • expires_at definido según tu operación (ventana realista según reglas del negocio)
  • Logs con request_id, idempotency-key y timestamps para depuración y soporte

¿Qué sigue?

Ahora que tienes un flujo básico funcionando: