Contratos como serviço, na sua plataforma

A API /v1 permite que a sua plataforma crie, complete, acompanhe e assine contratos com validade jurídica (Lei 14.063/2020), com seus templates, seu white-label e a IA perguntando só o que você permitir. Tudo que o app faz, a API faz.

Quer plugar num assistente (Claude, ChatGPT, Gemini) em vez de escrever código? Guia de integrações, que inclui um OpenAPI enxuto pronto para GPT Actions e function calling.

Autenticação

Toda chamada leva Authorization: Bearer cnsc_sk_…. Cada chave pertence a um tenant, carrega escopos (contracts:read/write, templates:read/write, sign:request) e tem rate-limit por minuto. Chaves são exibidas uma única vez; guarde com segurança.

curl https://api.contratocombinado.com/v1/usage -H "Authorization: Bearer cnsc_sk_SUACHAVE"

Quickstart: do template ao PDF em 3 chamadas

1. Crie um template com cláusulas, {{placeholders}} tipados e regras:

curl -X POST https://api.contratocombinado.com/v1/templates \
  -H "Authorization: Bearer cnsc_sk_SUACHAVE" -H "Content-Type: application/json" \
  -d '{
    "name": "Campanha com modelo",
    "contract_type": "Contrato de campanha publicitária",
    "body": {"clauses": [
      {"number": 1, "title": "Partes", "text": "AGENCIA: {{agencia}}. MODELO: {{modelo}}."},
      {"number": 2, "title": "Cache", "text": "Cache de {{cache}}, pago em até 15 dias."},
      {"number": 3, "title": "Direito de imagem", "text": "Uso limitado à campanha por {{prazo_imagem}}."}
    ]},
    "variables": [
      {"key": "agencia", "required": true}, {"key": "modelo", "required": true},
      {"key": "cache", "required": true}, {"key": "prazo_imagem", "required": false}
    ],
    "min_clauses": ["Direito de imagem"],
    "question_policy": {"ask": ["prazo_imagem"]}
  }'

2. Gere o contrato. Com dados completos, mode=fill responde na hora (201, sem IA):

curl -X POST https://api.contratocombinado.com/v1/contracts \
  -H "Authorization: Bearer cnsc_sk_SUACHAVE" -H "Content-Type: application/json" \
  -H "Idempotency-Key: pedido-123" \
  -d '{
    "template_id": "TEMPLATE_ID", "mode": "fill",
    "variables": {"agencia": "Sua Agência LTDA", "modelo": "Ana Souza", "cache": "R$ 3.000,00", "prazo_imagem": "12 meses"},
    "parties": [
      {"role": "agencia", "name": "Sua Agência LTDA", "kind": "PJ"},
      {"role": "modelo", "name": "Ana Souza", "kind": "PF"}
    ]
  }'

3. Baixe os artefatos:

curl https://api.contratocombinado.com/v1/contracts/CASE_ID/outputs/draft.pdf -H "Authorization: Bearer cnsc_sk_SUACHAVE" -o contrato.pdf
curl https://api.contratocombinado.com/v1/contracts/CASE_ID/outputs/summary.json -H "Authorization: Bearer cnsc_sk_SUACHAVE"

Os três modos

fillPuro placeholder: dados completos → render determinístico, síncrono (201), sem IA. Variável obrigatória faltando → 422 com a lista.
assistedA IA adapta as cláusulas ao contexto e pergunta só o que a sua question_policy permite (202 + job). Cláusulas mínimas viram gate de completude.
fullTexto livre; a IA conduz a investigação inteira (202 + job).

Perguntas pendentes chegam de duas formas: webhook case.needs_input (você renderiza na sua UI e responde via POST /v1/contracts/{id}/answers) ou o embed abaixo.

Embed: o fluxo dentro da sua plataforma

curl -X POST https://api.contratocombinado.com/v1/embed-sessions \
  -H "Authorization: Bearer cnsc_sk_SUACHAVE" -H "Content-Type: application/json" \
  -d '{"contract_id": "CASE_ID", "surface": "complete"}'
# → { "url": "https://contratocombinado.com/#/embed/<token>", "expires_at": ... }

Coloque a url num iframe. Surfaces: complete (o usuário responde as perguntas, em formulário ou conversa), review (cláusulas com tradução leiga) e status. O iframe emite postMessage para a sua página ({source:"cnsc", type}): cnsc:ready, cnsc:status, cnsc:resized (altura) e cnsc:completed. Seu logo, cor e rodapé via PUT /v1/branding.

Assinatura com validade jurídica

curl -X POST https://api.contratocombinado.com/v1/contracts/CASE_ID/signature-requests \
  -H "Authorization: Bearer cnsc_sk_SUACHAVE" -H "Content-Type: application/json" \
  -d '{"signers": [
    {"name": "Sua Agência LTDA", "email": "contratos@suaagencia.com", "role": "agencia"},
    {"name": "Ana Souza", "email": "ana@email.com", "role": "modelo"}
  ]}'
# → { "request_id": ..., "signers": [{ "name", "email", "sign_url" }] }

Cada signatário recebe convite por e-mail (com o seu branding) e você recebe o sign_url de cada um. Embede no seu fluxo (o iframe emite cnsc:signed). Assinatura eletrônica avançada: consentimento + código por e-mail + trilha de auditoria (IP, horário) + selagem imutável com manifesto assinado pela plataforma (Ed25519) e âncora pública OpenTimestamps. Acompanhe em GET /v1/contracts/{id}/signature.

Webhooks

Configure webhook_url e webhook_secret no seu tenant (no provisionamento). Eventos: case.completed, case.needs_input (com as questions[]), case.blocked. Cada POST leva x-contracts-signature: sha256=<hex>, que é o HMAC-SHA256 do corpo cru com o seu secret:

import hmac, hashlib

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, header)

Erros e idempotência

Erros seguem problem+json (RFC 7807): {"title", "detail", "status"}. Nos POSTs, envie Idempotency-Key: o retry devolve o MESMO caso e não cobra duas vezes. Casos de outro tenant respondem 404 (indistinguível de inexistente).

Referência de endpoints

POST/v1/templatesCria template (body, variables, min_clauses, question_policy)
GET/v1/templates · /v1/templates/{id}Lista / detalha templates do tenant
POST/v1/templates/{id}/versionsNova versão (snapshot imutável)
POST/v1/contractsCria contrato (mode fill|assisted|full, parties, variables, context)
GET/v1/contracts · /v1/contracts/{id}Lista / estado (status, questions, outputs, job)
POST/v1/contracts/{id}/answersResponde perguntas pendentes via API
GET/v1/contracts/{id}/outputs/{file}Baixa draft.json, draft.pdf, summary.json…
POST/v1/contracts/{id}/signature-requestsConvida signatários; devolve sign_url por parte
GET/v1/contracts/{id}/signatureStatus da assinatura (partes, selagem)
POST/v1/embed-sessionsToken de embed (complete | review | status)
PUT/v1/brandingWhite-label: nome, logo, cor, rodapé
GET/v1/usageConsumo do tenant por dimensão

Especificação viva: Swagger · openapi.json

Chave sandbox

Estamos em beta fechado. Peça sua chave sandbox (engine real, quota reduzida) em contato@contratocombinado.com.br contando o seu caso de uso. Respondemos com a chave e o secret de webhook.