API Go

GoSoft · Módulo Realty

API Go

Lectura de contratos de venta de inmuebles y de sus recibos de cobro, pensada para que SAP Business One tome de GoSoft exactamente lo que muestra la ficha del contrato: estado, titular, detalle, pagos y último plan. JSON plano, siempre por unidad de negocio.

Controladores app/Controllers/Api/Go/ Formato JSON · UTF-8 Auth Bearer token Moneda la del contrato Modo sólo lectura

Convenciones

Todos los endpoints comparten autenticación, envoltura de error, paginación y el modo de nombrar la unidad de negocio. Conviene leer esto antes que los endpoints.

URL base

El host identifica a la empresa (multi-tenant). Todo cuelga de /api/go/v1.

Producción
https://{empresa}.gosoft.app/api/go/v1/contratos
https://{empresa}.gosoft.app/api/go/v1/recibos
https://{empresa}.gosoft.app/api/go/v1/unidades
https://{empresa}.gosoft.app/api/go/v1/inmuebles

Autenticación

Cada llamada lleva un token Bearer. La empresa lo emite desde GoSoft para la persona que representa al sistema externo (Personal → Acceso GoSoft → Acceso a la API) y entrega un PDF con las credenciales. Es una cadena de 64 caracteres hexadecimales y no vence. Si se filtra, la empresa lo rota y el anterior deja de servir en el acto.

El token ve sólo sus unidades

Responde únicamente por las unidades de negocio habilitadas a esa persona en GoSoft. Pedir otra unidad devuelve 403 UNIDAD_SIN_ACCESO. Una cuenta sin unidades asignadas (la cuenta de servicio histórica del ERP) ve todas las unidades activas.

Cabecera
Authorization: Bearer 3f9c1e0b7a2d4c8e6f5a9b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e
Token por query string

Se acepta también ?token=... en la URL, para pruebas rápidas desde un navegador. No lo uses desde el ERP: queda en el historial y en los logs de acceso. La integración manda siempre la cabecera.

Envoltura de respuesta

A diferencia de la API Multi Pagos, acá el status HTTP es real: 200 es éxito y cualquier otro es error. El éxito devuelve el objeto pedido directamente, sin envoltura. El error trae un codigo estable para ramificar; el mensaje es para humanos y puede cambiar de redacción.

Éxito200
{
  "codigo": 6557,
  "unidad": { ... },
  "estado": { ... }
  // el objeto, tal cual
}
Error4xx
{
  "error": {
    "codigo": "RANGO_EXCEDIDO",
    "mensaje": "El rango no puede superar 31 días; se pidieron 45."
  }
}
Una excepción

El 401 por token ausente o inválido lo emite el filtro de autenticación compartido con la app móvil, y tiene otra forma: {"ok": false, "error": "unauthorized", "message": "..."}. Trátalo por el status HTTP, no por el cuerpo.

La unidad de negocio

Toda consulta lleva ?unidad=. El código es el mininame de la unidad seguido de su id, con guión: VALL1-7. Se aceptan además las variantes VALL17, VALL1 y 7; si el mininame no corresponde al id (VALL1-1) la unidad no existe.

Un contrato pertenece a su unidad

Pedir el contrato 6557 con unidad=TERR1-1 responde no encontrado aunque el contrato exista, porque es de LOS VALLES. Un token no puede pasear por las unidades cambiando el número a mano.

Cabeceras

CabeceraValorNota
AuthorizationBearer <token>Obligatoria en todos los endpoints.
Acceptapplication/jsonRecomendada. Todo es GET, no hay cuerpo que enviar.

Paginación (endpoints 02, 04 y 06)

ParámetroDefaultMáximoNota
pagina1—Se recorre hasta paginacion.paginas.
por_pagina50200Un valor mayor se recorta a 200 sin error.

Flujo de integración

No hay handshake: con el token y el código de unidad se consulta directo.

PASO 1

Recibir el token

La empresa genera el token en GoSoft y entrega el PDF de credenciales.

PASO 2

Conocer las unidades

Vienen en el PDF de credenciales, y GET /unidades los lista con su inventario.

PASO 3

Consultar

Por código cuando se conoce el contrato o recibo; por período para sincronizar el mes.

PASO 4

Paginar

Recorrer pagina hasta paginas; el orden es estable por fecha e id.


ENDPOINT 01

Un contrato

GET /api/go/v1/contratos/{codigo}?unidad=VALL1-7

Todo lo que muestra la ficha del contrato: estado actual, titular principal, detalle del inmueble, recibos de cobro y último plan de pagos con su cronograma.

Parámetros

CampoDóndeDescripción
codigorutareqCódigo del contrato. Es el mismo número que ve el operador en la ficha.
unidadqueryreqUnidad de negocio a la que pertenece el contrato.

Ejemplo de llamada

cURL
curl "https://demo.gosoft.app/api/go/v1/contratos/6557?unidad=VALL1-7" \
  -H "Authorization: Bearer 3f9c1e0b7a2d4c8e6f5a9b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e"
Respuesta200
{
  "codigo": 6557,
  "unidad": {
    "codigo": "VALL1-7",
    "nombre": "LOS VALLES"
  },
  "estado": {
    "nombre": "Vigente",
    "moneda": "USD",
    "fecha_contrato": "2024-01-30",
    "registrado_en": "2026-02-23 16:19:14"
  },
  "titular": {
    "id": 1661,
    "nombre": "MARIO ANDRES CASTELLANOS REYES",
    "documento": "0501199001234",
    "celular": "99001122",
    "email": "mario.castellanos@ejemplo.hn",
    "direccion": ""
  },
  "detalle": {
    "moneda": "USD",
    "items": [
      {
        "codigo": "BAL27LV",
        "descripcion": "",
        "tipo": "Terreno urbano",
        "ubicacion": "LOS VALLES",
        "manzano": "A",
        "numero": "27",
        "uv": "A27",
        "piso": "0",
        "area_m2": 180,
        "area_varas": 258.17,
        "precio_lista": 46470.6,
        "descuento": 0,
        "precio": 46470.6
      }
    ],
    "precio_total": 46470.6,
    "descuento_total": 0,
    "monto_final": 46470.6
  },
  "pagos": {
    "total": 7218.94,
    "cantidad": 12,
    "anulados": 0,
    "items": [
      {
        "recibo": 6692,
        "numero": "0000",
        "referencia": "586201964",
        "fecha": "2024-01-30",
        "monto": 4683.03,
        "moneda": "USD",
        "monto_local": 116000.06,
        "tc": 24.7703,
        "documento": "CI",
        "glosa": "Contrato 6557 Periodos:  0, Parcial 1",
        "cuenta": {
          "codigo": "01.01.01.002.144",
          "nombre": "BAC - 730398681 HNL - CHEQUES"
        },
        "contrato_nro": 6557,
        "persona": "MARIO ANDRES CASTELLANOS REYES",
        "unidad": {
          "codigo": "VALL1-7",
          "nombre": "LOS VALLES"
        },
        "estado": "Vigente"
      }
      // ... un item por recibo, vigente o anulado
    ]
  },
  "plan": {
    "id": 2200,
    "numero": 1,
    "metodo": "Clásico",
    "estado": "Vigente",
    "moneda": "USD",
    "capital": 41823.54,
    "saldo_inicial": 46470.6,
    "descuento": 0,
    "cuotas": 1,
    "frecuencia": 1,
    "interes_anual": 0,
    "tipo_interes": "Anual",
    "fecha_inicio": "2027-03-02",
    "creado_en": "2026-02-23",
    "cronograma": [
      {
        "periodo": 0,
        "vencimiento": "2026-03-01",
        "cuota": 4647.06,
        "interes": 0,
        "amortizacion": 4647.06,
        "saldo": 41823.54,
        "pagado": 4647.06,
        "descuento": 0,
        "sancion": 0,
        "por_pagar": 0
      },
      {
        "periodo": 1,
        "vencimiento": "2027-03-02",
        "cuota": 41823.54,
        "interes": 0,
        "amortizacion": 41823.54,
        "saldo": 0,
        "pagado": 2571.88,
        "descuento": 0,
        "sancion": 0,
        "por_pagar": 39251.66
      }
    ]
  }
}

Campos de estado

CampoDescripción
nombreEstado actual: Reservado, Vigente, Finalizado, Revertido, Pendiente, Retenido, Devuelto, Pagado, Anulado, Eliminado.
monedaMoneda del contrato. Todos los importes de detalle, pagos.monto y plan están en esta moneda.
fecha_contratoFecha del contrato. Es la que usa el filtro por período del endpoint 02.
registrado_enFecha y hora en que se cargó en el sistema.

Campos de detalle

CampoDescripción
items[]Un item por inmueble vendido. Normalmente uno: un contrato es un terreno.
items[].codigoCódigo del inmueble en el catálogo.
items[].tipo · ubicacionTipo de inmueble y urbanización o edificio que lo contiene.
items[].manzano · numero · uv · pisoUbicación del lote.
items[].area_m2 · area_varasSuperficie en metros cuadrados y en varas cuadradas.
items[].precio_listaPrecio bruto: superficie por precio unitario, según el detalle de construcción.
items[].descuentoDescuento negociado al firmar. Baja el precio del contrato.
items[].precioprecio_lista − descuento.
precio_total · descuento_total · monto_finalSumas de los items. monto_final es el precio del contrato.
items_sin_fichaSólo aparece si es mayor a cero. Líneas del contrato cuyo inmueble ya no existe en el catálogo. Ver reglas de negocio.

Campos de pagos

CampoDescripción
totalSuma de los recibos vigentes, en la moneda del contrato. Los anulados no suman.
cantidadRecibos vigentes.
anuladosRecibos anulados. items trae cantidad + anulados elementos.
items[]Un recibo por elemento, con la misma forma que devuelve el endpoint 03. Ver allí el detalle de cada campo.

Campos de plan

CampoDescripción
id · numeroIdentificador del plan y su número de orden dentro del contrato. Se devuelve siempre el último plan activo.
metodoForma de cálculo: Clásico, Manual_Pure, Personalizado, ...
estadoVigente o Finalizado.
capitalMonto financiado por el plan.
saldo_inicialSaldo del contrato al arrancar el plan.
descuentoDescuento aplicado en la reprogramación. Baja el saldo, no el precio.
cuotas · frecuenciaCantidad de cuotas y periodicidad en meses.
interes_anual · tipo_interesTasa y tipo.
cronograma[]Una fila por cuota. periodo 0 es la cuota inicial o enganche; puede haber más de una fila con periodo 0.
cronograma[].cuota · interes · amortizacionImporte de la cuota y su apertura en interés y capital, según el plan.
cronograma[].saldoSaldo del plan después de esa cuota.
cronograma[].pagado · descuento · sancionLo cobrado contra la cuota, el descuento otorgado al pagar y la mora cobrada.
cronograma[].por_pagarcuota − pagado − descuento, nunca negativo.
Contrato de otra unidad, o inexistente404
{
  "error": {
    "codigo": "CONTRATO_NO_ENCONTRADO",
    "mensaje": "No existe el contrato 6557 en la unidad TERR1-1."
  }
}
Sin unidad400
{
  "error": {
    "codigo": "UNIDAD_REQUERIDA",
    "mensaje": "Falta el parámetro unidad (por ejemplo VALL1-7)."
  }
}
Ojo con el estado

El estado viaja sólo como texto. Los nombres de los estados son configurables por unidad en GoSoft (una empresa puede llamar Apartado a la Reserva), así que conviene mapearlos por tabla y avisar si aparece uno nuevo, en vez de asumir la lista fija.

ENDPOINT 02

Contratos por período

GET /api/go/v1/contratos?unidad=VALL1-7&desde=2026-08-01&hasta=2026-08-31

Contratos de una unidad cuya fecha de contrato cae en el rango. Cada elemento es el objeto completo del endpoint 01.

Parámetros (query string)

CampoTipoDescripción
unidadstringreqUnidad de negocio.
desdeYYYY-MM-DDreqInicio del rango, inclusive.
hastaYYYY-MM-DDreqFin del rango, inclusive. Máximo 31 días contados desde desde.
paginaintopcDefault 1.
por_paginaintopcDefault 50, máximo 200.

Ejemplo de llamada

cURL · agosto, de a 50
curl "https://demo.gosoft.app/api/go/v1/contratos?unidad=VALL1-7&desde=2026-08-01&hasta=2026-08-31&pagina=1" \
  -H "Authorization: Bearer 3f9c1e0b7a2d4c8e6f5a9b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e"
Respuesta200
{
  "unidad": {
    "codigo": "VALL1-7",
    "nombre": "LOS VALLES"
  },
  "desde": "2026-08-01",
  "hasta": "2026-08-31",
  "paginacion": {
    "pagina": 1,
    "por_pagina": 50,
    "total": 49,
    "paginas": 1
  },
  "contratos": [
    {
      "codigo": 10338,
      "unidad": { "codigo": "VALL1-7", "nombre": "LOS VALLES" },
      "estado": { "nombre": "Revertido", "moneda": "USD", "fecha_contrato": "2026-08-01", "registrado_en": "2026-08-01 10:12:44" },
      "titular": { ... },
      "detalle": { ... },
      "pagos": { ... },
      "plan": { ... }
    }
    // ... ordenados por fecha_contrato y código, ascendente
  ]
}
Más de un mes400
{
  "error": {
    "codigo": "RANGO_EXCEDIDO",
    "mensaje": "El rango no puede superar 31 días; se pidieron 45."
  }
}
Sin contratos en el rango200
{
  "unidad": { "codigo": "VALL1-7", "nombre": "LOS VALLES" },
  "desde": "2026-12-01",
  "hasta": "2026-12-31",
  "paginacion": { "pagina": 1, "por_pagina": 50, "total": 0, "paginas": 0 },
  "contratos": []
}
Todos los estados

El período devuelve los contratos en cualquier estado, incluidos revertidos y anulados. Si el ERP sólo quiere los vigentes, filtra por estado.nombre del lado del integrador: así una reversión posterior también se ve al re-sincronizar el mes.

ENDPOINT 03

Un recibo

GET /api/go/v1/recibos/{recibo}?unidad=VALL1-7

Un recibo de cobro suelto, con la misma forma que tiene adentro de pagos.items[] del contrato. Un mapeo sirve para los dos lugares.

Parámetros

CampoDóndeDescripción
reciborutareqNúmero de recibo. Es el recibo de pagos.items[].
unidadqueryreqUnidad del terreno del contrato al que pertenece el recibo. Ver reglas de negocio.

Ejemplo de llamada

cURL
curl "https://demo.gosoft.app/api/go/v1/recibos/10787?unidad=TERR1-1" \
  -H "Authorization: Bearer 3f9c1e0b7a2d4c8e6f5a9b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e"
Recibo vigente200
{
  "recibo": 6700,
  "numero": "0000",
  "referencia": "412400753",
  "fecha": "2024-04-08",
  "monto": 282.4,
  "moneda": "USD",
  "monto_local": 7000.02,
  "tc": 24.7876,
  "documento": "CI",
  "glosa": "Contrato 6557 Periodos:  Parcial 1",
  "cuenta": {
    "codigo": "01.01.01.002.144",
    "nombre": "BAC - 730398681 HNL - CHEQUES"
  },
  "contrato_nro": 6557,
  "persona": "MARIO ANDRES CASTELLANOS REYES",
  "unidad": {
    "codigo": "VALL1-7",
    "nombre": "LOS VALLES"
  },
  "estado": "Vigente"
}
Recibo anulado200
{
  "recibo": 10787,
  "numero": "0000",
  "referencia": "FT26231ZRY5B",
  "fecha": "2026-08-19",
  "monto": 5075,
  "moneda": "USD",
  "monto_local": 133722.7,
  "tc": 26.3493,
  "documento": "CI",
  "glosa": "Contrato 4162 · Periodos: Parcial 1",
  "cuenta": {
    "codigo": "01.01.01.002.179",
    "nombre": "FICOHSA - 200011495809 USD - CHE"
  },
  "contrato_nro": 4162,
  "persona": "CLAUDIA PATRICIA MEJIA ORDOÑEZ",
  "unidad": {
    "codigo": "TERR1-1",
    "nombre": "TERRALTA"
  },
  "estado": "Anulado",
  "anulacion": {
    "fecha": "2026-08-20 18:13:11",
    "por": "ROSA MARIA FLORES PADILLA",
    "motivo": "ANULACION POR TASA DE CAMBIO INCORRECTA"
  }
}

Campos del recibo

CampoDescripción
reciboNúmero del comprobante de ingreso en GoSoft. Es el que aparece en los reportes contables.
numero · referenciaNúmero y referencia del documento de pago (cheque, transferencia, factura del banco).
fechaFecha del cobro. Es la que usa el filtro por período del endpoint 04.
monto · monedaImporte en la moneda del contrato.
monto_local · tcImporte en moneda local del asiento y tipo de cambio aplicado.
documentoTipo de documento: CI comprobante de ingreso, Recibo, Transaccion, ...
glosaConcepto del comprobante. Nombra el contrato y las cuotas cubiertas.
cuentaCuenta contable donde entró el dinero, con su código del plan de cuentas. Es el lado debe del asiento: caja o banco. null si el recibo no tiene asiento de débito.
cuentas[]Sólo aparece si hay más de una. Cobro partido entre varias cuentas, cada una con su monto y monto_local. cuenta queda con la mayor.
contrato_nroCódigo del contrato al que pertenece. Es el codigo del endpoint 01.
personaQuién pagó. Casi siempre es el titular, pero puede ser un tercero.
unidadUnidad de negocio del terreno del contrato.
estadoVigente o Anulado. No hay otros.
anulacionSólo en anulados. Fecha y hora, usuario que anuló y motivo. Alguno puede venir null en recibos muy viejos.
Recibo de otra unidad, o inexistente404
{
  "error": {
    "codigo": "RECIBO_NO_ENCONTRADO",
    "mensaje": "No existe el recibo 5989 en la unidad MARS2-6."
  }
}
Sin token401
{
  "ok": false,
  "error": "unauthorized",
  "message": "Missing token"
}
ENDPOINT 04

Recibos por período

GET /api/go/v1/recibos?unidad=VALL1-7&desde=2026-06-01&hasta=2026-06-30

Recibos de una unidad cuya fecha de cobro cae en el rango. Es la consulta para conciliar el mes: trae vigentes y anulados, salvo que se filtre.

Parámetros (query string)

CampoTipoDescripción
unidadstringreqUnidad de negocio del terreno.
desdeYYYY-MM-DDreqInicio del rango, inclusive.
hastaYYYY-MM-DDreqFin del rango, inclusive. Máximo 31 días.
estadostringopcvigente o anulado. Sin el parámetro salen los dos.
paginaintopcDefault 1.
por_paginaintopcDefault 50, máximo 200.

Ejemplo de llamada

cURL · sólo vigentes de junio
curl "https://demo.gosoft.app/api/go/v1/recibos?unidad=VALL1-7&desde=2026-06-01&hasta=2026-06-30&estado=vigente&por_pagina=200" \
  -H "Authorization: Bearer 3f9c1e0b7a2d4c8e6f5a9b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e"
Respuesta200
{
  "unidad": {
    "codigo": "VALL1-7",
    "nombre": "LOS VALLES"
  },
  "desde": "2026-06-01",
  "hasta": "2026-06-30",
  "estado": "Vigente",
  "paginacion": {
    "pagina": 1,
    "por_pagina": 200,
    "total": 91,
    "paginas": 1
  },
  "recibos": [
    {
      "recibo": 9034,
      "numero": "0000",
      "referencia": "412516204",
      "fecha": "2026-06-01",
      "monto": 165.42,
      "moneda": "USD",
      "monto_local": 4300.05,
      "tc": 25.9945,
      "documento": "CI",
      "glosa": "Contrato 7912 · Periodos: Parcial 4",
      "cuenta": { "codigo": "01.01.01.002.144", "nombre": "BAC - 730398681 HNL - CHEQUES" },
      "contrato_nro": 7912,
      "persona": "ANA LUCIA MARTINEZ PONCE",
      "unidad": { "codigo": "VALL1-7", "nombre": "LOS VALLES" },
      "estado": "Vigente"
    }
    // ... ordenados por fecha y número de recibo, ascendente
  ]
}
estado fuera de la lista400
{
  "error": {
    "codigo": "ESTADO_INVALIDO",
    "mensaje": "estado debe ser vigente o anulado."
  }
}
Fechas al revés400
{
  "error": {
    "codigo": "RANGO_INVERTIDO",
    "mensaje": "La fecha desde no puede ser posterior a hasta."
  }
}
El campo estado de la cabecera

Repite el filtro aplicado: Vigente, Anulado o Todos. Sirve para que una respuesta guardada diga por sí sola qué se pidió.

ENDPOINT 05

Inventario por unidad

GET /api/go/v1/unidades?unidad=TERRA-6

Cuántos inmuebles tiene la unidad y en qué estado están: los mismos números que muestra el panel en la vista Simple. Sin ?unidad= devuelve todas las unidades del token, cada una con su bloque inventario.

Parámetros (query string)

CampoTipoDescripción
unidadstringopcUna unidad. Sin el parámetro, todas las del token.

Ejemplo de llamada

cURL
curl "https://demo.gosoft.app/api/go/v1/unidades?unidad=TERRA-6" \
  -H "Authorization: Bearer 3f9c1e0b7a2d4c8e6f5a9b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e"
Una unidad200
{
  "unidad": { "codigo": "TERRA-6", "nombre": "TERRANOVA" },
  "inventario": {
    "total": 270,
    "libres": 8,
    "reservados": 1,
    "vigentes": 235,
    "finalizados": 26,
    "no_disponibles": 0
  },
  "actualizado_en": "2026-10-22 12:00:00"
}
Todas (sin ?unidad=)200
{
  "unidades": [
    {
      "unidad": { "codigo": "CANAA-1", "nombre": "CANAAN" },
      "inventario": { "total": 279, "libres": 7, ... }
    }
    // ... una por unidad del token
  ],
  "actualizado_en": "2026-10-22 12:00:00"
}

Campos de inventario

CampoQué cuenta
totalInmuebles vendibles de la unidad. Siempre es la suma de los cinco de abajo.
libresSin contrato activo y a la venta.
reservadosCon una reserva activa.
vigentesCon un contrato vigente.
finalizadosCon un contrato finalizado.
no_disponiblesSin contrato, pero marcados como “no vender” en GoSoft. El panel los muestra dentro de Libres.
ENDPOINT 06

Catálogo de inmuebles

GET /api/go/v1/inmuebles?unidad=TERRA-6&estado=libre

Los inmuebles de una unidad con sus datos de venta y su estado. No trae datos de clientes ni de contratos.

Parámetros (query string)

CampoTipoDescripción
unidadstringreqUnidad de negocio.
estadostringopclibre, reservado, vigente, finalizado o no_disponible. Sin el parámetro salen todos.
paginaintopcDefault 1.
por_paginaintopcDefault 50, máximo 200.

Ejemplo de llamada

cURL · sólo los libres
curl "https://demo.gosoft.app/api/go/v1/inmuebles?unidad=TERRA-6&estado=libre&por_pagina=200" \
  -H "Authorization: Bearer 3f9c1e0b7a2d4c8e6f5a9b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e"
Respuesta200
{
  "unidad": { "codigo": "TERRA-6", "nombre": "TERRANOVA" },
  "estado": "libre",
  "paginacion": { "pagina": 1, "por_pagina": 200, "total": 8, "paginas": 1 },
  "items": [
    {
      "id": 2933,
      "codigo": "TN-A1",
      "tipo": "Terreno urbano",
      "proyecto": "TERRANOVA",
      "plano": null,
      "uv": null,
      "manzano": "A",
      "numero": "1",
      "piso": null,
      "complemento": null,
      "area_m2": 179.19,
      "area_varas": 0,
      "precio_m2": 277700,
      "precio_lista": 49761063,
      "estado": "libre"
    }
    // ... ordenados por proyecto, manzano y número
  ]
}
CampoQué es
idId del inmueble en GoSoft. Es estable: sirve de llave.
planoEl sub-plano (piso, cluster) cuando el proyecto los tiene; null si el inmueble cuelga directo del proyecto.
piso, complementoEn departamentos: piso y número de departamento.
precio_listaÁrea por precio del m², la misma cuenta del plano público. Es el precio de lista, no el negociado.

Webhook de estados

GoSoft avisa al sistema externo cuando un inmueble de sus unidades cambia de estado (se reserva, se vende, se finaliza, se revierte o se anula). Se configura en GoSoft, en la misma persona del token: Personal → Acceso GoSoft → Acceso a la API → Webhook. La URL y el secreto de firma salen en el PDF de credenciales.

QuéCómo
EnvíoPOST JSON a la URL configurada (https). Llega a los pocos minutos del cambio.
X-GoSoft-Eventoinmueble.estado, o ping cuando se prueba desde GoSoft.
X-GoSoft-EntregaId único de la entrega. Si llega dos veces, descartar la repetida.
X-GoSoft-Firmat=<unix>,v1=<hex>: HMAC-SHA256 de "<t>.<cuerpo>" con el secreto. Recalcular y comparar con v1 antes de usar el aviso.
RespuestaCualquier 2xx confirma. Si no, se reintenta a los 1, 5, 15, 60 y 360 minutos.
Cuerpo · inmueble.estado
{
  "evento": "inmueble.estado",
  "entrega": 812,
  "fecha": "2026-10-22T16:44:30-04:00",
  "empresa": "zabdiel.gosoft.app",
  "unidad": { "codigo": "TERRA-6", "nombre": "TERRANOVA" },
  "inmueble": {
    "id": 2933, "codigo": "TN-A1", "proyecto": "TERRANOVA",
    "manzano": "A", "numero": "1", "piso": null, "complemento": null
  },
  "estado_anterior": "libre",
  "estado": "reservado",
  "inventario": { "total": 270, "libres": 7, "reservados": 2, ... }
}
Verificar la firma (PHP)
$cuerpo = file_get_contents('php://input');
preg_match('/t=(\d+),v1=([a-f0-9]+)/',
  $_SERVER['HTTP_X_GOSOFT_FIRMA'], $m);
$ok = hash_equals(
  hash_hmac('sha256', $m[1] . '.' . $cuerpo, SECRETO),
  $m[2]
) && abs(time() - (int) $m[1]) < 600;
El aviso no reemplaza la consulta

inventario trae los totales de la unidad en ese momento. Ante cualquier duda (un aviso perdido, el sistema estuvo caído), GET /unidades y GET /inmuebles dan el estado vigente.

Inicio de sesión único

El personal entra a su panel con su usuario de GoSoft, sin otra contraseña. Hay dos formas; la empresa elige una en la persona del token y los datos salen en el PDF de credenciales. Una persona deshabilitada en GoSoft deja de poder entrar.

Opción A · OpenID Connect

DatoValor
Descubrimientohttps://{empresa}.gosoft.app/.well-known/openid-configuration
Flujoauthorization code con PKCE (S256); client_id y client_secret del PDF.
Alcancesopenid profile email
id_tokenJWT RS256; llave pública en /oauth/jwks. Devuelve el nonce si se envió.
userinfoGET /oauth/userinfo con el access token. 401 si la persona se deshabilitó.

Opción B · Enlace firmado

En GoSoft aparece Ir al panel web en el menú del usuario. Abre <url-del-panel>?token=<JWT>: RS256, firmado con la misma llave de /oauth/jwks, vence a los 60 segundos y su jti debe aceptarse una sola vez. aud es el origen del panel.

Datos de la persona (las dos opciones)

Claims
{
  "sub": "286",                     // id estable de la persona en la empresa
  "name": "ALEXANDER ALVAREZ",
  "preferred_username": "alexanderav286",
  "email": "persona@empresa.com",
  "rol": "administrador",           // administrador (nivel 4) o editor
  "nivel": 4,
  "activo": true,
  "empresa": "CONSTRUCTORA ZBL"
}

Ambiente de pruebas

La empresa demo https://inmobiliaria.gosoft.app, con datos de prueba. Cada integración tiene ahí sus propios accesos, que salen en el PDF de credenciales: token de API, usuario de prueba y, con OpenID Connect, su propio client_id. Los avisos del webhook de la demo llegan a la misma URL y con el mismo secreto.

Misma API, otra empresa
curl "https://inmobiliaria.gosoft.app/api/go/v1/unidades" \
  -H "Authorization: Bearer <token de pruebas>"

Tabla de errores

El status HTTP es real. El codigo es estable; el mensaje puede cambiar de redacción.

HTTPcodigoCausa y qué hacer
401unauthorizedToken ausente, con formato inválido, o de una cuenta deshabilitada. Otra envoltura: ver Convenciones. Pedir a GoSoft que verifique la cuenta de servicio.
400UNIDAD_REQUERIDAFalta ?unidad=.
404UNIDAD_NO_ENCONTRADAEl código no corresponde a ninguna unidad activa, o el mininame no coincide con el id.
403UNIDAD_SIN_ACCESOLa unidad existe pero no está habilitada para la persona del token. Pedir a la empresa que la habilite.
400CODIGO_INVALIDOEl código de contrato no es un entero positivo.
404CONTRATO_NO_ENCONTRADOEl contrato no existe, o pertenece a otra unidad.
400RECIBO_INVALIDOEl número de recibo no es un entero positivo.
404RECIBO_NO_ENCONTRADOEl recibo no existe, o el terreno de su contrato es de otra unidad.
400RANGO_REQUERIDOFalta desde o hasta.
400FECHA_INVALIDAUna fecha no tiene formato YYYY-MM-DD o no existe en el calendario.
400RANGO_INVERTIDOdesde es posterior a hasta.
400RANGO_EXCEDIDOMás de 31 días. Partir la consulta por mes.
400ESTADO_INVALIDOestado fuera de la lista del endpoint: vigente o anulado en recibos; libre, reservado, vigente, finalizado o no_disponible en inmuebles.
500—Fallo inesperado del servidor. Es sólo lectura: reintentar tal cual es seguro.

Reglas de negocio

Decisiones del lado de GoSoft que explican por qué los números son los que son.

El precio del contrato

El precio no se toma del importe guardado en la cabecera del contrato, que en algunos registros históricos está duplicado. Se recalcula igual que la ficha: superficie por precio unitario del detalle de construcción, menos el descuento negociado al firmar. Es la misma fórmula de las auditorías y de los reportes de saldos, así que monto_final coincide con lo que ve el operador en pantalla.

La unidad de un recibo es la de su terreno

Un cobro puede haberse registrado estando parado en otra unidad de negocio, y la unidad que quedó grabada en el comprobante es la equivocada. Por eso unidad del recibo, y el filtro ?unidad= de los endpoints 03 y 04, salen del lote que se vendió y no del comprobante. Es la regla que hace que un recibo aparezca siempre donde está su contrato.

Los anulados se listan, no suman

pagos.total y pagos.cantidad cuentan sólo recibos vigentes; los anulados se listan aparte en anulados y vienen en items[] con su bloque anulacion. Un cobro revertido es información, pero no es plata que entró.

La cuenta contable del recibo

cuenta es el lado debe del asiento del comprobante: la caja o el banco donde entró el dinero, con su código del plan de cuentas. Se conserva también en los recibos anulados, porque la cuenta por la que pasó la plata sigue siendo un dato aunque el cobro se haya revertido. Un recibo tiene una sola cuenta; si alguna vez hay varias, aparecen todas en cuentas[] con su importe.

Claves que aparecen sólo cuando hace falta

ClaveCuándo apareceQué significa
detalle.items_sin_fichaSi es mayor a ceroLíneas del contrato cuyo inmueble ya no existe en el catálogo. La ficha web también las omite, así que monto_final coincide con la pantalla, pero está incompleto: hay que revisar el contrato.
pagos.items[].cuentasSi hay más de una cuentaCobro partido entre caja y banco.
pagos.items[].anulacionSi estado es AnuladoFecha, usuario y motivo de la anulación.

La respuesta normal no trae ninguna de las tres. El mapeo del ERP debe tolerar su ausencia y su presencia.

El inventario

Un inmueble es cada lote o departamento vendible de los proyectos de la unidad (no cuentan los pisos ni el proyecto mismo). Su estado sale del contrato activo que lo ocupa: reserva, vigente o finalizado; sin ninguno está libre, salvo que esté marcado como “no vender”. Cada inmueble cae en un solo estado, así que las cifras siempre suman el total. Los números se calculan en el momento de la consulta.

Rango de un mes

Los endpoints por período aceptan hasta 31 días, contados en días y no en meses de calendario: del 1 al 31 de agosto entra, del 1 de junio al 15 de julio no. El tope existe para que una consulta no barra el histórico entero; para cargar años anteriores se recorre mes a mes.

Recomendaciones de integración

  • Manda el token en la cabecera Authorization, nunca en la URL.
  • Guarda recibo y contrato_nro como llaves: son los números que aparecen en los reportes contables del cliente.
  • Para conciliar un mes, pide los recibos por período sin filtrar estado: así las anulaciones posteriores también se reflejan al re-sincronizar.
  • Mapea estado.nombre del contrato por tabla y avisa si llega un valor nuevo.
  • Trata el 401 por status HTTP; su cuerpo tiene otra forma.
  • Ante un 500 o un timeout, reintenta: la API no escribe nada.