QR de cobro
Este circuito permite generar códigos QR de cobro sobre una cuenta habilitada, y consultar su estado y su resultado.
Flujo de integración
- Autenticación — una sola vez, o cuando el token expire.
- Obtener cuentas de cobro — al integrar por primera vez, o cuando se habilite una cuenta nueva.
- Generar un QR — una vez por cada cobro.
- Seguimiento del cobro — por webhook o consultando el estado en polling.
- Listar cobros y detalle de un cobro — para la conciliación posterior.
Eliminar un QR es opcional, y solo aplica a un QR que todavía no fue cobrado.
No existe un endpoint de modificación. Para cambiar el monto o el vencimiento de un QR hay que eliminarlo y generar uno nuevo.
Cuentas de cobro
El token no está asociado a una cuenta puntual. Te autenticás con tus credenciales y, en cada acción sobre un QR, indicás explícitamente sobre qué cuenta querés operar mediante portfolioId y personId.
En cada llamada se valida que ese par esté habilitado para tus credenciales. Solo podés operar sobre las cuentas que te fueron habilitadas de antemano.
Ambos valores salen de Obtener cuentas de cobro:
account.ides elportfolioIdaccount.owners[].ides elpersonId
Se descubren al integrar, no en cada cobro. Guardalos de tu lado.
Todos los endpoints de esta sección reciben sus parámetros por query string, incluido el DELETE. Ninguno usa cuerpo del mensaje. El resto de la sección PSP as a Service usa body JSON, así que prestá atención al cambio.
Tipos de QR
El parámetro qrUseType define el comportamiento del QR generado.
| Valor | Nombre | Comportamiento |
|---|---|---|
1 | QrRegularUse | Reutilizable: admite varios cobros. |
2 | QrSingleUse | Un solo cobro. Es el valor por defecto. |
3 | QrWithOrderUse | amount y expirationDate deben omitirse. Fuera del alcance de este circuito. |
Usá QrSingleUse (2) si querés trackear un pedido puntual. Un QrRegularUse clona su registro en cada cobro, con lo cual el order_id deja de identificar de forma confiable al movimiento. Además cambia el estado que vas a leer al consultar — ver más abajo.
Vigencia
Si generás un QrSingleUse sin expirationDate, el QR vence a los 15 minutos. Podés pasar un expirationDate explícito para darle más duración.
Un QrWithOrderUse siempre lleva expirationDate nulo: mandar un valor devuelve QrInterop_InvalidExpirationDateForQrUseType.
El código QR
generate-qr devuelve el campo qr_raw: el string EMV que tenés que codificar como imagen de tu lado. La API no devuelve una imagen.
También devuelve order_id, que es el identificador que el resto de los endpoints pide bajo el nombre propagoQrId. Son el mismo valor.
Estados
El estado de un QR se calcula en el momento de la consulta a partir del tipo, el vencimiento y si fue cobrado o no.
| Estado | Significado |
|---|---|
PENDING | Vigente, sin cobrar. QR de un solo uso con vencimiento. |
ACTIVE | Vigente, sin cobrar. QR reutilizable con vencimiento. |
UNDEFINED | Vigente, sin cobrar, sin fecha límite. |
COLLECTED | Cobrado. Incluye el movementId. |
EXPIRED | Venció sin cobrarse. |
NOTFOUND | No existe, o no pertenece a la cuenta indicada. |
PENDING y ACTIVE no son dos momentos del mismo QR. Son el mismo estado —vigente y sin cobrar— para tipos de QR distintos. Un QR nunca pasa de uno al otro.
Según el tipo que uses, vas a ver esta secuencia:
| Si generás… | Vas a ver |
|---|---|
QrSingleUse | PENDING → COLLECTED o EXPIRED |
QrRegularUse con vencimiento | ACTIVE → COLLECTED o EXPIRED |
QrRegularUse sin vencimiento | UNDEFINED → COLLECTED |
QrWithOrderUse | UNDEFINED → COLLECTED |
Siguiendo el circuito recomendado, los únicos estados que vas a encontrar son PENDING, COLLECTED y EXPIRED.
UNDEFINED no es un error: es el estado natural de un QR vigente sin fecha límite, como el QR estático y permanente de un comercio.
Seguimiento del cobro
Hay dos formas de enterarte de que un QR se cobró.
Por notificación (recomendado). Suscribiéndote al evento NEW_MONEY_MOVEMENT de Webhooks recibís un POST en tu servidor cuando se registra el movimiento. La notificación trae el order_id del QR que lo originó, así que podés correlacionarla con el cobro que estabas esperando sin consultar nada.
Por consulta en polling. Consultá el estado con un intervalo prudente —por ejemplo cada 3 a 5 segundos— hasta obtener COLLECTED o EXPIRED. Evitá consultar en un loop ajustado.
Se pueden combinar: el webhook como mecanismo principal, y una consulta de estado como respaldo o para reconciliar si tu servidor estuvo caído.
Un QR sin expirationDate no tiene condición de corte. Se queda en UNDEFINED hasta que alguien lo cobre, que puede no pasar nunca. Si generás QR sin vencimiento, tu polling necesita un límite propio de intentos o de tiempo.
Monto y moneda
Los montos están expresados en pesos argentinos. No hay campo de moneda.
No hay mínimo ni máximo. Solo se valida que el monto no sea cero.
Cada llamada a generate-qr crea un QR nuevo. No hay idempotencia: si reintentás una generación que ya había funcionado, vas a terminar con dos QR válidos. Guardá el order_id antes de reintentar.
Manejo de errores
Los errores de negocio de esta sección devuelven HTTP 400 con el siguiente formato:
{
"exceptionType": "Business",
"errors": [
{
"code": "ApiExternal_WrongAccountPermission",
"description": "<mensaje descriptivo>"
}
]
}| HTTP | Código | Cuándo ocurre |
|---|---|---|
| 400 | ApiExternal_WrongAccountPermission | El par portfolioId / personId no está habilitado para tus credenciales |
| 400 | ApiExternal_OrderNotFound | El propagoQrId no tiene un movimiento asociado |
| 400 | QrInterop_InvalidExpirationDateForQrUseType | Se envió expirationDate en un QrWithOrderUse |
| 400 | QrInterop_InvalidAmount | El monto enviado es cero |
| 401 | — | Falta el header Authorization, o el token está vencido o es inválido |
Una cuenta que no existe y una cuenta ajena devuelven el mismo error. Es intencional: evita que un tercero pueda deducir qué identificadores existen sondeando la API.