QR Estático - Factura
Mediante esta opción se puede generar de manera completamente offline un código QR estático que podrá ser impreso en una factura u enviado via email, whatsapp o el medio que fuese. Este QR se genera con un código de Referencia que evita que el mismo pueda ser pagado múltiples veces.
Información General
Paises
- 🇦🇷 Argentina
Formato del QR
EMV QR Merchant Presented Mode ( MPM )
Librerias para Generarlo
- NodeJS: https://github.com/steplix/emv-qrcps
Pasos
1) Obtener primero el Punto de Venta sobre el cual se generarán los QR. Esto puede hacerse desde la Consola en "Administrar POS". De aquí se debe obtener el "ID".
2) Solicitar a nuestro equipo todos los datos indicados en la tabla.
3) Utilizando alguna de las librerias generar el QR con la siguiente información
Nombre del Campo | Campo | Sub-Campo | Tipo | Valor |
|---|---|---|---|---|
Payload Format Indicator / Indicador de Formato | 00 | | Fijo | 01 |
Point of Initiation Method / Metodo de Iniciación | 01 | | Fijo | 11 |
Reversed Domain / Dominio Reverso | 41 | | Sub-Campos | |
| | 00 | Fijo | io.sugaway.interoperable |
| | 01 | Fijo | prisma |
| | 98 | Fijo | 30598910045 |
| | 99 | Fijo | 01 |
Merchant ID / ID Del Comercio | 50 | | Sub-Campos | |
CUIT | | 00 | Dinámico | Solicitar a Soporte |
CUIT Formateado | | 01 | Dinámico | Campo anterior en formato XX-XXXXXXXX-X |
Merchant Account / Cuenta del Comercio | 51 | | Sub-Campos | |
CVU | | 00 | Dinámico | Solicitar a Soporte |
Merchant Category Code / Código de Categoria del Comercio | 52 | | Dinámico | Solicitar a Soporte |
Currency / Moneda | 53 | | Fijo | 032 |
Total | 54 | | Dinámico | Total de la operación en formato NNNN.DD. Donde N es la parte entera y D los decimales. Este total debe tener siempre 2 decimales. |
Country Code / Código de País | 58 | | Fijo | AR |
Merchant Name / Nombre del Comercio | 59 | | Dinámico | Solicitar a Soporte |
Merchant City / Ciudad del Comercio | 60 | | Dinámico | Solicitar a Soporte |
Zip Code / Código Postal | 61 | | Dinámico | Solicitar a Soporte |
| 80 | 01 | Dinámico | D1=1775150280;T2=150.00;D2=1775409480; Donde T2 es el Total 2. D1 y D2 son los vencimientos como Timestamp en Milisegundos |
| 81 | 01 | Dinámico | Firma del campo 80 |
Additional Data / Datos Adicionales | 62 | | Sub-Campos | |
Point of Sale / Punto de Venta | | 01 | Dinámico | Dato obtenido en el punto 1 del tutorial. Este dato siempre va a ser el mismo en todos los QR. Solicitar a Soporte. |
Reference / Referencia | | 07 | Dinámico | Código único de operación, este campo permitirá que la factura o la operación no pueda ser abonada múltiples veces. |
Ejemplo
Código generado en el formato especificado
00020101021141490024io.sugaway.interoperable98113059891004599020150280009121231234011112-123123-4512600229999999999999999999999520473995913Mi Comercio 26004CABA5802AR6108C1082ABF5303032540410.5626201183T3WN9P9G22KT7UHDA0536B3B3ACB6-CB14-4A3F-A05D-91E013D810D863041F39Generación de Firma
Estructura
El QR estático firmado utiliza los campos estándar EMV QR Merchant Presented Mode más tres campos adicionales para importes con vencimientos firmados:
Campo | Nombre | Contenido |
|---|---|---|
54 | Amount | Primer importe (T1) |
80 | Unreserved Template | Subcampo 01: payload firmado en base64url |
81 | Unreserved Template | Subcampo 01: firma ECDSA del payload en base64url |
Formato del Payload (Campo 80.01)
El contenido del subcampo 01 del campo 80 es un string codificado en base64url sin padding. Al decodificarlo se obtiene:
Donde:
- T{n} es un importe con 2 decimales (ej: 100.00)
- D{n} es el timestamp de vencimiento del importe T{n} en formato Unix epoch en segundos
- n es un índice secuencial comenzando en 1
- T1 se replica además en el campo 54 del QR (campo estándar EMV Amount)
Importante: T1 se incluye tanto en el campo 54 como dentro del payload firmado. Esto garantiza que si alguien modifica el campo 54 del QR, la verificación de firma falla.
Ejemplo decodificado:
Esto define:
- $100.00 válido hasta el timestamp 1775150280
- $150.00 válido hasta el timestamp 1775236680
Al momento del pago, el sistema selecciona el primer importe cuyo vencimiento aún no haya expirado. Si todos los importes están vencidos, se rechaza la operación. Actualmente se soportan hasta 2 importes con vencimientos.
Codificación Base64url sin Padding
Se utiliza la variante URL-safe de Base64 definida en RFC 4648 §5:
- Codificar el string en Base64 estándar
- Reemplazar + por -
- Reemplazar / por _
- Eliminar los = del final (padding)
Para decodificar, realizar el proceso inverso: reemplazar - por +, _ por /, agregar = hasta que el largo sea múltiplo de 4, y decodificar Base64.
Generación de la Firma (Campo 81.01)
Algoritmo: ECDSA con SHA-256 sobre curva P-256 (prime256v1)
Tamaño de la firma: 64 bytes (86 caracteres en base64url)
Proceso:
- Construir el payload en texto plano: T1={amount};D1={ts};T2={amount};D2={ts};
- Codificar en base64url sin padding → este valor va en el campo 80.01
- Firmar el valor codificado en base64url (el string del paso 2) con ECDSA-SHA256 usando la clave privada
- Codificar la firma en base64url sin padding → este valor va en el campo 81.01
Nota: Se firma el string base64url (paso 2), no el texto plano original. Esto es importante para que la verificación sea consistente.
Ejemplos por Lenguaje
JavaScript (Web Crypto API)
Python
PHP
Go
C# (.NET)
Java
Verificación
Al recibir el QR, el sistema:
- Lee el campo 54 (primer importe), campo 80.01 (payload base64url) y campo 81.01 (firma base64url)
- Obtiene la clave pública del certificado activo de la entidad para el message type qr
- Si la entidad no tiene certificado propio, busca el del operador padre (Payment Facilitator)
- Verifica la firma ECDSA-SHA256 del payload usando la clave pública
- Decodifica el payload base64url para obtener los importes y vencimientos
- Valida que T1 del payload coincida con el campo 54 del QR
- Selecciona el monto correspondiente según el vencimiento vigente
- Si todos los importes están vencidos, rechaza la operación
Ejemplo completo de QR
Certificados
Los certificados se gestionan desde la consola en la sección Firmas. Para QR se utiliza el algoritmo ECDSA con curva P-256 (prime256v1).
Al crear un certificado:
- Se genera un par de claves (pública y privada) ECDSA P-256
- La clave pública se almacena en el servidor para verificación
- La clave privada se entrega al usuario una única vez para que firme los QR desde su dispositivo
- La clave privada es un archivo PEM que debe guardarse de forma segura
Para submerchants operados por un Payment Facilitator: si el submerchant no tiene certificado propio, el sistema utiliza automáticamente el certificado del operador padre.
Restricciones
Restricción | Valor |
|---|---|
Algoritmo | ECDSA SHA-256 (único permitido para QR) |
Curva | P-256 / prime256v1 (única permitida para QR) |
Codificación | base64url sin padding (RFC 4648 §5) |
Formato de firma | IEEE P1363 (raw r‖s, 64 bytes) |
Largo campo 80.01 | ≤ 95 caracteres (payload base64url) |
Largo campo 81.01 | 86 caracteres (firma 64 bytes en base64url) |
Largo firma | 86 caracteres base64url (64 bytes raw) |
Máximo importes | 2 (T1/D1 + T2/D2) |