FINORA Core · Guía
Integrar los sistemas satélite del banco con FINORA Core como sistema de registro
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 Core | Lo hace el sistema satélite |
|---|---|
| Lleva el saldo de cada cuenta: contable, bloqueado y disponible | Muestra el saldo que le devuelve el core en ese momento |
| Valida fondos, estado de la cuenta, retenciones y bloqueos | Pide la operación y respeta el rechazo |
| Registra la transacción con su referencia contable estable | Guarda la referencia del core junto a su propio comprobante |
| Genera el asiento por el concepto contable del producto y del canal | Nunca arma un asiento a mano para un movimiento de cliente |
| Cierra el día y produce el balance de comprobación | Lee el mayor para conciliar o reportar |
| Avisa por webhook o por el flujo de eventos | Reacciona 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én | Sistemas fuera de la red del core: canales, aliados, fintechs | Sistemas internos del banco: taquilla, ERP, conciliador |
| Identidad | Credencial 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) |
| Alcances | Por dominio: clients:*, deposits:*, loans:*, gl:*, webhooks:*, events:read, config:*, license:read, fx:* | Finos: account:read, payment:write, credit:payment, gl:read, accounting:write… |
| Qué agrega | Institución y entorno por subdominio o X-Finora-Tenant, límites por cliente, circuit breaker, errores uniformes | Acceso a rutas que el gateway no publica: cheques, apply-concept, chequeras |
| Dónde se describe | El gateway de API del core | Esta 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).
| Sistema | Alcances en la API del core | Alcances en el gateway |
|---|---|---|
| Taquilla | account:read, payment:write | No aplica: los cheques no se publican en /v1 |
| ERP del banco | gl:read, accounting:write (si contabiliza por concepto) | gl:read |
| Banca por internet o móvil | account:read, payment:write, credit:read, credit:payment | clients:read, deposits:read, deposits:write, loans:read, loans:write |
| Receptor de avisos | webhook:read, events:read | webhooks: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 core | Alcance | Qué hace |
|---|---|---|
GET /api/v1/ext/accounts/by-code/{accountCode} | account:read | Resuelve el número de cuenta: UUID, titular, producto, moneda, estado |
GET /api/v1/ext/accounts/{accountId} | account:read | Datos de la cuenta, estado y saldos |
GET /api/v1/ext/accounts/{accountId}/balance | account:read | Saldo contable, bloqueado y disponible, con los saldos por fase |
GET /api/v1/ext/accounts/{accountId}/transactions | account:read | Movimientos del más reciente al más antiguo, por cursor (size 1-100, from, to) |
GET /api/v1/ext/accounts?customerId=… | account:read | Todas las cuentas de un cliente |
POST /api/v1/ext/accounts | account:write | Abre una cuenta a un cliente existente, con Idempotency-Key |
GET, POST /api/v1/ext/accounts/{accountId}/blocks | account:read, account:status | Bloqueos, con aprobación a cuatro ojos (account:authorize) |
GET /api/v1/ext/accounts/by-code/00010001010000000002X-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 core | En el gateway | Qué hace |
|---|---|---|
POST /api/v1/payments/deposit | POST /v1/deposits/{depositId}/deposit-transactions | Acredita desde un origen externo (efectivo en taquilla, transferencia entrante) |
POST /api/v1/payments/withdrawal | POST /v1/deposits/{depositId}/withdrawal-transactions | Debita para entregar fuera del banco; valida fondos antes |
POST /api/v1/payments/transfer | POST /v1/deposits/{depositId}/transfer-transactions | Transfiere entre dos cuentas del mismo banco |
POST /api/v1/payments/depositX-Api-Key: <credencial de la taquilla>Idempotency-Key: 6f1c2b8e-0d4a-4c1e-9a77-2f0b9d3e5a10Content-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.
-
Valida con
POST /api/v1/checks/validate(alcanceaccount:read):{ "accountCode": "00010001010000000002", "checkNumber": "000101", "amount": "250.00" }Responde siempre 200. Si
payableesfalse,reasondice por qué (CHEQUE_ANULADO,FONDOS_INSUFICIENTES,CUENTA_BLOQUEADA,CHEQUE_EN_PROCESO…). Si estrue, el cheque queda reservado para tu credencial hastareservedUntil(15 minutos por defecto) y otra validación del mismo cheque respondeCHEQUE_EN_PROCESO. Validar no mueve saldo. -
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 porPCH-. El core marca el cheque como pagado (CLEARED) en la misma transacción del débito.
POST /api/v1/checks/pay (alcance payment:write, Idempotency-Key obligatoria) valida, debita y marca el cheque como
pagado en una sola transacción: un cheque no se paga dos veces aunque dos cajeros lo intenten a la vez.
{ "accountCode": "00010001010000000002", "checkNumber": "000101", "amount": "250.00", "currency": "VES", "reference": "PCH-000123", "description": "Pago de cheque por taquilla", "channel": "AGENCIA"}Responde 201 con paymentId, checkId, checkStatus: "CLEARED" y ledgerRef. Si el cheque no es pagable,
422 con reason; si hay otro pago del mismo cheque en curso, 409.
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.
7. Créditos: consultar, cobrar y cancelar
Sección titulada «7. Créditos: consultar, cobrar y cancelar»| Método y ruta en el core | Alcance | Qué hace |
|---|---|---|
GET /api/v1/ext/credit-products | credit:read | Productos de crédito |
POST /api/v1/ext/credits/simulations | credit:read | Simula la tabla de amortización |
POST /api/v1/ext/credits | credit:write | Crea la solicitud |
POST /api/v1/ext/credits/{creditId}/approval | credit:approve | Aprueba o rechaza, a cuatro ojos |
POST /api/v1/ext/credits/{creditId}/disbursement | credit:disburse | Desembolsa el crédito aprobado |
GET /api/v1/ext/credits/{creditId}, …/schedule | credit:read | Estado y plan de pagos |
POST /api/v1/ext/credits/{creditId}/payments | credit:payment | Cobra cuotas |
GET /api/v1/ext/credits/{creditId}/payoff-quote | credit:read | Cotiza la cancelación total |
POST /api/v1/ext/credits/{creditId}/payoff | credit:payment | Cancela 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.
Aplicar un concepto: apply-concept
Sección titulada «Aplicar un concepto: apply-concept»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.
Leer el mayor
Sección titulada «Leer el mayor»Las consultas del mayor están en /api/v1/ext/gl (alcance gl:read) y el gateway las publica en /v1:
| En el core | En el gateway | Qué devuelve |
|---|---|---|
GET /api/v1/ext/gl/accounts | GET /v1/glaccounts | Plan 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:search | POST /v1/gljournalentries:search | Lí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-balance | GET /v1/gltrialbalance | Balance de comprobación |
POST /api/v1/ext/gl/reports | POST /v1/accounting/reports | Encola 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.
Asientos manuales por API
Sección titulada «Asientos manuales por API»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
POSTa tu URL por cada evento (un asiento contabilizado, un cambio de cuenta). Cada aviso traeX-Finora-Signature(t=<segundos>,v1=<hex>, HMAC del cuerpo crudo) yX-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/eventso crea una suscripción con cursor confirmado en/api/v1/ext/event-subscriptions(en el gateway,/v1/eventsy/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/modulesX-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.
Lista de verificación antes de salir
Sección titulada «Lista de verificación antes de salir»- 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
ledgerRefo 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.
Errores frecuentes
Sección titulada «Errores frecuentes»| Lo que pasa | Por qué | Qué hacer |
|---|---|---|
| Un depósito aparece dos veces | El reintento llevó una Idempotency-Key nueva | Reusa la misma clave en cada reintento de la misma operación |
CHEQUE_EN_PROCESO al validar | Otra credencial o una validación anterior reservó el cheque | Espera a reservedUntil o paga con la credencial que lo reservó |
| El retiro no marca el cheque pagado | Cambió la credencial, la cuenta, el monto o la referencia no empieza por PCH- | Usa los mismos datos de la validación |
403 MODULE_DISABLED | El módulo no está licenciado en esa instalación | Pide la habilitación a quien administra la suscripción |
422 manual-concept-unavailable | La instalación no configuró el concepto de asientos manuales | Contabiliza por apply-concept o pide que se configure el concepto |
apply-concept responde 400 | El concepto no existe en esa compañía o el monto no valida | Revisa conceptCode y cia con el contador del banco |
| El canal muestra un saldo viejo | Lo guardó en su base y no escucha los avisos | Lee el saldo del core o suscríbete a AccountChanged |
Sigue aprendiendo
Sección titulada «Sigue aprendiendo»- Ruta del integrador del core: el orden completo para dominar la integración.
- Tu primera llamada a la API del core: token, plan de cuentas y un asiento en el sandbox.
- Contabilidad declarativa por producto y canal: por qué el satélite pide un concepto y no arma el asiento.
- Las referencias OpenAPI interactivas están en FINORA Developers.