PSP as a Service
QR de cobro
Introducción

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

  1. Autenticación — una sola vez, o cuando el token expire.
  2. Obtener cuentas de cobro — al integrar por primera vez, o cuando se habilite una cuenta nueva.
  3. Generar un QR — una vez por cada cobro.
  4. Seguimiento del cobro — por webhook o consultando el estado en polling.
  5. 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.id es el portfolioId
  • account.owners[].id es el personId

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.

ValorNombreComportamiento
1QrRegularUseReutilizable: admite varios cobros.
2QrSingleUseUn solo cobro. Es el valor por defecto.
3QrWithOrderUseamount 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.

EstadoSignificado
PENDINGVigente, sin cobrar. QR de un solo uso con vencimiento.
ACTIVEVigente, sin cobrar. QR reutilizable con vencimiento.
UNDEFINEDVigente, sin cobrar, sin fecha límite.
COLLECTEDCobrado. Incluye el movementId.
EXPIREDVenció sin cobrarse.
NOTFOUNDNo 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
QrSingleUsePENDING → COLLECTED o EXPIRED
QrRegularUse con vencimientoACTIVE → COLLECTED o EXPIRED
QrRegularUse sin vencimientoUNDEFINED → COLLECTED
QrWithOrderUseUNDEFINED → 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:

JSON 400
{
    "exceptionType": "Business",
    "errors": [
        {
            "code": "ApiExternal_WrongAccountPermission",
            "description": "<mensaje descriptivo>"
        }
    ]
}
HTTPCódigoCuándo ocurre
400ApiExternal_WrongAccountPermissionEl par portfolioId / personId no está habilitado para tus credenciales
400ApiExternal_OrderNotFoundEl propagoQrId no tiene un movimiento asociado
400QrInterop_InvalidExpirationDateForQrUseTypeSe envió expirationDate en un QrWithOrderUse
400QrInterop_InvalidAmountEl 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.