---
title: "Assinar documentos em lote"
description: "Como assinar vários documentos do Signer com o certificado do usuário de uma só vez, a partir da sua aplicação: as chamadas de assinatura pública do Signer, feitas uma vez por documento, com o Web PKI assinando todos os hashes depois de uma única confirmação."
canonical: "https://docs.lacunasoftware.com/articles/signer/integration/batch-signing"
locale: "pt-BR"
product: "Signer"
last_updated: "2026-10-12"
---

# Assinar documentos em lote

A sua aplicação pode fazer o usuário assinar vários documentos do Signer com o certificado dele, confirmando uma única vez. O Signer não tem
um endpoint de assinatura em lote: a sua aplicação faz as chamadas de *assinatura pública* do Signer, início e conclusão, uma vez por
documento, enquanto o [Web PKI](https://docs.lacunasoftware.com/articles/web-pki) assina cada hash no navegador depois de uma única confirmação. 

> **Aviso: Fora da referência da API**
>
> Os endpoints de assinatura pública desta página não estão na referência da API do Signer (Swagger). Os samples da Lacuna os descrevem como
> suportados para integrações de clientes; a única fonte sobre assinatura em lote é o sample em Java
> [`batch-pades-signature-signer`](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/java/springmvc/src/main/java/com/lacunasoftware/pkisuite/controller/BatchSignerSignatureController.java).

## Antes de começar

* O seu servidor chama o Signer com uma chave de API, como no restante do [Guia de Integração](https://docs.lacunasoftware.com/articles/signer/integration-guide). 
* A sua página carrega o Web PKI para listar os certificados do usuário e assinar os hashes. 
* O certificado precisa pertencer ao participante: o Signer verifica se ele tem o CPF do participante e, se não tiver, falha com
  `CpfMismatch`. O sample cria cada documento com o CPF lido do certificado que o usuário escolheu. 

## Fluxo

1. **Servidor**: para cada documento, obtenha a URL de ação do participante e extraia dela a **chave** (key) e o **ticket** do documento.
1. **Navegador**: o Web PKI lê o certificado do usuário e pede que ele autorize todas as assinaturas de uma vez.
1. **Servidor**: para cada documento, inicie a assinatura com a chave, o ticket e o certificado; o Signer devolve o hash a assinar e um
   token.
1. **Navegador**: o Web PKI assina o hash.
1. **Servidor**: conclua a assinatura com a chave, a assinatura e o token.

## 1. Obter a chave e o ticket de cada documento

Os documentos precisam já existir no Signer, com o usuário como signatário no fluxo deles (veja [Criar documentos](https://docs.lacunasoftware.com/articles/signer/integration/documents)); o
sample cria dez, só para a demonstração. 
Para cada documento, o sample chama `POST /api/documents/{id}/action-url` com o `emailAddress` e o `identifier` do participante e extrai a
chave e o ticket do `embedUrl` devolvido, cujo formato é `…/document/key/{key}/sign-embedded?ticket={ticket}`: 

```java
private static final Pattern KEY_PATTERN = Pattern.compile("/key/([^/?]+)");
private static final Pattern TICKET_PATTERN = Pattern.compile("[?&]ticket=([^&]+)");
```

```java
List<CreateDocumentResult> results = signerClient.createDocument(documentRequest);
UUID documentId = results.get(0).getDocumentId();

ActionUrlRequest actionUrlRequest = new ActionUrlRequest();
actionUrlRequest.setEmailAddress(SIGNER_EMAIL);
actionUrlRequest.setIdentifier(cpf);
ActionUrlResponse actionUrlResponse = signerClient.getActionUrl(documentId, actionUrlRequest);

String embedUrl = actionUrlResponse.getEmbedUrl();
String key = extractGroup(KEY_PATTERN, embedUrl, "key");
String ticket = extractGroup(TICKET_PATTERN, embedUrl, "ticket");
```

A chave vai na URL das chamadas de início e de conclusão; o ticket autoriza a assinatura e vai na requisição de início. Guarde o ticket no
servidor, associado à chave: o sample o guarda na sessão HTTP. 

* O formato da chave e do ticket só aparece nos comentários dos samples, não na referência da API. 
* Para criar muitos documentos, a referência da API recomenda várias requisições (para 100 documentos, 10 requisições de 10), com
  `disablePendingActionNotifications` definido, e depois `POST /api/users/notify-pending` quando todos estiverem criados. 

## 2. Autorizar todas as assinaturas de uma vez

No navegador, o sample lê o certificado escolhido e chama o `preauthorizeSignatures` do Web PKI com o número de documentos, para que o
usuário veja um único diálogo de confirmação: 

```js
pki.readCertificate(selectedCertThumbprint).success(function (certEncoded) {
	selectedCertContent = certEncoded;
	pki.preauthorizeSignatures({
		certificateThumbprint: selectedCertThumbprint,
		signatureCount: formElements.documentsIds.length
	}).success(startBatch); // Callback to be called if the user authorizes the signatures.
});
```

## 3. Iniciar, assinar e concluir cada assinatura

**Início.** O seu servidor envia o certificado e o ticket para `POST /api/documents/keys/{key}/signature/certificate`. A resposta traz
`toSignHash`, `digestAlgorithm` e `token`, além de `success` e `validationResults`: 

```java
String ticket = StorageMock.getSignerTicket(session, request.getId());
PublicStartSignatureRequest startRequest = new PublicStartSignatureRequest();
startRequest.setCertificate(Base64.getDecoder().decode(request.getCertContent()));
startRequest.setTicket(ticket);
StartSignatureResponse result = signerClient.startPublicSignature(request.getId(), startRequest);
```

**Assinatura.** O navegador assina o hash com o `signHash` do Web PKI: 

```js
pki.signHash({
	thumbprint: formElements.certificateSelect.val(),
	hash: step.toSignHash,
	digestAlgorithm: step.digestAlgorithm
}).success(function (signature) {
	step.signature = signature;
	done(step);
}).error(function (error) {
	renderFail(step, error);
	done();
});
```

**Conclusão.** O seu servidor envia a assinatura e o token para `POST /api/documents/keys/{key}/signature`; a resposta traz `success` e
`validationResults`: 

```java
CompleteSignatureRequest completeRequest = new CompleteSignatureRequest();
completeRequest.setSignature(Base64.getDecoder().decode(request.getSignature()));
completeRequest.setToken(request.getToken());
signerClient.completePublicSignature(request.getId(), completeRequest);
```

O certificado, o hash e a assinatura trafegam em Base64. 
O sample executa as três etapas como um pipeline de filas, dois documentos por vez em cada etapa. Um documento que falha sai do pipeline e
os demais seguem, sem nova tentativa: 

```js
startQueue.process(startSignature, {threads: 2, output: performQueue});
performQueue.process(performSignature, {threads: 2, output: completeQueue});
completeQueue.process(completeSignature, {threads: 2, completed: onBatchCompleted});
```

Depois da conclusão, baixe cada documento assinado pelo seu servidor, por exemplo com `GET /api/documents/{id}/content?type=Signatures`,
para que a chave de API nunca chegue ao navegador. Veja [Baixar e listar documentos](https://docs.lacunasoftware.com/articles/signer/integration/download-and-list). 

## O que as fontes ainda não dizem

* TODO(docs): o formato do algoritmo de hash: o sample em Java diz que o Signer devolve um OID (como `2.16.840.1.101.3.4.2.1`) e o converte
  para o nome que o Web PKI espera (como `SHA-256`), enquanto o sample de assinatura pública em .NET espera um nome como `SHA256`. 
* TODO(docs): limites de documentos por lote e de requisições (rate limiting) nas chamadas de assinatura; o sample só diz para ajustar a
  concorrência ao seu plano do Signer. 
* TODO(docs): por quanto tempo o ticket e o token valem, e se uma chamada de conclusão pode ser repetida.
* TODO(docs): os códigos de erro das chamadas de início e de conclusão, e o que significam `success` e `validationResults`.
* TODO(docs): se as chamadas `keys/{key}` exigem o header `X-Api-Key`; o cliente Java sempre o envia. 

## Veja também

* [Criar documentos](https://docs.lacunasoftware.com/articles/signer/integration/documents)
* [Assinatura embutida](https://docs.lacunasoftware.com/articles/signer/embedded-signature), para assinar um documento por vez dentro da sua aplicação
* [Referência rápida do Signer](https://docs.lacunasoftware.com/articles/signer/quick-reference)

**Demonstrações e exemplos**

- Sign multiple Signer documents with Web PKI: [Java](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/java/springmvc/src/main/java/com/lacunasoftware/pkisuite/controller/BatchSignerSignatureController.java)
