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

> Como uma instituição menor chega ao Pix por meio da sua participação direta: a posição de liquidação que cadastrar um indireto cria, como o dinheiro dela chega, como ela fica sabendo de uma movimentação e o que cadastrar um indireto custa de forma permanente.

A sua instituição é um **participante direto**: ela está presente no sistema de liquidação nacional do Pix (SPI) por direito próprio, e este plugin é como ela chega lá. Um **participante indireto** é uma instituição menor que não tem conexão própria e chega ao SPI **pela sua**. Ele é cliente da sua instituição, não cliente do trilho.

Nada dessa relação existe no BACEN. Ela existe no registro do seu tenant, e você a cria com `POST /v1/indirects`.

<Note>
  Esta página descreve o que uma participação hospedada **é** e como ela se comporta. O provisionamento — a chave de criptografia do segredo de entrega, a postura de hospedagem e a própria chamada de cadastro — é [Hospedar participantes indiretos](/pt/interfaces/pix-jd/hosting-indirect-participants), que dá continuidade à numeração da página de configuração. Desses, apenas a chave de criptografia recusa todo cadastro sozinha — provisione-a primeiro. A postura de hospedagem controla os caminhos do dinheiro, não o registro, então você pode cadastrar participantes antes de ativá-la.
</Note>

## Quem é responsável pelo quê

***

Quase todo mal-entendido operacional aqui é alguém procurando a resposta na coluna errada.

|                             | Responsabilidade                                                                                                          |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| Banco Central / SPI         | movimenta dinheiro **entre instituições**. Não conhece clientes finais                                                    |
| JD                          | a ponte técnica: entrega os avisos e assina os QR codes. Não toma decisões de negócio                                     |
| Você, o participante direto | a **conta Pix** de cada participante indireto — que ela existe, está ativa e tem saldo. E a liquidação entre instituições |
| O participante indireto     | **as contas dos seus próprios clientes**                                                                                  |

Na prática: quando chega um Pix para um cliente de um participante indireto, **o dinheiro para com você**, em uma conta que representa a posição daquela instituição. Você não sabe — e não pode saber — qual dos clientes dela é o dono. O participante indireto credita o cliente dele no próprio core, depois de receber o seu aviso.

## O que cadastrar um indireto cria

***

Cadastrar um participante indireto faz mais do que gravar uma linha. O plugin também cria a **posição de liquidação** dessa instituição no Midaz: uma conta do ledger cujo alias é `@pi_` seguido do ISPB da instituição, o código de oito dígitos que o BACEN atribui a cada participante. Um indireto no ISPB `12345678` liquida em `@pi_12345678`.

É nessa posição que o dinheiro dessa instituição fica. A resposta a retorna como `piAccountAlias`, e o alias deriva de `ispb` — você nunca o escolhe, e um cliente nunca cria a conta.

Uma posição por instituição é todo o propósito disso. Um crédito que chega para um indireto cai apenas na conta desse indireto, então o dinheiro de uma instituição nunca se mistura com o de outra, nem com o seu. Essa segregação é a propriedade que o registro existe para garantir.

<Note>
  O alias usa **underscore**, não barra: `@pi_12345678`. O Midaz rejeita barra em um alias de usuário, então um nome no formato de caminho não resolve a nada.
</Note>

<h2 id="before-you-register-anyone">
  Antes de cadastrar alguém
</h2>

***

A participação indireta vem desligada por padrão. A flag do systemplane por tenant **`plugin-br-pix-jd.indirects/enabled`** deve estar ligada, e o valor padrão dela é `false`.

Vale saber o que a flag realmente controla, porque as duas metades se comportam de formas diferentes:

* **A API de gerenciamento funciona com a flag desligada.** Você pode cadastrar participantes, listá-los e ler um deles antes da habilitação. O onboarding antes do go-live é proposital.
* **Nenhum dinheiro se move com a flag desligada.** A resolução — a etapa que decide a qual indireto um crédito recebido pertence — reporta a funcionalidade como desabilitada, então um crédito recebido nunca é roteado para uma conta `@pi`, e nenhum indireto pode originar uma ordem de saída.

Duas operações recusam de imediato enquanto a flag está desligada, com `422 PIX-0111`: a escrita de certificado de QR próprio em `PATCH /v1/indirects/{indirectId}`, e `GET /v1/indirects/{indirectId}/jwks`.

Uma coisa continua funcionando com a flag desligada que você poderia esperar que estivesse controlada: **a fila de exceções**, para que um crédito já retido para triagem nunca fique preso atrás de uma chave.

<Note>
  A leitura falha fechada. Se o systemplane não responde, se o valor não resolve, ou se ele volta com o tipo errado, o plugin lê a flag como **desligada** — nunca ligada por acidente. Um caminho do dinheiro que "voltou a se comportar como um direto" sem que ninguém tenha tocado na chave é esse mecanismo. Olhe o systemplane.
</Note>

## Cadastrando um indireto

***

<Steps>
  <Step title="Ative a funcionalidade para o tenant">
    Defina `plugin-br-pix-jd.indirects/enabled` como `true`. O cadastro funciona sem isso, mas nada liquida até que esteja ligada.
  </Step>

  <Step title="POST /v1/indirects">
    Envie o `name` da instituição, o `ispb` dela, e um bloco `delivery` contendo `endpointUrl` (uma URL HTTPS) e `secret`. A resposta é `201` e traz `indirectId` — o identificador pelo qual toda chamada posterior é roteada — e `piAccountAlias`.
  </Step>

  <Step title="Nada para consultar em loop — um 201 significa pronto">
    Toda etapa roda **antes que a linha do registro seja gravada**: a verificação de unicidade do ISPB, a verificação opcional no diretório da JD, depois a criação da conta `@pi_{ispb}` no Midaz. Apenas então a linha é gravada, e ela é gravada como `ACTIVE`. Não há estado intermediário nem nada a esperar.
  </Step>

  <Step title="Em caso de falha, corrija a causa e envie o POST de novo">
    Uma etapa que falha responde com um **erro codificado** que nomeia a etapa, e **nenhuma linha do registro é gravada**, então o ISPB continua livre. Corrija a causa e envie o POST de novo — reenviar é a recuperação, e não há uma rota de nova tentativa separada porque nada ficou parcialmente escrito para retomar.
  </Step>
</Steps>

**O cadastro é atômico: um `201` significa pronto, e uma falha não deixa nenhuma linha no registro.** O `status` em um `201` é sempre `ACTIVE`. Se você está escrevendo um cliente que fica consultando em loop até o participante ficar roteável, apague esse loop — ele está esperando por uma transição que não pode acontecer.

A única coisa que uma falha pode deixar para trás é a **conta de liquidação**, quando essa etapa teve sucesso e uma posterior não. Ela não é desfeita, e é inofensiva: nada é roteado para uma conta `@pi` sem uma linha `ACTIVE` no registro apontando para ela, e criar a conta é idempotente por alias, então a próxima tentativa adota a mesma conta em vez de criar uma segunda. O que uma falha nunca deixa é uma linha no registro ou um ISPB retido.

A resposta ainda traz um objeto `provisioning` com um campo `failedStep`. Ele é **legado e sempre `null`** para tudo o que este serviço cadastra, porque um cadastro malsucedido não deixa nenhuma linha para carregar um marcador.

Os estados do ciclo de vida são `ACTIVE`, `SUSPENDED` e `CLOSED`.

<Warning>
  `PENDING_PROVISIONING` é um estado **aposentado** com uma aresta afiada. Nada mais é cadastrado nele, e ele ainda é aceito como filtro em `GET /v1/indirects` para que linhas gravadas antes de o cadastro se tornar atômico continuem sendo lidas como elas mesmas. Mas esse estado **não tem transições de ciclo de vida em nenhuma direção** — uma linha legada não pode ser suspensa nem encerrada; toda ação sobre ela é recusada com `409 PIX-0094`.

  Uma linha assim é legível, **não roteável**, e ainda mantém o ISPB dela contra o índice de unicidade aberto. Então ela bloqueia qualquer novo cadastro dessa instituição, e nenhuma chamada de API consegue liberá-la. Limpar uma é uma decisão de operador e de dados, propositalmente não uma operação de API. Se você herdou um tenant de antes dessa mudança, rode `GET /v1/indirects?status=PENDING_PROVISIONING` uma vez para descobrir se você tem alguma.
</Warning>

## Como o dinheiro chega a um participante indireto

***

Acompanhe um Pix recebido. Nada nesse caminho é um endpoint que o indireto chama; é o seu plugin que faz o trabalho.

1. **"Esta conta pode receber?"** Antes de mover o dinheiro, o Banco Central pergunta se a conta de destino aceita o crédito. A pergunta chega até **você**, porque o participante indireto não tem linha própria com o SPI.
2. **Um Pix chega** para uma conta mantida na instituição indireta e alcança sua participação direta, entregue ao webhook de cash-in do plugin.
3. **A resolução encontra o indireto** pelo ISPB no bloco do recebedor, consultado no registro de participação. Quatro desfechos, e apenas o primeiro credita um indireto:

   * corresponde a uma participação `ACTIVE`, então o crédito é lançado no alias `@pi_{ispb}` dessa participação;
   * é o **seu próprio** ISPB, então é o seu livro, e o CRM resolve a conta como de costume;
   * não corresponde a nada, ou corresponde a uma participação suspensa ou encerrada, então o crédito fica **retido** para um operador fazer a triagem;
   * a resolução falha por infraestrutura, então o plugin **nem credita nem retém**. Ela falha fechada de propósito: nada relacionado a dinheiro é adivinhado.

   Uma falha de resolução nunca é armazenada em cache, então um indireto que acabou de ficar ativo não fica sombreado por uma resposta negativa anterior.
4. **O crédito é lançado em `@pi_{ispb}`.** O plugin registra a movimentação contra essa posição de liquidação e vincula seu próprio registro de transação ao indireto. **O aviso é gravado na mesma transação de banco de dados que o crédito** — ou os dois existem, ou nenhum existe.
5. **Um aviso assinado é enviado** ao `delivery.endpointUrl` que você cadastrou, carregando o payload da JD byte a byte. Aqui é o plugin chamando a instituição, não o contrário.
6. **O participante indireto credita o próprio cliente**, no próprio core.

<Warning>
  O CRM não é consultado no caminho indireto. O destino vem do registro de participação, nunca dos dados que o chamador enviou. Isso é proposital: se um participante indireto fosse cadastrado por engano com o seu próprio ISPB, créditos destinados ao seu próprio livro cairiam na conta dele. Por isso a verificação "esse ISPB é nosso?" roda antes da verificação "corresponde a um participante indireto?".
</Warning>

O aviso carrega dois headers que a instituição receptora verifica:

| Header               | Valor                                                                                                                       |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `X-Lerian-Signature` | `sha256=` seguido do HMAC-SHA256 em hex dos bytes exatos do corpo bruto, assinado com o `secret` cadastrado desse indireto. |
| `X-Lerian-Timestamp` | O horário de envio em segundos Unix-epoch, para que o receptor limite o replay com sua própria janela de validade.          |

A entrega é **pelo menos uma vez**. O mesmo aviso pode ser reenviado após uma falha que permite nova tentativa, ou uma queda entre o envio e o lançamento contábil, e o `endToEndId` é estável entre as tentativas — então um receptor deve deduplicar pelo `endToEndId` e tratar um payload repetido como já processado.

<Note>
  O `secret` armazenado é apenas-escrita. Toda leitura de um indireto retorna `delivery.secret` como `***`, então um secret perdido é substituído com um `PATCH`, nunca recuperado.
</Note>

## Quando o aviso nunca chega

***

O envio pode falhar de forma permanente — as tentativas se esgotam, ou o endpoint responde `4xx`, depois do que o aviso é marcado como inválido e nunca mais tentado. **O dinheiro é lançado corretamente de qualquer forma.** A consequência é mais restrita e pior do que parece: a movimentação é real, e a instituição não sabe dela.

`GET /v1/indirects/{indirectId}/transactions` é o que fecha essa lacuna. Ele retorna as movimentações que realmente se liquidaram na conta `@pi_{ispb}` de um indireto, o que faz dele o registro definitivo, não o aviso. Varrer esse endpoint em um agendamento é como uma instituição para de depender de a entrega ter funcionado, e é também a única forma de reler uma janela depois de uma indisponibilidade própria.

As regras de janela, paginação e unidade que decidem se uma conciliação está correta — a janela `since` semiaberta obrigatória, centavos inteiros, paginação por cursor do mais antigo para o mais novo, o `limit` limitado silenciosamente — são o contrato de [Listar as transações de um participante indireto](/pt/reference/interfaces/pix-jd/list-indirect-participant-transactions). Ler o feed não muda nada e não reenvia nenhum aviso.

## Hospedando o QR code sob o certificado próprio da instituição

***

Por padrão, um QR code dinâmico emitido para um indireto é assinado e publicado sob a sua participação direta. Um indireto pode publicar o próprio em vez disso: defina `qrCertificate.ownCertificate` com um `publicBaseUrl` em `PATCH /v1/indirects/{indirectId}`, e o documento assinado passa a ser servido a partir do próprio host da instituição.

A instituição não pode produzir as chaves de validação sozinha, porque a JDPI mantém o certificado e faz a assinatura. `GET /v1/indirects/{indirectId}/jwks` retorna o JWK Set desse indireto para que a instituição possa publicá-lo no próprio host, para que PSPs pagadores validem contra ele. Busque-o quando configurar o certificado e de novo sempre que ele rotacionar.

O status do ciclo de vida deliberadamente não controla essa leitura: um indireto suspenso ou encerrado ainda tem QR codes ativos em circulação, e reter a chave quebraria a validação deles.

## Lendo o 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
```

Os filtros são `status` e `ispb` (8 dígitos, exato); as regras de paginação por cursor e o `limit` limitado silenciosamente são o contrato de [Listar participantes indiretos](/pt/reference/interfaces/pix-jd/list-indirect-participants).

Um `GET` por id, e a lista, são sempre a verdade atual. Os caminhos do dinheiro leem uma projeção em cache, então uma suspensão pode levar até o TTL do cache de resolução — 30 segundos por padrão — para ser vista por todas as réplicas. O bloqueio do ledger vindo de `suspend` já se aplica no momento da chamada.

## Suspendendo, reativando e encerrando

***

`PATCH /v1/indirects/{indirectId}` carrega no máximo uma `action` de ciclo de vida — `suspend`, `reactivate` ou `close` — e cada uma escreve tanto no ledger quanto no 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`** desabilita tanto o envio quanto o recebimento na conta `@pi` do indireto. O próprio ledger recusa o dinheiro desse participante, por isso uma suspensão vale mesmo em uma réplica cujo cache de resolução ainda está desatualizado. **`reactivate`** reabilita os dois.
* **`close`** é irreversível. `CLOSED` é terminal, e depois disso toda mudança de campo na linha também é recusada.

Um encerramento nunca apaga nada. A conta `@pi` fica permanentemente bloqueada, mas é mantida, então um novo cadastro posterior do mesmo ISPB reaproveita a conta histórica — desbloqueada, reativada, e com o histórico contábil intacto.

Um `PATCH` que carrega apenas campos, sem `action`, muda esses campos. Um `PATCH` que não carrega nada é um no-op que retorna a linha atual, não um erro.

<Warning>
  **Não existe DELETE em `/v1/indirects`, e `CLOSED` é terminal.** A única saída do registro é `close`, que mantém a linha e a conta. Um indireto cadastrado por engano contra um tenant ativo permanece no registro desse tenant para sempre, e o ISPB dele fica retido contra a restrição de unicidade aberta até ser encerrado. Todo código de instituição que você usa é permanente — verifique `name`, `ispb` e o endpoint de entrega antes de chamar.
</Warning>

## O que dá errado

***

Toda recusa que esse registro pode responder — seu status, sua condição exata, e o que foi ou não gravado quando ela disparou — está nas páginas de operação: [Cadastrar um participante indireto](/pt/reference/interfaces/pix-jd/register-an-indirect-participant), [Atualizar um participante indireto](/pt/reference/interfaces/pix-jd/update-an-indirect-participant), [Consultar um participante indireto](/pt/reference/interfaces/pix-jd/get-an-indirect-participant), [Listar participantes indiretos](/pt/reference/interfaces/pix-jd/list-indirect-participants), [Consultar o JWK Set de um participante indireto](/pt/reference/interfaces/pix-jd/get-an-indirect-participant-jwk-set), e [Listar as transações de um participante indireto](/pt/reference/interfaces/pix-jd/list-indirect-participant-transactions). O catálogo completo, com o `detail` exato que cada código carrega, é a [Lista de erros do Pix JD](/pt/reference/interfaces/pix-jd/pix-jd-error-list).

<Note>
  **Se deve repetir é decidido pelo status, não pela família do código.** `PIX-0107` e `PIX-0123` são a mesma condição vista duas vezes: um `409` significa que o trilho leu a configuração e constatou que a chave está ausente — apenas um operador muda isso, então repetir entra em loop para sempre. Um `503` significa que a própria leitura não terminou, então a chave **não** é sabidamente ausente, e repetir é correto. Nenhum dos dois grava nada.
</Note>

## Para onde ir agora

***

* **[Hospedar participantes indiretos](/pt/interfaces/pix-jd/hosting-indirect-participants)** — o provisionamento: a chave de criptografia, a postura, e a chamada de cadastro.
* **[Cadastrar um participante indireto](/pt/reference/interfaces/pix-jd/register-an-indirect-participant)** — o contrato completo da requisição e cada recusa.
* **[Listar as transações de um participante indireto](/pt/reference/interfaces/pix-jd/list-indirect-participant-transactions)** — o feed de conciliação, com as regras de paginação por completo.
* **[Atualizar um participante indireto](/pt/reference/interfaces/pix-jd/update-an-indirect-participant)** — mudanças de campo, ações de ciclo de vida e a configuração de certificado próprio.
* **[Pix Direto via JD](/pt/interfaces/pix-jd/direct-pix-via-jd)** — a participação direta sobre a qual tudo isso roda, e como as movimentações liquidadas chegam ao Midaz.
