Saltar al contenido principal
Para liquidar un Pix en el Banco Central, una institución necesita una conexión con la infraestructura del Sistema Financiero Nacional. Esa conexión es cara y lenta de obtener, y no todas las instituciones tienen una. Una institución sin ella usa la conexión de otra institución. Se convierte en participante indirecto, y un participante directo liquida por ella y la hospeda. El modelo directo e indirecto explica ese arreglo: quién mantiene la cuenta de liquidación, y dónde se aloja el dinero de cada institución. Un tenant que hospeda participantes indirectos es primero un participante directo. Completa los pasos 1 a 7 de Configurar el riel exactamente como lo indica esa página. Esta página es su paso 8 para un despliegue que liquida Pix para otras instituciones. Si tu despliegue liquida solo el Pix de sus propios clientes, omite esta página.
Haz el paso 1 antes del paso 3. Sin la clave de cifrado, todo registro falla. Haz el paso 2 antes del paso 4: con la postura apagada, el paso del certificado se rechaza con 422 PIX-0111. Haz el paso 4 y el paso 5 después del paso 3, porque ambos actúan sobre la participación que el registro crea. Los pasos 4 y 5 no dependen entre sí.
Esta página cubre el aprovisionamiento. Participantes indirectos explica qué es una participación hospedada, cómo le llega un crédito entrante, cómo se comporta su ciclo de vida y cada rechazo que puede responder.
Para dar a un participante indirecto una credencial propia de Pix JD, consulta Socios en Pix JD.

Paso 1: la clave de cifrado del secreto de entrega

En SaaS, no hay nada que hacer en este paso. Lerian configura la clave para tu tenant. Sigue al paso 2. El resto de este paso se aplica a un despliegue self-hosted.
Por qué existe este paso. Cuando registras un participante indirecto, entregas un secreto de entrega. El plugin firma con él cada aviso que envía al endpoint de esa institución. Así la institución sabe que el aviso realmente vino de ti. Ese secreto se almacena cifrado, y la clave que lo cifra no viene de la base de datos. Viene de afuera. Si la clave no está configurada, todo registro que lleve un secreto falla. Esa falla cubre toda la superficie de escritura del flujo indirecto.
El mensaje garantiza que no se almacenó ningún secreto. El cifrado falla antes de cualquier escritura, así que no hay una fila a medio crear con un secreto en texto plano que haya que ir a limpiar. Corrige la clave y repite el POST. Esa es toda la recuperación.
Este 409 significa “aprovisiónala”, no “vuelve a intentarlo más tarde”. El riel buscó la clave y encontró que no existe. Solo un operador puede agregarla. Si repites la llamada sin ese cambio, falla de la misma forma. Por eso el código es un 409 y no dice nada sobre un reintento.Su hermano es 503 PIX-0123, “Indirect delivery key source unavailable”. Lo obtienes cuando el riel no pudo leer la clave, porque su fuente de la clave la rechazó o no respondió. Entonces el riel no sabe que la clave no existe, porque la lectura no se completó. La respuesta nombra la dependencia que falló, y un reintento es la acción correcta. Ambos códigos rechazan el registro y no almacenan nada. El par permite distinguir una configuración incompleta de una caída.
El plugin arranca sin la clave, y no se niega a arrancar. El proceso escribe una advertencia en el log al iniciar y levanta sano. En el arranque, nada distingue un despliegue que va a hospedar participantes indirectos de uno que nunca registra ninguno. Así que el síntoma llega en el primer registro, no en el despliegue. Si no leíste el log de arranque, el rechazo es tu primer aviso.
Dónde vive, y por qué no está en el systemplane. Este contraste explica dónde va cada tipo de valor en este riel.
No pongas la clave de cifrado en el systemplane. El systemplane es el plano de configuración en vivo, legible por la API de administración, y ese es el hogar correcto para todo lo que no es un secreto. El material de credenciales no va ahí, y el riel separa los dos a propósito.Tampoco la guardes en un commit: ni en un .env versionado, ni en un values.yaml, ni en un archivo de compose.
El formato: exactamente 64 caracteres hexadecimales. Es una clave AES-256 (32 bytes), codificada en hexadecimal. Eso es 64 caracteres hexadecimales, ni 63 ni 65.
Genera una por despliegue. No copies la clave de otro entorno y no reutilices la de otro servicio.
Un valor ausente, en blanco o mal formado producen todos el mismo 409 PIX-0107. No hay valor predeterminado ni degradación a guardar el secreto en claro. Eso es deliberado: un valor predeterminado silencioso aquí guardaría los secretos de los clientes cifrados con una clave que todo el mundo conoce.
En un despliegue self-hosted, define la variable de despliegue:
Ese marcador de posición deliberadamente no es una clave válida. Pegado tal cual, falla en modo cerrado con el rechazo anterior. No cifra los secretos de tus clientes con un valor publicado en una página de documentación. El plugin lee la clave al arrancar, así que un cambio necesita reiniciar el proceso. El vínculo del ISPB es distinto: el plugin lo lee en cada llamada, y un cambio tiene efecto sin reinicio.
No escribas el valor en una línea de comandos. Termina en el historial de tu shell y en los logs de CI. Léelo de un vault, o escríbelo con read -rs, que no hace eco.
Cómo verificar que quedó aplicada. Ninguna ruta lee la clave de vuelta, porque es un secreto. Hay dos señales. El log de arranque. Con la clave resoluble, la advertencia “key unavailable” no aparece. Si aparece, ningún registro que lleve un secreto pasará. El comportamiento. Registra un participante indirecto. La respuesta cambia de 409 PIX-0107 a 201.
Piensa antes de usar la verificación por comportamiento. Un registro es permanente. No hay ruta de eliminación, y la única salida es close, que conserva la fila y retiene el ISPB. En un entorno de producción, no uses un registro desechable para probar la clave. Usa un ISPB que pienses operar. El log de arranque te ahorra ese costo.

Paso 2: declara que este tenant hospeda participantes indirectos

Define plugin-br-pix-jd.indirects/enabled en true. Es una escritura de configuración, así que exige Plugin PIX JD Editor.
El plugin responde 204 cuando acepta el valor. El valor es un booleano JSON, sin comillas: {"value":"true"} responde 400. El registro funciona con la postura apagada, así que puedes registrar participantes antes de habilitarla. La postura controla las rutas del dinero y el certificado de QR propio del paso 4. Con la postura apagada, el paso 4 responde 422 PIX-0111. Antes de registrar a nadie muestra lo que hace cada mitad.
La lectura falla en modo cerrado. Cuando una ruta del dinero “vuelve a comportarse como directa” y nadie cambió la clave, esta es la causa. Mira el systemplane.

Paso 3: registra un participante indirecto

Una sola llamada hace todo el ensamblado. Verifica el ISPB, crea la cuenta de liquidación @pi_{ispb} en Midaz y marca la participación como activa. Exige Plugin PIX JD Contributor o Plugin PIX JD Editor.
Un 201 significa que la participación está lista para usar. El status siempre es ACTIVE. No necesitas hacer polling.
No escribas el ISPB de un participante indirecto en tenancy/jd_integration_binding. Esa clave es la identidad que el plugin presenta a JD. El ISPB de un tercero ahí hace que el plugin se presente como otra institución. Nada te avisa: el plugin acepta cualquier ISPB válido, y la escritura responde 204. La clave es una por tenant, no una por participante indirecto. Cada participante indirecto que hospedas llega al SPI a través de tu ISPB.
El registro es permanente. No hay DELETE en /v1/indirects, y CLOSED es terminal. Un registro hecho por error en un tenant en vivo se queda ahí. Su ISPB queda retenido contra la regla de unicidad hasta que alguien lo cierre. Revisa el nombre, el ISPB y el endpoint antes de llamar. Ensaya en un entorno desechable.
Participantes indirectos tiene los rechazos, las acciones del ciclo de vida y cómo leer el registro de vuelta.

Paso 4: configura su propio certificado de QR, si tiene uno

Omite este paso para un participante indirecto que no tiene un certificado de QR propio en JD. Sus códigos QR dinámicos se firman entonces con tu certificado y se sirven en tu host, como para tus propios clientes. Por qué existe este paso. Algunos participantes indirectos tienen su propio certificado de QR en JD. JD firma entonces sus códigos QR dinámicos con ese certificado. La app del pagador verifica la firma contra el conjunto de claves que encuentra en el mismo host que el payload del QR. Por eso el payload y el conjunto de claves de ese participante deben estar en el host propio del participante, no en el tuyo. Acceso: Plugin PIX JD Contributor o Plugin PIX JD Editor.
1

Nombra el host del participante

Envía PATCH /v1/indirects/{indirectId} con el indirectId del registro:
El presupuesto de 77 caracteres. JD limita la URL de un payload de QR a 77 caracteres. El plugin la arma como publicBaseUrl, luego QRCODE_PAYLOAD_PATH, luego, en SaaS, el ISPB de tu institución, luego el tipo del cobro y un identificador de hasta 22 caracteres. Con el QRCODE_PAYLOAD_PATH predeterminado, qr, quedan 37 caracteres para el host. Un despliegue con un QRCODE_PAYLOAD_PATH más largo deja menos. Entonces cada código QR dinámico de este participante responde 422 PIX-0112. Elige el host contra ese presupuesto antes de registrarlo.Un 200 devuelve la participación. Verifica que qrCertificate.ownCertificate sea true y que qrCertificate.publicBaseUrl sea el host que enviaste.
2

Publica el conjunto de claves del participante en su host

El participante no puede generar su conjunto de claves por sí mismo, porque JD tiene el certificado y firma. Lee el conjunto de claves desde el plugin:
La respuesta es un documento application/jwk-set+json. Sirve esos bytes tal como están, con ese tipo de medio, en https:// más el host del participante más / más QRCODE_JWK_PATH. Con el QRCODE_JWK_PATH predeterminado, eso es https://pix.indirect.example.com/v1/qrcodes/jwks. En SaaS, la ruta termina con un segmento más: el ISPB de tu institución, por ejemplo https://pix.indirect.example.com/v1/qrcodes/jwks/12345678. Lee el conjunto de claves de nuevo cada vez que JD rote el certificado del participante.El header X-JWK-Set-Freshness dice fresh o stale. stale significa que JD no respondió y el plugin sirvió su última copia. Léelo de nuevo antes de publicar.
Los payloads también van al host del participante. Cuando creas un código QR dinámico con el indirectId de este participante, el plugin no sirve su payload. La respuesta trae payloadJws, y el participante lo sirve en payloadUrl en su propio host. Crear un código QR dinámico describe esa respuesta, y cómo recuperar un payload que no recibiste.

Paso 5: fondea la posición

El registro crea la cuenta @pi_{ispb} vacía. Un Pix entrante la acredita, pero un pago saliente necesita saldo primero. Sin fondos, todo pago que sale a través de ese participante indirecto falla por saldo insuficiente. Tú haces la carga inicial. Refleja el arreglo: en JD administras el límite de esa institución, y en tu ledger cargas su posición. La mecánica es la misma que la del paso de fondeo de Configurar el riel. Contabiliza una transacción de Midaz desde @external/BRL, con las mismas variables que esa página. Solo cambia el destino, al piAccountAlias del registro. Es una transacción de Midaz, así que exige Midaz Editor o Midaz Contributor.
Si pierdes la respuesta de una recarga, envía de nuevo el cuerpo exactamente igual dentro de 300 segundos. Midaz entonces registra la recarga una sola vez. Después de esa ventana, revisa el saldo de la posición antes de enviar la recarga de nuevo.Cambia la description solo para una recarga nueva. Una description nueva en un reintento real agrega un segundo crédito por error.
La posición también controla la salida de la participación. El plugin rechaza close con 409 PIX-0096 mientras la cuenta @pi mantiene fondos, disponibles o retenidos, y nombra la causa. Lleva la posición a cero antes de cerrar. Una posición con fondos mantiene la participación abierta hasta que lo hagas. Cómo verificar. Lee el saldo de la cuenta de vuelta en Midaz. La verificación más segura es por comportamiento: un pago saliente a través del participante indirecto deja de recibir rechazos por saldo insuficiente.

Declara al cliente del participante indirecto

Un participante indirecto mantiene a sus clientes en su propio core, no en tus libros. Una solicitud para uno de esos clientes declara al cliente, y no nombra ninguna cuenta tuya: Cada solicitud también lleva el indirectId. El plugin no lee ningún registro del cliente declarado, y lo envía a JD.
  • Una solicitud con el cliente declarado y una cuenta (accountId, o account_id en la consulta), o sin ninguno de los dos, responde 400 PIX-0061.
  • Una cuenta funciona cuando tu propia credencial envía la solicitud. Con un socio detrás de la solicitud, la cuenta responde 400 PIX-0061.
  • El plugin no revisa ningún límite de cuenta en una orden con un pagador declarado. El saldo de la posición @pi_{ispb} limita la orden.
  • Un accountType 4 declarado responde 422 PIX-0098.

Devolver un Pix que recibió un participante indirecto

Un Pix para un cliente de un participante indirecto llega a la posición @pi_{ispb} de ese participante. Para devolverlo, envía POST /v1/refunds con el indirectId de ese participante. La devolución entonces debita esa posición. No necesita accountId: quien devuelve es el receptor que nombra el Pix original. Con un socio detrás de la solicitud, un accountId responde 400 PIX-0061. El plugin rechaza la devolución en estos casos, y no mueve dinero:
  • 422 PIX-0135: el Pix original llegó a la posición de un participante indirecto, y la devolución no tiene indirectId.
  • 404 PIX-0147: la devolución nombra a otro participante indirecto, o el Pix original llegó a una cuenta directa y la devolución tiene un indirectId.
El indirectId pasa las mismas verificaciones que en una orden de pago. La postura de hospedaje debe estar encendida, y la participación debe estar en ACTIVE.

Las claves del systemplane del namespace indirects

Hay cinco claves, todas en plugin-br-pix-jd.indirects, y todas existen siempre. Las tres claves de entrega y de resolución tienen efecto solo cuando enabled es true, porque ajustan las rutas del dinero. validate_ispb_on_jd es la excepción. Controla un paso del registro, que funciona mientras enabled sigue en false.
El plugin responde 204 cuando acepta un valor y 400 cuando el validador lo rechaza. Los booleanos y los enteros van sin comillas. Un valor fuera del rango responde 400. El plugin no lo recorta.
Los dos pasos que por sí solos pueden detener el flujo indirecto no están en este namespace. La identidad es la clave del systemplane tenancy/jd_integration_binding. Sin ella, todo pago falla con 409 PIX-0092. La clave de cifrado viene de una variable de despliegue o de un almacén de secretos. Sin ella, todo registro falla con 409 PIX-0107.