Doc-sign — API (kunk-api)
Prefixo:
/api/v1/doc-signDomínio nativo (não/modules/*). Substitui as rotas de compatibilidade/terms/*.
Envelope padrão: ../../api/errors. Auth: cookie associate_session (associado) ou session_token (operador).
Auth por rota
Seção intitulada “Auth por rota”| Grupo | Quem |
|---|---|
| Templates (CRUD / publish) | Operador com role Administrador (ou permissão dedicada doc_sign.manage) |
| Contracts create (painel) | Operador staff (Acolhimento+) no user_code alvo |
| Contracts create (me) | Associado autenticado — só o próprio user_code |
| Sign / view by token | Público com signing_token válido ou associado dono |
| Verify | Staff ou associado dono |
Templates
Seção intitulada “Templates”| Método | Path | Descrição |
|---|---|---|
| GET | /doc-sign/templates |
Lista os 2 kinds + versão current |
| GET | /doc-sign/templates/:kind |
Detalhe + content_json draft/current + versões |
| PUT | /doc-sign/templates/:kind/draft |
Body { content_json } (documento TipTap) |
| POST | /doc-sign/templates/:kind/publish |
Versiona JSON, gera PDF, marca current |
| GET | /doc-sign/templates/:kind/sample-variables |
Defaults fictícios editáveis p/ prévia |
| POST | /doc-sign/templates/:kind/preview-pdf |
PDF de teste (não persiste); body { content_json?, variables? } |
| GET | /doc-sign/templates/:kind/versions |
Histórico |
| GET | /doc-sign/templates/versions/:versionId |
JSON + PDF da versão |
| POST | /doc-sign/templates/:kind/reset |
Zera o kind (versões, logo, rascunho → texto padrão) |
PUT …/draft
Seção intitulada “PUT …/draft”{ "content_json": { "type": "doc", "content": [ /* TipTap */ ] } }POST …/publish
Seção intitulada “POST …/publish”Request: { notes?: string }
Response:
{ "data": { "template_id": "…", "kind": "self", "version": { "id": "…", "version_number": 3, "content_sha256": "…", "pdf_file_id": "…", "pdf_sha256": "…" } }}Erros: TEMPLATE_INVALID_VARIABLES, PDF_RENDER_FAILED.
Contracts
Seção intitulada “Contracts”| Método | Path | Descrição |
|---|---|---|
| POST | /doc-sign/contracts |
Gera (ou reusa pending) contrato preenchido |
| GET | /doc-sign/contracts |
Staff: lista recentes (limit, offset, status) |
| GET | /doc-sign/contracts/:id |
Status, variáveis, urls de PDF |
| GET | /doc-sign/contracts/me |
Contrato relevante do associado logado |
| GET | /doc-sign/contracts/by-user/:userCode |
Staff: lista contratos do user |
| POST | /doc-sign/contracts/:id/resend-email |
Reenvia link |
| POST | /doc-sign/contracts/:id/void |
Anula pending (staff) |
| GET | /doc-sign/contracts/:id/verify |
Recalcula e compara hashes |
| GET | /doc-sign/contracts/:id/audit |
JSON do audit + link PDF |
POST /doc-sign/contracts
Seção intitulada “POST /doc-sign/contracts”{ "user_code": "uuid-opcional-se-me", "send_email": true, "regenerate": false, "replace_completed": false}send_email default true (omitido ou true): envia e-mail com signing_url ao criar/reusar pending. Após assinatura, envia confirmação com PDF assinado + audit log em anexo (se SMTP configurado).
Response:
{ "data": { "id": "uuid", "status": "pending", "kind": "with_patient", "signing_url": "https://termos.exemplo/assinar/…", "filled_pdf_url": "/api/v1/files/…", "variables": { } }}Regras:
- Se já existe contrato
completedpara ouser_codeou o mesmoemail_account→ 409CONTRACT_ALREADY_COMPLETED. - Idempotente no cadastro: se existir
pending, retorna o existente (meta.reused: true). - Painel “Novo Termo” sem
completed: pode void dopendinganterior e criar novo. - Escolhe
kind:another+paciente →with_patient;himself|pet→self. - Emite
contract.createde opcionalmenteemail.sent. - Sem template publicado do kind → 422
TEMPLATE_NOT_PUBLISHED.
Conclusão (assinatura)
Seção intitulada “Conclusão (assinatura)”| Método | Path | Descrição |
|---|---|---|
| GET | /doc-sign/sign/:token |
Payload para a UI (content_json preenchido, título, métodos) |
| POST | /doc-sign/sign/:token/view |
Registra form.viewed (+ IP, UA, session_id, timezone) |
| POST | /doc-sign/sign/:token/complete |
Conclui assinatura |
POST …/complete
Seção intitulada “POST …/complete”{ "method": "draw", "typed_name": null, "signature_image_base64": "data:image/png;base64,…", "timezone": "America/Sao_Paulo", "consent": true}Server:
- Valida token / status pending
submission.started- Persiste
term_signatures+ imagem - Gera PDF assinado + audit PDF + hashes
status=completed,submission.completed- Integração cadastro (mesma API):
users.adhesion_term = contract.id(UUID)- se
associate_status === 4→5
- Retorna urls do PDF assinado e audit
Sem webhook. Sem session_id no body nem no audit.
Erros: CONTRACT_NOT_PENDING, CONTRACT_ALREADY_COMPLETED, TOKEN_INVALID, SIGNATURE_REQUIRED, CONSENT_REQUIRED, TEMPLATE_NOT_PUBLISHED.
Status (compatibilidade)
Seção intitulada “Status (compatibilidade)”| Método | Path | Descrição |
|---|---|---|
| GET | /doc-sign/status |
{ status: "ready" } quando o módulo está ativo |
| GET | /terms/status |
Alias deprecado → mesmo handler |
| POST | /terms/contracts |
Alias deprecado → POST /doc-sign/contracts |
Com doc-sign ativo, as rotas /terms/* deixam de responder TERMS_MODULE_IN_DEVELOPMENT.
Metadados de auditoria em todo POST de view/complete
Seção intitulada “Metadados de auditoria em todo POST de view/complete”Capturar no server (não confiar só no client):
| Campo | Fonte |
|---|---|
ip |
req (X-Forwarded-For confiável atrás do proxy) |
user_agent |
header |
timezone |
body (IANA), default UTC se ausente |
occurred_at |
now no server |
Não registrar session_id.
Relação com cadastramento / painel
Seção intitulada “Relação com cadastramento / painel”| Cliente | Uso |
|---|---|
apps/registration fase 4 |
POST /doc-sign/contracts (me) + embed/redirect signing_url; polling ou redirect pós-complete |
apps/kunk Associados |
Novo Termo / Copiar link via endpoints staff |
apps/doc-sign |
UI admin de templates + página /assinar/:token |
Detalhe de avanço de fase: flow §6.
OpenAPI
Seção intitulada “OpenAPI”Incluir paths em ../../api/openapi.yaml na mesma entrega da implementação.
