POST /v1/indirects.
Esta página es lo que es una participación hospedada y cómo se comporta. El aprovisionamiento — la clave de cifrado del secreto de entrega, la postura de hospedaje y la llamada de registro misma — es Hospedar participantes indirectos, que continúa la numeración de la página de configuración. De esos, solo la clave de cifrado rechaza todo registro por sí sola — aprovisiónala primero. La postura de hospedaje controla las rutas del dinero, no el registro, así que puedes registrar participantes antes de activarla.
Quién es responsable de qué
Casi todo malentendido operativo aquí es alguien buscando la respuesta en la columna equivocada.
En la práctica: cuando llega un Pix para un cliente de un participante indirecto, el dinero se detiene en ti, en una cuenta que representa la posición de esa institución. Tú no sabes — y no puedes saber — cuál de sus clientes es el dueño. El participante indirecto acredita a su cliente en su propio core, después de recibir tu aviso.
Qué crea registrar uno
Registrar un participante indirecto hace más que escribir una fila. El plugin también crea la posición de liquidación de esa institución en Midaz: una cuenta del ledger cuyo alias es
@pi_ seguido del ISPB de la institución, el código de ocho dígitos que BACEN asigna a cada participante. Un indirecto con ISPB 12345678 liquida en @pi_12345678.
Esa posición es donde se aloja el dinero de esa institución. La respuesta la devuelve como piAccountAlias, y el alias se deriva de ispb — tú nunca lo eliges, y un cliente nunca crea la cuenta.
Una posición por institución es precisamente el objetivo. Un crédito que llega para un indirecto aterriza solo en la cuenta de ese indirecto, así que el dinero de una institución nunca se mezcla con el de otra ni con el tuyo. Esa segregación es la propiedad que el registro existe para ofrecer.
El alias usa un guion bajo, no una barra:
@pi_12345678. Midaz rechaza una barra en un alias de usuario, así que un nombre con forma de ruta no resuelve a nada.Antes de registrar a nadie
La participación indirecta está apagada de forma predeterminada. El flag de systemplane por tenant
plugin-br-pix-jd.indirects/enabled debe estar activo, y su valor predeterminado es false.
Vale la pena saber qué controla realmente el flag, porque las dos mitades se comportan distinto:
- La API de gestión funciona con el flag apagado. Puedes registrar participantes, listarlos y leer uno antes de la habilitación. La incorporación previa al lanzamiento es deliberada.
- Ningún dinero se mueve con el flag apagado. La resolución — el paso que decide a qué indirecto pertenece un crédito entrante — reporta la función como deshabilitada, así que un crédito entrante nunca se enruta a una cuenta
@piy ningún indirecto puede originar una orden saliente.
422 PIX-0111: la escritura del certificado QR propio en PATCH /v1/indirects/{indirectId}, y GET /v1/indirects/{indirectId}/jwks.
Una cosa sigue funcionando con el flag apagado que podrías esperar que estuviera controlada: la cola de excepciones, para que un crédito ya estacionado para revisión nunca quede atrapado detrás de un interruptor.
La lectura falla de forma cerrada. Si el systemplane no responde, si el valor no resuelve, o si llega con el tipo equivocado, el plugin lee el flag como apagado — nunca activo por accidente. Una ruta de dinero que “volvió a comportarse como una directa” sin que nadie haya tocado la clave es este mecanismo. Revisa el systemplane.
Registrar uno
1
Activa la función para el tenant
Define
plugin-br-pix-jd.indirects/enabled en true. El registro funciona sin ella, pero nada liquida hasta que esté activa.2
POST /v1/indirects
Envía el
name de la institución, su ispb, y un bloque delivery que contenga endpointUrl (una URL HTTPS) y secret. La respuesta es 201 y trae indirectId — el identificador por el que se enruta cada llamada posterior — y piAccountAlias.3
Nada por lo que hacer polling — un 201 significa listo
Cada paso se ejecuta antes de escribir la fila del registro: la verificación de unicidad del ISPB, la verificación opcional en el directorio de JD, y luego la creación de la cuenta
@pi_{ispb} en Midaz. Solo entonces se escribe la fila, y se escribe como ACTIVE. No hay estado intermedio ni nada que esperar.4
Ante una falla, corrige la causa y vuelve a hacer POST
Un paso fallido responde con un error codificado que nombra el paso, y no se escribe ninguna fila en el registro, así que el ISPB sigue libre. Corrige la causa y vuelve a hacer POST — volver a enviarlo es la recuperación, y no hay una ruta de reintento separada porque nada quedó a medio escribir para reanudar.
201 significa listo, y una falla no deja fila en el registro. status en un 201 siempre es ACTIVE. Si estás escribiendo un cliente que hace polling hasta que el participante se vuelve enrutable, elimina ese bucle — está esperando una transición que no puede ocurrir.
Lo único que una falla puede dejar atrás es la cuenta de liquidación, cuando ese paso tuvo éxito y uno posterior no. No se revierte, y es inofensiva: nada se enruta a una cuenta @pi sin una fila ACTIVE en el registro que apunte a ella, y crear la cuenta es idempotente por alias, así que tu siguiente intento adopta la misma cuenta en lugar de crear una segunda. Lo que una falla nunca deja es una fila en el registro o un ISPB retenido.
La respuesta todavía trae un objeto provisioning con un campo failedStep. Es heredado y siempre null para todo lo que este servicio registra, porque un registro fallido no deja fila que lleve un marcador.
Los estados del ciclo de vida son ACTIVE, SUSPENDED y CLOSED.
Cómo el dinero llega a un participante indirecto
Sigue un Pix entrante. Nada en esta ruta es un endpoint que el indirecto llama; es tu plugin el que hace el trabajo.
- “¿Esta cuenta puede recibir?” Antes de mover el dinero, el Banco Central pregunta si la cuenta de destino acepta el crédito. La pregunta llega a ti, porque el participante indirecto no tiene línea al SPI.
- Llega un Pix para una cuenta que se mantiene en la institución indirecta y alcanza tu participación directa, entregado al webhook de cash-in del plugin.
-
La resolución encuentra al indirecto por el ISPB en el bloque del receptor, buscado en el registro de participación. Cuatro resultados, y solo el primero acredita a un indirecto:
- coincide con una participación
ACTIVE, así que el crédito se contabiliza en el alias@pi_{ispb}de esa participación; - es tu propio ISPB, así que es tu libro, y el CRM resuelve la cuenta como de costumbre;
- no coincide con nada, o coincide con una participación suspendida o cerrada, así que el crédito queda estacionado para que un operador lo revise;
- la resolución falla por infraestructura, así que el plugin no acredita ni estaciona. Falla de forma cerrada a propósito: nada relacionado con dinero se supone.
- coincide con una participación
-
El crédito se contabiliza en
@pi_{ispb}. El plugin registra el movimiento contra esa posición de liquidación y vincula su propio registro de transacción con el indirecto. El aviso se registra en la misma transacción de base de datos que el crédito — o existen ambos, o no existe ninguno. -
Se envía un aviso firmado al
delivery.endpointUrlque registraste, que lleva el payload de JD byte por byte. Es el plugin el que llama a la institución, no al revés. - El participante indirecto acredita a su propio cliente, en su propio core.
La entrega es al menos una vez. El mismo aviso puede reenviarse después de una falla reintentable o una caída entre el envío y el registro contable, y el
endToEndId es estable entre intentos — así que un receptor debe deduplicar por endToEndId y tratar un payload repetido como ya procesado.
El
secret almacenado es de solo escritura. Cada lectura de un indirecto devuelve delivery.secret como ***, así que un secreto perdido se reemplaza con un PATCH, nunca se recupera.Cuando el aviso nunca llega
El envío puede fallar de forma permanente — se agotan los reintentos, o el endpoint responde
4xx, después de lo cual el aviso se marca inválido y no se vuelve a intentar. El dinero se contabiliza correctamente de cualquier forma. La consecuencia es más puntual y peor de lo que suena: el movimiento es real, y la institución no lo sabe.
GET /v1/indirects/{indirectId}/transactions es lo que cierra esa brecha. Devuelve los movimientos que realmente se liquidaron en la cuenta @pi_{ispb} de un indirecto, lo que la convierte en el registro autoritativo en lugar del aviso. Barrerla según una programación es cómo una institución deja de depender de que la entrega haya funcionado, y también es la única forma de releer una ventana después de una interrupción propia.
Las reglas de ventana, paginación y unidad que deciden si una conciliación es correcta — la ventana since semiabierta obligatoria, los centavos como enteros, la paginación por cursor de más antiguo a más reciente, el limit recortado en silencio — son el contrato de Listar las transacciones de un participante indirecto. Leer el feed no cambia nada y no reenvía ningún aviso.
Hospedar el código QR bajo el certificado propio de la institución
De forma predeterminada, un código QR dinámico emitido para un indirecto se firma y se publica bajo tu participación directa. Un indirecto puede publicar el suyo propio en su lugar: define
qrCertificate.ownCertificate con un publicBaseUrl en PATCH /v1/indirects/{indirectId}, y el documento firmado se sirve desde el host propio de la institución.
La institución no puede producir las claves de validación por sí misma, porque JDPI mantiene el certificado y hace la firma. GET /v1/indirects/{indirectId}/jwks devuelve el JWK Set de ese indirecto para que la institución pueda publicarlo en su propio host, para que los PSP pagadores validen contra él. Obtenlo cuando configures el certificado y de nuevo cada vez que rote.
El estado del ciclo de vida deliberadamente no controla esa lectura: un indirecto suspendido o cerrado todavía tiene códigos QR activos en circulación, y retener la clave rompería su validación.
Leer el registro
status e ispb (8 dígitos, exactos); las reglas de paginación por cursor y el limit recortado en silencio son el contrato de Listar participantes indirectos.
Un GET por id, y la lista, son siempre la verdad actual. Las rutas del dinero leen una proyección en caché, así que una suspensión puede tardar hasta el TTL de la caché de resolución — 30 segundos de forma predeterminada — en verse en cada réplica. El bloqueo del ledger de suspend ya se aplicó en el momento de la llamada.
Suspender, reactivar y cerrar
PATCH /v1/indirects/{indirectId} lleva como máximo un action de ciclo de vida — suspend, reactivate o close — y cada uno escribe tanto el ledger como el registro.
suspenddeshabilita tanto el envío como la recepción en la cuenta@pidel indirecto. El ledger mismo rechaza el dinero de ese participante, por lo que una suspensión se mantiene incluso en una réplica cuya caché de resolución todavía está desactualizada.reactivatevuelve a habilitar ambos.closees irreversible.CLOSEDes terminal, y después se rechaza también todo cambio de campo en la fila.
@pi queda bloqueada de forma permanente pero se conserva, así que un registro posterior del mismo ISPB reutiliza la cuenta histórica — desbloqueada, reactivada, y con su historial contable intacto.
Un PATCH que lleva solo campos y ningún action cambia esos campos. Un PATCH que no lleva nada es un no-op que devuelve la fila actual, no un error.
Qué sale mal
Todo rechazo que este registro puede responder — su estado, su condición exacta, y qué se escribió o no cuando se disparó — está en las páginas de operación: Registrar un participante indirecto, Actualizar un participante indirecto, Obtener un participante indirecto, Listar participantes indirectos, Obtener el JWK Set de un participante indirecto, y Listar las transacciones de un participante indirecto. El catálogo completo, con el
detail exacto que lleva cada código, es la lista de errores de Pix JD.
Si conviene reintentar lo decide el estado, no la familia del código.
PIX-0107 y PIX-0123 son la misma condición vista dos veces: un 409 significa que el riel leyó la configuración y estableció que la clave está ausente — solo un operador cambia eso, así que reintentar se repite para siempre. Un 503 significa que la lectura misma no se completó, así que no se sabe que la clave falte, y reintentar es correcto. Ninguno de los dos almacena nada.A dónde ir después
- Hospedar participantes indirectos — el aprovisionamiento: la clave de cifrado, la postura, y la llamada de registro.
- Registrar un participante indirecto — el contrato de solicitud completo y todo rechazo.
- Listar las transacciones de un participante indirecto — el feed de conciliación, con las reglas de paginación completas.
- Actualizar un participante indirecto — cambios de campo, acciones de ciclo de vida y la configuración del certificado propio.
- Pix Directo vía JD — la participación directa sobre la que se apoya todo esto, y cómo los movimientos liquidados llegan a Midaz.

