Cada rota com todos os campos de entrada e de resposta, e o botão para disparar uma chamada sem sair da página. É por onde se tira dúvida de campo.
Sai do mesmo metadado que define as rotas — também em openapi.json, para gerar o cliente.As sete chamadas na ordem, do token ao resultado, com as variáveis já encadeadas: o que uma devolve, a seguinte usa. É por onde se faz a primeira análise.
Importe junto o environment do ambiente em que vai trabalhar: a tabela de ambientes está logo abaixo.O caminho inteiro, de uma vez
202 com o id. O crédito é separado agora.A caixa tracejada é a única em que seu sistema não fala conosco: ele fala direto com o armazenamento.
Você precisa de três coisas do lado de cá, e todas são pedidas ao ONRTDPJ uma única vez: a sua empresa cadastrada com a chave pública, a autorização do cartório (que define o teto diário e, se quiser, o endereço do webhook) e crédito de IA na conta daquela serventia — sem saldo a análise é recusada mesmo com tudo o mais pronto.
A asserção vale por pouquíssimo tempo (recomendado 120 s, teto de 300 s), e o
servidor compara o exp com o horário real dele, em UTC, tolerando só
60 segundos de diferença. O iat/exp são
unix timestamp — são UTC por definição, não dependem do fuso do seu Windows;
o que importa é o relógio absoluto da máquina estar certo. Se ele estiver atrasado,
a asserção chega expirada; se estiver adiantado, chega com vida longa demais — e nos
dois casos a resposta é credencial inválida, levando você a procurar defeito na chave e no
cadastro, que estão certos. É também o que faz "funcionar na segunda tentativa".
Antes de depurar qualquer coisa: abra time.is na máquina que gera a asserção. Se acusar mais de ~30 s de diferença, sincronize o relógio (Windows: Data e hora → Sincronizar agora; deixe o fuso em automático) e teste de novo. Use validade de 120 s e gere-e-troque o token na sequência, sem deixá-lo esfriar.
Os ambientes
O que muda de um para o outro é só o endereço. O caminho das rotas, os campos e a audiência da asserção são os mesmos em todos.
| Ambiente | Endereço | O que é | Swagger | Postman |
|---|---|---|---|---|
| Local | http://localhost:3100 |
A stack rodando na sua máquina — é a porta da borda, não a do serviço. | abrir | baixar |
| Homologação | https://iah.rtdbrasil.org.br |
O ambiente de testes do ONRTDPJ. É onde você exercita a integração antes de valer. | abrir | baixar |
| Produção | https://ia.rtdbrasil.org.br |
O ambiente de produção do ONRTDPJ — onde a integração passa a valer. | abrir | baixar |
No Postman, importe os environments acima (um clique cada) e troque pelo seletor do canto
superior direito. A coleção fala apenas {{host}} — não edite o endereço dentro
dela. Com o endereço escrito na coleção, disparar contra o ambiente errado fica a uma
distração de distância.
Fora do Postman, a mesma ideia: o endereço é a única coisa que sua configuração precisa trocar.
1 · Autenticação
Prefere ver funcionando antes de ler? No fim desta seção há duas ferramentas que rodam nesta página: uma gera um par de chaves, a outra assina a asserção e pede um token de verdade. Dois minutos, sem instalar nada.
Primeiro: gere o seu par de chaves
Quem gera é você, na sua máquina, e a privada nunca sai dela — nem para nós. É o que faz um vazamento do nosso banco não virar acesso ao cartório de ninguém: o que guardamos é a metade que não assina nada. Nós nunca pedimos, nunca recebemos e não temos onde guardar uma chave privada.
Dois comandos, e qualquer um dos dois serve. A curva é P-256 (para ES256):
# com openssl — dois arquivos, privada e pública
openssl ecparam -genkey -name prime256v1 -noout -out privada.pem
openssl ec -in privada.pem -pubout -out publica.pem
# a pública em JWK, que é o formato que a tela do cadastro pede
node -e "console.log(JSON.stringify(require('crypto').createPublicKey(require('fs').readFileSync('publica.pem')).export({format:'jwk'})))"
# só com Node, sem openssl — gera o par e imprime a pública em JWK
node -e "const c=require('crypto');const {publicKey,privateKey}=c.generateKeyPairSync('ec',{namedCurve:'P-256'});
require('fs').writeFileSync('privada.jwk.json',JSON.stringify(privateKey.export({format:'jwk'})));
console.log(JSON.stringify(publicKey.export({format:'jwk'})))"
Entregue ao ONRTDPJ só a JWK pública — ela tem kty, crv,
x e y. Se o que você copiou tem d, p ou
q, é a PRIVADA: a tela do cadastro recusa e diz por quê, mas a essa altura ela já saiu da
sua máquina — gere outro par e descarte esse.
Escolha um kid que diga onde a chave vive (producao-2027,
homologacao-2026). É por ele que o servidor sabe qual das suas chaves confere a assinatura,
e é o que permite trocar de chave sem parar a integração: cadastra-se a nova, vira-se o
kid nas asserções, e só então revoga-se a antiga.
Os valores que o ONRTDPJ lhe entrega
São quatro, e todos estão numa tela só — Cartórios › a serventia › API de análise por IA › Dados para quem vai integrar, com botão de copiar. Peça-os a quem administra o cartório:
| Valor | Onde entra |
|---|---|
| id da sua empresa | iss e sub da asserção — sai do cadastro da empresa |
| identificador da serventia | o campo cns do pedido de token |
| audiência | aud da asserção — é um identificador, não um endereço que se chama |
| endereço base | o começo de toda URL desta API |
Não há senha nem chave fixa. Você assina uma asserção (um JWT curto) com a sua chave privada e a troca por um token de acesso de 10 minutos. Quem guarda segredo é você; nós guardamos só a sua chave pública, e por isso um vazamento do nosso lado não dá acesso a ninguém.
A asserção que você assina
| Campo | O que vai |
|---|---|
iss | o id da sua empresa integradora (o que o Console Nacional lhe deu) |
sub | o mesmo valor de iss |
aud | a URL desta porta de token — o valor exato está na referência |
jti | identificador único da asserção; repetir um já usado é recusado |
exp | curto: ela vale para UMA troca, não para o dia |
kid (cabeçalho) | qual das suas chaves assinou |
alg (cabeçalho) | ES256 ou RS256 |
Como assinar a asserção, linha a linha
Um JWT são três pedaços separados por ponto: cabeçalho, corpo e
assinatura. Os dois primeiros são JSON codificado em base64url — que é o base64
comum com + virando -, / virando _ e sem os
= do fim. A assinatura é feita sobre o texto cabeçalho.corpo, e entra como
terceiro pedaço.
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Li4ufQ ← cabeçalho
.eyJpc3MiOiIuLi4iLCJzdWIiOiIuLi4iLCJhdWQiOiIuLi4ifQ ← corpo
.MEUCIQD... ← assinatura
O JOSE exige a assinatura em formato cru (os dois números R e
S, 32 bytes cada, colados). A maioria das bibliotecas de criptografia devolve
DER por padrão, que é outro empacotamento dos mesmos números. As duas são "a
assinatura certa", e só uma passa: com DER a verificação recusa, e o erro chega como
credencial inválida — o que leva a procurar defeito na chave, no kid e no
cadastro, que estão todos certos. Em Node isso é a opção
dsaEncoding: 'ieee-p1363'; em Python, o PyJWT já faz certo sozinho.
Em Node, sem biblioteca nenhuma
const { createSign, createPrivateKey, randomUUID } = require('node:crypto');
const fs = require('node:fs');
const INTEGRADOR = '';
const KID = '';
const AUD = '';
const SERVENTIA = '';
const BASE = '';
const b64u = (x) => Buffer.from(x).toString('base64url');
function assinarAssercao() {
const chave = createPrivateKey({
key: JSON.parse(fs.readFileSync('privada.jwk.json')), format: 'jwk',
});
const agora = Math.floor(Date.now() / 1000);
const cab = { alg: 'ES256', typ: 'JWT', kid: KID };
const corpo = {
iss: INTEGRADOR, sub: INTEGRADOR, aud: AUD,
jti: randomUUID(), // único a cada troca — repetir é recusado
iat: agora, exp: agora + 120,
};
const entrada = `${b64u(JSON.stringify(cab))}.${b64u(JSON.stringify(corpo))}`;
const assin = createSign('SHA256').update(entrada).end()
.sign({ key: chave, dsaEncoding: 'ieee-p1363' }); // ← cru, não DER
return `${entrada}.${assin.toString('base64url')}`;
}
async function pegarToken() {
const r = await fetch(`${BASE}/token`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ client_assertion: assinarAssercao(), cns: SERVENTIA }),
});
if (!r.ok) throw new Error(`token recusado: ${r.status} ${await r.text()}`);
const { access_token } = await r.json();
return access_token; // vale 10 minutos
}
Em Python, com PyJWT
import time, uuid, json, jwt, requests
from cryptography.hazmat.primitives.serialization import load_pem_private_key
CHAVE = load_pem_private_key(open('privada.pem','rb').read(), password=None)
def assinar():
agora = int(time.time())
return jwt.encode(
{'iss': INTEGRADOR, 'sub': INTEGRADOR, 'aud': AUD,
'jti': str(uuid.uuid4()), 'iat': agora, 'exp': agora + 120},
CHAVE, algorithm='ES256', headers={'kid': KID},
)
def pegar_token():
r = requests.post(f'{BASE}/token',
json={'client_assertion': assinar(), 'cns': SERVENTIA})
r.raise_for_status()
return r.json()['access_token']
Não há refresh token. O token vale 10 minutos; para renovar, assina-se uma
asserção NOVA — com jti novo — e troca-se de novo. É a mesma chamada, e é barata.
Na prática: guarde o token em memória com a hora em que ele vence e troque quando faltar menos de um
minuto. Não guarde em disco nem em banco — em dez minutos ele não vale mais, e um token guardado é um
segredo a mais para vazar. Se um pedido voltar 401, troque por um token novo e repita o
pedido uma vez; se voltar 401 de novo, o problema é a autorização, não o token, e repetir
não resolve.
A troca
POST /integracao/ia/v1/token
{
"client_assertion": "<o JWT que você acabou de assinar>",
"cns": "<o IDENTIFICADOR da serventia — NÃO o número do CNS>"
}
→ 200 { "access_token": "...", "token_type": "Bearer", "expires_in": 600, "scope": "analise:ler" }
Use o token em Authorization: Bearer <access_token>. Ele carrega a serventia:
nenhuma rota abaixo pergunta de qual cartório é o pedido, e mandar isso no corpo é
recusado — é o que impede o integrador legítimo de um cartório de ler os documentos de outro.
Experimente aqui, sem instalar nada
As duas caixas abaixo fazem, dentro desta página, exatamente o que os exemplos acima fazem em Node e
em Python — e servem para a coisa mais útil que existe ao integrar uma API assinada: ter um
resultado certo para comparar com o seu. Quando a sua implementação voltar
credencial inválida, assine a mesma asserção aqui e veja onde as duas diferem.
Gerar um par aqui, agora
Roda no seu navegador, com crypto.subtle. Nada sai desta aba — a privada
aparece só na tela, e some quando você fechar. Para teste. Em produção, gere a chave
na máquina que vai assinar, com os comandos acima.
Pública em JWK — é esta que você entrega ao ONRTDPJ
Privada em JWK — fica com você, nunca envie
Privada em PEM (PKCS#8) — o formato que o openssl e o PyJWT leem
Assinar a asserção e trocar pelo token
Preencha com os valores que o Console lhe deu (o botão Credenciais, na ficha do cartório ou na da empresa, traz todos). A asserção é assinada aqui; o token é pedido à API deste mesmo ambiente.
A asserção assinada — é o client_assertion do corpo
O que vai no POST
O que a API respondeu
2 · O de/para das naturezas
A análise é pedida pelo código de natureza do nosso catálogo. A correspondência com o código do seu sistema é mantida por você: nós não guardamos essa tabela, e é de propósito — uma tradução mantida do nosso lado seria uma segunda cópia do seu catálogo, desatualizando em silêncio.
GET /integracao/ia/v1/naturezas
→ 200 {
"uf": "MG",
"atualizadoEm": "2026-09-28T13:00:00.000Z",
"naturezas": [
{ "codigo": "LOCACAO_PREDIO", "rotulo": "Contrato de locação de prédio",
"naturezaMaeCodigo": null, "especialidade": "RTD",
"conteudoFinanceiroObrigatorio": true,
"posicoesJuridicasMinimas": ["LOCADOR", "LOCATARIO"] },
{ "codigo": "NOTIFICACAO_INDIVIDUAL", "rotulo": "Notificação extrajudicial · individual",
"naturezaMaeCodigo": "NOTIFICACAO", "especialidade": "RTD",
"conteudoFinanceiroObrigatorio": false,
"posicoesJuridicasMinimas": ["NOTIFICANTE", "NOTIFICADO"] }
]
}
- A UF não é parâmetro. Ela sai da serventia do token — quem pergunta não escolhe contra qual catálogo lê.
- Releia periodicamente. O catálogo muda quando o cartório personaliza ou o estado
publica natureza nova;
atualizadoEmdiz de quando é a leitura. - Código desconhecido é recusado ao pedir a análise, e a mensagem aponta para cá. Aceitá-lo não daria erro: a análise rodaria com a lista geral do estado e devolveria um parecer completo e cego para o que aquela natureza exige.
3 · O envio do documento
O arquivo não passa pela nossa aplicação. Pedimos que você o mande direto ao armazenamento, com uma autorização curta para uma única chave. É o que permite contrato escaneado de quarenta páginas sem prender um processo que atende o balcão ao mesmo tempo.
1) POST /integracao/ia/v1/arquivos/preparar { "nome": "contrato.pdf", "tamanho": 2400000 }
→ 200 { "arquivoId": "...", "url": "https://...", "metodo": "PUT",
"expiraEm": "...", "tetoBytes": 314572800 }
2) PUT <url> (o corpo é o arquivo; esta chamada NÃO passa por nós)
3) POST /integracao/ia/v1/arquivos/{arquivoId}/confirmar
→ 200 { "arquivoId": "...", "nome": "...", "mime": "application/pdf",
"tamanho": 2400000, "sha256": "..." }
| Campo do preparo | Obrigatório | Observação |
|---|---|---|
nome | sim | com extensão — é dela que sai o primeiro sinal do formato |
tamanho | não | serve para recusar cedo o que já se sabe grande demais; não é acreditado — a confirmação pergunta ao armazenamento qual foi o tamanho real |
- Só existe depois de confirmado. Na confirmação conferimos que o objeto chegou, o tamanho real e se os primeiros bytes são de um formato aceito. Arquivo recusado é apagado.
- Confirmar duas vezes devolve o mesmo arquivo. Repetição de chamada de rede é normal.
- Preparar não gasta crédito. Só a análise gasta.
Transcrever um PDF digitalizado leva dezenas de segundos, e as quatro chamadas acima levam
segundos. Peça a análise assim mesmo. Se a leitura ainda não terminou, a análise
nasce aguardando_ocr e entra na fila sozinha quando o texto ficar pronto.
Não implemente uma espera fixa antes de pedir: ela funciona na sua máquina e quebra no documento
grande do seu cliente. Se quiser acompanhar o passo, existe
GET /integracao/ia/v1/arquivos/{id} — mas é opcional, e o aviso
arquivo.pronto chega sozinho para quem cadastrou webhook.
Em que pé está a leitura (opcional)
GET /integracao/ia/v1/arquivos/{arquivoId}
→ 200 { "arquivoId": "...", "nome": "contrato.pdf",
"leitura": "pendente" | "concluida" | "falhou",
"paginas": 11, "temAssinatura": null, "assinaturas": [] }
O campo se chama leitura, e não situacao, de propósito:
situacao já é da ANÁLISE, e dois campos com o mesmo nome e significados diferentes na
mesma API é como se confunde quem integra. E temAssinatura vem null — e não
false — enquanto não houve leitura: ausência de leitura não é ausência de assinatura.
4 · Pedir a análise
Repetir o mesmo pedido não cria outra análise. Enquanto o mesmo arquivo estiver
aguardando_ocr, na_fila ou analisando, você recebe de volta a
MESMA análise, com o mesmo id e sem custo novo. Repetição de chamada de rede é normal e
não pode cobrar duas vezes.
Você pode mandar o texto em vez do arquivo. Se já tem o teor — passou o próprio
OCR, ou o documento nasceu digital do seu lado —, use teor no lugar de
arquivoId e pule os passos 3, 4 e 5 inteiros.
POST /integracao/ia/v1/analises
{
"arquivoId": "<o id devolvido no passo 5>",
"especieAto": "registro_integral",
"naturezaCodigo": "LOCACAO_PREDIO"
}
→ 202 { "id": "...", "situacao": "na_fila" | "aguardando_ocr",
"origemDoTeor": "arquivo", "especieAto": "registro_integral",
"uf": "MG", "criadoEm": "..." }
Vários documentos na mesma análise
arquivoId aceita UM id (string) ou uma LISTA de ids (array). Com a lista, TODOS
entram juntos na mesma análise — o primeiro é o documento principal e os demais são
complementares, exatamente como o exame do balcão trata o título e seus anexos. Útil quando o
ato se prova em mais de um arquivo (contrato + aditivo, ata + lista de presença).
POST /integracao/ia/v1/analises
{
"arquivoId": ["<id do principal>", "<id do anexo>"],
"especieAto": "registro_integral",
"naturezaCodigo": "LOCACAO_PREDIO"
}
Ou, se você já tem o texto
POST /integracao/ia/v1/analises
{
"teor": "ATA DA ASSEMBLEIA GERAL EXTRAORDINÁRIA DO CONDOMÍNIO…",
"nomeDoDocumento": "ata-do-meu-sistema.pdf",
"especieAto": "registro_integral",
"naturezaCodigo": "ATA_CONDOMINIO"
}
→ 202 { "id": "...", "situacao": "na_fila", "origemDoTeor": "informado",
"arquivoId": null, ... }
É alternativa a arquivoId, não complemento: mandar os dois é
recusado com 400 — com os dois não haveria como saber sobre qual dos textos o parecer foi feito.
E a resposta marca origemDoTeor: "informado" de propósito. Com arquivo, o que se
examina é o documento; com teor, é o que você afirmou que o
documento diz. É a mesma análise e não é a mesma cadeia de responsabilidade — e quem ler o parecer
depois precisa poder saber disso sem ir perguntar.
A cobrança é por página, e sem arquivo não há página para contar: ela é estimada pelo tamanho do texto.
| Campo | Obrigatório | O que é |
|---|---|---|
arquivoId | um ou outro |
o arquivo que você confirmou no passo 5. Pode ser pedido antes de a leitura terminar — a análise espera sozinha |
teor | um ou outro |
o texto já extraído do seu lado, no lugar do arquivo. Mandar os dois é recusado |
nomeDoDocumento | não | como a análise se chama na lista do cartório quando não há arquivo com nome |
especieAto | sim | a espécie do ato pretendido — lista abaixo |
naturezaCodigo | não | sem ele vale a lista geral do estado, e a resposta diz isso |
uf | — | não mande. Vem da serventia do token; mandá-la é recusado, não ignorado |
Espécies aceitas: registro_integral · registro_extrato · averbacao · anotacao · cancelamento · notificacao · arquivamento · matricula_rcpj · registro_pj · certidao · busca_apreensao
O pedido foi aceito, não concluído. A leitura roda em segundo plano. Guarde o
id e consulte por ele, ou espere o webhook.
Repetir é seguro. Enquanto o mesmo arquivo estiver aguardando_ocr,
na_fila ou analisando, o pedido repetido devolve a MESMA análise, com o
mesmo id e sem custo novo.
aguardando_ocr — a situação que você vai ver, e não é erroSignifica que o arquivo ainda está sendo transcrito. A análise entra na fila sozinha quando o texto ficar pronto; não é preciso pedir de novo nem esperar antes de pedir.
Se a leitura não terminar em 15 minutos, a análise falha com o motivo e nada é cobrado.
Quando a resposta não é 202
| Código | O que aconteceu | O que fazer |
|---|---|---|
400 | espécie ou natureza que o catálogo não conhece, ou uf no corpo |
a mensagem diz qual campo e para onde ir; não repita sem corrigir |
401 | token vencido, inválido, ou autorização revogada | troque uma asserção nova por outro token |
403 | o teto diário de gasto daquela serventia acabou | não é velocidade: reabre à meia-noite, e só o cartório altera o teto. Não implemente recuo exponencial para isto |
404 | o documento não existe para esta serventia | confira se o arquivo foi confirmado |
409 | a serventia ainda não tem UF configurada | tem conserto do nosso lado: avise o cartório |
5 · Receber o resultado
Há dois caminhos, e eles não se excluem. O webhook é opcional; a consulta funciona sempre, e é o que sustenta quem está atrás de um firewall sem endereço público.
a) Consulta por id
GET /integracao/ia/v1/analises/{id}
→ 200 { "id": "...", "situacao": "na_fila" | "analisando" | "pronta" | "falhou",
"resultado": { ... } // só quando "pronta" }
Enquanto for na_fila ou analisando, não é erro — é o estado
normal de quem ainda está lendo. Quando for pronta, vem junto a ficha extraída, os achados e o
checklist respondido.
b) Reconciliação — o que mudou desde a última leitura
GET /integracao/ia/v1/analises?desde=2026-09-28T13:00:00.000Z
→ 200 { "analises": [...], "atualizadoAte": "...", "temMais": false }
É a rota de quem ficou fora do ar e precisa recuperar o que perdeu, sem consultar uma por uma.
Guarde atualizadoAte e mande de volta como desde na próxima. A paginação é por
tempo, e não por página: item que termina entre uma página e outra escapa de paginação por
posição, e some sem ninguém notar.
c) Webhook, se o cartório cadastrou um
POST <a URL que o cartório cadastrou>
x-rtdpj-signature: t=<época>,v1=<hmac-sha256>
x-rtdpj-delivery: <id da entrega>
{ "evento": "analise.concluida", "id": "...", "situacao": "pronta",
"analiseId": "...", "especieAto": "...", "naturezaCodigo": "...", "terminadoEm": "..." }
- Confira a assinatura antes de confiar no aviso (passo a passo logo abaixo). Aceitar sem conferir deixa qualquer um simular uma conclusão.
- Deduplique por
x-rtdpj-delivery. Reentrega é normal — você pode ter recebido e caído antes de responder. - Responda 2xx rápido. Qualquer outra coisa é falha, e tentamos de novo com espera crescente até desistir. O corpo do aviso é um resumo: o resultado inteiro vem na consulta por id.
Como validar a assinatura (x-rtdpj-signature)
O header vem no formato t=<época>,v1=<hmac>. O v1 é um
HMAC-SHA256 em hexadecimal sobre a string <t>.<corpo>,
em que <t> é a época do próprio header e <corpo> é o corpo
cru da requisição. O segredo é o whsec_… que apareceu uma única
vez quando o cartório autorizou (ou trocou) o webhook — se o perder, gera-se outro.
- Leia
x-rtdpj-signaturee separetev1. - Pegue o corpo CRU da requisição — antes de qualquer parse ou re-serialização.
- Monte
base = t + "." + corpoCru. - Calcule
esperado = HMAC-SHA256(segredo, base)em hexadecimal. - Compare
esperadocomv1em tempo constante.
Parsear o JSON e re-serializar para calcular o HMAC. A string muda (espaços, ordem
das chaves) e a assinatura nunca bate. Use o corpo exatamente como chegou na rede.
Recomenda-se ainda rejeitar avisos com t muito antigo — por exemplo, tolerância de 5
minutos — contra reenvio malicioso.
// Node
const crypto = require('crypto');
function validaWebhook(rawBody, headerSig, segredo) {
const p = Object.fromEntries(headerSig.split(',').map(x => x.split('=')));
const base = p.t + '.' + rawBody; // rawBody = corpo CRU (a string recebida)
const esperado = crypto.createHmac('sha256', segredo).update(base).digest('hex');
const bate = esperado.length === p.v1.length
&& crypto.timingSafeEqual(Buffer.from(esperado), Buffer.from(p.v1));
const fresco = Math.abs(Date.now() / 1000 - Number(p.t)) <= 300; // anti-replay
return bate && fresco;
}
# Python
import hmac, hashlib, time
def valida_webhook(raw_body: bytes, header_sig: str, segredo: str) -> bool:
p = dict(kv.split('=', 1) for kv in header_sig.split(','))
base = (p['t'] + '.').encode() + raw_body # raw_body = corpo CRU (os bytes recebidos)
esperado = hmac.new(segredo.encode(), base, hashlib.sha256).hexdigest()
return hmac.compare_digest(esperado, p['v1']) and abs(time.time() - int(p['t'])) <= 300
Delphi: THashSHA2.GetHMAC(t + '.' + corpoCru, segredo,
SHA256) e compare o hex devolvido com o v1 — sempre com o corpoCru, não
com o JSON re-serializado.
Mesmo com webhook, mantenha a reconciliação rodando de tempos em tempos. Entrega perdida acontece — rede, manutenção, certificado vencido do seu lado — e a análise já foi paga. Quem só escuta o aviso perde exatamente aquilo que mais custou.
6 · Limites e comportamento
| Assunto | Como é |
|---|---|
| Validade do token | 10 minutos; renove trocando uma asserção nova |
| Tamanho do arquivo | o teto vem na resposta do preparo (tetoBytes) |
| Escopo do token | analise:ler — não alcança registro, selo nem livro |
| Teto de gasto | diário, por serventia; definido pelo cartório, reabre à meia-noite |
| Crédito | do cartório, não seu; separado no momento do pedido |
| Isolamento | você lê apenas as análises que a SUA credencial pediu, naquela serventia |
7 · Para começar agora
Os dois caminhos do começo desta página continuam valendo, e nenhum depende do outro. Escolha pelo que você quer fazer primeiro — entender ou executar.
Os campos de cada entrada e de cada resposta, e o botão para disparar uma chamada ali mesmo. O openapi.json é a mesma coisa em arquivo, para gerar o cliente na sua linguagem.
Cada ambiente tem o seu — os links estão na tabela de ambientes.As sete chamadas na ordem, com exemplos reais. Importe junto o environment do ambiente em que vai trabalhar, e não edite o endereço dentro da coleção.
O environment de cada ambiente também sai da tabela de ambientes.