Convenciones
La integración tiene dos direcciones y cada una se autentica de forma distinta. Conviene tenerlas claras antes de leer los endpoints.
| Dirección | Quién llama | Autenticación | Servicios |
|---|---|---|---|
| Entrante | El banco llama a GoSoft | JWT HS256 que emite GoSoft | /bg-qr/login · /bg-qr/payments |
| Saliente | GoSoft llama al banco | X-Api-Key + Bearer del banco |
access, collections, cancellations, status, transactions |
URL base de los servicios entrantes
El host identifica a la empresa (multi-tenant). Los paths son exactos por exigencia de la spec.
https://{empresa}.gosoft.app/bg-qr/login
https://{empresa}.gosoft.app/bg-qr/payments
Envoltura de respuesta
Los servicios entrantes responden en el formato de la spec. A diferencia de otras APIs de
GoSoft, acá el status HTTP sí es real y acompaña al
result.
{
"result": "COD000", // codigo de la spec
"message": "Autenticacion satisfactoria" // texto legible
}
| result | Significado | HTTP |
|---|---|---|
| COD000 | Operación satisfactoria. | 200 |
| COD001 | Parámetros insuficientes, credenciales inválidas o qrId inexistente. | 400 / 401 / 404 |
| COD002 | Reservado por la spec. | — |
| COD003 | Error al procesar el pago del lado de GoSoft. | 422 / 500 |
Cabeceras
| Cabecera | Valor | Nota |
|---|---|---|
| Content-Type | application/json | Obligatoria. También se acepta form-urlencoded como respaldo. |
| Authorization | Bearer <token> | Sólo en /bg-qr/payments. Se aceptan los prefijos Bearer, JWT Bearer o el token pelado. |
Cada llamada del banco —exitosa o fallida— queda registrada en
bg_qr_webhook_log con IP, cuerpo, cabeceras, status y resultado. Si hay una
discrepancia, esa tabla es la fuente de verdad para el reclamo.
Flujo del cobro
El registro del pago depende del webhook, no de la pantalla: aunque nadie esté mirando el estado, el cobro se contabiliza igual.
Generar la orden
GoSoft pide al banco una orden de cobro por el saldo del documento y recibe el QR.
Mostrar el QR
El QR se imprime en el PDF de la venta o cobranza, junto al link de estado.
El cliente paga
Escanea desde su banca móvil. El banco procesa y acredita la cuenta.
El banco avisa
Llama a /bg-qr/login y luego a /bg-qr/payments con el qrId.
Se contabiliza
GoSoft genera el comprobante de ingreso y baja el saldo de las ventas cubiertas.
Login del banco
Sección 7 de la spec. El banco se autentica contra GoSoft y recibe el token que usará para confirmar pagos.
Cuerpo (JSON)
| Campo | Tipo | Descripción | |
|---|---|---|---|
| userName | string | req | Usuario del webhook, entregado por GoSoft a la empresa y de ahí al banco. |
| password | string | req | Contraseña del webhook. Comparación en tiempo constante. |
Ejemplo de llamada
curl -X POST "https://demo.gosoft.app/bg-qr/login" \
-H "Content-Type: application/json" \
-d '{
"userName": "bg_webhook_demo",
"password": "**********"
}'
{
"result": "COD000",
"message": "Autenticacion satisfactoria",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiZ193ZWJob29rX2RlbW8ifQ.k7Qw..."
}
{
"result": "COD001",
"message": "Parametros de entrada insuficientes (userName/password)"
}
{
"result": "COD001",
"message": "Credenciales invalidas para userName 'bg_webhook_demo'"
}
Es un JWT HS256 emitido y firmado por GoSoft, con vigencia de
3600 segundos. Lleva el usuario en sub y la empresa en
company_id. Al vencer, el banco vuelve a llamar a /bg-qr/login.
Las credenciales del webhook son por empresa: viven en
bg_qr_credentials, no en un archivo de configuración compartido.
Registro de pago
Sección 8 de la spec. El banco confirma que una orden de cobro fue pagada. Esta llamada es la que genera el asiento contable.
Cuerpo (JSON)
| Campo | Tipo | Descripción | |
|---|---|---|---|
| qrId | string | req | Identificador de la orden de cobro devuelto por el banco al generarla. |
| transactionId | string | opc | Número de transacción del banco. Queda como número de documento del comprobante. Si viene vacío se usa QR{qrId}. |
| payDate | string | opc | Fecha de pago en formato ddmmyyyy. Si no es válida se usa la fecha del servidor. |
Ejemplo de llamada
curl -X POST "https://demo.gosoft.app/bg-qr/payments" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
-d '{
"qrId": "3286941",
"transactionId": "BG-0000884213",
"payDate": "20082026"
}'
{
"result": "COD000",
"message": "Pago registrado correctamente"
}
{
"result": "COD000",
"message": "Pago ya registrado"
}
Si el QR ya estaba pagado, GoSoft responde COD000 con
«Pago ya registrado» y no genera un segundo comprobante.
El banco puede reintentar sin riesgo de duplicar el ingreso.
Todo el registro corre dentro de una transacción: un comprobante por el total, la acreditación a cuentas por cobrar de cada venta cubierta y un débito al fondo del Banco Ganadero.
Respuestas de error
{
"result": "COD001",
"message": "Token JWT invalido o expirado (Authorization)"
}
{
"result": "COD001",
"message": "Falta qrId en el body"
}
{
"result": "COD001",
"message": "qrId no encontrado en bg_qr_orders"
}
{
"result": "COD003",
"message": "Falta configuracion contable (fondo/CxC)"
}
El pago existe en el banco pero GoSoft no pudo contabilizarlo: falta configuración contable o el QR no tiene ventas asociadas. El banco debe reintentar: una vez corregida la configuración, la misma llamada registra el pago. Nada queda a medias, porque la escritura es transaccional.
Estado del QR
Espejo del estado del cobro, para la pantalla del cajero o para el cliente. Es sólo lectura: el pago se registra por el webhook, no por esta vista.
Parámetro de ruta
| Campo | Tipo | Descripción | |
|---|---|---|---|
| public_token | string | req | Token aleatorio de la orden. Nunca se expone el qrId en esta ruta. |
Ejemplo de llamada
curl "https://demo.gosoft.app/qr-pago-estado/9f3c1ab84d27e6b5c081"
{
"found": true,
"estado": "paid",
"amount": 1250.50,
"currency": "BOB",
"pay_date": "2026-08-20"
}
{
"found": false
}
Valores de estado
| Valor | Significado |
|---|---|
| pending | QR emitido, aún sin confirmación de pago del banco. |
| paid | El banco confirmó el pago y GoSoft lo contabilizó. |
| cancelled | La orden fue anulada, o el documento se cobró por otro medio. |
La misma orden tiene una página para humanos en
GET /qr-pago/{public_token}, que hace polling contra este endpoint
y se actualiza sola cuando el pago entra. Es el link que se imprime junto al QR.
Servicios del banco que consume GoSoft
Lado saliente de la integración. Se documentan para trazabilidad: la especificación oficial de estos servicios es la del banco.
Bases por ambiente
QA https://api.bg.com.bo/bgqa/ws-servicio-codigo-qr-empresas/service/v1/qrcode/
PROD https://api.bg.com.bo/bgprod/empresas/ws-servicio-codigo-qr-empresas/service/v1/qrcode/
| Servicio | Spec | Para qué lo usa GoSoft |
|---|---|---|
| POST access | §2 | Obtener el token del banco. Requiere el header X-Api-Key. |
| POST collections | §3 | Generar la orden de cobro y recibir la imagen del QR. |
| POST cancellations | §4 | Anular un QR vigente antes de emitir uno nuevo por el saldo actualizado. |
| POST transactions | §5 | Listar órdenes de cobro y pago por rango de fechas. |
| POST status | §6 | Consultar el estado de una orden puntual. |
Ejemplo: generación de la orden de cobro
POST .../qrcode/collections
Authorization: Bearer <token del banco>
{
"accountReference": "1000123456",
"amount": "1250.50",
"currency": "BOB",
"gloss": "Venta #40821",
"expirationDate": "27082026",
"singleUse": 1,
"userName": "empresa_demo",
"apiKey": "**********"
}
{
"result": "COD000",
"message": "Orden generada",
"qrId": "3286941",
"qrImage": "iVBORw0KGgoAAAANSUhEUgAA..."
}
El banco usa ddmmyyyy sin separadores, tanto en
expirationDate como en los rangos de transactions y en el
payDate que envía al confirmar el pago.
El amount viaja como cadena con dos decimales y punto
decimal: "1250.50", nunca 1250.5 ni con separador de miles.
apiKey, userName, password y
accountReference son distintos para cada empresa y viven en
bg_qr_credentials, nunca en el código ni en variables de entorno. Una
empresa puede tener además un juego de credenciales separado para ventas sin factura.
Estados y códigos
Cada orden guarda dos estados independientes: en qué punto del cobro está, y si la fila sigue vigente.
Estado del cobro order_state
| Valor | Estado | Descripción |
|---|---|---|
| 1 | Pendiente | QR emitido y vigente, esperando que el cliente pague. |
| 2 | Pagado | El banco confirmó el pago y existe comprobante de ingreso. |
| 3 | Anulado | La orden se dio de baja sin cobro. |
Vigencia de la orden status
| Valor | Estado | Descripción |
|---|---|---|
| 1 | Activo | Único estado que se muestra y se puede cobrar. |
| 0 | Anulado | Baja confirmada también en el banco. |
| 3 | Baja pendiente | Anulado en GoSoft pero aún vivo en el banco: la anulación remota falló y se reintenta automáticamente hasta cerrarla. |
Si el banco falla al anular y la orden se marcara igual como dada de baja, un cliente podría escanear un QR viejo y pagar un monto que ya no corresponde, sin rastro. Con la baja pendiente el caso queda visible y se reintenta. Ninguna consulta de QR cobrables incluye el estado 3.
Tabla de errores
Respuestas de los servicios entrantes, con su status HTTP real.
| HTTP | result | message | Causa y qué hacer |
|---|---|---|---|
| 400 | COD001 | Parametros de entrada insuficientes (userName/password) | Falta usuario o contraseña en el login. |
| 401 | COD001 | Credenciales invalidas para userName '...' | Usuario o contraseña del webhook incorrectos, o credencial inactiva. |
| 401 | COD001 | Token JWT invalido o expirado (Authorization) | Token vencido (dura 1 hora) o firmado con otro secreto. Repetir el login. |
| 400 | COD001 | Falta qrId en el body | La confirmación de pago llegó sin identificar la orden. |
| 404 | COD001 | qrId no encontrado en bg_qr_orders | La orden no fue emitida por esta empresa, o se apuntó al host equivocado. |
| 422 | COD003 | QR sin ventas asociadas | La orden quedó huérfana. Reportar a GoSoft; el banco debe reintentar luego. |
| 422 | COD003 | Falta configuracion contable (fondo/CxC) | La empresa no configuró el fondo del banco o la cuenta por cobrar. |
| 500 | COD003 | Excepcion: ... | Fallo inesperado. La transacción se revierte; el reintento es seguro. |
Reglas de negocio
Límites de la spec y comportamientos propios de GoSoft.
Límites de la orden de cobro
| Concepto | Valor |
|---|---|
| Monto máximo por QR | 69.000,00 Bs |
| Caducidad máxima | 365 días |
| Uso | singleUse = 1 (un solo pago por QR) |
| Monedas | BOB · USD |
| Timeout de conexión / lectura | 15 s / 30 s |
QR de un solo uso, siempre al día
Cada vez que se reimprime un documento, GoSoft anula el QR anterior y emite uno nuevo por el saldo actual. La razón: el documento pudo haberse cobrado parcialmente en efectivo o por transferencia, y un QR viejo seguiría cobrando un monto que ya no corresponde.
Cobranza conjunta
Un QR puede cubrir varias ventas a la vez (cobranza de cuentas por cobrar). Al confirmarse el pago se genera un solo comprobante por el total y se baja el saldo de cada venta cubierta. Si el cliente tenía además el QR de una venta individual incluida en esa cobranza, ese QR hermano se anula al momento de pagar, no antes: hasta entonces el cliente puede elegir cuál pagar.
Degradación ante fallas del banco
Si el banco no responde al generar la orden, el documento se imprime igual, sin QR. Nunca se bloquea una venta por una falla del servicio de QR.
Recomendaciones de integración
- Reintentar
/bg-qr/paymentsante cualquier respuesta que no seaCOD000: el endpoint es idempotente. - Renovar el token con
/bg-qr/logincuando llegue un401; no cachearlo más de una hora. - Enviar siempre
transactionId: es lo que permite conciliar el extracto del banco con el comprobante de GoSoft. - Apuntar al host de la empresa correcta; el
qrIdno existe fuera de su propio tenant. - Ante una discrepancia, pedir el detalle de
bg_qr_webhook_log: guarda cada llamada recibida con su cuerpo original.