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

# Hospedar participantes indirectos

> Los tres pasos de aprovisionamiento que agrega un despliegue cuando liquida Pix en nombre de otras instituciones: la clave de cifrado del secreto de entrega, la postura de hospedaje, el registro de cada participante indirecto y las claves del systemplane del namespace indirects.

Para liquidar un Pix en el Banco Central, una institución tiene que estar conectada a la infraestructura del Sistema Financiero Nacional. Eso es caro y lento, y no todas las instituciones lo hacen. Una institución que no lo hace usa la conexión de otra: se convierte en **participante indirecto**, y un participante directo liquida por ella y la **hospeda**.

Un tenant que hospeda participantes indirectos es primero un participante directo. Todo lo que está en [Configurar el riel](/es/interfaces/pix-jd/pix-jd-setup) — el vínculo del ISPB, la organización, el ledger, el activo, las cuentas, los registros del CRM, las veinte rutas contables — se aprovisiona exactamente como está escrito allí. Llama a eso la cadena del participante directo, pasos 1 a 6. Esta página es lo que agregas encima, y su numeración continúa desde ahí. Si tu despliegue liquida solo el Pix de sus propios clientes, omite esta página.

| # | Paso                                                                | Dónde                                                            |
| - | ------------------------------------------------------------------- | ---------------------------------------------------------------- |
| 1 | el ISPB de este despliegue (`tenancy/jd_integration_binding`)       | [la página de configuración](/es/interfaces/pix-jd/pix-jd-setup) |
| 2 | organización, ledger, activo, cuentas, titulares del CRM            | [la página de configuración](/es/interfaces/pix-jd/pix-jd-setup) |
| 3 | los veinte tramos de rutas contables                                | [la página de configuración](/es/interfaces/pix-jd/pix-jd-setup) |
| 4 | el activo del asiento y la cuenta de compensación                   | [la página de configuración](/es/interfaces/pix-jd/pix-jd-setup) |
| 5 | la ventana diaria                                                   | [la página de configuración](/es/interfaces/pix-jd/pix-jd-setup) |
| 6 | las filas de límites de transacción, que no tienen ruta de creación | [la página de configuración](/es/interfaces/pix-jd/pix-jd-setup) |
| 7 | **la clave de cifrado del secreto de entrega**                      | abajo                                                            |
| 8 | **la postura de hospedaje, `indirects/enabled = true`**             | abajo                                                            |
| 9 | **el registro de cada participante indirecto**                      | abajo                                                            |

<Warning>
  El paso 7 va antes del paso 9, no después: sin la clave de cifrado, todo registro del paso 9 falla. Los pasos 7 y 8 son independientes entre sí — la postura no valida la clave, y la postura tampoco lee la clave.
</Warning>

<Note>
  Esta página es el aprovisionamiento. 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 están en [Participantes indirectos](/es/reference/interfaces/pix-jd/indirect-participants).
</Note>

### Paso 7: la clave de cifrado del secreto de entrega

**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, y 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.** Esto no es un caso límite — es toda la superficie de escritura del flujo indirecto.

```text theme={null}
409  PIX-0107  "Indirect Delivery Encryption Not Provisioned"
     "No delivery-secret encryption key is provisioned for this tenant, so the
      indirect participant was not saved and no secret was stored. ..."
```

Lee la garantía en medio de esa frase: **no secret was stored**. 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. Corregir la clave y repetir el `POST` es toda la recuperación.

<Note>
  **Aquí `409` significa "aprovisiónala", no "vuelve a intentarlo más tarde".** El riel buscó la clave y estableció que no está, y solo un operador puede ponerla ahí — así que repetir la llamada sin ese cambio falla de forma idéntica. Por eso el código es un `409` y no dice nada sobre reintentar.

  Su hermano es `503 PIX-0123`, *"Indirect delivery key source unavailable"*, que es lo que obtienes cuando la clave **no se pudo leer**: el backend de custodia la rechazó o no respondió. Ahí **no** se sabe que la clave falte — la lectura misma no se completó — por lo que la respuesta nombra la dependencia que falla y reintentar es la jugada correcta. Ambos rechazan el registro y no almacenan nada; el par existe para que puedas distinguir una configuración incompleta de una caída.
</Note>

<Warning>
  El plugin arranca sin la clave. No hay rechazo en el arranque: el proceso escribe una advertencia en el log al iniciar y levanta sano, porque nada en el arranque distingue un despliegue que va a hospedar participantes indirectos de uno que nunca registra ninguno — la clave se lee en cada solicitud, no una sola vez al arrancar. 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.
</Warning>

**Dónde vive, y por qué no está en el systemplane.** Este contraste explica dónde va cada tipo de valor en este riel.

|                 | El ISPB (`tenancy/jd_integration_binding`)                                         | La clave de cifrado                                           |
| --------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------- |
| Qué es          | **identidad** — el número que te identifica ante BACEN                             | **una credencial** — material criptográfico                   |
| ¿Es un secreto? | no. Un ISPB, un id de organización y un id de ledger no son credenciales           | sí                                                            |
| Dónde vive      | el **systemplane**, para que se pueda leer y escribir por la API de administración | **fuera** del systemplane                                     |
| De dónde viene  | la API de administración del systemplane                                           | la variable de despliegue `INDIRECTS_DELIVERY_ENCRYPTION_KEY` |

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

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

```bash theme={null}
openssl rand -hex 32
```

Genera una por despliegue. No copies la clave de otro entorno y no reutilices la de otro servicio.

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

En single-tenant, define la variable de despliegue:

```bash theme={null}
# in the process environment — never in a versioned file
INDIRECTS_DELIVERY_ENCRYPTION_KEY="paste-the-64-hex-characters-here"
```

Ese marcador de posición deliberadamente no es una clave válida: pegado tal cual, falla en modo cerrado con el rechazo anterior en lugar de cifrar los secretos de tus clientes con un valor publicado en una página de documentación.

Se lee al arrancar, así que cambiarla necesita reiniciar el proceso. Eso es distinto del vínculo del ISPB, que se lee en cada llamada y se sana sin reinicio.

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

**Cómo verificar que quedó aplicada.** Ninguna ruta lee la clave de vuelta, y así debe ser — 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 pasa de `409 PIX-0107` a `201`.

<Warning>
  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. No gastes un registro desechable para probar la clave en un entorno de producción; usa un ISPB que realmente pienses operar. El log de arranque te ahorra ese costo.
</Warning>

### Paso 8: declara que este tenant hospeda participantes indirectos

`plugin-br-pix-jd.indirects/enabled` tiene que ser `true`.

```bash theme={null}
curl -s -o /dev/null -w '%{http_code}\n' -X PUT \
  -H "Authorization: Bearer $PIX_JD_BEARER_TOKEN" -H 'Content-Type: application/json' \
  -d '{"value":true}' \
  "$PIX_JD_BASE_URL/system/plugin-br-pix-jd.indirects/enabled"
```

`204` cuando se acepta. Es un booleano JSON, sin comillas: `{"value":"true"}` responde `400`.

La API de gestión funciona con la postura apagada, así que puedes registrar participantes antes de habilitarla — lo que la postura controla son las rutas del dinero. El desglose completo de lo que hace cada mitad está en [Antes de registrar a nadie](/es/reference/interfaces/pix-jd/indirect-participants#before-you-register-anyone).

<Note>
  La lectura falla en modo cerrado. Si el systemplane no responde, si la clave no se resuelve, o si el valor vuelve con el tipo equivocado, el plugin lo lee como **apagado** — nunca encendido por accidente. Una ruta del dinero que "volvió a comportarse como una directa" sin que nadie haya tocado la clave es este mecanismo. Mira el systemplane.
</Note>

### Paso 9: registra un participante indirecto

Una sola llamada ejecuta todo el ensamblado: verifica el ISPB, crea la cuenta de liquidación `@pi_{ispb}` en Midaz y marca la participación como activa.

```bash theme={null}
# The signing secret must never appear in a process argument list: `ps` and
# command logging expose arguments. Read it silently, export it, let jq pull it
# from the environment, and have curl read the body from standard input.
IFS= read -r -s -p 'delivery secret for this participant: ' INDIRECT_DELIVERY_SECRET; printf '\n'
export INDIRECT_DELIVERY_SECRET

jq -n '{
  name: "Indirect PSP Ltda",
  ispb: "87654321",
  messagingMode: "raw",
  delivery: { endpointUrl: "https://indirect.example.com/pix", secret: env.INDIRECT_DELIVERY_SECRET }
}' | curl -s -X POST "$PIX_JD_BASE_URL/v1/indirects" \
  -H "Authorization: Bearer $PIX_JD_BEARER_TOKEN" -H 'Content-Type: application/json' \
  --data-binary @-
unset INDIRECT_DELIVERY_SECRET
```

| Campo                  | Regla                                                                       | Si está mal                    |
| ---------------------- | --------------------------------------------------------------------------- | ------------------------------ |
| `name`                 | de 1 a 120 caracteres                                                       | `422 PIX-0098`                 |
| `ispb`                 | exactamente 8 dígitos — el ISPB de la **institución indirecta**, no el tuyo | `422 PIX-0098`                 |
| `delivery.endpointUrl` | una URL `https` válida, donde se entregan los avisos                        | `422 PIX-0098`                 |
| `delivery.secret`      | el secreto simétrico de firma, acordado con esa institución                 | `422 PIX-0098` si está ausente |
| `messagingMode`        | `raw` es el único valor hoy                                                 | `422 PIX-0098`                 |

Un `201` significa que la participación está lista para usar: el registro es atómico, `status` siempre es `ACTIVE`, y no hay nada por lo que hacer polling.

<Warning>
  No escribas el ISPB de un participante indirecto en `tenancy/jd_integration_binding`. Esa clave es la identidad que el plugin presenta a JD, así que el ISPB de un tercero ahí hace que el plugin se presente como otra institución — y nada te avisa, porque 8 dígitos válidos se aceptan y la escritura responde `204`. La clave es una por participante directo, no una por participante indirecto: cada participante indirecto que hospedas llega al SPI a través de tu ISPB.
</Warning>

<Warning>
  **El registro es permanente.** No hay `DELETE` en `/v1/indirects`, y `CLOSED` es terminal. Un participante indirecto registrado por error en un tenant en vivo no vuelve a salir, y 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.
</Warning>

Los rechazos, las acciones del ciclo de vida y cómo leer el registro de vuelta están en [Participantes indirectos](/es/reference/interfaces/pix-jd/indirect-participants).

### Las claves del systemplane del namespace `indirects`

Cinco claves, todas en `plugin-br-pix-jd.indirects`, y todas existen siempre. Las tres claves de entrega y de resolución solo tienen efecto una vez que `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`.

| Clave                      | Tipo     | Rango   | Predeterminado | Qué es                                                                                                                                                          |
| -------------------------- | -------- | ------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`                  | booleano | —       | `false`        | la postura de hospedaje                                                                                                                                         |
| `delivery_concurrency`     | entero   | 1–256   | `8`            | cuántos `POST` de entrega corren en paralelo. El aislamiento es por participante: un endpoint atascado ocupa como máximo un espacio y nunca bloquea a los demás |
| `delivery_max_attempts`    | entero   | 1–64    | `8`            | el presupuesto de reintentos antes de que una fila de entrega termine en `INVALID`. La recuperación desde ahí es manual                                         |
| `resolution_cache_ttl_sec` | entero   | 0–86400 | `30`           | cuánto tiempo permanece en cache una resolución. `0` deshabilita el cache, y por eso el mínimo es 0                                                             |
| `validate_ispb_on_jd`      | booleano | —       | `false`        | con `true`, el registro consulta el directorio de participantes de JD y **falla de forma reintentable** si JD está caído                                        |

```bash theme={null}
PUT() { curl -s -o /dev/null -w "$1 -> %{http_code}\n" -X PUT \
          -H "Authorization: Bearer $PIX_JD_BEARER_TOKEN" -H 'Content-Type: application/json' \
          -d "$2" "$PIX_JD_BASE_URL/system/$1"; }

PUT plugin-br-pix-jd.indirects/enabled                  '{"value":true}'
PUT plugin-br-pix-jd.indirects/delivery_concurrency     '{"value":8}'
PUT plugin-br-pix-jd.indirects/delivery_max_attempts    '{"value":8}'
PUT plugin-br-pix-jd.indirects/resolution_cache_ttl_sec '{"value":30}'
PUT plugin-br-pix-jd.indirects/validate_ispb_on_jd      '{"value":false}'
```

`204` cuando se acepta, `400` cuando el validador rechaza. Los booleanos y los enteros van sin comillas, y un valor fuera del rango responde `400` en lugar de recortarse en silencio.

<Note>
  Ninguno de los dos pasos que por sí solos rompen el flujo indirecto vive en este namespace. La identidad es la clave del systemplane `tenancy/jd_integration_binding`, y sin ella todo pago rechaza con `409 PIX-0092`. La clave de cifrado vive en una variable de despliegue o en un almacén de secretos, y sin ella todo registro rechaza con `409 PIX-0107`.
</Note>
