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

# Configuração do trilho

> Provisione o Pix Direto via JD do zero: a cadeia do ledger Midaz, os registros de titular no CRM, as vinte rotas contábeis, o vínculo de integração com a JD que carrega o seu ISPB e as verificações que provam que cada passo foi aplicado.

Um deploy novo do Pix Direto via JD sobe, responde à health probe dele e recusa todo pagamento. Nada está quebrado: o trilho precisa que uma cadeia de objetos exista antes de poder mover dinheiro, e enquanto eles não existem ele falha fechado em vez de adivinhar.

Esta página é essa cadeia, em ordem, com a falha que cada elo ausente produz. A Lerian executa esse provisionamento com você durante o onboarding. Use a página para saber o que precisa existir, o que cada valor significa e como provar que ele foi aplicado.

<Note>
  Esta cadeia de provisionamento vale para um **deploy single-tenant**. Na oferta multi-tenant gerenciada (SaaS), a plataforma provisiona e resolve tudo isso — credenciais, vínculos, CRM e os serviços com que o trilho conversa — automaticamente por tenant; nenhum destes passos é seu para executar.
</Note>

<Note>
  A ordem é uma cadeia de dependências, não uma preferência. O Midaz recusa cada elo enquanto o anterior está ausente, e uma chave de systemplane precisa ser escrita antes que um pagamento possa materializar os limites de transação. Onde um passo pode rodar em qualquer ordem, a página diz isso.
</Note>

## Antes de começar

Você conversa com três serviços, e confundi-los é o erro inicial mais comum.

| Serviço                            | Endereço                                        | As rotas começam com         | Header extra        |
| ---------------------------------- | ----------------------------------------------- | ---------------------------- | ------------------- |
| Ledger (Midaz)                     | `MIDAZ_URL_ONBOARDING`, `MIDAZ_URL_TRANSACTION` | `/v1/organizations/...`      | —                   |
| CRM (titulares de conta)           | `CRM_URL`                                       | `/v1/holders`, `/v1/aliases` | `X-Organization-Id` |
| O plano de administração do plugin | o endereço do próprio plugin                    | `/system/...`                | —                   |

Você também precisa de:

* Um bearer token para o ledger, um para o CRM e um para o plugin. Eles podem vir de audiences diferentes.
* A permissão `systemplane:write` no token do plugin. Sem ela as escritas de configuração respondem `403`.
* `SYSTEMPLANE_ENABLED=true` no plugin. Sem esse valor, o grupo de rotas `/system` sequer é montado e toda escrita de configuração responde `404`.
* O **ISPB** da sua instituição: o identificador de 8 dígitos com que você foi credenciado no BACEN.

Os exemplos abaixo usam estas variáveis de shell. Onde o trilho já tem um nome para um valor, a variável carrega esse mesmo nome, então o que você lê aqui é o que você define no momento do deploy. Todo UUID, documento e ISPB é um placeholder — use os valores que o seu próprio ambiente retorna.

```bash theme={null}
# Addresses. The first two are this rail's own deployment variables.
MIDAZ_URL_ONBOARDING="https://midaz-onboarding.example.com"
MIDAZ_URL_TRANSACTION="https://midaz-transaction.example.com"
CRM_URL="https://crm.example.com"
PIX_JD_BASE_URL="https://pix-jd.example.com"       # this deployment's own address

# Three different bearers. They are not interchangeable.
MIDAZ_BEARER_TOKEN="..."                           # for the ledger
CRM_BEARER_TOKEN="..."                             # for the CRM
PIX_JD_BEARER_TOKEN="..."                          # for the plugin, needs systemplane:write

MIDAZ_HEADERS=(-H "Authorization: Bearer $MIDAZ_BEARER_TOKEN"
               -H 'Content-Type: application/json')
```

<Note>
  O Midaz expõe uma superfície de onboarding e uma superfície de transação, e este trilho as configura separadamente. Um deploy que serve as duas a partir de um endereço dá o mesmo valor às duas variáveis. As chamadas abaixo estão agrupadas pelo objeto que cada uma cria.
</Note>

<Warning>
  O CRM exige o header `X-Organization-Id` em toda rota de coleção. Sem ele uma consulta não fica limitada à sua organização, e o que volta é outro registro ou nada.
</Warning>

## Provisione o ledger e os registros de titular

Estes passos rodam contra o Midaz e o CRM. Eles criam as contas em que o trilho lança e os registros de titular a partir dos quais ele resolve as contrapartes.

<Steps>
  <Step title="Crie a organização e o ledger">
    A organização é a sua instituição nos livros. O ledger é o livro em que ela lança. Uma instituição pode ter mais de um ledger; este trilho lança em exatamente um.

    ```bash theme={null}
    curl -s -X POST "$MIDAZ_URL_ONBOARDING/v1/organizations" "${MIDAZ_HEADERS[@]}" -d '{
      "legalName": "Example Institution",
      "legalDocument": "12345678000199",
      "address": { "country": "BR" }
    }'
    # -> {"id": "..."}  keep it as $MIDAZ_ORGANIZATION_ID

    curl -s -X POST "$MIDAZ_URL_ONBOARDING/v1/organizations/$MIDAZ_ORGANIZATION_ID/ledgers" "${MIDAZ_HEADERS[@]}" -d '{
      "name": "Pix ledger"
    }'
    # -> {"id": "..."}  keep it as $MIDAZ_LEDGER_ID
    ```

    Um `201` sem `id` no corpo não é sucesso: nada consegue endereçar o que foi criado, nem você nem a limpeza depois. Pare aí em vez de levar um id vazio para o passo seguinte.
  </Step>

  <Step title="Crie o ativo BRL e espere ele aparecer">
    O ativo é a moeda em que o dinheiro é registrado. Para Pix ele é `BRL`.

    ```bash theme={null}
    curl -s -X POST "$MIDAZ_URL_ONBOARDING/v1/organizations/$MIDAZ_ORGANIZATION_ID/ledgers/$MIDAZ_LEDGER_ID/assets" "${MIDAZ_HEADERS[@]}" -d '{
      "name": "BRL",
      "type": "currency",
      "code": "BRL"
    }'
    ```

    Tanto `201` quanto `409` são boas respostas. Um ativo é endereçado pelo código dele dentro de um ledger, então "já existe" é indistinguível de sucesso.

    Duas coisas acontecem aqui, e a segunda passa fácil despercebida:

    1. O ledger começa a aceitar contas naquele ativo. Antes disso, ele recusa toda conta com `0034 Asset Code Not Found`.
    2. O Midaz cria a conta **`@external/BRL`** junto. Ela é a única conta em um livro que pode ser debitada sem ter sido creditada antes, então é de onde vem o saldo inicial e é a contraparte de toda liquidação com o mundo externo.

    <Warning>
      O `201` chega antes de o ativo aparecer na listagem. Um script que cria o ativo e cria uma conta na linha seguinte é exatamente o que quebra de forma intermitente. Faça polling da listagem até o código aparecer, com um prazo:

      ```bash theme={null}
      deadline=$(( $(date +%s) + 12 ))
      until curl -s "$MIDAZ_URL_ONBOARDING/v1/organizations/$MIDAZ_ORGANIZATION_ID/ledgers/$MIDAZ_LEDGER_ID/assets" "${MIDAZ_HEADERS[@]}" \
            | jq -e '.items[]? | select(.code=="BRL")' >/dev/null; do
        if [ "$(date +%s)" -ge "$deadline" ]; then
          echo "aborted: BRL did not appear in the listing within 12s" >&2
          echo "do not create the account: it would be refused with 0034" >&2
          exit 1
        fi
        sleep 0.15
      done
      ```
    </Warning>
  </Step>

  <Step title="Crie uma conta por papel">
    Crie uma conta para cada papel que o seu ambiente exercita — pagador, recebedor e o que mais o seu produto tiver.

    ```bash theme={null}
    curl -s -X POST "$MIDAZ_URL_ONBOARDING/v1/organizations/$MIDAZ_ORGANIZATION_ID/ledgers/$MIDAZ_LEDGER_ID/accounts" "${MIDAZ_HEADERS[@]}" -d '{
      "name": "payer account",
      "assetCode": "BRL",
      "type": "deposit",
      "alias": "@payer",
      "status": { "code": "ACTIVE" }
    }'
    # -> {"id": "..."}  keep it as $MIDAZ_ACCOUNT_ID
    ```

    O id da conta é consumido duas vezes mais adiante: no vínculo do CRM abaixo e como o `accountId` de toda chamada de negócio que você faz contra o plugin. O **alias** (`@payer`) é o nome curto pelo qual o livro é lido e recebe lançamentos, e ele reaparece no passo seguinte no lugar menos provável.
  </Step>

  <Step title="Crie o titular no CRM">
    O titular é o dono da conta. O plugin resolve **quem** é uma contraparte a partir do CRM, não do ledger.

    ```bash theme={null}
    curl -s -X POST "$CRM_URL/v1/holders" \
      -H "Authorization: Bearer $CRM_BEARER_TOKEN" -H 'Content-Type: application/json' \
      -H "X-Organization-Id: $MIDAZ_ORGANIZATION_ID" -d '{
      "type": "NATURAL_PERSON",
      "document": "12345678909",
      "name": "Example Person",
      "externalId": "@payer",
      "addresses": { "primary": { "city": "SAO PAULO" } }
    }'
    # -> {"id": "..."}  keep it as $CRM_HOLDER_ID
    ```

    Quatro campos, três armadilhas:

    * **`type` segue o tamanho do documento.** `NATURAL_PERSON` para um CPF (11 dígitos), `LEGAL_PERSON` para um CNPJ (14). O plugin converte esse tipo no número que vai na mensagem para a JD, então errar aqui registra a parte como o tipo errado de pessoa.
    * **`externalId` tem que ser o alias da conta no ledger** (`@payer`), e o nome do campo esconde isso. O CRM o descreve como um identificador externo de correlação, o que soa opcional. Para este trilho não é: é ali que o plugin lê qual conta do livro pertence ao titular. Um titular sem `externalId` produz uma conta que resolve, parece completa e falha em todo pagamento.
    * **`addresses.primary.city` é obrigatório para QR codes e Pix Automático.** É a cidade do recebedor impressa no código, e o plugin se recusa a gerar um QR sem ela, respondendo `422 PIX-0033` e apontando para `payee.city`. Nenhum caminho de pagamento lê o campo, e é por isso que a ausência dele passa despercebida até alguém gerar um QR.

    <Warning>
      Um titular aceita exatamente uma conta. `externalId` é um valor único por titular, então dar duas contas ao mesmo titular faz a segunda mover dinheiro na primeira. Para uma segunda conta, crie um segundo titular.
    </Warning>
  </Step>

  <Step title="Vincule o titular à conta">
    O titular e a conta no ledger existem, e nada os une ainda. Este passo é a união, e é assim que o plugin descobre **onde creditar** um Pix recebido.

    ```bash theme={null}
    curl -s -X POST "$CRM_URL/v1/holders/$CRM_HOLDER_ID/aliases" \
      -H "Authorization: Bearer $CRM_BEARER_TOKEN" -H 'Content-Type: application/json' \
      -H "X-Organization-Id: $MIDAZ_ORGANIZATION_ID" -d '{
      "ledgerId":  "'"$MIDAZ_LEDGER_ID"'",
      "accountId": "'"$MIDAZ_ACCOUNT_ID"'",
      "bankingDetails": {
        "branch":      "0001",
        "account":     "1234567",
        "type":        "CACC",
        "openingDate": "2020-01-02",
        "bankId":      "12345678"
      }
    }'
    ```

    | Campo                   | O que é                                                                            | Se estiver ausente                                                                                                              |
    | ----------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
    | `ledgerId`, `accountId` | o livro e a conta dos passos anteriores                                            | o vínculo não endereça nada                                                                                                     |
    | `branch`, `account`     | agência e número da conta — as coordenadas pelas quais um Pix recebido é resolvido | o crédito não encontra destino                                                                                                  |
    | `type`                  | `CACC` corrente, `SLRY` salário, `SVGS` poupança, `TRAN` pagamento                 | o plugin compara esse tipo com o do pagamento e recusa com `400 PIX-0019` quando eles divergem                                  |
    | `openingDate`           | a **data** de abertura da conta, não um instante                                   | `400 PIX-0061`, dizendo que a data de abertura não pôde ser determinada, na verificação de chave e na abertura de reivindicação |
    | `bankId`                | o ISPB de 8 dígitos da sua própria instituição                                     | veja o aviso abaixo                                                                                                             |

    <Warning>
      Nunca envie `bankId` como string vazia. Uma string vazia é um valor: ela registra "esta conta pertence à instituição cujo ISPB é vazio", o que é pior do que não dizer nada. Se você ainda não tem o ISPB, omita o campo.

      Contas com `bankId` preenchido pagam; contas criadas sem ele responderam um erro de servidor no cash-out. Esse sintoma está medido, mas o mecanismo não está confirmado. Preencha — é o seu próprio ISPB, não custa nada, e a alternativa é depurar um erro que não nomeia nada.
    </Warning>

    Confira o que foi registrado, e sempre filtre. Uma consulta sem filtro retorna o primeiro vínculo da organização, que é como uma verificação acaba aprovando a conta de outra pessoa:

    ```bash theme={null}
    curl -s -G "$CRM_URL/v1/aliases" \
      -H "Authorization: Bearer $CRM_BEARER_TOKEN" -H "X-Organization-Id: $MIDAZ_ORGANIZATION_ID" \
      --data-urlencode 'document=12345678909' \
      --data-urlencode 'banking_details_branch=0001' \
      --data-urlencode 'banking_details_account=1234567' | jq
    ```
  </Step>

  <Step title="Coloque saldo nas contas">
    Uma conta nova tem zero, e você não pode pagar a partir de uma conta vazia. O crédito inicial vem de `@external/BRL`, criada junto com o ativo no passo 2.

    ```bash theme={null}
    curl -s -X POST "$MIDAZ_URL_TRANSACTION/v1/organizations/$MIDAZ_ORGANIZATION_ID/ledgers/$MIDAZ_LEDGER_ID/transactions/json" "${MIDAZ_HEADERS[@]}" -d '{
      "description": "opening balance",
      "send": {
        "asset": "BRL",
        "value": "100.00",
        "source":     { "from": [ { "accountAlias": "@external/BRL",
                                    "amount": { "asset": "BRL", "value": "100.00" } } ] },
        "distribute": { "to":   [ { "accountAlias": "@payer",
                                    "amount": { "asset": "BRL", "value": "100.00" } } ] }
      }
    }'
    ```

    <Warning>
      Dois corpos idênticos são um lançamento só. O Midaz colapsa a repetição: o segundo `POST` responde `201` carregando o id do primeiro lançamento, e nada se move. Uma recarga que "funcionou" e não mudou o saldo é isto. Mude o `description` em cada crédito.
    </Warning>

    `@external/BRL` pode ser nomeada no corpo, mas nunca em um caminho. O alias contém uma barra e a rota do ledger não a decodifica, então ler o saldo dela por caminho responde `404` ou um `200` vazio. Lançar a partir dela é normal; lê-la desse jeito não é.
  </Step>

  <Step title="Crie as vinte rotas contábeis">
    Todo caminho de dinheiro neste trilho tem o próprio par de rotas de operação do Midaz — uma perna de crédito e uma perna de débito. Dez perfis, duas pernas cada, então vinte rotas. O passo de configuração mais abaixo guarda os UUIDs delas.

    ```bash theme={null}
    # a CREDIT leg -> operationType "destination" (money ARRIVES)
    curl -s -X POST "$MIDAZ_URL_ONBOARDING/v1/organizations/$MIDAZ_ORGANIZATION_ID/ledgers/$MIDAZ_LEDGER_ID/operation-routes" "${MIDAZ_HEADERS[@]}" -d '{
      "title": "pix-jd out credit",
      "description": "Pix JD accounting route",
      "operationType": "destination"
    }'

    # a DEBIT leg -> operationType "source" (money LEAVES)
    curl -s -X POST "$MIDAZ_URL_ONBOARDING/v1/organizations/$MIDAZ_ORGANIZATION_ID/ledgers/$MIDAZ_LEDGER_ID/operation-routes" "${MIDAZ_HEADERS[@]}" -d '{
      "title": "pix-jd out debit",
      "description": "Pix JD accounting route",
      "operationType": "source"
    }'
    ```

    Cada chamada retorna `{"id": "..."}`, e esse id é o que as chaves de roteamento abaixo guardam.

    <Warning>
      A direção é invertível e nada avisa você. Um débito **sai** do pagador, então é a perna `source`; um crédito **chega**, então é `destination`. Trocadas, todo lançamento continua respondendo sucesso — na direção errada. Nenhum código de status relata isso.
    </Warning>

    Procure uma rota pelo título antes de criá-la. Duas rotas com o mesmo título fazem a busca seguinte escolher qualquer uma das duas, então se você provisiona o mesmo livro mais de uma vez, liste primeiro.
  </Step>
</Steps>

## Configure o trilho

A configuração viva do plugin fica no **systemplane** dele: valores que você escreve pela API de administração, que passam a valer sem um novo deploy e sem um reinício. Toda escrita é um `PUT` para `/system/<namespace>/<key>` com um corpo `{"value": ...}`, e `204 No Content` é o sucesso — o plano não retorna corpo em uma escrita.

O tenant vem do bearer validado, nunca da URL nem do corpo.

<Note>
  Pergunte ao plugin o que ele espera em vez de confiar em uma cópia. `GET /system/-/catalog` lista cada chave com o tipo e a descrição dela, e `GET /system/-/catalog/<namespace>/<key>` descreve uma. O catálogo é a fonte da verdade; esta página é uma cópia dele, e cópias envelhecem.
</Note>

<Steps>
  <Step title="Escreva o vínculo de integração com a JD — o seu ISPB">
    **O que é.** O ISPB é o número de 8 dígitos que identifica a sua instituição no Banco Central. É o "quem sou eu" que vai em toda mensagem de Pix, e o plugin não consegue assinar nada como seu sem ele.

    **Por que você não adivinharia isso.** O ISPB não é uma variável de deploy. Ele vem da chave de systemplane `tenancy/jd_integration_binding`, e não existe fallback por ambiente. Enquanto a chave está vazia o plugin sobe, responde à health probe dele, parece saudável — e recusa **todo** pagamento em **toda** rota de dinheiro.

    **O que quebra sem ele.** `409 PIX-0092`, *"Tenant Pix integration not provisioned"*. Uma bateria de ponta a ponta juntou 86 recusas desse único valor vazio; o código seguinte mais frequente na mesma execução apareceu 6 vezes. O texto da resposta pede que você contate o suporte e não nomeia a chave, então o código é o que você procura.

    <Warning>
      Reiniciar não ajuda. Este não é um valor lido no boot — o plugin lê a chave em cada chamada, então reiniciar um deploy que não tem ISPB devolve um deploy que continua sem ISPB. Escrever a chave ajuda, com a aplicação rodando: a requisição seguinte passa, sem um novo deploy.
    </Warning>

    **A armadilha: o valor é uma string que contém JSON.** O corpo é sempre `{"value": ...}`, e aqui `value` não é um objeto. É uma **string** cujo conteúdo é um documento JSON. É assim que ele é armazenado, com as aspas internas escapadas:

    ```text theme={null}
    "{\"ispb\":\"12345678\",\"organizationId\":\"...\",\"ledgerId\":\"...\"}"
    ```

    | Forma                                                  | Resultado |
    | ------------------------------------------------------ | --------- |
    | `{"value":"{\"ispb\":\"12345678\",...}"}` — uma string | correto   |
    | `{"value":{"ispb":"12345678",...}}` — um objeto        | recusado  |

    Deixe o `jq` fazer o escaping:

    ```bash theme={null}
    # Replace all three with your own values before you run this.
    INSTITUTION_ISPB="12345678"                                    # 8 digits, your institution's ISPB
    MIDAZ_ORGANIZATION_ID="3fa85f64-5717-4562-b3fc-2c963f66afa6"   # same value as the deployment variable
    MIDAZ_LEDGER_ID="9c858901-8a57-4791-81fe-4a34d4dd8ab5"         # same value as the deployment variable

    # 1) build the document
    BINDING_DOCUMENT="$(jq -nc \
            --arg ispb   "$INSTITUTION_ISPB" \
            --arg orgId  "$MIDAZ_ORGANIZATION_ID" \
            --arg ledgerId "$MIDAZ_LEDGER_ID" \
            '{ispb:$ispb, organizationId:$orgId, ledgerId:$ledgerId}')"

    # 2) wrap the document as a STRING inside {"value": ...} and write it
    curl -s -o /dev/null -w '%{http_code}\n' -X PUT \
      -H "Authorization: Bearer $PIX_JD_BEARER_TOKEN" -H 'Content-Type: application/json' \
      -d "$(jq -nc --arg document "$BINDING_DOCUMENT" '{value:$document}')" \
      "$PIX_JD_BASE_URL/system/tenancy/jd_integration_binding"
    ```

    | Campo            | Regra                                                              | Obrigatório na escrita | Lido em tempo de execução                              |
    | ---------------- | ------------------------------------------------------------------ | ---------------------- | ------------------------------------------------------ |
    | `ispb`           | exatamente 8 dígitos, `0`–`9`, sem máscara e sem espaços           | sim                    | sim                                                    |
    | `organizationId` | um UUID válido e diferente de zero (o UUID só de zeros é recusado) | sim                    | não — em tempo de execução usa `MIDAZ_ORGANIZATION_ID` |
    | `ledgerId`       | um UUID válido e diferente de zero                                 | sim                    | não — em tempo de execução usa `MIDAZ_LEDGER_ID`       |

    <Note>
      Os três campos são obrigatórios na escrita, e essa é a parte surpreendente. O deploy não lê `organizationId` nem `ledgerId` desta chave — o livro em que ele lança continua vindo de `MIDAZ_ORGANIZATION_ID` e `MIDAZ_LEDGER_ID`. O validador de escrita pede os três mesmo assim. Preencha os dois UUIDs com os mesmos valores que essas variáveis carregam.

      Duas fontes da verdade para o mesmo fato poderiam divergir sem ninguém perceber, e é por isso que a resposta em tempo de execução fica com os valores de deploy.
    </Note>

    <Warning>
      A decodificação é estrita: um campo desconhecido é recusado, não ignorado, e ele derruba a escrita inteira. Isso inclui o campo aposentado `routeProfiles` — as rotas contábeis foram para as chaves `routing.*` abaixo — então um documento copiado de uma configuração antiga não entra. Qualquer coisa depois do primeiro documento JSON também é recusada.
    </Warning>

    **Como conferir que foi aplicado.** Leia a chave de volta. Ela não guarda segredo, então o valor volta aberto:

    ```bash theme={null}
    curl -s -H "Authorization: Bearer $PIX_JD_BEARER_TOKEN" \
      "$PIX_JD_BASE_URL/system/tenancy/jd_integration_binding" | jq
    ```

    ```json theme={null}
    {
      "namespace": "tenancy",
      "key": "jd_integration_binding",
      "value": "{\"ispb\":\"12345678\",\"organizationId\":\"...\",\"ledgerId\":\"...\"}"
    }
    ```

    Se `value` volta como um objeto em vez de uma string entre aspas, você escreveu a forma errada. Se volta `""`, a escrita não aconteceu — confira o código de status do `PUT`. A confirmação real é comportamental: as rotas de dinheiro que respondiam `409 PIX-0092` param de responder isso.

    Um ISPB malformado não pode ser armazenado por esta rota. O validador de escrita é o mesmo decodificador que a leitura usa, então um ISPB de 7 dígitos ou um UUID quebrado é recusado na hora com `400 validation_error` em vez de ser descoberto no primeiro pagamento.

    <Note>
      É por isso que você não vai encontrar `409 PIX-0121` — *"Tenant Pix integration ISPB invalid"* — seguindo esta página. É o código de um vínculo que **está** provisionado e cujo `ispb` não tem 8 dígitos, e esta rota não consegue criar esse estado. Ele aparece apenas quando um valor chegou à chave por outro caminho: uma escrita direta no banco de dados do plugin ou uma escrita feita antes de o validador existir. Ele está documentado porque, se você chegar a vê-lo, a mensagem dele é a que nomeia tanto a chave quanto o campo a corrigir.
    </Note>

    <Warning>
      Um `400` aqui não é um problema de permissão. Essa leitura já custou tempo: três cenários de teste leram exatamente este `400` como "meu bearer não tem concessão de admin". Falta de permissão é `403`. Este `400` significa que o valor que você enviou está errado. A resposta não diz qual campo, então confira os 8 dígitos primeiro — é o erro mais comum.
    </Warning>

    | Resposta               | O que significa                                                             |
    | ---------------------- | --------------------------------------------------------------------------- |
    | `204`                  | escrito                                                                     |
    | `400 validation_error` | o **valor** foi recusado pelo formato dele — não é um problema de permissão |
    | `400 unknown_key`      | o nome da chave ou do namespace está errado                                 |
    | `401`                  | o bearer não autenticou                                                     |
    | `403`                  | autenticado, mas sem `systemplane:write`                                    |
    | `404`                  | o grupo `/system` não está montado — `SYSTEMPLANE_ENABLED` é falso          |
    | `503`                  | o plano de configuração está indisponível                                   |

    A string vazia é aceita, e é o valor sentinela de "não provisionado". Escrevê-la leva o deploy de volta a recusar com `409 PIX-0092`, então não faça isso em um ambiente que está pagando.
  </Step>

  <Step title="Escreva as vinte chaves de roteamento">
    **O que é.** Para cada caminho de dinheiro, o par de UUIDs das rotas de operação do Midaz criadas acima. Todas as vinte chaves ficam no namespace `tenant_policy`, todas guardam uma string e todas guardam um UUID de rota que já existe no Midaz.

    ```
    tenant_policy/routing.<profile>.operation_credit_route
    tenant_policy/routing.<profile>.operation_debit_route
    ```

    | Perfil                    | Quando é usado                                            |
    | ------------------------- | --------------------------------------------------------- |
    | `out`                     | um pagamento enviado                                      |
    | `out_reversal`            | o estorno de um pagamento enviado                         |
    | `in`                      | um crédito recebido                                       |
    | `in_qrcode`               | um crédito recebido por um QR code                        |
    | `intra_psp`               | um pagamento entre duas contas da sua própria instituição |
    | `intra_psp_reversal`      | o estorno desse pagamento                                 |
    | `med_credit`, `med_debit` | as duas pernas de uma devolução de MED (fraude)           |
    | `pixautomatico_debit`     | o débito do Pix Automático                                |
    | `pixautomatico_reversal`  | o estorno do Pix Automático                               |

    **O que quebra sem ela.** Uma perna ausente não degrada o fluxo, ela o recusa: o caminho de dinheiro correspondente falha fechado com `409 PIX-0105`. Isso é deliberado — recusar uma transação é melhor do que lançá-la contra uma rota indefinida. Se um fluxo específico "não funciona" e os outros funcionam, este é o primeiro lugar para olhar.

    ```bash theme={null}
    # OPERATION_ROUTES is the table YOU fill with the UUIDs the ledger step returned:
    # one line per profile and leg, "<profile> <leg> <operation route UUID>". Twenty
    # lines when every flow is provisioned. There is no magic function here.
    OPERATION_ROUTES="
    out                    credit 1f0a4c2e-5b91-4d77-9a10-6c3b8e2f0a01
    out                    debit  1f0a4c2e-5b91-4d77-9a10-6c3b8e2f0a02
    out_reversal           credit 1f0a4c2e-5b91-4d77-9a10-6c3b8e2f0a03
    out_reversal           debit  1f0a4c2e-5b91-4d77-9a10-6c3b8e2f0a04
    "

    operation_route_id() {
      printf '%s\n' "$OPERATION_ROUTES" | awk -v profile="$1" -v leg="$2" \
        '$1 == profile && $2 == leg { print $3 }'
    }

    for profile in out out_reversal in in_qrcode intra_psp intra_psp_reversal \
                   med_credit med_debit pixautomatico_debit pixautomatico_reversal; do
      for leg in credit debit; do
        uuid="$(operation_route_id "$profile" "$leg")"
        if [ -z "$uuid" ]; then
          echo "MISSING the UUID for $profile.$leg — that flow will refuse with PIX-0105" >&2
          continue
        fi
        curl -s -o /dev/null -w "$profile/$leg -> %{http_code}\n" -X PUT \
          -H "Authorization: Bearer $PIX_JD_BEARER_TOKEN" -H 'Content-Type: application/json' \
          -d "{\"value\":\"$uuid\"}" \
          "$PIX_JD_BASE_URL/system/tenant_policy/routing.$profile.operation_${leg}_route"
      done
    done
    ```

    **Como conferir.** Cada escrita responde `204`. Um perfil que o seu produto nunca exercita pode ficar vazio — aquele fluxo então recusa, que é o que você quer em vez de um lançamento em uma rota indefinida.

    <Warning>
      Uma string vazia é o valor sentinela de "ainda não provisionado" e é aceita. O UUID só de zeros é **recusado**: ele faz parse sem erro, mas nunca é um identificador real do Midaz. Um script que preenche as rotas não usadas com zeros como um "vazio seguro" passa em qualquer checagem ingênua de formato e é rejeitado por esta. Use a string vazia.
    </Warning>
  </Step>

  <Step title="Defina o ativo de lançamento e a conta de compensação">
    **O que é.** O ativo em que o dinheiro é lançado e a conta externa que representa o mundo fora da sua instituição.

    **Onde os valores vão depende do modo de deploy**, e é aqui que um `204` pode enganar você:

    O ativo de lançamento vem de `MIDAZ_ASSET_ID` e a conta de compensação vem de `MIDAZ_EXTERNAL_ID` — as duas variáveis de deploy.

    <Warning>
      As duas chaves de systemplane `tenant_policy/midaz.asset_id` e `tenant_policy/midaz.external_id` existem, aceitam uma escrita e respondem `204` — e nada as lê: o plugin resolve o ativo e a conta de compensação a partir das variáveis de deploy. Você pode escrever as duas, receber `204` nas duas e ainda assim ter o caminho de dinheiro recusando, porque as variáveis continuam vazias. Um `204` aqui não é confirmação de que o valor vai ser usado.
    </Warning>

    **Os dois nomes mentem sobre o formato.** Apesar do `_ID`:

    | Valor                  | O que ele quer                        |
    | ---------------------- | ------------------------------------- |
    | o ativo de lançamento  | o **código** do ativo: `BRL`          |
    | a conta de compensação | o **alias** da conta: `@external/BRL` |

    Um UUID em qualquer um dos dois responde `PIX-4011` e não nomeia nenhuma conta.

    **O que quebra sem isso.** `409 PIX-0106`, *"Tenant ledger configuration missing"*. A resposta nomeia as duas metades e os dois lugares onde defini-las, então ela diz qual delas está faltando. É um código diferente de `PIX-0105`: um tenant pode ter todas as vinte pernas de rota corretas e ainda recusar todo lançamento porque o ativo ou a conta de compensação está sem valor.
  </Step>

  <Step title="Defina a janela diária">
    As duas pontas da janela em que os limites de transação são contabilizados. As duas são inteiros de 0 a 23 — horas do relógio, não timestamps — e as duas são chaves de systemplane nos **dois** modos de deploy.

    ```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 tenant_policy/transaction_limits.daily_period_init '{"value":6}'
    PUT tenant_policy/transaction_limits.daily_period_end  '{"value":20}'
    ```

    Os valores acima são um exemplo; use os seus. O que não muda é o tipo JSON: um inteiro, sem aspas. Um valor fora da faixa responde `400` em vez de ser silenciosamente ajustado ao limite.
  </Step>

  <Step title="Declare se este deploy hospeda participantes indiretos">
    `plugin-br-pix-jd.indirects/enabled` declara o que o tenant **é**. Um participante direto simples define o valor como `false`.

    ```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":false}' \
      "$PIX_JD_BASE_URL/system/plugin-br-pix-jd.indirects/enabled"
    ```

    É um booleano JSON, sem aspas: `{"value":"true"}` responde `400`. Se este deploy liquida Pix em nome de outras instituições, defina o valor como `true` e siga [Hospedagem de participantes indiretos](/pt/interfaces/pix-jd/hosting-indirect-participants) — há mais um valor a provisionar antes de você poder registrar alguém, e sem ele todo registro recusa.
  </Step>

  <Step title="Materialize os limites de transação com um pagamento pequeno">
    Este é o passo menos adivinhável da página, porque o produto não oferece jeito de criar o que ele precisa.

    **O que você espera.** Você provisiona uma conta e lê o limite disponível dela.

    **O que acontece.** `GET /v1/limits/available` responde `404 PIX-0063`, *"The specified transaction limit was not found in the system. Please verify the identifier and try again."*, e `GET /v1/limits` responde `{"data":[]}`. Parece uma conta quebrada. Não é: é o estado inicial normal de uma conta que nunca transacionou.

    `PIX-0063` nomeia o que quer que tenha sido consultado, então a [lista de erros](/pt/reference/interfaces/pix-jd/pix-jd-error-list) imprime a forma genérica dele — *"The specified entity was not found in the system"* — e esta rota preenche com `transaction limit`. Mesmo código, mesmo `404`.

    **Por que você não conserta isso criando algo.** Não existe rota de criação. `PATCH /v1/limits` atualiza uma linha que já precisa existir. As linhas são materializadas por exatamente uma coisa: a verificação prévia de limite de um pagamento **de saída**. Na primeira vez que a conta envia um pagamento, o plugin percebe que ela não tem linhas, cria os padrões, lê de novo e segue.

    **Então o passo é: envie um pagamento pequeno de saída.** Um centavo basta, e é o que o provisionamento automatizado faz.

    <Warning>
      Uma conta sem linhas de limite não é uma conta sem limite. Se a criação automática não consegue estabelecer os limites, o pagamento é **recusado**, não liberado.

      E não tente forçar as linhas enviando um valor acima do teto. A verificação de **saldo** roda antes do aplicador de limites, então um valor alto é recusado por falta de fundos e o aplicador nunca é alcançado — nenhuma linha aparece. Tem que ser um pagamento comum que cabe no saldo.
    </Warning>

    **Como conferir.** `GET /v1/limits` vai de `{"data":[]}` para uma lista, e `/v1/limits/available` vai de `404` para `200`.

    Este passo depende de as chaves de roteamento estarem escritas antes: ele materializa as linhas fazendo um pagamento real, e sem rota o pagamento é recusado com `PIX-0105`. Todo o resto desta página pode ser feito em qualquer ordem.
  </Step>
</Steps>

## Hospedagem de participantes indiretos

Um deploy que liquida Pix em nome de outras instituições adiciona três passos de provisionamento sobre a cadeia acima: a chave de criptografia do segredo de entrega, a postura de hospedagem e o registro de cada participante indireto. Eles estão em [Hospedagem de participantes indiretos](/pt/interfaces/pix-jd/hosting-indirect-participants), e a numeração deles continua a desta página — passos 7 a 9. Se o seu deploy liquida apenas o Pix dos próprios clientes, o seu provisionamento acaba aqui.

## Como é cada passo pulado

Toda recusa abaixo é um `409`, menos a de limites, e **nenhuma delas se resolve esperando**. Elas se resolvem provisionando o valor ausente.

| Ausente                                                       | Resposta       | O que você vê                                                                                                |
| ------------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------ |
| o vínculo do ISPB                                             | `409 PIX-0092` | toda rota de dinheiro recusa. O texto pede que você contate o suporte e não nomeia nenhuma chave             |
| uma perna de rota contábil                                    | `409 PIX-0105` | apenas os fluxos que usam aquele perfil recusam; os outros continuam funcionando                             |
| o ativo de lançamento ou a conta de compensação               | `409 PIX-0106` | todo lançamento recusa, e a resposta nomeia as duas metades e onde defini-las                                |
| as linhas de limite de transação                              | `404 PIX-0063` | *"The specified transaction limit was not found in the system. Please verify the identifier and try again."* |
| a chave de criptografia de entrega (apenas no fluxo indireto) | `409 PIX-0107` | todo registro indireto recusa; nada foi armazenado                                                           |

<Note>
  O `PIX-0092` parar de aparecer não significa que os pagamentos passam. Ele é a primeira barreira, não a última: com o vínculo no lugar, uma rota contábil vazia ainda recusa com `PIX-0105`, e um ativo ou uma conta de compensação ausente ainda recusa com `PIX-0106`. Três códigos, três causas, três correções diferentes.
</Note>

### Não repita um `409`. Repita o irmão `503` dele

Esta é a distinção que diz se o problema é a sua configuração ou a indisponibilidade de alguém, e o status a carrega.

Um `409` acima é **conhecimento positivo de ausência**: o trilho leu a sua configuração com sucesso e não encontrou nada ali. Apenas um operador pode fornecer o valor, então repetir a requisição não pode mudar a resposta — um cliente que respeita a semântica de nova tentativa entraria em loop para sempre contra uma condição que nunca se resolve sozinha. Cada uma dessas respostas nomeia o que definir.

A maior parte dessas condições tem um **irmão `503`** para o caso em que o trilho não conseguiu ler a configuração. Nada foi estabelecido sobre o que você provisionou, a resposta nomeia a dependência com falha, e repetir é o movimento certo.

| A sua configuração está incompleta — provisione, não repita                          | A fonte não respondeu — repita                                                   |
| ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------- |
| `409 PIX-0092` a integração Pix do tenant não está provisionada                      | `503 PIX-0051` a integração Pix do tenant não pôde ser alcançada                 |
| `409 PIX-0121` o vínculo existe e o `ispb` dele não tem 8 dígitos                    | `503 PIX-0051` (mesmo irmão: o vínculo não pôde ser lido)                        |
| `409 PIX-0106` o ativo de lançamento ou a conta de compensação não está provisionado | `503 PIX-0122` a identidade do ledger não pôde ser lida do plano de configuração |
| `409 PIX-0107` a chave de criptografia do segredo de entrega não está provisionada   | `503 PIX-0123` a chave não pôde ser lida da fonte de chaves dela                 |

<Warning>
  **As rotas contábeis são a exceção, e vale saber disso.** `PIX-0105` não tem irmão `503`: uma perna de rota ausente, vazia, malformada, o UUID só de zeros **ou ilegível** respondem todas esse mesmo `409`. Então, diferente de todo outro código aqui, um `PIX-0105` sozinho não separa "esta perna nunca foi provisionada" de "o plano de configuração não respondeu". Leia as vinte pernas de volta antes de concluir que é indisponibilidade.
</Warning>

<Note>
  As duas metades de cada par recusam a operação, e nenhuma delas lança nem armazena nada. A diferença está inteira no que fazer em seguida, e é por isso que são códigos separados em vez de um envelope cobrindo os dois.

  `PIX-0121` é um caso especial de outro jeito: você não consegue provocá-lo pela API de administração, porque o validador de escrita recusa um `ispb` malformado antes de ele ser armazenado. Ele aparece apenas quando um valor chegou à chave por outro caminho — veja o passo do vínculo acima.
</Note>

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

## Prove que a configuração está completa

Rode estas verificações em ordem. Cada uma falha por um motivo diferente, e é isso que faz a sequência valer mais do que um único teste de fumaça.

1. **O ledger aceita uma conta.** Crie uma conta descartável e apague-a. Se o livro recusar, a recusa nomeia o elo ausente. Pule isto e o mesmo problema volta depois como "conta não encontrada" dentro de um fluxo de pagamento, três camadas longe da causa. Nunca coloque saldo na conta de teste: o Midaz se recusa a apagar uma conta com saldo.
2. **O vínculo volta na leitura como uma string entre aspas** carregando o seu ISPB, como mostrado acima.
3. **A consulta de alias retorna a sua conta**, filtrada por documento, agência e número da conta.
4. **Uma rota de dinheiro para de responder `409 PIX-0092`.** Esta é a mesma chamada que você já estava fazendo — não é preciso nenhum aparato de teste.
5. **`GET /v1/limits` retorna uma lista** para uma conta que enviou o primeiro pagamento dela.

<Note>
  **Alguns passos de provisionamento não são seus.** A bateria de ponta a ponta da Lerian estabelece mais quatro coisas antes de rodar: um conjunto de infrações de MED, credenciais para o dublê de teste da JD e dois arquivos internos de escrituração. Esses são fixtures de teste sem equivalente em um deploy real — em produção as infrações chegam da JD, e a JD se autentica sozinha. Não tente construí-los.
</Note>

## Para onde ir agora

<Columns cols={2}>
  <Card title="Variáveis de ambiente" href="/pt/interfaces/pix-jd/pix-jd-environment-variables">
    A configuração deste trilho no momento do deploy: conectividade com a JD, os endpoints do ledger e do CRM, a hospedagem de QR e os provedores de notificação.
  </Card>

  <Card title="Participantes indiretos" href="/pt/reference/interfaces/pix-jd/indirect-participants">
    O que é uma participação hospedada, como um crédito de entrada chega a ela, o ciclo de vida dela e toda recusa que ela pode responder.
  </Card>

  <Card title="Pix Direto via JD" href="/pt/interfaces/pix-jd/direct-pix-via-jd">
    Como as movimentações de Pix liquidadas chegam ao Midaz, e como os dois sistemas se correlacionam.
  </Card>

  <Card title="Lista de erros do Pix JD" href="/pt/reference/interfaces/pix-jd/pix-jd-error-list">
    Todo código `PIX-NNNN`, o status dele e o texto `detail` que a resposta carrega.
  </Card>
</Columns>
