FINORA Core · Conceptos
El gateway de API del core: una puerta pública para sistemas externos
El problema: cada sistema quiere entrar por su propia puerta
Sección titulada «El problema: cada sistema quiere entrar por su propia puerta»Un banco no vive solo de su core. El ERP de contabilidad corporativa quiere leer el plan de cuentas, el conciliador quiere los asientos del día, una fintech aliada quiere abrir cuentas y una app quiere saldos. Si cada uno entra directo al core, con su propio usuario y sus propias reglas, el banco pierde el control: no sabe quién llamó, no puede limitar cuánto llama y un reintento mal hecho duplica un asiento.
La idea: una sola puerta, con portero
Sección titulada «La idea: una sola puerta, con portero»El gateway de API del core es esa puerta. Expone una API pública y estable bajo /v1, separada de la API interna
del core, y en cada petición hace el trabajo del portero: identifica al sistema, comprueba qué puede hacer, decide a qué
institución va, frena los excesos, evita los duplicados y traduce los errores a un formato único.
flowchart LR
C["Sistema del banco<br/>(ERP, app, conciliador)"] -->|"HTTPS + token o apiKey"| G
subgraph G["Gateway de API del core"]
direction TB
G1["Correlación<br/>X-Request-Id"] --> G2["Versión de la API"]
G2 --> G3["Credencial<br/>(token o apiKey)"]
G3 --> G4["Institución y entorno<br/>subdominio o X-Finora-Tenant"]
G4 --> G5["Límite de peticiones<br/>por cliente e institución"]
G5 --> G6["Alcance por dominio"]
G6 --> G7["Idempotencia<br/>en las escrituras"]
G7 --> G8["Circuit breaker<br/>por institución"]
end
G8 -->|"credencial propia de la institución"| K["FINORA Core<br/>de esa institución"]
El sistema externo nunca conoce la credencial con la que el gateway entra al core: esa la guarda el operador del gateway, una por institución. Así el banco puede revocar a un consumidor sin tocar a los demás.
La superficie /v1
Sección titulada «La superficie /v1»Contamos los puntos de entrada en el código del gateway: 86 operaciones. Una es el token, que acepta el cuerpo en dos formatos (formulario y JSON). De las restantes, 18 responden 501 a propósito: son las que una API de core bancario suele tener pero el core no ofrece por API (modificar o borrar un cliente, castigar un crédito, crear una cuenta contable…). En lugar de fallar con un 500, dicen qué hacer en su lugar.
| Dominio | Rutas | Qué cubre |
|---|---|---|
| Autenticación | /v1/oauth/token | El token del sistema consumidor |
| Clientes | /v1/clients | Búsqueda por texto, consulta, alta, sus cuentas y sus créditos |
| Captaciones | /v1/deposits, /v1/deposit-products | Productos, apertura, saldo, movimientos, bloqueos, cierre, depósitos, retiros y transferencias |
| Créditos | /v1/loans, /v1/loan-products | Simulación, solicitud, aprobación, desembolso, pagos, cuota de cancelación y cancelación |
| Contabilidad | /v1/glaccounts, /v1/gljournalentries, /v1/gltrialbalance, /v1/transactionchannels, /v1/accounting/reports | Plan de cuentas con saldos, asientos manuales, búsqueda, reverso, balance de comprobación y reportes asíncronos. Detalle en la referencia de la API contable |
| Divisas | /v1/fx | Cotización, operación y liquidación |
| Licencia | /v1/license/modules | Qué módulos tiene activos la institución |
| Webhooks | /v1/webhooks | Suscripciones, entregas y reenvío. Ver Webhooks firmados del core |
| Eventos | /v1/events, /v1/subscriptions | Lectura ordenada por cursor. Ver Consumir el streaming de eventos |
| Configuración | /v1/configuration/accounting.yaml | La configuración contable como código. Ver la guía |
Los cuerpos de las respuestas son los del core, sin renombrar campos.
Credenciales: token o apiKey
Sección titulada «Credenciales: token o apiKey»Cada sistema consumidor recibe un client_id y un client_secret. Con ellos tiene dos formas de identificarse:
- Token OAuth 2.0 (recomendada).
POST /v1/oauth/tokencongrant_type=client_credentials. La respuesta traeaccess_token,token_type: Bearer,expires_in: 900(15 minutos),scope,tenantyenvironment. El secreto viaja una vez cada 15 minutos, no en cada petición. - Cabecera
apiKey.apiKey: <client_id>.<client_secret>en cada petición, sin token. Es más cómoda, pero el secreto viaja siempre: úsala solo si tu cliente no puede manejar tokens.
Con los valores por defecto, tras cinco fallos seguidos la credencial queda bloqueada 15 minutos (429
GW_LOGIN_BLOQUEADO), y tras diez
credenciales inválidas desde una misma dirección en 15 minutos se bloquea esa dirección para todos (429
GW_IP_BLOQUEADA), incluso con una credencial válida. Cómo cambiar un secreto sin cortar el servicio está en
Rotar una credencial de API con periodo de gracia.
Alcances por dominio
Sección titulada «Alcances por dominio»Cada consumidor tiene una lista de alcances: clients:read, deposits:write, gl:read… Un GET exige el
alcance :read del dominio y un POST, PUT, PATCH o DELETE el :write. Hay excepciones de sentido común: una
búsqueda (gljournalentries:search), una simulación de crédito o un reporte contable son lectura aunque viajen en
POST. Sin el alcance, 403 GW_ALCANCE_INSUFICIENTE.
Hay un segundo filtro, detrás: la credencial del gateway ante el core tiene sus propios permisos, y algunos son
críticos (postear asientos, aprobar créditos, leer el stream de eventos). Si el gateway te deja pasar pero el
core no, recibes 403 CORE_ACCESO_DENEGADO.
Varias instituciones en el mismo gateway
Sección titulada «Varias instituciones en el mismo gateway»Un gateway puede atender a varias instituciones, cada una con su propio core. La institución se nombra de dos formas:
- por el subdominio:
https://<institucion>.<su-gateway>/v1/...; - por la cabecera
X-Finora-Tenant: <institucion>contra el host genérico.
Si no nombras ninguna, vale la del token. Si nombras una distinta de la de tu credencial, 403 TENANT_CRUZADO: un
consumidor de un banco nunca ve los datos de otro. Una institución suspendida responde 423 y un dominio que no
contrató, 403 MODULO_NO_HABILITADO.
Sandbox: pruebas sin tocar producción
Sección titulada «Sandbox: pruebas sin tocar producción»Cada institución puede tener un sandbox: otra institución en el registro, con otro core y otra base, sus propias
credenciales y sus propios límites. Se pide por el subdominio <institucion>.sandbox.<su-gateway> o con la cabecera
X-Finora-Environment: sandbox. El token lleva su entorno: uno de producción usado contra el sandbox, o al revés,
responde 403 ENTORNO_CRUZADO. Toda respuesta autenticada trae la cabecera X-Finora-Environment para que sepas
siempre dónde estás.
Idempotencia: reintentar sin duplicar
Sección titulada «Idempotencia: reintentar sin duplicar»Toda escritura exige la cabecera Idempotency-Key con un UUID (v4 recomendado). La clave vale 6 horas:
- La primera petición la reserva. Otra con la misma clave mientras la primera sigue en curso: 409
IDEMPOTENCIA_EN_CURSO. - Repetida con el mismo cuerpo, devuelve la respuesta original con
Idempotent-Replayed: true, sin llamar al core. Es lo que te salva cuando se cayó la red justo después de enviar un asiento. - Misma clave con otro cuerpo: 422
IDEMPOTENCIA_CUERPO_DISTINTO. - Un rechazo (4xx) o un fallo (5xx) no se guarda: corrige y reintenta con la misma clave.
sequenceDiagram participant S as Tu sistema participant G as Gateway participant K as Core S->>G: POST asiento · Idempotency-Key: K1 G->>K: POST (clave derivada de K1) K-->>G: 201 asiento G--xS: la respuesta se pierde en la red S->>G: POST mismo asiento · Idempotency-Key: K1 G-->>S: 201 el mismo asiento · Idempotent-Replayed: true Note over G,K: el core no recibe la segunda petición
Paginación con totales
Sección titulada «Paginación con totales»Las listas usan offset (desde 0) y limit (50 por defecto, hasta 1000) y la respuesta es un arreglo JSON. Con
paginationDetails=ON llegan además las cabeceras Items-Total, Items-Offset e Items-Limit. Los movimientos de una
cuenta y los eventos se paginan por cursor: la cabecera Items-Next-Cursor trae la posición siguiente.
detailsLevel=FULL agrega datos que cuestan otra consulta al core (el saldo de una cuenta, el cronograma de un
crédito).
Acciones con verbo
Sección titulada «Acciones con verbo»Lo que no es crear, leer o modificar se expresa como una acción pegada al recurso con dos puntos:
POST /v1/gljournalentries:search, POST /v1/gljournalentries/{voucher}:reverse, POST /v1/loans/{id}:disburse,
POST /v1/webhooks/{id}:reset-circuit. Un asiento contabilizado no se borra ni se modifica: se reversa.
Errores en un solo formato
Sección titulada «Errores en un solo formato»Todo error es application/problem+json (RFC 7807), con un codigo estable, el requestId de la petición y, para
clientes que ya esperan ese esquema, errorCode (el estado HTTP), errorReason (la categoría) y errorSource (el
campo o la cabecera culpable cuando se conoce):
{ "type": "urn:finora:core-gateway:solicitud-invalida", "title": "Solicitud inválida", "status": 400, "detail": "La búsqueda de asientos exige un criterio {\"field\":\"bookingDate\",\"operator\":\"BETWEEN\"} con value y secondValue.", "codigo": "RANGO_DE_FECHAS_REQUERIDO", "requestId": "3f2c9a71e8b44d0f9b6c1a2e5d7f8a90", "timestamp": "2026-10-19T14:05:12.481-04:00", "errorCode": 400, "errorReason": "INVALID_PARAMETERS", "errorSource": "filterCriteria"}Los rechazos del core llegan como CORE_<TIPO> y conservan sus datos de negocio. La lista completa está en
Códigos de error del gateway de API.
Correlación, límites y circuit breaker
Sección titulada «Correlación, límites y circuit breaker»X-Request-Id. Mándalo tú (8 a 64 caracteres[A-Za-z0-9._-]) o el gateway genera uno. Vuelve en la respuesta, viaja al core y aparece en cada error: es lo que le das a soporte para encontrar tu petición.- Límites. Una cubeta de fichas por consumidor y otra por institución. Las cabeceras
X-RateLimit-Limit,X-RateLimit-RemainingyX-RateLimit-Resetmuestran la más cercana a agotarse. Al pasarte, 429LIMITE_EXCEDIDOconRetry-AfteryalcanceLimite(CLIENTEoTENANT). - Circuit breaker por institución. Si el core de una institución empieza a fallar (errores 5xx, red o tiempos
agotados, nunca un rechazo de negocio), el gateway deja de llamarlo un rato y responde 503
CORE_CIRCUITO_ABIERTO. El core caído de un banco no arrastra a los demás.
Para seguir
Sección titulada «Para seguir»- Tu primera llamada a la API del core: token, plan de cuentas, un asiento, una búsqueda y un reverso.
- Referencia de la API contable.
- Ruta del integrador del core.