A API /v1 permite que a sua plataforma crie, complete, acompanhe e assine contratos com validade jurídica entre as partes (MP 2.200-2/2001, art. 10 §2º), com seus templates, seu white-label e a IA perguntando só o que você permitir. O que a integração precisa (criar, analisar, negociar, assinar, prazos e auditoria) está na API. Ficam só na tela do app o chat sobre o contrato, a importação de arquivos, o modelo de cláusulas da empresa e as áreas da empresa.
Gera contratos dos seus clientes? Crie seu intermediador: ambiente de teste grátis na hora, produção a partir de R$ 29 por mês.
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.
Toda chamada leva Authorization: Bearer cnsc_sk_…. Cada chave pertence a um tenant, carrega escopos (contracts:read/write, templates:read/write, sign:write, account:read/write e, para os contratos de nível 2 e 3, contracts:operate e contracts:intervene) e tem rate-limit por minuto. O antigo sign:request continua aceito como sinônimo de sign:write. Chaves são exibidas uma única vez; guarde com segurança. A chave pessoal (cnsc_uk_, da página de integrações) só tem contracts:read/write e account:read, e pedir assinatura com ela vira uma proposta que uma pessoa confirma. A chave de empresa (também cnsc_uk_, gerada em Minha conta, Identidades, por quem responde por uma empresa verificada) é a do sistema da empresa: o que ela cria nasce na carteira da empresa, e o pedido de assinatura sai na hora, para as partes do contrato, dentro do plano de quem gerou a chave. Ela para de valer se essa pessoa deixar de responder pela empresa. Pela chave pessoal você alcança o que alcança na tela, inclusive a restrição por área da empresa; a chave da empresa alcança a carteira inteira. O limite por minuto (GET /v1/usage, campo rate_limit) é 120 na chave pessoal e na de empresa, 60, 120 ou 300 conforme o plano do intermediador e até 30 na chave de teste do intermediador.
curl https://api.contratocombinado.com/v1/usage -H "Authorization: Bearer cnsc_sk_SUACHAVE"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"O que cada parte pode negociar. Em cada cláusula do template, negociacao define o modo: fixa (a parte aceita ou recusa, o texto não muda), faixa (a parte escolhe o valor de uma variável entre min e max), catalogo (a parte escolhe uma das opcoes redigidas por você) ou livre. Com "obrigatoria": true, a cláusula não pode ser removida. Se o template declara negociacao em alguma cláusula, as demais ficam fixa, e o contrato precisa ser criado com mode=fill. Uma proposta fora disso é recusada pelo servidor, inclusive a que nasce da sugestão da IA.
O tipo_contrato que o GET devolve é derivado do template, nunca escolhido: essencial (tudo fixa e "analise_por_lado": false), negociado (alguma cláusula negociável ou análise por lado ligada) ou mediado (nível 3). Enquanto houver tópico aberto na mesa do contrato, o pedido de assinatura responde 409. Em qualquer nível, impasse_status diz se o contrato está em impasse, de que tipo ( divergencia: tópico aberto na mesa; sem_resposta: proposta há mais de 3 dias sem decisão) e desde quando, sem o conteúdo. Cada parte traz requirements: currently_due (o que ela deve agora, inclusive marco.<chave> que o papel dela confirma), past_due (o que já venceu), eventually_due (o que ainda vai ser pedido, como a assinatura), blocked_reason e current_deadline.
Marcos. Em body.marcos o template declara o que acontece depois da assinatura: cada marco tem chave, rotulo, tipo (entrega, evento, pagamento ou data), prazo ({"data": "2026-12-01"}, {"dias_da_assinatura": 30} ou {"variavel": "data_entrega"}), quem_confirma (o papel de uma parte, qualquer_parte ou intermediador, este só com nível 2) e, se quiser, aceite_tacito_dias. Variável pode ter tipo (texto, numero, moeda, data, opcao com opcoes, pessoa); fora do tipo, 422 variable_invalid. O GET devolve em marcos o estado de cada um: pendente, confirmado, contestado, vencido ou aceito_tacitamente (passou o prazo e mais esses dias sem contestação). O motivo de uma contestação fica entre as partes.
Prazo de resposta. Proposta de mudança sem resposta não vira aceite: ela expira. body.prazo_de_resposta_dias (de 7 a 30; sem o campo, 15) define o prazo, copiado para o contrato na criação. Três dias antes, quem precisa decidir recebe um lembrete por e-mail. No prazo, a proposta fica expirada e, se era aditivo ou distrato, sai aditivo.recusado ou distrato.recusado com "motivo": "expirada". Pedido de assinatura vencido fica expirada e sai contrato.expirado.
Aditivo fora do modelo. Depois de assinado, o contrato é das partes: nos níveis 0 a 2 um aditivo pode mudar cláusula fixa, sem veto do intermediador. O aditivo.proposto traz fora_do_modelo com o que saiu da trava (fixa:cl_3, removida:cl_5, clausula_nova), e o GET do contrato traz fora_do_modelo (e, a partir do nível 1, clausulas_fora_do_modelo) depois do aceite. No nível 3 o mesmo aditivo espera a sua decisão de exceção, como a contraproposta. Regra do seu negócio (taxa, pagamento pela plataforma) mora nos seus termos de uso com cada parte, não no contrato entre elas.
Troca de signatário. Uma parte que é empresa escolhe quem assina por ela: o responsável pela empresa (ou quem assina hoje) troca para outro membro da empresa com CPF na conta, antes de essa pessoa assinar. As outras partes recebem aviso, sem novo aceite, e você recebe signatario.trocado com o party_id. O intermediador não troca: antes do vínculo, corrija o e-mail pelo PATCH da parte. Pessoa física não troca (seria trocar a parte).
{"number": 2, "title": "Prazo", "text": "Entrega em {{prazo}} dias.",
"negociacao": {"modo": "faixa", "variavel": "prazo", "min": 10, "max": 30, "unidade": "dias"}}
{"number": 3, "title": "Foro", "text": "Foro de São Paulo.",
"negociacao": {"modo": "catalogo", "opcoes": [{"id": "rj", "texto": "Foro do Rio de Janeiro."}]}}Para o sistema da sua empresa enviar documentos para assinar, sem intermediário. Quase tudo abaixo também existe na tela e no conector MCP. O conector não baixa o PDF assinado nem configura o webhook: isso se faz pela API ou pela tela.
curl -X POST https://api.contratocombinado.com/v1/contracts/documents \
-H "Authorization: Bearer cnsc_uk_SUACHAVE" \
-F "file=@contrato.pdf" \
-F 'meta={"title": "Contrato de prestação de serviços", "send": true,
"signers": [{"name": "Ana Souza", "email": "ana@cliente.com.br", "cpf": "12345678909"}],
"authentication": ["cpf"], "expires_in_days": 15}'Acompanhe. GET /v1/contracts/CASE_ID/signature traz cada pessoa e, quando todos assinam, sealed. O PDF assinado sai em GET /v1/contracts/CASE_ID/signed-pdf (os anexos com ?attachment=N). Com o webhook ligado, você recebe contrato.assinado sem perguntar. Para cancelar o pedido: POST /v1/contracts/CASE_ID/signature-request/cancel; para reenviar o convite a quem não assinou: POST …/signature-request/resend com {"email"}.
O mesmo documento para muitas pessoas: um contrato e um convite para cada uma, em segundo plano.
curl -X POST https://api.contratocombinado.com/v1/contracts/documents/batch \
-H "Authorization: Bearer cnsc_uk_SUACHAVE" \
-F "file=@termo.pdf" \
-F 'meta={"operation_id": "UM-UUID-SEU", "title": "Termo de adesão",
"signers": [{"name": "Quem assina pela empresa", "email": "rh@suaempresa.com.br"}],
"recipients": [{"name": "Ana Souza", "email": "ana@x.com"}, {"name": "Bruno Lima", "email": "bruno@x.com"}]}'
curl https://api.contratocombinado.com/v1/contracts/documents/batch/BATCH_ID -H "Authorization: Bearer cnsc_uk_SUACHAVE"Modelos. Guarde o PDF com quem assina sempre, as posições e as opções em POST /v1/document-templates, e envie só com template_id (sem file), no envio único ou no lote. Com variables, cada contrato sai com o nome, o e-mail, o CPF de quem recebe ou a data escritos no PDF.
| Assinaturas | As do plano de quem gerou a chave, por ciclo. Uso e limite em GET /v1/usage (signatures); acabou, 402 plan_limit. |
| Convites | Empresa verificada: até 60 pedidos e 90 destinatários diferentes a cada 24 horas (conta sem empresa verificada: 20 e 30; conta com menos de 24 horas: 5 e 8). Quem denunciou o seu convite não recebe outro. Cada pessoa recebe no máximo 3 convites seus a cada 24 horas, somando todos os contratos (cancelar e recriar o pedido não zera). Passou, 429 invite_rate, recipient_limit ou reported. |
| Reenvio | Até 3 por pessoa a cada 24 horas (429 resend_limit), com link novo; o anterior para de valer. |
| Arquivos | PDF até 15 MB, com até 9 anexos no mesmo total. |
| Lote e modelos | Até 50 pessoas por lote; até 20 modelos ativos por empresa. |
Gere a chave de teste em Minha conta, Identidades, logo abaixo da chave da empresa. Ela usa as mesmas rotas (documento, lote, modelos, status) e nada sai para fora: os contratos ficam fora da carteira real, não contam no plano, e as pessoas usam e-mail @teste.contratocombinado.com, em que o nome decide o que acontece: aceita@ assina e recusa@ recusa (para várias, aceita+1@, aceita+2@). A assinatura é simulada na hora, sem e-mail, selo nem PDF assinado, então não há pedido para cancelar nem convite para reenviar. O webhook do teste é só dele: ligue com PUT /v1/webhook usando a chave de teste. Criar ou analisar contrato com IA não existe na chave de teste (403 sandbox_unsupported).
fill | Puro placeholder: dados completos → render determinístico, síncrono (201), sem IA. Variável obrigatória faltando → 422 com a lista. |
assisted | O corpo do template, as cláusulas mínimas e a question_policy entram como instrução para a IA, que adapta as cláusulas ao contexto e pergunta o que faltar (202 + job). É orientação ao modelo, não trava automática: confira as cláusulas mínimas na minuta. |
full | Texto livre, sem template; a IA conduz a investigação inteira pelo mesmo caminho do assisted (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.
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, só se a origem da sua página estiver em embed_origins (PUT /v1/branding, até 10 origens https://host[:porta]). Sem lista, nenhuma mensagem sai; o webhook continua sendo a fonte de verdade. A mesma lista decide onde a página aparece: num iframe de origem fora dela, o embed e o sign_url não mostram o contrato, só um link para abrir numa aba própria. O resto do site não abre em iframe nenhum. Ponha referrerpolicy="origin" no seu <iframe>: alguns navegadores só sabem a origem da sua página por aí, e sem ela o iframe recusa. Seu logo (só https, host público), cor (#RRGGBB) e rodapé vão no mesmo PUT /v1/branding.
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 para as origens de embed_origins). Assinatura eletrônica (MP 2.200-2/2001, art. 10, § 2º): 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.
Ligue o webhook com PUT /v1/webhook e body {"url": "https://..."} (escopo account:write). O webhook existe para a chave do intermediador, para a chave de empresa e para a chave pessoal do advogado (quem responde por uma identidade no plano de advogado): ele recebe os eventos dos contratos dos clientes que representa e lê esses contratos em GET /v1/contracts/{id} (título, situação, partes e texto; sem escrever). A chave pessoal de quem não é advogado recebe 403. Na primeira vez a resposta traz o secret, uma única vez; trocar só a url mantém o secret, e "rotate": true gera um novo. Na rotação, o secret anterior continua assinando por 24 horas, para você trocar sem perder evento. Eventos: contrato.assinado (o contrato foi selado), case.completed, case.needs_input (com as questions[]), case.blocked e case.failed (o processamento falhou; traz code, estável, como job_failed, ai_unavailable, job_timeout ou job_interrupted, e message, em português). Os case.* trazem, além dos campos de sempre (event, case_id, status...), o mesmo cabeçalho dos demais: id, type, created_at e contract_id. O id é o mesmo em toda retentativa.
Contrato criado com parties também emite parte.convidada, parte.convite_reenviado, parte.entrou, assinatura.parte_assinou, contrato.assinado, contrato.cancelado, contrato.encerrado e, quando uma parte ou você mexe num marco, marco.confirmado, marco.contestado e marco.reaberto, e quando o prazo passa, marco.vencido e marco.aceito_tacitamente (com milestone, a chave do marco), e contrato.pronto_para_assinar quando todas as partes entraram, sem mesa aberta nem proposta pendente (com version_id; qualquer parte pode pedir a assinatura, ou você pela API). Também contrato.criado, contrato.recusado, contrato.expirado (pedido de assinatura vencido), pendencia.vencendo e pendencia.vencida (convite da parte), prazo.proximo (marco em até 3 dias), impasse.aberto/impasse.resolvido, signatario.trocado (a empresa trocou quem assina por ela), rodada.aberta (pedido de ajustes com round_id) e proposta.recebida (com proposta_id e kind; o texto se lê pela API). Aditivo e distrato emitem aditivo.proposto, aditivo.aceito, aditivo.recusado, aditivo.assinado, distrato.proposto, distrato.aceito, distrato.recusado e distrato.assinado; o teste de configuração emite webhook.teste. O corpo traz id (para deduplicar), type, created_at, contract_id, party_id quando houver, a sua metadata e, em data, o contrato exatamente como GET /v1/contracts/{id} devolve em intermediador. Não há garantia de ordem: o GET é a fonte da verdade.
Com a chave de empresa, o webhook (ligado pela API ou em Minha conta, Identidades) recebe os eventos da carteira da empresa, criados pela API ou pela tela: assinatura.parte_assinou, contrato.assinado, contrato.cancelado, contrato.encerrado, os de aditivo e os de distrato, além de rodada.aberta, proposta.recebida, signatario.trocado e contrato.aprovado (aprovação interna completa, com version_id; só nasce em contrato de empresa). Aí data traz title, status, created_at e parties (com name, role, side e signed).
Cada POST segue o padrão Standard Webhooks: webhook-id (o mesmo nas retentativas), webhook-timestamp e webhook-signature, verificáveis pelas bibliotecas oficiais com o secret como ele foi entregue. Continua indo também x-contracts-signature: sha256=<hex>, o HMAC-SHA256 do corpo cru:
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)Só resposta 2xx conta como entregue: 3xx (o redirecionamento não é seguido), 4xx e 5xx são falha. Entrega que falha é re-tentada depois de 30 s, 2 min, 10 min, 30 min, 1 h, 3 h, 6 h e 12 h; depois disso fica como falhou. Se o endereço falhar sem parar por 3 dias, o webhook é desativado e os administradores (na chave de empresa, quem responde pela empresa) recebem um e-mail; cadastrar de novo com PUT religa. Para ver o que saiu e o que falhou, use GET /v1/webhook/deliveries?limit=50: cada entrega vem com event, status (entregue, pendente, retentando ou falhou), attempts, last_error, created_at e delivered_at.
Erros seguem problem+json (RFC 7807): {"title", "detail", "status", "code", "param"}. Trate pelo code, que é estável; param aponta o campo que errou, quando se sabe. Exceção: o 422 de validação do corpo ou de parâmetro fora da faixa sai no formato padrão do FastAPI, {"detail": [...]}, sem code. O plano do tenant tem teto mensal (mês UTC) de contratos criados e de pedidos de assinatura: estourou, a resposta é 402 com type: "credito_insuficiente", antes de qualquer trabalho. Uso e limite em GET /v1/usage (campo limits). Contrato criado com parties consome crédito quando é enviado às partes, uma vez por contrato, pelo tipo: essencial, negociado ou mediado. Sem saldo, o send responde 402 antes de qualquer convite sair. O saldo do mês fica em GET /v1/usage (campo credito); quanto um template vai custar, em POST /v1/contracts/estimate. Em POST /v1/contracts, /contracts/analyze, /contracts/documents, /ask, /answers, /attachments e /risk-refresh, envie o header Idempotency-Key: o retry devolve o MESMO resultado e não cobra duas vezes. Em /ask não há o header: a chave vai no corpo, em idempotency_key. No lote (/contracts/batch) a chave vai em cada item (idempotency_key). As demais rotas de escrita não usam a chave: chamar send de novo só reenvia a quem ainda não entrou, e um segundo signature-requests com pedido ativo responde 409 sem criar outro. Em /contracts/documents, o retry com a mesma chave devolve o MESMO contrato (e o mesmo convite), sem criar outro; sem a chave, cada chamada cria um contrato novo. A mesma chave com outro arquivo ou outro meta responde 409 (idempotency_mismatch); enquanto o primeiro pedido ainda roda, o retry recebe 409 idempotency_in_progress com Retry-After. Casos de outro tenant respondem 404 (indistinguível de inexistente).
code)idempotency_mismatch: a mesma Idempotency-Key com outro pedido (409)idempotency_in_progress: o primeiro pedido com esta Idempotency-Key ainda está rodando (409); repita depois do Retry-Afterfield_too_large: descrição (free_text) acima de 20 mil caracteres, ou context, fields, variables ou usuario_final acima de 20 mil caracteres serializados (422); param diz qualjob_failed / ai_unavailable / job_timeout / job_interrupted: o processamento do contrato falhou (campos job.error_code no GET do contrato e code no webhook case.failed): erro geral, IA indisponível, demorou demais, ou foi interrompido; é seguro tentar de novoparties_incomplete / too_many_parties: partes sem documento e e-mail em todas, ou mais de 20party_name_invalid / party_document_invalid / party_email_invalid / party_email_duplicated / party_role_invalid: parte com o campo em param erradoparty_not_found / party_already_linked / party_invite_missing: sessão acao_da_parte: parte de outro contrato, já vinculada, ou contrato ainda não enviadometadata_invalid: metadata fora do formatotemplate_invalid / template_not_found: template (ou modelo de documento) que não passa na validação, ou que não existe, foi arquivado ou não é da sua partetemplate_forbidden / templates_limit: modelo de documento por quem não responde pela parte, ou já há 20 ativoscpf_required_by_template / one_recipient_required_by_template: o modelo escreve o CPF de quem recebe e faltou, ou o envio único com variáveis tem mais de uma pessoa recebendo (use o lote)file_empty / file_too_large / file_not_pdf / file_encrypted / file_unreadable / file_duplicate / too_many_files: o PDF (ou um anexo) vazio, acima de 15 MB, não é PDF, tem senha, não abre, repetido, ou mais de 9 anexossigners_invalid / title_invalid / fields_invalid / party_forbidden / documents_limit: documento: signatário sem nome ou e-mail, título, posição fora da página, empresa de que você não faz parte, ou 20 documentos parados sem pedido de assinaturacompany_key_suspended / company_key_required / company_not_verified / company_key_pf / company_key_missing: chave de empresa: quem a criou deixou de responder pela empresa ou ela perdeu a verificação, rota que exige a chave de empresa, empresa ainda não verificada, parte que é pessoa física, ou empresa sem chavetemplate_not_approved: o intermediador exige aprovação do jurídico e a versão atual do template ainda não foi aprovada (409); aprove no painelsubscription_inactive / sandbox_limit: assinatura do plano em atraso ou cancelada suspende a criação de contratos novos (402); o ambiente de teste envia até 200 contratos por mês (429)insufficient_scope: só no envio de documento com send=true sem o escopo sign:write (403). Nas demais rotas, a falta de escopo sai como forbiddencontract_not_found: contrato que não existe ou não é da sua chave (404)variable_invalid: valor de variável fora do tipo do template (data, número, opção); param diz qual (422)key_expired: o prazo que você deu à chave acabou (401); gere outra no painelinvalid_scopes / invalid_expiry / invalid_label: chave nova pelo painel: permissões fora das da integração ou nenhuma, validade fora de 7, 30, 90 ou 365 dias, rótulo com mais de 60 caracteres (422)plan_limit: assinaturas do plano acabaram neste ciclo (402); uso em GET /v1/usage, campo signaturesinvite_rate / reported / recipient_limit / resend_limit: teto de convites em 24 horas, a pessoa denunciou o seu convite, a mesma pessoa já recebeu 3 convites seus em 24 horas (somando os pedidos), ou mais de 3 reenvios para ela em 24 horas (429)aguardando_aprovacao / acima_da_alcada / sem_conteudo / fatores_invalidos / observadores_invalidos / cpf_faltando_na_parte: o pedido de assinatura espera aprovação, passa da alçada, o contrato não tem conteúdo, fator indisponível, observadores inválidos, ou falta o CPF de quem assina para o fator pedidono_active_request / signer_not_found / signer_already_answered / signer_waiting_turn / email_unavailable / email_indisponivel: cancelar ou reenviar sem pedido ativo, e-mail fora do pedido, pessoa que já respondeu ou ainda não tem a vez, ou o e-mail não saiu (o link anterior continua valendo)sandbox_unsupported: na chave de teste, criar ou analisar com IA, ou gerar variações de um contrato (grava na carteira real e gasta o plano); use o documento pronto, o lote e os modelosproposals_forbidden: propostas comerciais pela chave de empresa ou de teste: elas são da pessoa, só a chave pessoal as lê e converte (403)upload_invalid / upload_missing / webhook_off: envio direto ao armazenamento com dados errados ou arquivo que não chegou, ou teste de webhook desligado pelo painel. Na /v1, POST /v1/webhook/test com o webhook desligado responde 409 conflictparties_not_linked / negotiation_table_open / proposal_pending / not_ready_to_sign: o que segura a assinaturabatch_invalid / batch_item_key_required: lote fora de 1 a 100 itens, ou item sem idempotency_key; no envio em lote de documento, lista, posições ou operation_id fora do formatobatch_done: cancelar um lote que já terminou (409)batch_forbidden: envio em lote sem a chave de empresa, ou por quem não responde por empresa verificada (403)credito_insuficiente: sem saldo e sem excedente (402)llm_rate_limited: teto de uso do modelo atingidorate_limited: passou do limite de requisições por minuto da chave (429), ou reenviou um contrato ou convite cedo demais (envio recente, ou reenvio repetido à mesma parte); espere os segundos do cabeçalho Retry-After. O limite está em GET /v1/usage, campo rate_limitproduction_not_released: conta de produção ainda em revisão (403); use a chave de sandboxcost_ceiling_reached: teto de uso de IA do mês da conta atingido (402); fale com o suportepayment_required: limite de contratos do plano da conta atingido em POST /v1/contracts ou /contracts/analyze (402)payload_too_large: arquivo ou corpo grande demais (413)bad_request / unauthorized / forbidden / not_found / conflict / invalid_request / rate_limited / server_error: os demais, pelo status| POST | /v1/templates | Cria template (body, variables, min_clauses, question_policy) |
| GET | /v1/templates · /v1/templates/{id} | Lista / detalha templates do tenant |
| POST | /v1/templates/{id}/versions | Nova versão (snapshot imutável) |
| POST | /v1/contracts | Cria contrato (mode fill|assisted|full, parties, variables, context) |
| POST | /v1/contracts/batch | Até 100 contratos por pedido; cada item com idempotency_key própria e resultado próprio (reenviar não duplica). |
| POST | /v1/contracts/analyze | Analisa um contrato RECEBIDO (multipart: um PDF/DOCX/TXT/imagem). Abre um caso em modo analyze; mesma função da tool MCP analyze_contract. |
| GET | /v1/contracts · /v1/contracts/{id} | Lista (limit e offset) / estado (status, questions, outputs e status do job, que não tem rota própria). Com a chave pessoal, a lista traz a carteira da conta (os criados por qualquer chave ou pela tela, e os que a conta alcança), e não só os criados por essa chave; com a da empresa, a carteira da empresa. |
| POST | /v1/contracts/{id}/answers | Responde perguntas pendentes via API. Idempotency-Key evita um segundo turno no retry. |
| POST | /v1/contracts/{id}/ask | Pergunta em linguagem natural sobre o contrato (só leitura, com citações verbatim); mesma função da tool MCP ask_contract. idempotency_key evita cobrar retry. |
| GET | /v1/contracts/{id}/outputs/{file} | Baixa draft.json, draft.pdf, summary.json… |
| POST | /v1/contracts/{id}/attachments | Anexa documento de apoio ao contrato (contexto para a análise). Idempotency-Key evita anexar duas vezes. |
| POST | /v1/contracts/{id}/risk-refresh | Reavalia o risco na versão mais recente, só nas cláusulas que mudaram; mesma função da tool MCP refresh_risk. |
| POST | /v1/contracts/{id}/batches | Prévia CSV e confirmação de linhas; conta pessoal autorizada, versão salva e operação UUID. Um contrato por sucesso. |
| GET | /v1/contracts/{id}/batches | Lotes privados e resultado por linha; selected busca um lote, offset pagina o histórico |
| GET | /v1/proposals | Propostas da conta pessoal: selected, offset e full=true para conteúdo. Escopo contracts:read. |
| POST | /v1/proposals/{uuid} | action=save ou convert, operation UUID, revision esperada (0 na criação). Aceite e apresentação exigem confirmação humana na confirmation_path retornada. |
| GET | /v1/contracts/{id}/versions | Lista as versões do contrato, na ordem em que nasceram |
| GET | /v1/contracts/{id}/versions/diff | O que mudou entre duas versões, cláusula a cláusula |
| POST | /v1/contracts/{id}/send | Contrato criado com parties (nome, documento e email): envia a cada parte o convite para vincular a conta por e-mail confirmado e o próprio CPF ou CNPJ. Chamar de novo reenvia só a quem não vinculou (no máximo uma vez por minuto); mesma função da tool MCP send_contract. |
| PATCH | /v1/contracts/{id}/metadata | Edita a metadata do contrato (até 30 pares de texto): mescla as chaves enviadas e valor vazio remove. Nunca aparece para as partes; mesma função da tool MCP update_contract_metadata. |
| GET | /v1/contracts/{id}/signed-pdf | PDF assinado. Intermediador: contrato de nível de atuação 1 ou mais (definido no template com nivel_atuacao); no nível 0 responde 404. Chave de empresa ou pessoal: o PDF do próprio contrato, e ?attachment=N baixa o anexo N do envelope. |
| POST | /v1/contracts/documents | Contrato a partir de um PDF pronto (multipart: file + meta JSON com title, signers e send; attachments: até 9 PDFs assinados junto, tudo até 15 MB). Sem análise: é este arquivo que se assina, intacto, e o PDF assinado sai com o certificado ao fim. Com send=true, chave enterprise e chave de empresa pedem a assinatura na hora; chave pessoal recebe a proposta para confirmar. Mesma função da tool MCP send_document_for_signature. |
| POST | /v1/contracts/documents/batch | Envio em lote, só com a chave de empresa: o mesmo PDF (multipart: file + meta JSON com operation_id, recipients de 1 a 50 e signers fixos até 5) vira um contrato e um convite por destinatário, em segundo plano. Cota do plano e teto de convites valem por linha; uma recusa de cota para o resto. operation_id repetido devolve o mesmo lote. Mesma função da tool MCP send_document_batch. |
| POST | /v1/contracts/documents/batch/{batch_id}/cancel | Cancela o lote em andamento: quem ainda não recebeu não recebe (not_sent, motivo cancelado); quem já recebeu segue, e cada contrato se cancela pelo pedido de assinatura. Lote concluído: 409 batch_done. Mesma função da tool MCP cancel_document_batch. |
| GET | /v1/contracts/documents/batch/{batch_id} | Estado do lote e de cada destinatário (pending, sent, failed, not_sent), com o case_id do contrato e o motivo da falha. Mesma função da tool MCP get_document_batch. |
| GET | /v1/document-templates | Modelos de documento: PDFs guardados com a configuração do envio (title, signers que assinam sempre, fields, authentication, signing_order, expires_in_days, observers). O id vai como template_id em POST /v1/contracts/documents e no lote, sem subir o arquivo de novo. Mesma função da tool MCP list_document_templates. |
| POST | /v1/document-templates | Cria um modelo (multipart: file + meta JSON com name, title, signers, fields, variables e as opções do pedido). variables marca onde cada envio escreve o nome, o e-mail, o CPF de quem recebe ou a data; o PDF assinado é o preenchido. Até 20 ativos por parte; só quem responde pela parte. |
| POST | /v1/document-templates/{id}/archive | Arquiva o modelo: some da lista e libera a vaga. Contratos já criados com ele não mudam. |
| POST | /v1/contracts/{id}/signature-requests | Chave enterprise (sign:write): convida os signers do corpo e devolve sign_url por parte. Chave de empresa: convida as partes do contrato por e-mail e devolve request_id, invited e not_sent (sem signers no corpo). Nos dois, authentication (lista com cpf e/ou geo) exige de quem assina, além do código por e-mail, o CPF igual ao cadastrado (signers[].cpf) e a localização do navegador; o que foi conferido vai para a evidência e o manifesto. O fator sms (segundo código pelo celular, signers[].phone) ainda não está disponível e é recusado. signing_order=sequential faz cada signatário receber o convite só depois que o anterior (pela ordem de signers ou das partes) assinou; a mesma posição assina junto. observers (até 10, name e email) acompanham sem assinar: recebem o aviso do envio e a cópia assinada no fim. expires_in_days (1 a 60, padrão 7) define em quantos dias o convite vence; no pedido em ordem, cada vez ganha o prazo inteiro. Chave pessoal usa signature-proposal. |
| POST | /v1/contracts/{id}/archive-proposal | Chave pessoal: propõe arquivamento e devolve confirmation_url. A pessoa confirma na plataforma; esta chamada não arquiva. |
| POST | /v1/contracts/{id}/signature-proposal | Chave pessoal: prepara convites de assinatura. Retorna confirmation_url; não envia e-mail até a confirmação na plataforma. |
| POST | /v1/contracts/{id}/share-proposal | Chave pessoal: propõe acesso de leitura com email, level e days (30, 90 ou 180). Retorna confirmation_url; o link de acesso só aparece para a pessoa que confirmar na plataforma. |
| POST | /v1/contracts/{id}/changes-proposal | Chave pessoal: recebe uma lista de clause_id, complaint e proposed_text opcional. A pessoa confere destinatários e ajustes na plataforma antes de enviar. |
| POST | /v1/contracts/{id}/actuation-proposal | Chave pessoal: propõe trocar a atuação (a parte dona: CPF ou empresa) para uma parte do usuário, via nova_parte_id. Retorna confirmation_url; a pessoa confirma na plataforma e a troca só ocorre então. Barra contrato assinado, com convite aberto ou arquivado. |
| GET | /v1/contracts/{id}/history | Intermediador: o histórico do contrato, do mais novo ao mais antigo (criação, convite e entrada das partes, ações da equipe, assinatura, selo, propostas, marcos visíveis, troca de signatário). Cada passo traz at, event, party (o nome, quando o passo é de uma parte) e, conforme o caso, ref (id da proposta) e label (rótulo do marco). Nunca texto digitado, e-mail ou IP. O mesmo histórico aparece no painel. |
| GET | /v1/contracts/{id}/signature | Status da assinatura: cada parte (com a vez, no pedido em ordem) e a selagem (sealed: quando, hash do PDF e quantos anexos). Vale para a chave de empresa nos contratos da empresa. |
| GET | /v1/contracts/{id}/terms | Termos de vida do contrato: vigência, renovação (automatica sim, nao ou nao_diz, e o período), aviso prévio (dias e para que serve: nao_renovar, rescindir ou ambos), reajuste (índice, periodicidade e data-base) e multa rescisória, cada um com o trecho do documento e conferido_em (quando a pessoa conferiu o grupo na plataforma), mais os prazos que a plataforma calcula deles. Só com a chave pessoal ou a da empresa. |
| GET | /v1/agenda | Obrigações e prazos pendentes dos contratos que a chave alcança (com a chave pessoal, os criados por ela; com a da empresa, a carteira), o mais próximo primeiro. Origem engine: o que o documento diz. Origem prazo: o que a plataforma calcula, como último dia para avisar, próximo reajuste, fim da vigência, fim do sigilo do NDA, devolução do material, os 4 anos do contrato de serviço e o prazo do defeito oculto. Contrato encerrado, arquivado ou cancelado não entra na agenda da API. Paginada com limit e offset. Só com a chave pessoal ou a da empresa. |
| POST | /v1/contracts/{id}/signature-request/cancel | Chave de empresa: cancela o pedido de assinatura em andamento; os links deixam de valer e o contrato volta a minuta. Mesma função da tool MCP cancel_signature_request. |
| POST | /v1/contracts/{id}/signature-request/resend | Chave de empresa: reenvia o convite a quem ainda não assinou ({email}), com link novo; o anterior para de valer. Até 3 por pessoa a cada 24 horas; no pedido em ordem, só para quem já tem a vez. Mesma função da tool MCP resend_signature_invite. |
| POST | /v1/embed-sessions | Token de embed (complete | review | status | acao_da_parte). acao_da_parte leva party_id, vale 30 min e deixa a parte confirmar e-mail e documento, ler e assinar dentro do seu produto. |
| PUT | /v1/branding | White-label: display_name (até 80), logo_url (https, host público), primary_color (#RRGGBB), footer (até 200) e embed_origins (até 10 origens https que recebem postMessage). Campo inválido: 422. |
| PUT | /v1/webhook | Liga/atualiza o webhook de saída do tenant (body {url, rotate?}). O secret sai UMA vez, na primeira vez ou com rotate: true; trocar só a url o mantém. Recusa URL privada/loopback/http (SSRF). Escopo account:write. |
| GET | /v1/webhook | Estado do webhook: url configurada, eventos disponíveis, disabled_at (desativado por falha contínua) e até quando o secret anterior ainda assina. Nunca o secret. |
| GET | /v1/webhook/deliveries | Últimas entregas (limit até 100): event, status, attempts, last_error, created_at, delivered_at. Escopo account:read. |
| GET | /v1/webhook/deliveries/{id} | Uma entrega, com o corpo enviado e a próxima tentativa. Escopo account:read. |
| POST | /v1/webhook/deliveries/{id}/redeliver | Reenvia agora, com o mesmo corpo e o mesmo webhook-id (vale para o que falhou). Escopo account:write. |
| POST | /v1/webhook/test | Manda um evento webhook.teste ao endereço cadastrado e devolve como foi a entrega. Escopo account:write. |
| DELETE | /v1/webhook | Desliga o webhook (limpa url e secret). Escopo account:write. |
| GET | /v1/usage | Consumo do tenant por dimensão e, em limits, usado e limite do mês UTC por contrato e assinatura (os mesmos números que barram com 402). Em credito: crédito do mês, consumido, saldo e envios por tipo de contrato. Em rate_limit: o limite de requisições por minuto da chave (passou, 429 com Retry-After). |
| PATCH | /v1/contracts/{id}/parties/{party_id} | Nível 2: corrige nome, email, documento ou telefone de parte que ainda não entrou, antes da primeira assinatura. Mudar email ou documento vence o convite dela. Escopo contracts:operate; fica na trilha que as partes leem. Mesma função da tool MCP correct_party. |
| POST | /v1/contracts/{id}/parties/{party_id}/resend | Nível 2: reenvia o convite a uma parte que ainda não entrou (até 3 por dia por parte). Escopo contracts:operate. Mesma função da tool MCP resend_party_invite. |
| POST | /v1/contracts/{id}/cancel | Nível 2: cancela antes da primeira assinatura; pedido de assinatura aberto é cancelado junto e sai contrato.cancelado. Escopo contracts:operate. Mesma função da tool MCP cancel_contract. |
| POST | /v1/contracts/{id}/milestones/{chave}/confirm | Nível 2: confirma um marco que o template dá a você (quem_confirma: intermediador), no contrato assinado. Sai marco.confirmado. Escopo contracts:operate. Mesma função da tool MCP confirm_milestone. |
| POST | /v1/contracts/{id}/mesa | Nível 3: mensagem do intermediador, com identidade própria, num tópico aberto da mesa ({topico_id, corpo}). Só depois do envio: o convite avisa as partes que ele pode intervir. Escopo contracts:intervene. Mesma função da tool MCP post_to_negotiation_table. |
| POST | /v1/contracts/{id}/exceptions/{proposta_id}/decide | Nível 3: a proposta de uma parte que sai da trava do template espera você. Aprove ou negue ({decisao: aprovar|negar, motivo?}); aprovada, as partes seguem aceitando; negada, vira recusada. Escopo contracts:intervene. Mesma função da tool MCP decide_exception. |
| POST | /v1/contracts/estimate | Sem criar nada: o tipo de contrato que o template (template_id) gera e quanto crédito o envio vai consumir, com o saldo de agora. Só chave de tenant (a pessoal recebe 403). Mesma função da tool MCP estimate_contract. |
| GET | /v1/account/capabilities | O que a empresa da chave pode fazer, segundo o plano dela (com a conta em várias empresas, escolha pelo header X-CNSC-Parte). A chave de intermediador recebe 404. |
| GET | /v1/audit | Auditoria da empresa: eventos de assinatura (convite, abertura, assinatura, recusa, cópia enviada) e selagens de todos os contratos no período (from/to em AAAA-MM-DD, até um ano; padrão: últimos 30 dias). Paginado: limit, offset, has_more e next_offset. Nunca IP nem dado do aparelho. Com a chave de empresa, a empresa da chave. Mesma função da tool MCP get_audit_log. |
Especificação viva: Swagger · openapi.json
Para testar sem escrever código: importe o endereço do openapi.json no Postman ou no Insomnia (Importar, depois Link). Ele monta a coleção com todas as rotas; ponha a chave em Authorization, tipo Bearer.
No sandbox, as partes usam e-mail @teste.contratocombinado.com, e o nome antes do arroba define o que a parte faz: aceita@ entra e assina, recusa@ entra e recusa a assinatura, expira@ nunca entra, documento-divergente@ erra o documento. Para várias partes com o mesmo comportamento, use aceita+1@, aceita+2@. Nenhum e-mail sai, ninguém ganha conta e a assinatura é simulada (sem selo nem PDF assinado). A projeção, os webhooks e o crédito funcionam como em produção.
A chave sandbox (engine real, cota reduzida) sai na hora, quando você cria o seu intermediador; o webhook você mesmo liga com PUT /v1/webhook.