---
title: "Integração com o Lacuna Signer"
description: "Passo a passo para um perfil do Bulk Signer assinar pelo Lacuna Signer em vez de usar um certificado local, e quando escolher esse método."
canonical: "https://docs.lacunasoftware.com/articles/bulk-signer/lacuna-signer"
locale: "pt-BR"
product: "Bulk Signer"
last_updated: "2026-10-12"
---

# Integração com o Lacuna Signer

Passo a passo para o operador fazer um perfil assinar pelo **Lacuna Signer**, em vez de usar um
certificado mantido localmente. A assinatura com certificado local (PFX / PKCS#11 / repositório do
Windows) e a assinatura pelo Lacuna Signer **coexistem, cada uma em seu perfil** — pastas monitoradas
diferentes podem usar métodos de assinatura diferentes na mesma instância.

## Quando usar isto

Escolha **`Method = LacunaSigner`** para um perfil quando:

- Uma pessoa (e não um certificado mantido pelo servidor) precisa assinar cada documento — por exemplo,
  contratos com contra-assinatura, contratos de trabalho, documentação de admissão de RH.
- A identidade do signatário é a do participante, e não a do serviço. Cada documento despachado
  pertence ao participante, do lado do Signer.
- A trilha de auditoria que você quer é a que o Signer mantém (identidade do signatário, evidência da
  assinatura, motivos de recusa, expiração).

Escolha **`Method = Local`** (o padrão) quando:

- A assinatura é *do serviço* — assinatura automatizada de notas fiscais com o certificado de assinatura
  da empresa, assinatura de NF-e em tempo de execução em um token PKCS#11, contra-assinatura em lote.
- O certificado fica no host (PFX / HSM / repositório do Windows) e não há uma pessoa no circuito.

Os dois podem rodar lado a lado. Uma única instância pode monitorar `input/contracts/` (LacunaSigner) e
`input/nfe/` (PKCS#11 local) ao mesmo tempo.

Escolha **`Method = SignerFolder`** — a direção oposta — quando uma *pessoa* cria documentos **no Lacuna
Signer** e indica como participante o titular do certificado da organização, e a assinatura desse
participante deve chegar sem que ninguém precise tocar em um token. Veja
[Assinando em uma pasta do Lacuna Signer](https://docs.lacunasoftware.com/articles/bulk-signer/lacuna-signer#assinando-em-uma-pasta-do-lacuna-signer--signerfolder) abaixo.

## Resumo da arquitetura

```text
input/ ─▶ Observador ─▶ Queued ─▶ worker reivindica
                                        │
                    profile.Method?  ───┤
                                        │
   Local ───────────────────────────────▶ assina no slot ─▶ Verifying ─▶ Completed
                                        │
   LacunaSigner ─▶ upload + cria documento ─▶ AwaitingSigner  (slot de concorrência LIBERADO)
                                                     │
                       tique do worker de consulta ──┤
                                                     │
                              Pending      → continua AwaitingSigner
                              Concluded    → baixa os bytes ─▶ Verifying ─▶ Completed
                              Refused/Expired/Canceled → Failed
                              timeout      → Failed
```

São dois **workers que cooperam**, em vez de um:

1. **O worker do pipeline** reivindica jobs `Queued` e, em perfis LacunaSigner, *apenas* os despacha ao
   Signer (upload + criação do documento) e os passa para `AwaitingSigner`. O slot do pipeline é
   **liberado imediatamente após o despacho** — o job agora está retido do lado remoto, e o worker fica
   livre para pegar o próximo item.
2. **Um worker de polling separado** acorda a cada `Signer:PollIntervalSeconds` (padrão 30 s) e percorre
   todas as linhas `AwaitingSigner`. Para cada linha, ele verifica o status do documento na API do
   Signer; os documentos concluídos são baixados e passam pela mesma etapa final de verificar →
   criptografar → promover que o caminho Local usa.

Essa divisão importa: ocupar um slot de `Pipeline:MaxConcurrency` enquanto uma pessoa leva dias para
assinar anularia completamente o propósito da fila.

## A máquina de estados, estendida

Em perfis LacunaSigner, o `AwaitingSigner` se encaixa entre `Processing` e `Verifying`:

```text
Queued ─▶ Processing ─┬─ assinatura local ok ────────▶ Verifying ─▶ Completed
                      │                                            └▶ Failed
                      └─ despachado ao Signer ─▶ AwaitingSigner
                                                      │
                          concluído → download ───────┼──▶ Verifying ─▶ Completed
                          recusado/expirado/timeout ──┴──▶ Failed
                          cancel do operador ────────────▶ Canceled (cancelamento remoto em melhor esforço)
```

Perfis que usam apenas o método Local nunca entram em `AwaitingSigner`. Perfis LacunaSigner nunca
seguem o caminho local direto `Processing → Verifying`.

## Configuração

### `Signer:*` — um tenant por host

A conexão com o Signer é **global** — um endpoint + uma chave de API para o host, compartilhados por
todos os perfis que usam `Method = LacunaSigner` ou `Method = SignerFolder`. Os dois métodos leem
metades diferentes do restante do bloco:

| Chave | Tipo | Padrão | Override por env | Usada por | Obrigatória quando |
|-------|------|--------|------------------|-----------|--------------------|
| `Signer:Endpoint` | string | `""` | `Signer__Endpoint` | os dois métodos | Algum perfil usa `LacunaSigner` ou `SignerFolder`, ou qualquer outra parte de `Signer:` está definida. Padrão na nuvem: `https://signer.lacunasoftware.com`. |
| `Signer:ApiKey` | string | `""` | `Signer__ApiKey` | os dois métodos | **REQUIRED, SECRET**, mesma condição. Formato: `application-id\|secret`. |
| `Signer:PollIntervalSeconds` | int | `30` | `Signer__PollIntervalSeconds` | `LacunaSigner` | opcional — a frequência com que o worker de polling percorre as linhas `AwaitingSigner`. 1–3600. |
| `Signer:TimeoutHours` | int | `168` (7 dias) | `Signer__TimeoutHours` | `LacunaSigner` | opcional — quanto tempo um documento despachado pode esperar pelo participante. 1–8760. |
| `Signer:MaxConsecutiveApiFailures` | int | `5` | `Signer__MaxConsecutiveApiFailures` | `LacunaSigner` | opcional — o limite por documento do polling, descrito abaixo. 1–100. |
| `Signer:FolderSweepIntervalSeconds` | int | `300` (5 minutos) | `Signer__FolderSweepIntervalSeconds` | `SignerFolder` | opcional — a frequência com que cada pasta do Signer vinculada é listada; é o máximo que um documento espera até este host percebê-lo. 60–86400. |
| `Signer:WebhookSecret` | string | `""` (notificações desligadas) | `Signer__WebhookSecret` | `SignerFolder` | opcional, **SECRET** — o token `Bearer` que o Signer apresenta em uma [notificação](https://docs.lacunasoftware.com/articles/bulk-signer/lacuna-signer#notificações--o-webhook). Pelo menos 32 caracteres. Defini-lo conta como definir o bloco, então `Signer:Endpoint` e `Signer:ApiKey` passam a ser obrigatórias. |

Um host que precisa de apenas um método pode deixar as chaves do outro nos valores padrão: nada as lê.
Todas as chaves, com seus limites e recusas, também estão em
[Configuração](https://docs.lacunasoftware.com/articles/bulk-signer/configuration#signer--conexão-com-o-lacuna-signer).

O validador **só age sobre esta seção quando ela existe** — omita `Signer:*` por inteiro e nada aqui é
exigido, que é o que acontece em uma implantação puramente Local. Escreva qualquer parte dela e o bloco
inteiro é validado.

> **Aviso: Mudou na 2.1.0 — o bloco Signer:* é validado por si só**
>
> Até a 2.0.x, o bloco só era validado quando algum perfil selecionava `Method = LacunaSigner`. Os perfis
> agora ficam no banco de dados operacional e podem ser trocados para o Lacuna Signer pelo dashboard sem
> reinicialização, então a regra passou a valer ao contrário:
>
> - **Um bloco `Signer:` preenchido pela metade impede o boot**, mesmo que nenhum perfil o use — um
>   endpoint sem chave de API deixado para depois, por exemplo. A mensagem cita as duas chaves e sugere
>   remover a seção como solução.
> - **Selecionar `Method = LacunaSigner` é recusado quando o host não tem configurações `Signer:*`** — no
>   boot, para um perfil ainda importado da configuração pelo seed (carga inicial), e na página do perfil,
>   para um perfil que está sendo salvo.
> - **É a presença das configurações `Signer:*` no host que inicia o gateway do assinador remoto e o
>   worker de polling**, então um perfil trocado para o Lacuna Signer depois do boot começa a despachar
>   sem reinicialização. Em um host com o bloco inteiro definido e nenhum perfil que o use, o worker de
>   polling roda e não encontra nada a fazer a cada intervalo — remova a seção se este host assina tudo
>   localmente.

> **Aviso: A chave de API e o segredo do webhook são segredos.**
>
> Defina-os como `Signer__ApiKey` e `Signer__WebhookSecret` no `bulksigner.env` (Linux) / em uma variável
> de ambiente de máquina (Windows) / no `.env` (Docker). Os valores literais são mascarados nos logs.

Um perfil que seleciona `Method = SignerFolder` é recusado em um host sem configurações `Signer:*`
exatamente como um perfil `LacunaSigner`, e são essas mesmas configurações que iniciam a varredura de
pastas do Signer. Um perfil `SignerFolder` já armazenado, em um host que depois perdeu as configurações,
fica [degradado](https://docs.lacunasoftware.com/articles/bulk-signer/lacuna-signer#quando-o-próprio-perfil-não-consegue-trabalhar) — nunca impede o boot.

### Escolhendo o método pelo dashboard

**É aqui que você escolhe o método em uma implantação em execução.** O `Signing:Profiles[]` é um seed de
uso único, importado no primeiro boot (veja
[Configuração](https://docs.lacunasoftware.com/articles/bulk-signer/configuration#signingprofiles--perfis-de-assinatura-por-pasta)); por isso, a próxima
seção descreve como é um seed, e não onde você muda um perfil.

O painel **Certificado** em `/profiles/{name}` contém o método, e o formulário em `/profiles/_new`
também. Ele fica nesse painel, e não no de **Comportamento**, porque o método decide se o perfil tem ou
não uma chave local: escolha **Lacuna Signer**, e a origem do certificado e os dados dela são
substituídos pelos três campos do participante — nome, e-mail e identificador —, que são tudo o que
define de onde vem a assinatura de um perfil assim. Escolha **Pasta do Lacuna Signer**, e o certificado
continua, com um seletor de **Pasta do Lacuna Signer** acima dele — veja
[Assinando em uma pasta do Lacuna Signer](https://docs.lacunasoftware.com/articles/bulk-signer/lacuna-signer#assinando-em-uma-pasta-do-lacuna-signer--signerfolder) abaixo.

As direções da troca são diferentes, e o formulário informa qual se aplica antes de você salvar. A regra
por trás cabe em uma frase: uma mudança espera uma reinicialização exatamente quando deixa o perfil
precisando de uma chave que nenhuma instância em execução abriu.

| Troca | Quando passa a valer | O que acontece com o outro bloco |
|---|---|---|
| Local ou pasta do Signer → **Lacuna Signer** | No próximo job reivindicado. **Sem reinicialização** — o gateway roda em todo host que tem configurações `Signer:*`, e não só para os perfis que existiam no boot. | Os dados do certificado são apagados, inclusive a senha: uma credencial armazenada para uma chave que fica no serviço remoto é uma credencial que nada jamais usará. O vínculo com uma pasta do Signer é desfeito. |
| **Lacuna Signer** → Local ou pasta do Signer | Na próxima **reinicialização**, porque uma chave privada precisa ser aberta, e salvar o formulário não abre nenhuma. Até lá, o perfil aparece como **degradado** na própria página, e os jobs roteados para ele falham com `profile.degraded`. | O participante é apagado. |
| Local ↔ **pasta do Signer**, mesmo certificado | No próximo job reivindicado. **Sem reinicialização** — os dois assinam com a chave que este host já abriu, e ela é mantida. | Sair da pasta do Signer desfaz o vínculo com a pasta. |
| Qualquer salvamento que também mude um dado do certificado | Na próxima **reinicialização**, qualquer que seja o método — a regra do certificado não muda. | — |

As recusas acontecem ao salvar, no seu idioma de exibição: um participante sem algum dos três campos, um
e-mail sem `@`, e **selecionar o Lacuna Signer em um host sem configurações `Signer:*`** — a única recusa
cuja solução é uma mudança de configuração e uma reinicialização, e não um campo do formulário; por isso
a mensagem cita as chaves.

Os dígitos verificadores do identificador do participante **não** são validados. Diferentemente do CPF
de um aprovador — que este produto grava nos próprios registros de auditoria —, este é entregue ao
serviço remoto, e é o serviço que decide se conhece o participante.

### `Signing:Profiles[].Method` + bloco `Signer`

Seleção do método por perfil **como seed**, importada no primeiro boot com a tabela de perfis vazia. O
padrão é `Method = Local`, então os perfis que já existiam não precisam de mudança.

```json
"Signing": {
  "Profiles": [
    {
      "Name": "contracts",
      "Format": "Pades",
      "Method": "LacunaSigner",
      "Verify": true,
      "Encrypt": false,
      "ValidateCertificate": false,
      "Signer": {
        "Name": "Jack Bauer",
        "Email": "jack.bauer@example.com",
        "Identifier": "75502846369"
      }
    }
  ]
}
```

Validação no nível do perfil:

- `Method = LacunaSigner` **exige** um bloco `Signer:{Name, Email, Identifier}` não vazio. O validador
  recusa blocos parciais.
- `Method = LacunaSigner` **proíbe** um bloco `Certificate:*` (não há certificado local envolvido).
- `Method = LacunaSigner` **proíbe** `ValidateCertificate = true` (não há certificado local a validar).
- As regras de `Method = Local` não mudam: o bloco de certificado é obrigatório, e o bloco `Signer` é
  ignorado se estiver presente.
- `Method = LacunaSigner` não pode ser combinado com uma regra de aprovação cujo conjunto de assinantes
  seja `ProfileKeyAndApprovers` — o assinador remoto receberia um envelope de assinaturas de aprovadores,
  e não o arquivo de pagamento. Veja [Aprovações](https://docs.lacunasoftware.com/articles/bulk-signer/approvals#o-conjunto-de-assinantes).

As mesmas regras fazem um salvamento ser recusado na página do perfil. O perfil `default` derivado
(criado pelo seed quando `Signing:Profiles[]` é omitido) é sempre `Method = Local`.

## Fluxo do operador

1. **O operador coloca um arquivo** em uma pasta monitorada por um perfil LacunaSigner (ou usa
   `POST /api/files?profile=contracts`).
2. **O observador / endpoint** enfileira o job; `Status = Queued`.
3. **O worker do pipeline** reivindica o próximo slot, passa o job para `Processing` e então faz o
   upload e cria o documento no Signer. Em caso de sucesso, o job passa para `AwaitingSigner`, com o id
   do documento remoto registrado; o slot é liberado.
4. **O Signer** envia um e-mail ao participante, que assina pela interface do Signer quando puder.
5. **O worker de polling** executa um tique a cada `Signer:PollIntervalSeconds`. Em cada tique, ele
   carrega todas as linhas `AwaitingSigner`, das mais antigas para as mais novas, e, para cada uma:
   - **Pending** → não mexe na linha.
   - **Concluded** → baixa os bytes assinados, passa o job para `Verifying`, executa a mesma etapa final
     de verificar → opcionalmente criptografar → promover e passa o job para `Completed`.
   - **Refused / Expired / Canceled** → passa o job para `Failed` com `signer.document-rejected`.
   - **Timeout local** (`AwaitingSigner` por mais tempo que `Signer:TimeoutHours`) → passa o job para
     `Failed` com `signer.timeout`. O documento remoto é deixado como está, do lado do Signer.

O dashboard exibe `AwaitingSigner` como um status próprio (chip amarelo, ícone de ampulheta). A página
de detalhe do job mostra o id do documento remoto e a hora do despacho, e um card de estatística
**Aguardando assinatura** aparece quando algum perfil LacunaSigner está configurado.

## Semântica do cancelamento

Em perfis LacunaSigner, o cancelamento pelo operador passa a valer para **`{Queued, AwaitingSigner}`**.
`Processing` e `Verifying` continuam intocáveis.

Quando um operador cancela um job `AwaitingSigner`:

1. O job passa para `Canceled` localmente — mesmo handler, mesma trilha de auditoria.
2. Em seguida, o handler faz uma chamada de cancelamento remoto ao Signer, em **melhor esforço**. As
   falhas são registradas no log como Warning, mas **não** desfazem o cancelamento local.
3. Se o cancelamento remoto falhou, o participante ainda pode ver o documento na caixa de entrada do
   Signer. O job local está corretamente `Canceled` de qualquer forma.

O botão **Cancelar** na página do job pede confirmação antes: o diálogo mostra o nome do arquivo e explica o que
o cancelamento faz a partir do status atual do job — no caso de um job aguardando o Lacuna Signer, que o
documento remoto dele é cancelado em melhor esforço. O `POST /api/jobs/{id}/cancel` não pede
confirmação.

> **Aviso: O Limpar Jobs não cancela documentos remotos**
>
> O **Limpar Jobs** apaga todos os registros de jobs, qualquer que seja o status, inclusive
> `AwaitingSigner`, mas não faz nenhuma chamada ao Lacuna Signer: um documento já despachado continua na
> caixa de entrada do participante. Cancele esses jobs antes se o participante não deve assiná-los. Veja
> [Operação](https://docs.lacunasoftware.com/articles/bulk-signer/operations#limpar-jobs).

> **Observação: O cancelamento em melhor esforço é uma escolha deliberada.**
>
> Desfazer o cancelamento local porque uma ida e volta de rede falhou deixaria o operador sem saber em que
> estado o job ficou e contradiria o princípio de que "cancelar encerra a questão". O caso de um documento
> remoto órfão é raro e inofensivo — o participante pode ignorar o e-mail, ou o operador pode fazer a
> limpeza na administração do Signer.

## Falhas de API e o limite por job

A integração com o Signer distingue dois tipos de falha:

- **Transitória** — uma conexão recusada ou um timeout, um `5xx`, `408` ou `429`, ou uma resposta que
  não vem da API do Signer (a página de erro de um proxy). O worker de polling incrementa um contador de falhas por documento e segue para a próxima linha. O contador
  zera na primeira chamada bem-sucedida. Quando o `Signer:MaxConsecutiveApiFailures` é excedido para um
  único documento, aquele job falha com `code = signer.unreachable`. As outras linhas não são afetadas.
- **Permanente** — um 4xx que não se resolve com novas tentativas (chave de API inválida, documento
  desconhecido, requisição malformada). O job falha imediatamente com `code = signer.unreachable`.

Um reinício do processo zera os contadores de falha, que ficam em memória. Se a indisponibilidade de
origem foi resolvida entre as falhas e o reinício, o polling é retomado normalmente no próximo boot.

> **Aviso: Mudou na 2.16.0 — toda forma de "Signer fora do alcance" conta para o limite**
>
> Até a 2.15.x, só uma falha de conexão pura era reconhecida como o Signer estando inacessível. Um `5xx`,
> um `408` ou `429`, a página de erro de um proxy ou o timeout do próprio cliente REST durante um polling
> ou download era registrado no log e tentado de novo a cada tique, sem contar, até o
> `Signer:TimeoutHours`. A partir da 2.16.0, cada um deles conta para o `Signer:MaxConsecutiveApiFailures`
> e para o `bulksigner_signer_api_errors_total`; assim, uma indisponibilidade mais longa que o limite faz
> o job falhar com `signer.unreachable` — use **Tentar novamente** quando o Signer voltar. Um erro HTTP que
> a API do Signer não formatou, como um `4xx` puro vindo de algo no caminho, agora faz o job falhar na hora
> como permanente, como as recusas do próprio Signer sempre fizeram.

> **Observação: Assimetria entre despacho e polling.**
>
> O `Signer:MaxConsecutiveApiFailures` protege apenas o caminho de **polling**. Uma falha transitória
> durante o **despacho** faz o job falhar no primeiro erro, em vez de ser repetida até um limite — por
> design, já que o despacho é uma única chamada curta no início do job. Se o seu endpoint do Signer é
> instável a ponto de as falhas de despacho serem um problema, faça uma nova tentativa pelo dashboard ou
> por REST (`POST /api/jobs/{id}/retry`) quando o serviço remoto voltar.

## Recuperação após reinício — linhas `AwaitingSigner` NÃO são varridas

A varredura de recuperação na inicialização passa para `Failed` qualquer job travado em `Processing` /
`Verifying` (eles estavam em andamento quando o processo anterior morreu) — exceto um job
[`SignerFolder`](https://docs.lacunasoftware.com/articles/bulk-signer/lacuna-signer#assinando-em-uma-pasta-do-lacuna-signer--signerfolder), que não tem arquivo e é
encerrado pela resposta do Lacuna Signer (veja
[Quando a execução que o assinava termina](https://docs.lacunasoftware.com/articles/bulk-signer/lacuna-signer#quando-a-execução-que-o-assinava-termina)). **As linhas `AwaitingSigner`
são explicitamente excluídas** — o trabalho está retido do lado remoto; varrê-las localmente perderia
dados que não cabe ao host invalidar. O worker de polling retoma o polling dessas linhas no próximo
boot, exatamente de onde parou.

## O que chega a `output/`

Em perfis LacunaSigner, os bytes promovidos para `output/` são os bytes **que o Signer assinou** — a
assinatura do participante sobre o documento original, baixada depois que o documento é concluído. As
etapas de verificação e criptografia rodam sobre esses bytes exatamente como rodariam em um perfil
Local; então:

- `Verify = true` (padrão) — a assinatura é verificada com base na política configurada, após o
  download.
- `Encrypt = true` + `Encryption:Enabled = true` — os bytes baixados são criptografados com AES-256-GCM
  em um envelope BSENC v1; o texto claro nunca é gravado em `output/`.

Os arquivos de entrada originais só são apagados de `input/` depois que a etapa de verificação é
concluída com sucesso — a mesma garantia do caminho Local.

## Métricas

Instrumentos Prometheus específicos do Signer são expostos em `/api/metrics`:

| Métrica | Tipo | O que ela acompanha |
|---------|------|---------------------|
| `bulksigner_jobs_dispatched_to_signer_total{profile}` | Counter | Despachos bem-sucedidos ao Signer, rotulados pelo nome do perfil. |
| `bulksigner_jobs_awaiting_signer` | Gauge | Contagem atual de linhas `AwaitingSigner`. |
| `bulksigner_signer_poll_duration_seconds` | Histogram | Duração, por tique, de uma passada completa sobre as linhas `AwaitingSigner`. |
| `bulksigner_signer_api_errors_total{op}` | Counter | Falhas da API do Signer encontradas pelo worker de polling, rotuladas por operação (`poll`, `download`). Falhas de despacho e de cancelamento remoto ficam no registro do job — veja a nota sobre a assimetria acima. |

O método `SignerFolder` tem instrumentos próprios — veja [Métricas e auditoria](https://docs.lacunasoftware.com/articles/bulk-signer/lacuna-signer#métricas-e-auditoria)
abaixo.

## No modo cluster

Com o modo cluster ligado, **cada instância só faz polling no Lacuna Signer dos documentos que ela
mesma despachou**, de modo que duas instâncias nunca baixam os mesmos bytes assinados. Há duas
consequências para dashboards e alertas: o `bulksigner_jobs_awaiting_signer` é por instância — some os
valores de toda a frota —, e um job que uma instância despachou antes de morrer é reatribuído a uma
sobrevivente pela varredura de assunção. Uma linha sem dono algum não recebe polling de ninguém. Veja
[Alta disponibilidade](https://docs.lacunasoftware.com/articles/bulk-signer/high-availability) para os detalhes e a solução.

## Assinando em uma pasta do Lacuna Signer — `SignerFolder`

> **Dica: Novo na 2.16.0**
>
> Um terceiro método de assinatura. Nada muda para um host sem perfil `SignerFolder`.

Tudo o que está acima segue uma direção: este host envia um arquivo ao Signer, e uma pessoa o assina
lá. **`Method = SignerFolder`** é a outra: uma pessoa cria um documento **no Lacuna Signer**, em uma
pasta vinculada a um perfil do Bulk Signer, com o titular do certificado do perfil como participante;
este host o assina com o certificado do próprio perfil, e o Signer incorpora a assinatura ao documento e
o guarda. Nenhum arquivo entra em `input/`, nada chega a `output/`, e o documento deixa de ser
acompanhado assim que o Signer aceita a assinatura.

[![Assinatura em pasta do Lacuna Signer: o documento é criado e aguarda a vez do titular no Lacuna Signer, o Bulk Signer o encontra, assina com o certificado da empresa o hash que o Signer prepara, e o Signer incorpora a assinatura ao documento](https://docs.lacunasoftware.com/images/bulk-signer/signer-folder-pt.png)](https://docs.lacunasoftware.com/images/bulk-signer/signer-folder-pt.png)

*Clique no diagrama para abri-lo em tamanho real.*

As chamadas entre as três partes:

```text
 Pessoa                    Lacuna Signer                         Bulk Signer
   │  cria um documento na       │                                     │
   │  pasta vinculada, indicando │                                     │
   │  o titular do certificado ▶ │ ── notificação (opcional) ────────▶ │
   │                             │ ◀── varredura / checagem: relê ──── │
   │                             │                                     │ vez do titular? → job
   │                             │ ◀── inicia com o certificado ────── │
   │                             │ ─── hash a assinar ───────────────▶ │
   │                             │                                     │ assina com a chave do perfil
   │                             │ ◀── conclui com a assinatura ────── │
   │                             │ incorpora, guarda o documento       │
```

### O perfil

Ele mantém um certificado — qualquer [origem](https://docs.lacunasoftware.com/articles/bulk-signer/certificates), inclusive um PKCS#12 enviado e o Azure
Key Vault, com a recusa por host do modo cluster inalterada — e ganha uma **pasta do Lacuna Signer**,
pelo id da pasta no Signer, no lugar de uma pasta de entrada. O vínculo é **um para um e com a própria
pasta**: dois perfis não podem compartilhar uma pasta, e um documento em uma subpasta não é do perfil. O
titular do certificado é identificado pelo **CPF que o certificado traz** — certificados e-CPF e e-CNPJ
trazem um —, nunca por um campo digitado. O perfil reaproveita o `Signer:Endpoint` e a `Signer:ApiKey`
deste host (um tenant por host), e é recusado em um host sem eles. O seed pode declarar um perfil assim —
o formato da configuração e todas as recusas estão em
[Configuração](https://docs.lacunasoftware.com/articles/bulk-signer/configuration#assinando-em-uma-pasta-do-lacuna-signer--method--signerfolder) —, e o
dashboard também, como descrito abaixo.

### Escolhendo a pasta pelo dashboard

Em `/profiles/_new`, ou no painel **Certificado** de `/profiles/{name}`, escolha **Pasta do Lacuna
Signer** como método. Os campos do certificado continuam — este host assina com aquela chave — e um
seletor de **Pasta do Lacuna Signer** aparece acima deles: ele lista as pastas da organização do Signer a
que pertence a chave de API deste host, com busca pelo nome, inclusive pastas aninhadas, e grava o **id**
da pasta junto com o **nome com que você a escolheu**, que é o que a página do perfil mostra depois.
Apenas a própria pasta é vinculada, nunca as subpastas. Se não for possível contatar o Signer, o seletor
avisa e mantém a pasta já escolhida; nada mais no formulário é afetado. A página também informa, ao lado
do seletor, que o Signer escolhe o formato e que a política ICP-Brasil em um PDF é uma configuração da
organização no Signer.

Nesse método, o painel **Comportamento** esconde o que o Signer decide — a pasta de entrada, a
verificação, a criptografia e a checagem CNAB240 — e as salva desligadas; o formato continua visível,
mas é ignorado, guardado para uma mudança futura para um método que o leia. O salvamento é recusado, no
seu idioma, quando há:

- **nenhuma pasta**, ou uma pasta **em que outro perfil já assina** — com o nome desse perfil. Dois
  salvamentos que escolhem a mesma pasta no mesmo instante são decididos pelo banco operacional, e o
  perdedor recebe a mesma mensagem;
- um host **sem configurações `Signer:*`**;
- o perfil **`default`** — é para ele que vão os uploads sem perfil e as pastas sem vínculo, e este
  método não recebe arquivos;
- a mudança de um perfil para o método enquanto ele ainda tem **verificação, criptografia, validação do
  certificado ou a checagem CNAB240 ligadas, uma pasta de entrada ou uma regra de aprovação** — desligue,
  limpe a pasta ou remova a regra nos respectivos painéis antes;
- a mudança de um perfil **para fora** do método quando ele **não tem formato** escolhido — escolha um no
  painel **Comportamento** antes;
- em `/profiles/_new`, que abre o certificado enquanto você espera, um certificado **sem CPF**: nenhuma
  ação do fluxo no Signer poderia ser associada a ele. Use um e-CPF ou e-CNPJ ICP-Brasil.

### O Signer escolhe o formato, não o perfil

Um PDF é assinado em **PAdES**, um documento XML em **XAdES**, e qualquer outro em **CAdES** (AD-RB) — o
`Format` do perfil é ignorado, e o job registra o formato que o Signer vai usar. Em um PDF, **a aplicação
da política ICP-Brasil depende da configuração `UseBrazilianPdfSigningPolicies` da organização no
Signer**, e não do Bulk Signer: o padrão ADR-Básica do produto não alcança uma assinatura que o Signer
monta. Verificação, criptografia, validação do certificado e a checagem CNAB240 são do Signer ou não se
aplicam; por isso o perfil precisa ter `Verify`, `Encrypt`, `ValidateCertificate` e `CheckCnab240`
desligados, e não tem regra de aprovação — o fluxo, aprovadores inclusive, é decidido no Signer.

### Como um documento é encontrado

A cada `Signer:FolderSweepIntervalSeconds` (padrão: cinco minutos), uma **varredura** lista os documentos
pendentes da pasta de cada perfil habilitado e relê cada um com a própria chave de API deste host. Um
documento vira um **job** quando ainda está exatamente naquela pasta, ainda está pendente, e a ação do
fluxo **pendente atual** é uma ação de assinatura cujo identificador do participante é o CPF do titular.
Um documento cujos participantes anteriores ainda não agiram não gera nada — ele é encontrado de novo
quando chega a vez do titular, já que é o Signer, e não o Bulk Signer, que controla essa espera.

Cada par (documento, ação do fluxo) é **definitivo depois de ter tido um job**: um documento encontrado
de novo — pela próxima varredura, ou por outra instância no modo cluster — não cria nada, qualquer que
seja o status do job existente, e **Tentar novamente é o único caminho de volta** (abaixo). O par fica
registrado como descoberto em um registro próprio, que [excluir o job](https://docs.lacunasoftware.com/articles/bulk-signer/operations#excluindo-um-job) e
o [Limpar Jobs](https://docs.lacunasoftware.com/articles/bulk-signer/operations#limpar-jobs) mantêm; assim, nenhum dos dois faz a varredura assinar o
documento de novo.

Um documento pendente na pasta **sem nenhuma ação de assinatura para o titular** — nem mais adiante no
fluxo, nem já concluída — é algo que uma pasta vinculada um para um não deveria conter: ele é registrado
**uma vez** como um job `Failed` com `signer-folder.no-holder-action`, para que alguém o veja, e todas as
varreduras seguintes o deixam em paz.

A varredura roda com o pipeline pausado ou não — a descoberta só enfileira jobs; a pausa impede que eles
sejam reivindicados — e a pasta de um perfil desabilitado é ignorada. Uma **notificação** do Signer reduz
a espera para segundos — [abaixo](https://docs.lacunasoftware.com/articles/bulk-signer/lacuna-signer#notificações--o-webhook) —, e a varredura continua sendo a garantia de
qualquer forma.

### Como ele é assinado

O job é reivindicado como qualquer outro — sob a chave de pausa e o `Pipeline:MaxConcurrency`, e é por
isso que cada assinatura é um job — e o worker:

1. relê o documento e confere se a ação do fluxo ainda é do titular e ainda é a atual;
2. pede ao Signer a URL de ação do titular (CPF e o e-mail do participante da ação, e o id da ação quando
   o titular tem mais de uma pendente) e extrai dela a chave do documento e o ticket;
3. inicia uma assinatura pública com o certificado, recebendo o hash a assinar e o algoritmo de digest
   com que ele foi calculado;
4. recusa qualquer coisa que não seja SHA-256, SHA-384 ou SHA-512 — SHA-1 e um digest desconhecido ou
   ausente, pelo nome, e um hash com o tamanho errado — **antes de tocar na chave**;
5. assina o hash **como hash** com a chave do perfil e devolve a assinatura ao Signer, que a incorpora
   ao documento.

O job passa por `Processing`, depois por `Verifying` enquanto o Signer confere a assinatura, e então
`Completed` quando o Signer a aceita. A página do job e a lista `/jobs` mostram o nome do documento e o
tipo MIME dele.

### Quando ele não é assinado

Qualquer outro desfecho é um de dois, e **o documento nunca é cancelado nem recusado no Signer** em
nenhum deles: este host não o criou, e ele continua pendente lá.

- **`Canceled` — o documento seguiu adiante antes de este host assiná-lo.** Ele foi cancelado, recusado
  ou expirou no Signer, a ação do titular já foi concluída, ou o Signer respondeu à URL de ação ou ao
  início que a ação não está pendente (`NoPendingActionFoundForEmailAndIdentifier`,
  `SignatureNotPending`, `FlowActionNotPending`) **e uma segunda leitura confirma** — uma segunda leitura
  que ainda mostra a ação pendente significa que o Signer não associou o participante, e o job termina
  `Failed` com `signer-folder.signature-failed`. Nada deu errado aqui, então o job não tem código; o
  histórico diz `No longer pending at Lacuna Signer: <status>.` Uma ação que volta a esperar uma etapa
  anterior não "seguiu adiante" — é um fluxo editado por baixo deste host, e falha com
  `signer-folder.signature-failed`, já que um par que teve job nunca é redescoberto.
- **`Failed` com um código — todo o resto.** `signer-folder.signature-refused` quando o Signer recusou a
  assinatura na resposta (os resultados da validação ficam no histórico do job);
  `signer-folder.key-unavailable` quando a chave do perfil não assinou; `signer.unreachable` quando não
  foi possível contatar o Signer ou ele não respondeu de forma útil — uma conexão recusada, um timeout,
  um `5xx`, `408` ou `429`, ou uma resposta que não vem da API do Signer, como a página de erro de um
  proxy; `signer-folder.action-url-malformed` quando a URL de ação do Signer não trazia chave ou ticket;
  `signer-folder.profile-changed` quando o perfil do job saiu do método; `signer-folder.interrupted`
  quando a execução que o assinava terminou no meio da assinatura (abaixo);
  `signer-folder.signature-failed` para o resto — o documento saiu da pasta, a ação deixou de ser do
  titular, um digest sob o qual este host não assina —, com o motivo no histórico. Cada um está em
  [Diagnóstico de problemas](https://docs.lacunasoftware.com/articles/bulk-signer/troubleshooting#um-job-de-pasta-do-lacuna-signer-termina-failed-ou-canceled).

Uma falha depois de a assinatura ter sido entregue ao Signer — uma conclusão que deu timeout — informa no
job que o Signer pode tê-la aceitado; um **Tentar novamente** então relê o documento e termina `Canceled`
em vez de assinar duas vezes. Uma falha depois de a assinatura ter sido calculada, mas antes de ser
entregue, informa isso: o documento está intacto no Signer.

### Quando a execução que o assinava termina

Uma reinicialização, ou uma instância que parou de responder no modo cluster: a recuperação na
inicialização, e a sobrevivente que [assume o job](https://docs.lacunasoftware.com/articles/bulk-signer/high-availability), não podem olhar em `output/`
para um job assim; por isso elas **perguntam ao Lacuna Signer** — uma leitura do documento com a chave de
API deste host, nada mais — e encerram o job pela resposta:

| O job estava | O Lacuna Signer informa | O job termina |
|---|---|---|
| `Processing`, a chave nunca foi acionada | — (não é perguntado) | De volta à **fila**: nada foi tentado, então isto é recuperação, não uma nova tentativa. A próxima reivindicação relê o documento, como toda reivindicação |
| `Verifying` — a assinatura foi entregue ao Signer | a ação do fluxo do titular `Completed` | **`Completed`**, com o histórico dizendo que o Signer informa a ação como concluída. Nada é gravado em disco; não há o que gravar |
| `Processing`, depois da chave — a assinatura nunca saiu deste host | o documento ou a ação do titular seguiu adiante | **`Canceled`**, `No longer pending at Lacuna Signer: …` — o mesmo desfecho da etapa de assinatura, já que a assinatura deste job nunca chegou ao Signer |
| qualquer um, depois da chave | a ação do titular ainda pendente, ou qualquer estado que este host não interpreta como um desfecho | **`Failed`, `signer-folder.interrupted`**, com o histórico dizendo se a assinatura tinha sido entregue e o que o Signer informou |
| qualquer um, depois da chave | — o Signer não está configurado neste host, não responde ou responde com erro | **`Failed`, `signer-folder.interrupted`**, com o histórico dizendo que não foi possível perguntar ao Signer, e por quê |

Um job que passou da chave nunca volta à fila, diga o Signer o que disser: isso seria uma segunda
assinatura que ninguém decidiu. **Confira o documento no Lacuna Signer antes de usar Tentar novamente**
em um job `signer-folder.interrupted` — a nova tentativa o relê e termina `Canceled` se a ação do titular
já estiver concluída, então ela nunca assina duas vezes, de qualquer forma.

A consulta é limitada para que o Signer não consiga segurar um boot: cada leitura é interrompida após dez
segundos, a recuperação inteira para de perguntar após trinta, e, depois que o Signer deixa de responder,
os jobs restantes daquela recuperação seguem o caminho alternativo sem perguntar — o host sobe de
qualquer forma. Um job cuja conclusão este host não conseguiu registrar depois de o Signer aceitar a
assinatura é exatamente a linha `Verifying` que a tabela conclui no próximo início.

### Tentar novamente é o único caminho de volta

A partir de `Failed` e também de `Canceled` — inclusive o cancelamento de um job `Queued` pelo operador,
que é só local e nunca chega ao Signer. Uma nova tentativa é um job novo que aponta o antigo como pai,
para o mesmo documento e a mesma ação do fluxo, e ela **recomeça do zero**: a reivindicação relê o
documento, pede uma nova URL de ação e abre um novo início, cujo token é de uso único. Ela assina
enquanto a ação do titular ainda está pendente e termina `Canceled` quando não está mais. Só um job por
(documento, ação do fluxo) trabalha por vez; por isso, uma segunda tentativa enquanto a primeira está na
fila é recusada com `job.already-processing`. Um documento registrado com
`signer-folder.no-holder-action` não aceita nova tentativa — não há nada deste host a repetir, e, quando
o titular é adicionado no Signer, a próxima varredura encontra a nova ação sozinha.

### Quando o próprio perfil não consegue trabalhar

Três condições param um perfil `SignerFolder` sem parar o host nem nenhum outro perfil, e cada uma é
informada como um certificado que não abre: na própria página do perfil e em `/profiles` como *Este
perfil não consegue assinar*, como `degraded: true` no `GET /api/profiles`, e como uma linha
`signing-profile:<name>` em `/api/ready` que fica vermelha, mas não faz a resposta falhar. Um job já
enfileirado para o perfil falha com `profile.degraded`, citando o motivo; a varredura e as notificações
não criam job novo para ele, e um **Tentar novamente** cria, mas falha da mesma forma ao ser
reivindicado.

- **Este host não tem configurações `Signer:*`.** Todo salvamento e o seed recusam o método em um host
  assim; então este é um perfil armazenado cujo host perdeu o `Signer:Endpoint` e a `Signer:ApiKey`
  depois — ou um irmão do cluster configurado de outro jeito. Sem credencial, a varredura nem chega a
  iniciar, e nada na pasta seria encontrado; em vez de não fazer nada em silêncio, o perfil é degradado
  citando as duas chaves. Configure as chaves e reinicie, ou tire o perfil do método na página dele.
- **O certificado não tem CPF.** Nada no Signer poderia ser associado ao titular. Isso é detectado onde
  quer que o perfil seja resolvido — na inicialização e na próxima atualização depois de um salvamento
  que passou o perfil para o método com um certificado assim —, nunca impedindo o boot. Dê ao perfil um
  e-CPF ou e-CNPJ ICP-Brasil (lido na próxima reinicialização, como toda mudança de certificado), ou tire
  o perfil do método.
- **A pasta vinculada não existe mais no Signer** — foi excluída lá. Nada na inicialização pergunta ao
  Signer sobre uma pasta: é a **varredura** que descobre isso, e ela só pergunta ao Signer se a pasta
  ainda existe quando a listagem de pendentes da pasta volta vazia, já que o Signer lista uma pasta
  inexistente como vazia. Só a resposta do próprio Signer de que a pasta não existe (`FolderNotFound`)
  degrada o perfil; **uma indisponibilidade durante a pergunta não degrada** — é uma falha daquela
  varredura, avisada e perguntada de novo na próxima. Vincule o perfil a outra pasta na página dele: a
  degradação fica com a pasta antiga, na hora, sem reinicialização. A varredura também pergunta de novo a
  cada passada; assim, uma resposta errada — `Signer:ApiKey` ou `Signer:Endpoint` apontando por um
  instante para outra organização — se resolve sozinha quando o Signer encontra a pasta. Uma
  reinicialização esquece a degradação, e a primeira varredura depois dela a descobre de novo.

A varredura ignora a pasta de um perfil degradado — sem listagem, sem leitura, sem job, e uma notificação
para ela é descartada — e **avisa uma vez**, no console e no log durável, em vez de a cada passada. Veja
[Diagnóstico de problemas](https://docs.lacunasoftware.com/articles/bulk-signer/troubleshooting#um-perfil-de-pasta-do-signer-está-degradado-dizendo-que-o-certificado-não-tem-cpf).

### Nenhum arquivo chega a um perfil `SignerFolder`

Um upload que o nomeia, um reescaneamento ou uma pasta monitorada cujos arquivos são roteados para ele,
ou uma nova tentativa de um job de arquivo cujo perfil passou depois para o método é recusado na entrada
com `profile.takes-no-files`, antes de qualquer coisa ser preparada.

### Métricas e auditoria

| Métrica | Tipo | O que ela acompanha |
|---------|------|---------------------|
| `bulksigner_signer_folder_jobs_enqueued_total{profile}` | Counter | Jobs criados para documentos encontrados à espera, e para novas tentativas deles. Um documento encontrado de novo não cria nada e não é contado. |
| `bulksigner_signer_folder_signatures_total{outcome}` | Counter | Tentativas de assinatura: `signed`, `refused` (pelo Signer, na resposta), `no-longer-pending` (seguiu adiante antes de existir uma assinatura; terminou `Canceled`) ou `failed`. |
| `bulksigner_signer_folder_sweep_errors_total{op}` | Counter | Chamadas ao Signer que a varredura não conseguiu concluir (`list`, `folder` — a pergunta se uma pasta cuja listagem voltou vazia ainda existe —, `read`, `enqueue`) e passadas que falharam por inteiro (`pass`). Uma varredura que falha não perde nada; a próxima pergunta de novo. |
| `bulksigner_signer_notifications_total{outcome}` | Counter | Notificações recebidas — veja [abaixo](https://docs.lacunasoftware.com/articles/bulk-signer/lacuna-signer#notificações--o-webhook). |

**Uma varredura que continua falhando é uma linha de prontidão**: `signer-folder-sweep` em `/api/ready`
fica vermelha depois de três passadas seguidas com alguma falha cada — uma `Signer:ApiKey` revogada faz
todas falharem — e `/api/ready/details` diz desde quando e o que falhou por último, por etapa e tipo
(nunca a mensagem do Signer, que pode citar a chave de um documento). Ela nunca muda o veredito: um `503`
não traria o Signer de volta e pararia todo o resto que este host faz. Veja
[Diagnóstico de problemas](https://docs.lacunasoftware.com/articles/bulk-signer/troubleshooting#a-linha-signer-folder-sweep-em-apireadydetails-está-vermelha).

Os eventos operacionais são `SignerDocumentEnqueued`, `SignerDocumentWithoutHolderAction`,
`JobSignedAtSigner` e `JobNoLongerPendingAtSigner`.

### Notificações — o webhook

A varredura encontra um documento dentro de `Signer:FolderSweepIntervalSeconds`. Uma **notificação** o
encontra em segundos: o Signer chama este host quando um documento é criado, ou quando um participante
assina ou aprova — a etapa anterior à do titular é como se descobre que "chegou a vez do titular", já que
o Signer não tem evento para uma ação que passa a ficar pendente. Ela é opcional, e só vale a pena onde o
Signer consegue alcançar este host; um host sem entrada pública perde minutos, nunca documentos.

**Uma notificação é uma campainha, não uma ordem.** Nada no corpo dela é levado em conta como verdade.
Este host lê quais documentos ela cita e em que pasta ela diz que cada um está, enfileira uma **checagem**
para cada um que está na pasta vinculada a um perfil habilitado e responde — sem chamar o Signer dentro
da requisição. A checagem então faz exatamente o que a varredura faz para um documento: relê o documento
no Signer com a própria chave de API deste host, e só enfileira um job se ele ainda está exatamente
naquela pasta, pendente, e é a vez do titular. Uma notificação forjada pode, no máximo, fazer este host
perguntar ao Signer sobre um documento; uma repetida não cria nada, porque a checagem segue o caminho da
varredura e a idempotência dela. Os documentos de um perfil desabilitado são confirmados e descartados.

**Configurando.**

1. Gere um segredo aleatório longo — pelo menos 32 caracteres — e defina-o neste host como
   `Signer:WebhookSecret` (a variável de ambiente `Signer__WebhookSecret`; nunca no `appsettings.json`).
   Reinicie. Sem segredo, a rota responde `404`.
2. No Lacuna Signer, abra a página de **integrações da organização** e adicione um **webhook**:
   - **URL:** o endereço público deste host seguido de `/api/signer/notifications` — por exemplo,
     `https://bulksigner.example.com/api/signer/notifications`. Atrás de um proxy reverso, o endereço que
     o proxy publica.
   - **Autenticação:** **Bearer**, com o segredo do passo 1 como token. Não `X-API-Key` — esse header é a
     credencial REST do próprio produto, e uma notificação que chega com ele é recusada.
   - **Eventos:** o Signer entrega todo evento a todo webhook da organização; este host age sobre
     `DocumentsCreated`, `DocumentSigned` e `DocumentApproved` e apenas confirma o recebimento dos demais.
3. Use a entrega de teste do Signer, ou crie um documento na pasta vinculada, e leia
   `/api/ready/details`: a linha `signer-notifications` diz quando a última notificação chegou **àquela
   instância**. No modo cluster, cada instância informa só o que chegou a ela.

**O que ela responde.** `401` para um token Bearer ausente ou errado (`signer-notification.unauthorized`);
`202` quando um documento em uma pasta vinculada foi enfileirado para checagem, ou já estava esperando
por ela; `204` para toda outra entrega autenticada — um evento que não pode deixar um documento à espera,
uma pasta sem vínculo, a pasta de um perfil desabilitado, um corpo que este host não consegue ler —,
porque o Signer tenta de novo qualquer resposta que não seja 2xx, e uma nova tentativa não mudaria nada
disso; `503` só quando este host falhou (`signer-notification.unavailable`): o banco operacional não
está utilizável nesta instância, ou há checagens demais esperando. `429` é o limite de requisições da
própria rota (`RateLimiting:SignerNotification`), que o Signer também tenta de novo. As checagens ficam
em memória: uma reinicialização esquece as que ainda não foram feitas, e a próxima varredura encontra os
documentos delas. O contrato completo está em [API REST](https://docs.lacunasoftware.com/articles/bulk-signer/rest-api#notificações-do-signer).

## Referências cruzadas de diagnóstico

Veja em [Diagnóstico de problemas](https://docs.lacunasoftware.com/articles/bulk-signer/troubleshooting) os passos de diagnóstico para:

- API do Signer inacessível / avalanche de erros 5xx
- Chave de API errada — `401` em todas as chamadas
- Documento travado em `Pending` além de `Signer:TimeoutHours`
- O operador cancelou, mas o participante ainda vê o documento
- O dashboard não mostra o painel do Lacuna Signer mesmo com um perfil que o utiliza
- [Um job de pasta do Lacuna Signer termina `Failed` ou `Canceled`](https://docs.lacunasoftware.com/articles/bulk-signer/troubleshooting#um-job-de-pasta-do-lacuna-signer-termina-failed-ou-canceled)
- [Um perfil de pasta do Signer está degradado](https://docs.lacunasoftware.com/articles/bulk-signer/troubleshooting#um-perfil-de-pasta-do-signer-está-degradado-dizendo-que-o-host-não-tem-configurações-do-lacuna-signer) — sem configurações `Signer:*`, sem CPF, ou com uma pasta que não existe mais
- [A linha de prontidão `signer-folder-sweep` está vermelha](https://docs.lacunasoftware.com/articles/bulk-signer/troubleshooting#a-linha-signer-folder-sweep-em-apireadydetails-está-vermelha)
- [Documentos só são encontrados no intervalo da varredura, e não em segundos](https://docs.lacunasoftware.com/articles/bulk-signer/troubleshooting#documentos-do-lacuna-signer-só-são-encontrados-no-intervalo-da-varredura-e-não-em-segundos)

---

**A seguir:** [Arquivos de pagamento CNAB240](https://docs.lacunasoftware.com/articles/bulk-signer/cnab240).
**Anterior:** [Criptografia](https://docs.lacunasoftware.com/articles/bulk-signer/encryption).
