Ir al contenido
FINORA Academy
SistemaFINORA Core

FINORA Core · Guía

Integrar los sistemas satélite del banco con FINORA Core como sistema de registro

ImplementadoImplementadoIntermedio35 min

Un banco tiene muchos sistemas alrededor del core: la taquilla de la agencia, el ERP de la contabilidad corporativa, la banca por internet y la móvil, el conciliador, el sistema de nómina de un cliente empresa. Esta guía explica cómo conectarlos con FINORA Core de modo que el core sea el sistema de registro: el único lugar donde vive el saldo de una cuenta, donde queda cada transacción y donde se genera cada asiento contable. Al terminar sabrás qué puerta usa cada sistema, qué credencial y qué alcances pedir, qué rutas llamar y cómo enterarte de lo que pasa en el core sin consultarlo a cada rato.

1. Reparte bien el trabajo: qué es del core y qué es del satélite

Sección titulada «1. Reparte bien el trabajo: qué es del core y qué es del satélite»

La regla es una sola: el satélite nunca guarda un saldo propio ni contabiliza por su cuenta. Captura la operación, se la pide al core y muestra lo que el core responde.

Lo hace FINORA CoreLo hace el sistema satélite
Lleva el saldo de cada cuenta: contable, bloqueado y disponibleMuestra el saldo que le devuelve el core en ese momento
Valida fondos, estado de la cuenta, retenciones y bloqueosPide la operación y respeta el rechazo
Registra la transacción con su referencia contable estableGuarda la referencia del core junto a su propio comprobante
Genera el asiento por el concepto contable del producto y del canalNunca arma un asiento a mano para un movimiento de cliente
Cierra el día y produce el balance de comprobaciónLee el mayor para conciliar o reportar
Avisa por webhook o por el flujo de eventosReacciona al aviso en lugar de consultar en bucle
flowchart LR
  T["Taquilla<br/>(FINORA Sucursal u otra)"] -->|"cuentas, cheques, pagos"| K
  E["ERP del banco"] -->|"apply-concept, consultas del mayor"| K
  C["Canales<br/>(internet, móvil)"] -->|"/v1 por el gateway"| G["Gateway de API"]
  G --> K["FINORA Core<br/>sistema de registro"]
  K -->|"webhooks firmados<br/>y eventos"| E
  K -->|"webhooks firmados<br/>y eventos"| C

2. Elige la puerta: el gateway o la API del core

Sección titulada «2. Elige la puerta: el gateway o la API del core»

FINORA Core tiene dos puertas para sistemas externos. No son excluyentes: cada sistema usa la que le corresponde.

Gateway de API (/v1)API del core (/api/v1)
Para quiénSistemas fuera de la red del core: canales, aliados, fintechsSistemas internos del banco: taquilla, ERP, conciliador
IdentidadCredencial del gateway por sistema (client_id y client_secret, por token OAuth o apiKey)Credencial de API del core por sistema (OAuth Bearer o cabecera X-Api-Key)
AlcancesPor dominio: clients:*, deposits:*, loans:*, gl:*, webhooks:*, events:read, config:*, license:read, fx:*Finos: account:read, payment:write, credit:payment, gl:read, accounting:write…
Qué agregaInstitución y entorno por subdominio o X-Finora-Tenant, límites por cliente, circuit breaker, errores uniformesAcceso a rutas que el gateway no publica: cheques, apply-concept, chequeras
Dónde se describeEl gateway de API del coreEsta guía y la API contable

Una regla práctica: si el sistema sale a internet o lo opera un tercero, va por el gateway. Si vive dentro del banco y necesita cheques o contabilizar por concepto, usa la API del core con su propia credencial.

3. Una credencial por sistema, con los alcances justos

Sección titulada «3. Una credencial por sistema, con los alcances justos»

Cada satélite recibe su propia credencial. Nunca compartas una entre la taquilla y el ERP: si una se filtra, se revoca sin apagar a la otra, y la auditoría del core registra qué sistema hizo cada operación (apikey:<id> en el campo de creación).

SistemaAlcances en la API del coreAlcances en el gateway
Taquillaaccount:read, payment:writeNo aplica: los cheques no se publican en /v1
ERP del bancogl:read, accounting:write (si contabiliza por concepto)gl:read
Banca por internet o móvilaccount:read, payment:write, credit:read, credit:paymentclients:read, deposits:read, deposits:write, loans:read, loans:write
Receptor de avisoswebhook:read, events:readwebhooks:read, events:read

Algunos alcances del core son críticos (gl:write, credit:payment, credit:approve, credit:disburse, account:status, account:authorize, events:read, config:write, license:write): una credencial con acceso general no los recibe si no se le dan de forma expresa. Pide solo los que tu sistema usa y revísalos cada mes.

4. Cuentas: encuentra la cuenta y lee su saldo

Sección titulada «4. Cuentas: encuentra la cuenta y lee su saldo»

La taquilla conoce la cuenta por su número de 20 dígitos; el resto de la API la pide por su UUID. El primer paso siempre es resolver una cosa en la otra.

Método y ruta en el coreAlcanceQué hace
GET /api/v1/ext/accounts/by-code/{accountCode}account:readResuelve el número de cuenta: UUID, titular, producto, moneda, estado
GET /api/v1/ext/accounts/{accountId}account:readDatos de la cuenta, estado y saldos
GET /api/v1/ext/accounts/{accountId}/balanceaccount:readSaldo contable, bloqueado y disponible, con los saldos por fase
GET /api/v1/ext/accounts/{accountId}/transactionsaccount:readMovimientos del más reciente al más antiguo, por cursor (size 1-100, from, to)
GET /api/v1/ext/accounts?customerId=…account:readTodas las cuentas de un cliente
POST /api/v1/ext/accountsaccount:writeAbre una cuenta a un cliente existente, con Idempotency-Key
GET, POST /api/v1/ext/accounts/{accountId}/blocksaccount:read, account:statusBloqueos, con aprobación a cuatro ojos (account:authorize)
GET /api/v1/ext/accounts/by-code/00010001010000000002
X-Api-Key: <credencial de la taquilla>
{
"accountId": "3d0c4f0e-9c7f-4b8e-8c1a-0a5b5f1d2e11",
"accountCode": "00010001010000000002",
"customerId": "b4c6c1d8-bedd-4d05-ae70-a3152d4e1417",
"holderName": "Cliente Uno",
"productCode": "PRD-CC-VES",
"currency": "VES",
"statusCode": "CUENTA ACTIVA",
"closed": false
}

Cada movimiento trae ledgerRef, la referencia contable estable, y voucher, el comprobante, que vale null hasta que el core lo contabiliza. Guarda el ledgerRef en tu sistema: es lo que une tu comprobante con el asiento del core.

5. Pagos: depósitos, retiros y transferencias

Sección titulada «5. Pagos: depósitos, retiros y transferencias»

El dinero entra y sale de una cuenta por tres rutas. Las tres exigen la cabecera Idempotency-Key y el alcance payment:write, y el core genera el asiento con el concepto contable del producto.

Método y ruta en el coreEn el gatewayQué hace
POST /api/v1/payments/depositPOST /v1/deposits/{depositId}/deposit-transactionsAcredita desde un origen externo (efectivo en taquilla, transferencia entrante)
POST /api/v1/payments/withdrawalPOST /v1/deposits/{depositId}/withdrawal-transactionsDebita para entregar fuera del banco; valida fondos antes
POST /api/v1/payments/transferPOST /v1/deposits/{depositId}/transfer-transactionsTransfiere entre dos cuentas del mismo banco
POST /api/v1/payments/deposit
X-Api-Key: <credencial de la taquilla>
Idempotency-Key: 6f1c2b8e-0d4a-4c1e-9a77-2f0b9d3e5a10
Content-Type: application/json
{
"destinationAccountId": "3d0c4f0e-9c7f-4b8e-8c1a-0a5b5f1d2e11",
"amount": "1000.00",
"currency": "VES",
"externalReference": "CAJA-20261024-0042",
"description": "Depósito en efectivo por taquilla",
"channel": "AGENCIA",
"channelCode": "CAJA"
}

La primera vez responde 201; si repites la petición con la misma clave, 200 con la misma respuesta y sin mover el saldo otra vez. channelCode es opcional: si el banco definió ese canal de transacción, la contrapartida del asiento usa la cuenta del canal (por ejemplo, la caja de la agencia). Ver Configurar un canal de transacción.

6. Cheques propios en taquilla: validar y pagar

Sección titulada «6. Cheques propios en taquilla: validar y pagar»

Los cheques solo están en la API del core (no en el gateway). Hay dos formas de pagarlos; elige una y no las mezcles.

Es el contrato que usa FINORA Sucursal: la taquilla muestra al cajero si el cheque es pagable, el cajero confirma y entonces se hace el retiro.

  1. Valida con POST /api/v1/checks/validate (alcance account:read):

    { "accountCode": "00010001010000000002", "checkNumber": "000101", "amount": "250.00" }

    Responde siempre 200. Si payable es false, reason dice por qué (CHEQUE_ANULADO, FONDOS_INSUFICIENTES, CUENTA_BLOQUEADA, CHEQUE_EN_PROCESO…). Si es true, el cheque queda reservado para tu credencial hasta reservedUntil (15 minutos por defecto) y otra validación del mismo cheque responde CHEQUE_EN_PROCESO. Validar no mueve saldo.

  2. Retira con POST /api/v1/payments/withdrawal, con la misma credencial, la misma cuenta, el mismo monto y una referencia de pago de cheque que empiece por PCH-. El core marca el cheque como pagado (CLEARED) en la misma transacción del débito.

Las chequeras y el ciclo de vida de cada cheque (emitir, entregar, anular, orden de no pago, devolución) están en /api/v1/ext/accounts/{accountId}/checkbooks y /api/v1/ext/accounts/{accountId}/checks.

Método y ruta en el coreAlcanceQué hace
GET /api/v1/ext/credit-productscredit:readProductos de crédito
POST /api/v1/ext/credits/simulationscredit:readSimula la tabla de amortización
POST /api/v1/ext/creditscredit:writeCrea la solicitud
POST /api/v1/ext/credits/{creditId}/approvalcredit:approveAprueba o rechaza, a cuatro ojos
POST /api/v1/ext/credits/{creditId}/disbursementcredit:disburseDesembolsa el crédito aprobado
GET /api/v1/ext/credits/{creditId}, …/schedulecredit:readEstado y plan de pagos
POST /api/v1/ext/credits/{creditId}/paymentscredit:paymentCobra cuotas
GET /api/v1/ext/credits/{creditId}/payoff-quotecredit:readCotiza la cancelación total
POST /api/v1/ext/credits/{creditId}/payoffcredit:paymentCancela el crédito

El cobro aplica el orden legal: cargos, mora, interés y capital, de la cuota más antigua a la más nueva. Sin amount, cobra lo que falta de la próxima cuota. Un monto mayor es un adelanto: cubre las cuotas siguientes en orden, sin recalcular el plan. Si se paga la última cuota, el crédito pasa a CLOSED.

{ "amount": "1185.60", "originAccountId": "3d0c4f0e-9c7f-4b8e-8c1a-0a5b5f1d2e11", "channelCode": "CAJA" }

8. Contabilidad: contabilizar por concepto y leer el mayor

Sección titulada «8. Contabilidad: contabilizar por concepto y leer el mayor»

El satélite que necesita registrar un hecho contable que no es un movimiento de cuenta (una comisión cobrada en el ERP, un gasto, un ajuste) no arma el asiento: le dice al core qué concepto contable aplicar y por qué monto. El concepto lo define el contador del banco y fija las cuentas, las piernas y la moneda.

POST /api/v1/accounting/apply-concept (alcance accounting:write):

{
"cia": "001",
"conceptCode": "COMISION-SERVICIO",
"baseAmount": 100.00,
"currency": "VES",
"description": "Comisión por servicio",
"reference": "ERP-000123",
"idempotencyKey": "erp-000123"
}

Responde { "ok": true, "status": "success", "anchorId": "…" }. Si el concepto no existe o la validación falla, 400 con ok: false y el motivo en status. La clave de idempotencia va en el cuerpo: úsala siempre, con tu número de documento, para que un reintento no duplique el asiento. customerAccount (UUID) es opcional y ata el asiento a la cuenta de un cliente.

Las consultas del mayor están en /api/v1/ext/gl (alcance gl:read) y el gateway las publica en /v1:

En el coreEn el gatewayQué devuelve
GET /api/v1/ext/gl/accountsGET /v1/glaccountsPlan de cuentas, filtrable por tipo, moneda y si es postable
GET /api/v1/ext/gl/accounts/{glCode}?balanceDate=…GET /v1/glaccounts/{glCode}Una cuenta con su saldo por moneda a una fecha
POST /api/v1/ext/gl/journal-entries:searchPOST /v1/gljournalentries:searchLíneas del mayor por criterios (fecha, cuenta, referencia)
GET /api/v1/ext/gl/journal-entries/{voucher}GET /v1/gljournalentries/{voucher}Un asiento completo por comprobante
GET /api/v1/ext/gl/trial-balanceGET /v1/gltrialbalanceBalance de comprobación
POST /api/v1/ext/gl/reportsPOST /v1/accounting/reportsEncola un reporte contable asíncrono

El detalle de campos, criterios y errores está en la referencia de la API contable. El saldo de una cuenta del mayor incluye lo pendiente del cierre; el balance de comprobación solo cuenta lo ya contabilizado.

POST /api/v1/ext/gl/journal-entries (alcance crítico gl:write, Idempotency-Key) postea un asiento balanceado de varias piernas y agencias. Funciona solo si la instalación configuró el concepto de asientos manuales; sin él responde 422 manual-concept-unavailable.

9. Entérate de lo que pasa: webhooks firmados y eventos

Sección titulada «9. Entérate de lo que pasa: webhooks firmados y eventos»

En lugar de preguntarle al core cada minuto si cambió un saldo, suscríbete a sus avisos.

  • Webhooks firmados. El core hace un POST a tu URL por cada evento (un asiento contabilizado, un cambio de cuenta). Cada aviso trae X-Finora-Signature (t=<segundos>,v1=<hex>, HMAC del cuerpo crudo) y X-Finora-Webhook-Id, que es el mismo en todos los reintentos: verifica la firma y deduplica por ese id. Alta, entregas y reenvío en /api/v1/ext/webhooks (core) o /v1/webhooks (gateway). Ver Recibir y verificar los webhooks del core.
  • Flujo de eventos. Si necesitas todos los eventos en orden y poder retomar donde quedaste, lee /api/v1/ext/events o crea una suscripción con cursor confirmado en /api/v1/ext/event-subscriptions (en el gateway, /v1/events y /v1/subscriptions). Ver Consumir el streaming de eventos.

Lo habitual: el ERP escucha AccEntryPosted para conciliar, y los canales escuchan AccountChanged para refrescar el saldo que muestran.

10. Licencias por módulo: qué puede usar tu sistema

Sección titulada «10. Licencias por módulo: qué puede usar tu sistema»

FINORA se licencia por módulo. Antes de poner un satélite en marcha, comprueba que los módulos que usa están habilitados en esa instalación:

GET /api/v1/ext/license/modules
X-Api-Key: <credencial con license:read>

Cada módulo trae code, enabled, licensed, enforced y los prefijos de API que cubre. Los que importan para esta guía son ACCOUNTS, TRANSACTIONS, CREDITS, CHECKBOOKS, ACCOUNTING, API (la API externa en general), GL_API (la API contable) y GATEWAY. Si el core tiene licencia registrada y un módulo está apagado, toda ruta de ese módulo responde:

HTTP/1.1 403 Forbidden
{ "error": "MODULE_DISABLED", "module": "GL_API" }

Un 403 MODULE_DISABLED no se arregla con más alcances: lo resuelve quien administra la suscripción. Ver Suscripción y licencias por módulo.

  • Cada satélite tiene su propia credencial, con solo los alcances que usa.
  • Toda escritura lleva una clave de idempotencia generada una vez por operación y guardada antes de llamar.
  • El satélite guarda el ledgerRef o el comprobante que devuelve el core junto a su propio documento.
  • Ningún saldo se calcula en el satélite: siempre se lee del core.
  • El receptor de webhooks verifica la firma sobre el cuerpo crudo y deduplica por X-Finora-Webhook-Id.
  • Los módulos que usa el sistema aparecen habilitados en /license/modules.
  • Las pruebas se hicieron contra el sandbox de la institución, nunca contra datos reales.
Lo que pasaPor quéQué hacer
Un depósito aparece dos vecesEl reintento llevó una Idempotency-Key nuevaReusa la misma clave en cada reintento de la misma operación
CHEQUE_EN_PROCESO al validarOtra credencial o una validación anterior reservó el chequeEspera a reservedUntil o paga con la credencial que lo reservó
El retiro no marca el cheque pagadoCambió la credencial, la cuenta, el monto o la referencia no empieza por PCH-Usa los mismos datos de la validación
403 MODULE_DISABLEDEl módulo no está licenciado en esa instalaciónPide la habilitación a quien administra la suscripción
422 manual-concept-unavailableLa instalación no configuró el concepto de asientos manualesContabiliza por apply-concept o pide que se configure el concepto
apply-concept responde 400El concepto no existe en esa compañía o el monto no validaRevisa conceptCode y cia con el contador del banco
El canal muestra un saldo viejoLo guardó en su base y no escucha los avisosLee el saldo del core o suscríbete a AccountChanged