# Integração de sistemas com o UnifevSigner

Como um sistema da Unifev (ex.: o sistema do Colégio) manda um PDF para assinatura pelo
WhatsApp e recebe o documento assinado de volta.

## 1. Acesso

| | |
|---|---|
| Endereço da API | `http://172.30.1.90:8096/` — **só pela rede interna** (pela internet `/api` dá 404) |
| Painel e portal de assinatura | `https://signer.unifev.com.br` |
| Autenticação | cabeçalho `X-Api-Key: <chave do sistema>` |
| Formato | multipart/form-data (envio) e JSON (consultas) |

A chave é gerada no painel, em **Administração › Sistemas integrados**, e só aparece uma vez.
Guarde no cofre de senhas do sistema (Web.config / appsettings fora do Git), nunca no código.
No cadastro do sistema define-se o **cofre padrão** (ex.: Colégio) e, opcionalmente, a URL do
webhook que recebe os avisos.

## 2. Descobrir os cofres

`GET /api/cofres` lista os cofres ativos. Cada cofre tem uma **chave fixa** (`cfr_...`) que não
muda se o cofre for renomeado. É ela que vai no campo `cofre` do envio. A chave também aparece na
tela do cofre no painel, com botão de copiar.

```json
[
  {
    "chave": "cfr_4f723b337efe",
    "nome": "Colégio",
    "descricao": null,
    "padraoDoSistema": false,
    "pastas": [ { "id": 12, "caminho": "2026" }, { "id": 13, "caminho": "2026/Matrículas" } ]
  }
]
```

`GET /api/cofres/{chave}` traz um cofre só. Não é preciso criar as pastas antes: o envio cria o
caminho informado em `pasta` se ele não existir.

## 3. Criar um envio

`POST /api/envios` — multipart com dois campos:

| Campo | O que é |
|---|---|
| `arquivo` | O PDF (até 25 MB, sem senha). |
| `dados` | JSON com os dados abaixo. |

```json
{
  "titulo": "Contrato de prestação de serviços educacionais 2026 — Ana Souza",
  "cofre": "cfr_4f723b337efe",
  "pasta": "2026/Matrículas",
  "modo": "paralelo",
  "prazoDias": 7,
  "chaveExterna": "contrato:2026:1234",
  "webhookUrl": "https://colegio.unifev.com.br/signer/webhook",
  "signatarios": [
    { "nome": "Maria Aparecida Souza", "telefone": "17999998888", "cpf": "12345678909", "papel": "Responsável financeiro" },
    { "nome": "João Carlos Souza", "telefone": "17999997777", "papel": "Responsável legal" }
  ]
}
```

| Campo | Regra |
|---|---|
| `cofre` | **Chave do cofre** (`cfr_...`, veja `GET /api/cofres`). Também aceita o nome exato. Vazio = cofre padrão do sistema, se houver; sem nenhum dos dois, 422. |
| `pasta` | Caminho separado por `/`. Pastas que não existem são criadas. |
| `modo` | `paralelo` (todos recebem já) ou `sequencial` (um por vez, na ordem). |
| `prazoDias` | 1 a 90. Padrão 7. Depois disso o envio expira. |
| `chaveExterna` | Id do documento no seu sistema. **Repetir a chave não cria outro envio**: devolve o existente (200 em vez de 201). Use sempre. |
| `telefone` | Celular com DDD; aceita pontuação e com/sem 55. |
| `cpf` | Opcional; se vier, é validado. Aparece mascarado no documento. |
| `papel` | Opcional: a qualidade em que assina. Sai no documento. |

Respostas:

| HTTP | Quando |
|---|---|
| **201** | Envio criado e convites disparados. Corpo abaixo. |
| **200** | Mesma `chaveExterna` já existia; corpo do envio existente. |
| **400** | Arquivo ausente / JSON inválido. |
| **401** | Chave ausente ou errada. |
| **422** | Regra de negócio: cofre não encontrado, telefone inválido, CPF inválido, PDF com senha… Ver `detail`. |
| **429** | Muitas requisições; aguarde. |

Corpo (201/200 e nas consultas):

```json
{
  "codigo": "Kj3f...", "codigoVerificacao": "SAQW-493A-6SM9-54PA", "chaveExterna": "contrato:2026:1234",
  "titulo": "...", "cofre": { "chave": "cfr_4f723b337efe", "nome": "Colégio" }, "pasta": "Matrículas", "status": "Aguardando", "modo": "Paralelo",
  "criadoEm": "...", "expiraEm": "...", "concluidoEm": null,
  "hashOriginal": "sha256...", "hashFinal": null,
  "urlValidacao": "https://signer.unifev.com.br/validar/Kj3f...",
  "urlAssinado": null,
  "signatarios": [
    { "nome": "...", "papel": "...", "telefone": "5517*****8888", "status": "Enviado", "linkAssinatura": "https://signer.unifev.com.br/s/...", "assinadoEm": null }
  ]
}
```

`status` do envio: `Aguardando` → `Concluido`; ou `Cancelado`, `Expirado`, `Recusado`.
`status` do signatário: `Pendente`, `Enviado`, `Aberto`, `Verificado`, `Assinado`, `Recusado`.

## 4. Consultar e baixar

- `GET /api/envios/{codigo}` — estado atual.
- `GET /api/envios/por-chave/{chaveExterna}` — o mesmo, pela sua chave.
- `GET /api/envios/{codigo}/assinado.pdf` — o PDF final (só quando `status = Concluido`; 409 antes).
- `POST /api/envios/{codigo}/lembrar` — reenvia o convite a quem ainda não assinou.
- `POST /api/envios/{codigo}/cancelar` — corpo opcional `{ "motivo": "..." }`.

## 5. Webhook (opcional, recomendado)

Quando algo acontece, o UnifevSigner faz `POST` na `webhookUrl` do envio (ou a do sistema), JSON:

```json
{ "evento": "envio.concluido", "quando": "...", "envio": { "codigo": "...", "chaveExterna": "...", "status": "Concluido", "hashFinal": "...", "signatarios": [...] }, "extra": null }
```

Eventos: `signatario.assinou`, `envio.concluido`, `envio.recusado`, `envio.cancelado`, `envio.expirado`.

Cabeçalhos: `X-UnifevSigner-Evento` e `X-UnifevSigner-Assinatura: sha256=<HMAC-SHA256 do corpo com o segredo do webhook>`.
O segredo é mostrado junto com a chave de API. Confira a assinatura antes de confiar no corpo.
Responda 2xx; sem isso há até 3 tentativas. Ao receber `envio.concluido`, baixe o PDF em `/api/envios/{codigo}/assinado.pdf`.

## 6. Exemplo em C#

```csharp
var http = new HttpClient { BaseAddress = new Uri("http://172.30.1.90:8096/") };
http.DefaultRequestHeaders.Add("X-Api-Key", chave);

using var form = new MultipartFormDataContent();
form.Add(new ByteArrayContent(pdfBytes) { Headers = { ContentType = new("application/pdf") } }, "arquivo", "contrato.pdf");
form.Add(new StringContent(JsonSerializer.Serialize(new {
    titulo, cofre = "cfr_4f723b337efe", pasta = $"{ano}/Matrículas", chaveExterna = $"contrato:{ano}:{idContrato}",
    signatarios = new[] { new { nome, telefone, cpf, papel = "Responsável financeiro" } }
})), "dados");

var resp = await http.PostAsync("api/envios", form);
// 201 criado, 200 já existia, 422 ver detail
```

## 7. Cuidados

- Não bloquear o fluxo do seu sistema esperando a assinatura: ela leva horas ou dias. Use o webhook ou consulte depois.
- Telefone certo no cadastro é parte da segurança jurídica: o código de verificação vai para esse número.
- O PDF original nunca é alterado; o assinado tem páginas a mais (assinaturas, trilha, certificado).

