> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Participantes indirectos

> Cómo una institución más pequeña llega a Pix a través de tu participación directa: la posición de liquidación que crea registrar una, cómo le llega su dinero, cómo se entera de un movimiento y qué cuesta permanentemente registrar una.

Tu institución es un **participante directo**: está presente en el sistema nacional de liquidación de Pix (SPI) por derecho propio, y este plugin es cómo llega ahí. Un **participante indirecto** es una institución más pequeña que no tiene conexión propia y llega al SPI **a través de la tuya**. Es cliente de tu institución, no cliente del riel.

Nada de esa relación existe en el BACEN. Existe en el registro de tu tenant, y la creas con `POST /v1/indirects`.

<Note>
  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](/es/interfaces/pix-jd/hosting-indirect-participants), 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.
</Note>

## Quién es responsable de qué

***

Casi todo malentendido operativo aquí es alguien buscando la respuesta en la columna equivocada.

|                             | Responsabilidad                                                                                                                      |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| Banco Central / SPI         | mueve dinero **entre instituciones**. No conoce a los clientes finales                                                               |
| JD                          | el puente técnico: entrega los avisos y firma los códigos QR. No toma decisiones de negocio                                          |
| Tú, el participante directo | la **cuenta Pix** de cada participante indirecto — que exista, esté activa y mantenga un saldo. Y la liquidación entre instituciones |
| El participante indirecto   | **las cuentas de sus propios clientes**                                                                                              |

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.

<Note>
  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.
</Note>

<h2 id="before-you-register-anyone">
  Antes de registrar a nadie
</h2>

***

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 `@pi` y ningún indirecto puede originar una orden saliente.

Dos operaciones se rechazan de plano mientras el flag está apagado, con `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.

<Note>
  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.
</Note>

## Registrar uno

***

<Steps>
  <Step title="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.
  </Step>

  <Step title="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`.
  </Step>

  <Step title="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.
  </Step>

  <Step title="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.
  </Step>
</Steps>

**El registro es atómico: un `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`.

<Warning>
  `PENDING_PROVISIONING` es un estado **retirado** con un borde filoso. Ya no se registra nada en él, y todavía se acepta como filtro en `GET /v1/indirects` para que las filas escritas antes de que el registro se volviera atómico se sigan leyendo como tales. Pero ese estado no tiene **transiciones de ciclo de vida en ninguna dirección** — una fila heredada no puede suspenderse ni puede cerrarse; toda acción sobre ella se rechaza con `409 PIX-0094`.

  Esa fila es legible, **no enrutable**, y todavía retiene su ISPB contra el índice de unicidad abierta. Así que bloquea cualquier registro nuevo de esa institución, y ninguna llamada a la API puede liberarla. Despejar una es una decisión de operador y de datos, deliberadamente no una operación de la API. Si heredaste un tenant de antes de este cambio, ejecuta `GET /v1/indirects?status=PENDING_PROVISIONING` una vez para averiguar si tienes alguna.
</Warning>

## 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.

1. **"¿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.
2. **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.
3. **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.

   Un fallo de resolución nunca se almacena en caché, así que un indirecto que acaba de activarse no queda ensombrecido por una respuesta negativa anterior.
4. **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.
5. **Se envía un aviso firmado** al `delivery.endpointUrl` que registraste, que lleva el payload de JD byte por byte. Es el plugin el que llama a la institución, no al revés.
6. **El participante indirecto acredita a su propio cliente**, en su propio core.

<Warning>
  El CRM no se consulta en la ruta indirecta. El destino proviene del registro de participación, nunca de datos que envió quien llama. Eso es deliberado: si un participante indirecto quedara mal registrado con tu propio ISPB, los créditos destinados a tu propio libro llegarían a su cuenta. Por eso la verificación "¿este ISPB es nuestro?" se ejecuta antes que la verificación "¿coincide con un participante indirecto?".
</Warning>

El aviso lleva dos headers que la institución receptora verifica:

| Header               | Valor                                                                                                                                                     |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `X-Lerian-Signature` | `sha256=` seguido del HMAC-SHA256 en hexadecimal de los bytes exactos del cuerpo sin procesar, usando como clave el `secret` registrado de ese indirecto. |
| `X-Lerian-Timestamp` | La hora de envío en segundos Unix-epoch, para que el receptor pueda acotar la repetición con su propia ventana de vigencia.                               |

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.

<Note>
  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.
</Note>

## 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](/es/reference/interfaces/pix-jd/list-indirect-participant-transactions). 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

***

```bash theme={null}
# one participation
curl -s "$PIX_JD_BASE_URL/v1/indirects/$INDIRECT_PARTICIPANT_ID" -H "Authorization: Bearer $PIX_JD_BEARER_TOKEN" | jq

# the list — filters are exact and combine with AND
curl -s -G "$PIX_JD_BASE_URL/v1/indirects" -H "Authorization: Bearer $PIX_JD_BEARER_TOKEN" \
  --data-urlencode 'status=ACTIVE' --data-urlencode 'limit=25' | jq
```

Los filtros son `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](/es/reference/interfaces/pix-jd/list-indirect-participants).

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.

```bash theme={null}
curl -s -X PATCH "$PIX_JD_BASE_URL/v1/indirects/$INDIRECT_PARTICIPANT_ID" \
  -H "Authorization: Bearer $PIX_JD_BEARER_TOKEN" -H 'Content-Type: application/json' \
  -d '{"action":"suspend"}'
```

* **`suspend`** deshabilita tanto el envío como la recepción en la cuenta `@pi` del 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. **`reactivate`** vuelve a habilitar ambos.
* **`close`** es irreversible. `CLOSED` es terminal, y después se rechaza también todo cambio de campo en la fila.

Un cierre nunca elimina nada. La cuenta `@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.

<Warning>
  **No hay DELETE en `/v1/indirects`, y `CLOSED` es terminal.** La única salida del registro es `close`, que conserva la fila y la cuenta. Un indirecto registrado por error contra un tenant activo permanece para siempre en el registro de ese tenant, y su ISPB queda retenido contra la restricción de unicidad abierta hasta que se cierra. Cada código de institución que gastas es permanente — verifica `name`, `ispb` y el endpoint de entrega antes de llamar.
</Warning>

## 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](/es/reference/interfaces/pix-jd/register-an-indirect-participant), [Actualizar un participante indirecto](/es/reference/interfaces/pix-jd/update-an-indirect-participant), [Obtener un participante indirecto](/es/reference/interfaces/pix-jd/get-an-indirect-participant), [Listar participantes indirectos](/es/reference/interfaces/pix-jd/list-indirect-participants), [Obtener el JWK Set de un participante indirecto](/es/reference/interfaces/pix-jd/get-an-indirect-participant-jwk-set), y [Listar las transacciones de un participante indirecto](/es/reference/interfaces/pix-jd/list-indirect-participant-transactions). El catálogo completo, con el `detail` exacto que lleva cada código, es la [lista de errores de Pix JD](/es/reference/interfaces/pix-jd/pix-jd-error-list).

<Note>
  **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.
</Note>

## A dónde ir después

***

* **[Hospedar participantes indirectos](/es/interfaces/pix-jd/hosting-indirect-participants)** — el aprovisionamiento: la clave de cifrado, la postura, y la llamada de registro.
* **[Registrar un participante indirecto](/es/reference/interfaces/pix-jd/register-an-indirect-participant)** — el contrato de solicitud completo y todo rechazo.
* **[Listar las transacciones de un participante indirecto](/es/reference/interfaces/pix-jd/list-indirect-participant-transactions)** — el feed de conciliación, con las reglas de paginación completas.
* **[Actualizar un participante indirecto](/es/reference/interfaces/pix-jd/update-an-indirect-participant)** — cambios de campo, acciones de ciclo de vida y la configuración del certificado propio.
* **[Pix Directo vía JD](/es/interfaces/pix-jd/direct-pix-via-jd)** — la participación directa sobre la que se apoya todo esto, y cómo los movimientos liquidados llegan a Midaz.
