Documentación Open Finance Chile

Catálogo de Produtos / Documentación Open Finance Chile

Guía de Integración para Desarrolladores — Authorisation Server con RAR y Grant Management


Introducción y Visión General

La solución de Open Finance de Sensedia Chile implementa un Authorisation Server basado en el perfil de seguridad FAPI 2.0 y en las especificaciones internacionales:

 

Roles en el Ecosistema

El SFA chileno define cuatro roles principales para los participantes del ecosistema de Open Finance:

Rol Sigla Descripción
Institución Proveedora de Información IPI Entidad que almacena datos de clientes y los expone vía API.
Institución Proveedora de Cuentas IPC Entidad que aloja cuentas y procesa transacciones de pago.
Proveedor de Servicios Basados en Información PSBI Tercero receptor de datos (agregador financiero).
Proveedor de Servicios de Iniciación de Pagos PSIP Empresa autorizada para iniciar pagos desde cuentas de clientes.


Arquitectura de Componentes

La solución se compone de varios componentes que, en conjunto, cubren los requisitos funcionales y no funcionales exigidos por la regulación chilena.

 
Diagrama de arquitectura de componentes
Para visualizar mejor, haga clic con el botón derecho del mouse en "Abrir imagen en nueva pestaña".

Componentes clave

  • Sensedia API Management: Punto de entrada con soporte mTLS/TLS. Maneja rate limiting (60 TPM / 10 TPS por endpoint). Gobierna todas las APIs del ecosistema (edición, manejo, customización y capacidades de seguridad requeridas por el regulador).

  • Motor de consentimiento: Gestiona el ciclo de vida del consentimiento (estados, aprobadores múltiples, expiración) en la visión de IPI y IPC. Grant Management es parte del módulo para administrar grant_id con operaciones de creación, consulta, alteración y cambios.

  • Auth Server (FAPI 2.0): Implementa PAR, RAR, DCR/DCM y emite tokens OAuth 2.0 en el perfil regulatorio de Chile.

  • IPI/PSBI Journey (en construcción): Solicita y consume los datos proporcionados por los IPI para ofrecer productos o servicios nuevos o mejorados a los usuarios finales. Remueve la complejidad de integración entre participantes del ecosistema.

  • Cumplimiento regulatorio: La solución cubre los requisitos funcionales y no funcionales (almacenamiento en caché del directorio central, gestión de webhooks, gestión de certificados, entre otros) requeridos para los roles de IPI y IPC.

 
Sensedia Open Finance Product
Para visualizar mejor, haga clic con el botón derecho del mouse en "Abrir imagen en nueva pestaña".

Directorio Central CMF

La oferta incluye integración con el Directorio Central de la CMF, almacenando caché de los datos para garantizar precisión en las consultas. Se implementan mecanismos de actualización del caché conforme a la regulación. La copia local del participante es una réplica obligatoria que cada PSBI, PSIP, IPI e IPC mantiene en su infraestructura.

 

Ventana máxima entre sincronizaciones: 8 horas.

Este flujo debe ejecutarse cada vez que exista un aviso de actualización y, por defecto, en caso de no haber aviso, con una frecuencia mínima de 8 horas para cumplir con los requisitos del Perfil de Seguridad y del Anexo 3.

La copia local no es solo una lista de participantes — es el conjunto completo de datos que alimenta todos los flujos OIDC/FAPI:

  • Identificación de los participantes: datos legales y estados operativos (Activo/Normal, Activo/Mecanismo Alternativo, Inactivo/Desconectado, Suspendido, etc.).

  • Certificados digitales: mTLS de transporte + JWS de firma, con sus kid, vigencia y estado (activo, obsoleto, revocado).

  • JWKS públicos para validación cruzada (incluyendo el JWKS del propio Directorio para validar SSAs en DCR).

  • Servidores de autorización: emisor, URL de openid-configuration, endpoints de PAR/token, soporte a DCR.

  • Recursos API y versiones: familia (Accounts, Payments, etc.), ApiResourceId, ApiVersion, endpoints concretos.



Authorisation y Grant Management

El flujo para la gestión del consentimiento se divide en dos partes principales: OIDC (Autorización) y Gestión de Consentimiento. Ambos flujos, juntos, forman los pasos necesarios para la generación de credenciales de acceso a las APIs y, a continuación, la posibilidad de gestionar los tokens para el acceso a las APIs de Negocio.

Comencemos con OIDC: aunque es el nombre más técnico, podemos entender este flujo como el flujo inicial para la generación de credenciales.

 

Modelo de relación basado en entidades y API

Modelo de entidades y relacionamiento de APIs
Para visualizar mejor, haga clic con el botón derecho del mouse en "Abrir imagen en nueva pestaña".

Authorisation

Responsable de la autorización y emisión de tokens a partir del modelo OpenID Connect (OIDC).

Reglas OpenID Connect en el SFA chileno

El SFA adopta OIDC con una versión restringida por el Perfil FAPI 2.0 de la OpenID Foundation.

Permitidos:

  • Authorization Code Flow con PAR + JAR + RAR — el camino estándar para todos los consentimientos con interacción del usuario.

  • Refresh Token — solo si está asociado a un grant existente.

  • DCR — Dynamic Client Registration para la primera interacción con el servidor.

 

Auth Server OIDC API Endpoints

Método Endpoint Descripción
POST /par Pushed Authorization Request con RAR
GET /authorize Redirect para autenticación y consentimiento
POST /token Intercambia code por access_token + grant_id
GET /.well-known/openid-configuration Discovery metadata
POST /clients-registrations/openid-connect Dynamic Client Registration

Grant Management — Ciclo de Vida del Consentimiento

El grant_id es el identificador único de cada consentimiento. Las acciones de grant_management_action permiten manipular un grant existente:

Acción Descripción Requiere auth del usuario
create Genera nuevo consentimiento y grant_id
update Extiende duración sin alterar scope No (si solo vigencia)
replace Sustituye permissions por un conjunto nuevo
merge Combina permisos nuevos con existentes
query Consulta estado actual No
revoke Cancela consentimiento e invalida tokens No

Estados del Consentimiento

Estado Descripción
AwaitingAuthorisation Pendiente de autorización del Usuario Final
AwaitingMultiAuthorisation Requiere múltiples aprobaciones
Authorised Aprobado y activo
Rejected Rechazado por el Usuario Final
Revoked Revocado post-aprobación
Incomplete Firmas conjuntas no completadas a tiempo
Expired Vigencia expirada

Vigencia: un único uso, 7 días, 1 mes, 3 meses, 6 meses, 12 meses, o mientras dure el contrato.

 
State machine del consentimiento
Para visualizar mejor, haga clic con el botón derecho del mouse en "Abrir imagen en nueva pestaña".


Niveles de Granularidad

Las reglas de Granularidad y Dependencia definen una jerarquía para el acceso a los endpoints de las APIs, determinando la profundidad del acceso a los datos financieros y los permisos previos necesarios.

 

Regla de Granularidad (Niveles de Acceso)

La granularidad divide el nivel de detalle de la información en hasta tres niveles de profundidad:

  1. 1er nivel (Primer Nivel): Representa el permiso de acceso general y amplio a una categoría de productos. Se utiliza para consultar la lista de recursos disponibles de un cliente. Por ejemplo, acceder a la lista de todas las cuentas (GET /accounts/v1), tarjetas de crédito (GET /credit-card-accounts/v1/accounts) o préstamos (GET /loans/v1).

  2. 2do nivel (Segundo Nivel): Permite enfocarse en un producto específico dentro de esa lista, utilizando su identificador único. Por ejemplo, consultar los datos de solo una cuenta específica a través del endpoint GET /accounts/v1/{accountID}.

  3. 3er nivel (Tercer Nivel): Es el grado más profundo de acceso, orientado a consultar detalles operativos específicos y sensibles de ese recurso previamente identificado, como saldos, límites e historial de transacciones. Ejemplos incluyen los endpoints para saldos de cuentas (GET /accounts/v1/{accountID}/balance) o transacciones de inversiones (GET /investments/v1/{investmentID}/transactions).

 

Regla de Dependencia

La dependencia crea un sistema de prerrequisitos en cascada. No se puede conceder un acceso más granular sin que los niveles jerárquicamente superiores también formen parte del alcance autorizado:

  1. El acceso al 1er nivel tiene dependencia "N/A" (No aplicable), ya que es la capa base y no depende de ningún otro permiso.

  2. El acceso al 2do nivel tiene como dependencia "1er". Esto significa que, para consultar los detalles de un producto específico (como /{accountID}), el sistema exige que la institución también posea el permiso para consultar la lista general de cuentas de ese cliente.

  3. El acceso al 3er nivel tiene la dependencia "1er y 2do". Para que la institución pueda leer saldos, transacciones o límites, necesita obligatoriamente las autorizaciones conjuntas para listar las cuentas (1er nivel) y acceder a la cuenta por su ID único (2do nivel).

 

Resumen de Niveles y Dependencias

Nivel Ejemplo Dependencia
1er GET /accounts/v1 N/A
2do GET /accounts/v1/{accountId} 1er nivel
3er GET /accounts/v1/{accountId}/balances 1er y 2do

Para obtener más detalles sobre los niveles de acceso y los permisos, consulte la documentación oficial.



Grant Management API Endpoints

Endpoints REST para listar, consultar, auditar y revocar grants identificados por grant_id.

Método Endpoint Descripción
GET /grants Lista grants activos
GET /grants/{grant_id} Detalle de un grant
DELETE /grants/{grant_id} Revoca un grant
POST /grants/{grant_id}/revoke Revoca (alternativa)
GET /grants/history Historial de auditoría


Webhooks de Consentimiento (Sensedia → Institución)

La plataforma notifica al backend de la institución, de forma asíncrona, cada cambio relevante en el ciclo de vida de un consentimiento. La entrega es por HTTP POST hacia el endpoint que la institución registra como callback URL, con envoltura CloudEvents 1.0 y cuerpo application/cloudevents+json.

 

Esta funcionalidad se encuentra bajo construcción. La descripción a continuación refleja el contrato vigente y puede sufrir cambios hasta su publicación.

Dos canales distintos — no confundir

Existen dos flujos de eventos con contratos, namespaces y públicos diferentes:

Canal Entre quiénes Namespace Origen del contrato
Regulado Plataforma ↔ demás participantes del SFA y Directorio sfa.consent.* NCG N°569 / Anexo Técnico N°3
De producto (este documento) Plataforma → backend de la institución sensedia.consent.* Contrato propio de la solución Sensedia

El namespace sensedia.consent.* es deliberadamente distinto del regulatorio: los tipos de este catálogo no cambian porque la CMF publique los suyos.

 

Catálogo de eventos

El type nombra el hecho ocurrido, no el estado resultante — el estado viaja en data.newState. Un mismo estado puede ser resultado de hechos distintos, y hay hechos que no cambian el estado.

Tipo (sensedia.consent.) Hecho que lo dispara data.newState Acción esperada del receptor Terminal CMF
created El consentimiento fue creado y espera la autorización del titular AwaitingAuthorisation Mostrar como pendiente; todavía no hay acceso No No
authorised El titular aprobó; el consentimiento queda activo Authorised Habilitar el consumo de las APIs con el token No
rejected El titular denegó un consentimiento que aún estaba pendiente Rejected Cerrar la jornada; no reintentar sobre el mismo consentimiento
revoked Un consentimiento activo fue revocado Revoked Detener el acceso de inmediato
expired Terminó la vigencia del consentimiento Expired Detener el acceso; continuar exige un consentimiento nuevo No — en el canal regulado llega como revoked con newState=Expired
replaced El alcance del consentimiento fue sustituido por completo Authorisedsin cambio Releer el detalle: los permisos vigentes cambiaron No No
merged Se agregaron permisos al alcance vigente Authorisedsin cambio Releer el detalle: los permisos vigentes cambiaron No No

Terminal significa que no habrá más eventos para ese consent:{grantId}. La columna CMF indica si el hecho está tipificado por la normativa: sólo authorised, revoked y rejected lo están; los demás existen únicamente en este contrato de producto.

 

replaced y merged no cambian el estado: son los únicos casos en que previousState y newState vienen iguales. Un receptor que sólo observe el estado los ignoraría y quedaría con una visión desactualizada de lo que el titular consintió. Ante ellos, relea el detalle en GET {source}/grants/{grantId}.

El catálogo publica solamente hechos que ocurren: no se anticipan tipos para flujos que la plataforma todavía no ejecuta. Cuando se incorporen, entrarán como tipos nuevos — cambio retrocompatible, cubierto por la obligación del receptor de tolerar tipos desconocidos.

 

Envoltura del evento

CloudEvents 1.0 simplificado. Los atributos de extensión van en minúsculas y sin separadores porque así lo exige la especificación.

Campo Obligatorio Descripción
specversion Versión de CloudEvents — siempre "1.0"
contractversion Versión mayor de este contrato (hoy "1"). No confundir con specversion
type El hecho ocurrido, en el namespace sensedia.consent.*
source Emisor (issuer del realm). Base del callback de detalle: GET {source}/grants/{grantId}
subject Identificador del consentimiento, en el formato consent:{grantId}
id UID RFC 4122 del evento — igual al encabezado x-idempotency-key
time Instante de la ocurrencia (ISO-8601 UTC), no de la entrega
datacontenttype application/json
role No Rol en que actuó la plataforma: IPI/IPC (el cambio nació aquí) o PSBI/PSIP (llegó de un participante externo y se retransmite)
consenttype No SHARE (compartición de datos) o PAYMENT (iniciación de pago)
originorgid No El IPI/IPC de origen. Presente sólo cuando role es PSBI o PSIP
data { previousState, newState, reason? } — objeto abierto, puede ganar campos nuevos
event { streamId, sequence } — metadatos de ordenamiento

role, consenttype y originorgid viajan en la envoltura, y no dentro de data, porque describen el origen del evento y no el cambio de estado: así el receptor (o un gateway intermedio) puede enrutar y filtrar sin deserializar data.

Los roles del SFA ya vienen separados por dominio, de modo que role y consenttype están emparejadosIPI/PSBI siempre con SHARE, e IPC/PSIP siempre con PAYMENT. Las combinaciones cruzadas no existen.

 

Estados transportados por el webhook

El evento transporta cinco estados, que son un subconjunto de la máquina de estados del consentimiento, con el mismo nombre y el mismo significado que el status devuelto por la Grant Management API — no hay traducción que hacer:

  • AwaitingAuthorisation · Authorised · Rejected · Revoked · Expired

newState es el estado completo, no un delta — por eso aplicar last-writer-wins por event.sequence es seguro. previousState es nulo cuando el consentimiento acaba de ser creado.

El campo reason es opcional y no exhaustivo: trátelo como texto libre, nunca como enum cerrado. Valores en uso hoy: psu_denied (denegado por el usuario), psu_request (revocado a solicitud del usuario) y expired (fin de la vigencia).

 

Eventos livianos (thin): data lleva solamente la transición de estado — sin PII, sin RUT y sin montos. El detalle (permisos, finalidad, vigencia) se obtiene bajo demanda en GET {source}/grants/{grantId}.

Ejemplo de evento

POST /webhooks/consent HTTP/1.1
Content-Type: application/cloudevents+json
Authorization: Bearer <access_token>
x-idempotency-key: a1b2c3d4-0011-4455-8899-aabbccddeeff
x-webhook-interaction-id: 761bab4e-0179-11ee-be56-0242ac120002

{
  "specversion": "1.0",
  "contractversion": "1",
  "type": "sensedia.consent.revoked",
  "source": "https://as.sensedia.example/realms/institucion",
  "subject": "consent:9d8a7c6b-1e2f-4a3b-8c9d-0e1f2a3b4c5d",
  "id": "a1b2c3d4-0011-4455-8899-aabbccddeeff",
  "time": "2026-07-27T14:30:00Z",
  "datacontenttype": "application/json",
  "role": "PSBI",
  "consenttype": "SHARE",
  "originorgid": "org-987654",
  "data": {
    "previousState": "Authorised",
    "newState": "Revoked",
    "reason": "psu_request"
  },
  "event": {
    "streamId": "consent:9d8a7c6b-1e2f-4a3b-8c9d-0e1f2a3b4c5d",
    "sequence": 3
  }
}

La ruta /webhooks/consent es ilustrativa: vale la callback URL que la institución registre en la suscripción.

 

Encabezados HTTP

Encabezado Contenido ¿Cambia en el reintento?
Authorization Bearer <token> emitido por el API Gateway que publica la integración
x-idempotency-key UID RFC 4122 del evento, igual al campo id. Es la clave de deduplicación No
x-webhook-interaction-id UID RFC 4122 del intento (opcional). Sirve para correlacionar logs, no para deduplicar
Content-Type application/cloudevents+json

Deduplique siempre por x-idempotency-key. Deduplicar por x-webhook-interaction-id — que cambia en cada intento — haría que las reentregas legítimas se procesaran como eventos nuevos.

Entrega, reintentos y ACK

La entrega es solamente push (no hay API de consulta en esta fase) y con garantía al menos una vez: las reentregas son esperadas, por lo que la idempotencia es obligatoria en el receptor.

  • Reintentos: 1 / 2 / 5 / 15 / 60 minutos.

  • Presupuesto total: 24 horas; agotado el presupuesto, el evento pasa a dead-letter y genera alerta operacional.

  • Timeout: ~10 s por intento.

Respuesta del receptor Interpretación del emisor
2xx (se recomienda 202) ACK — evento aceptado. El cuerpo no es leído por el emisor
4xx Falla permanente, sin reintento — el evento pasa directamente a dead-letter
408 y 429 Excepciones: se tratan como falla transitoria, con reintento. En 429 el receptor puede enviar Retry-After
5xx o timeout Falla transitoria, con reintento según el cronograma

Cuándo responder: el ACK confirma que el receptor aceptó la responsabilidad por el evento, no que ya terminó de procesarlo. Responda al aceptar — persista o encole el evento y devuelva 2xx de inmediato, procesando de forma asíncrona. Procesar antes de responder consume el presupuesto de timeout del intento: si se agota, el emisor lo trata como falla transitoria y reintenta, generando una entrega duplicada de algo que el receptor ya estaba procesando. El ACK es síncrono, en la respuesta del propio POST: no existe confirmación diferida.

El contrato no tipa el cuerpo de error a propósito — el emisor sólo registra la clase del status en log. Si el receptor quiere devolver detalle, sugerimos RFC 9457 (application/problem+json).

 

Orden y deduplicación

No se garantiza el orden de llegada. Cada consentimiento es un stream propio (event.streamId), con numeración monotónica y sin saltos (event.sequence) asignada en el origen, en el orden real de los cambios de estado. La entrega, sin embargo, no está serializada: si un intento entra en reintento, el evento siguiente del mismo consentimiento puede llegar antes. Es deliberado — serializar bloquearía el stream completo detrás de un receptor no disponible.

Por lo tanto, el receptor debe:

  1. Deduplicar por x-idempotency-key, con una ventana de al menos 24 horas.

  2. Reconstruir el orden por event.sequence, nunca por el orden de llegada: guardar el mayor sequence ya aplicado por streamId y descartar el que llegue con valor menor o igual (evento antiguo o reentrega).

  3. Usar la ausencia de saltos para detectar que un evento anterior aún no ha llegado.

Como data.newState es el estado completo, aplicar last-writer-wins por sequence es seguro. El evento es la autoridad sobre el estado; el callback sirve para el detalle (permisos y metadatos), no para confirmar el estado.

 

Transporte y seguridad

La entrega es siempre sobre HTTPS (TLS 1.2+, se recomienda 1.3). La plataforma se autentica con un access token en el encabezado Authorization: Bearer, emitido por el API Gateway que publica la integración (OAuth2 client credentials).

La validación del token puede quedar en el propio API Gateway — es lo habitual cuando el endpoint de recepción se publica en él, y en ese caso el backend del receptor no necesita repetir la verificación. La exigencia es que ninguna solicitud llegue al procesamiento sin haber sido autenticada: si el endpoint también es alcanzable por fuera del gateway, el backend debe validar por su cuenta.

No hay firma del payload ni cifrado a nivel de aplicación: los eventos son livianos y no llevan datos sensibles.

 

Compatibilidad — obligaciones del receptor

El objeto data es abierto y va a crecer: se agregarán campos nuevos conforme evolucione el producto, como cambio retrocompatible. Por eso el receptor debe:

  • Ignorar campos desconocidos en data y en la envoltura, en lugar de rechazar el mensaje. Los deserializadores estrictos deben relajarse (ej. Jackson FAIL_ON_UNKNOWN_PROPERTIES=false, JsonSerializerOptions permisivo en .NET).

  • No depender del orden de las claves ni de la ausencia de un campo.

  • Tolerar valores nuevos de type y de estado: los tipos no reconocidos deben ignorarse respondiendo 2xx, nunca con 4xx/5xx — eso generaría reintentos y dead-letter innecesarios.

 

Política de versionamiento

El evento identifica su versión en contractversion, con la versión mayor del contrato (hoy "1"). Un receptor que necesite ramificar por versión debe hacerlo sobre ese valor, nunca sobre specversion.

Tipo de cambio Ejemplos Efecto
Retrocompatible Agregar campos a data o a la envoltura; agregar tipos de evento; agregar valores de estado o de reason No incrementa contractversion
Incompatible Quitar o renombrar un campo; cambiar la semántica de un campo existente; cambiar el significado de un type ya publicado Genera una versión mayor nueva

Una versión mayor nueva se anuncia con antelación y ambas conviven durante al menos 12 meses, para que la institución migre sin ventana de indisponibilidad. Nunca se reutiliza un nombre de type ya publicado con semántica distinta.

Sobre una eventual divergencia futura con la CMF: el namespace es independiente y estos tipos no cambian porque la CMF publique los suyos. Si la normativa define un homónimo con significado distinto, se trata como cambio incompatible (versión mayor nueva, comunicación previa y convivencia); si sólo agrega un estado que no teníamos, entra como tipo nuevo del catálogo — cambio retrocompatible.

 

Fuera del alcance de este contrato

  • Registro y verificación de la suscripción del endpoint.

  • Eventos del Directorio.

  • Eventos de pago (la transacción). Nota: el consentimiento de pago sí está cubierto — usa el mismo catálogo, la misma máquina de estados y el mismo subject; la única diferencia es consenttype: PAYMENT.

  • Recuperación de eventos por el receptor (feed de reconciliación tipo desde={checkpoint}): no existe en esta fase. La recuperación depende de los reintentos automáticos dentro de la ventana de 24 h — una indisponibilidad mayor puede exigir reconciliación manual entre las partes.



Actualizado en agosto/2026