webhooks-monitoramento-processos-judiciais-tempo-real.

Monitoramento de Processos Judiciais em Tempo Real | API

Monitoramento de Processos Judiciais com Webhooks: Guia para Desenvolvedores 2026 | Judit Blog
API e Tecnologia

Webhooks para Monitoramento de Processos Judiciais em Tempo Real

Abril 2026 8 min de leitura

O monitoramento de processos judiciais manualmente não escala. Um escritório com 500 processos ativos que depende de alguém verificando portais de tribunal diariamente está, na prática, operando às cegas — qualquer andamento que acontece entre uma verificação e outra pode passar despercebido por dias.

A solução técnica para esse problema é o webhook: no monitoramento de processos judiciais, em vez de a aplicação perguntar ao tribunal “houve novidade?”, a API avisa a aplicação quando algo acontece.

Este artigo explica como implementar isso corretamente com a Judit API — do conceito à produção.

Monitoramento de processos judiciais: tribunal → Judit API → webhook → seu sistema

Monitoramento de processos judiciais: polling vs. webhook

Antes de escrever código, vale entender por que polling é a abordagem errada para esse problema.

Polling: a abordagem ingênua

// Não faça isso em produção
setInterval(async () => {
  const resultado = await consultarProcesso(numeroCNJ);
  if (resultado.last_step.step_id !== ultimoStepConhecido) {
    notificar(resultado);
  }
}, 60 * 60 * 1000); // a cada 1 hora

O problema com polling é triplo. Primeiro, você paga por cada requisição, mesmo quando não há novidade — que é a maioria das vezes. Segundo, o intervalo mínimo entre verificações cria uma janela cega. Terceiro, em escala com centenas de processos monitorados, o volume de requisições consome cota rapidamente e pode gerar throttling.

Webhook: a abordagem correta

Com webhook, a lógica se inverte. Você registra um processo (ou CPF/CNPJ) para monitoramento uma única vez, com uma recurrence configurável em dias. A partir daí, quando a Judit detectar um novo andamento ao consultar o tribunal, ela faz um POST no endpoint que você configurou — com o processo completo e atualizado no payload.

Zero polling. Zero custo de requisições desnecessárias.


Arquitetura de integração para monitoramento de processos judiciais

Uma integração de monitoramento processual tem três componentes:

[Tribunal] → [Judit Crawler] → [Seu servidor (endpoint webhook)] → [Sistema interno]
  1. Registro do monitoramento — sua aplicação chama a API uma vez para cadastrar o processo, CPF, CNPJ ou OAB que quer acompanhar
  2. Endpoint receptor — um endpoint HTTP na sua infraestrutura que recebe e processa os callbacks
  3. Lógica de negócio — o que fazer com cada evento: salvar no banco, disparar notificação, atualizar score, acionar um fluxo

Autenticação

Todas as chamadas à Judit API usam o header api-key:

curl -H "api-key: SUA_API_KEY" https://tracking.prod.judit.io/tracking

A chave é obtida com o time comercial da Judit. Armazene-a em variável de ambiente — nunca no código-fonte.


1. Registrando um monitoramento

A chamada de registro precisa ser feita apenas uma vez por entidade monitorada. O endpoint é POST /tracking no host tracking.prod.judit.io.

Monitorando um processo pelo número CNJ

curl --location 'https://tracking.prod.judit.io/tracking' \
  --header 'api-key: SUA_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "recurrence": 1,
    "search": {
      "search_type": "lawsuit_cnj",
      "search_key": "1111111-04.2024.8.19.0001"
    },
    "callback_url": "https://seu-servidor.com/webhooks/judit"
  }'

Monitorando todas as ações de um CPF ou CNPJ

Para monitorar novas ações distribuídas contra um documento, use o endpoint de Monitoramento de Novas Ações (/tracking/document):

curl --location 'https://tracking.prod.judit.io/tracking/document' \
  --header 'api-key: SUA_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "recurrence": 1,
    "search": {
      "search_type": "cpf",
      "search_key": "123.456.789-00"
    },
    "callback_url": "https://seu-servidor.com/webhooks/judit"
  }'

Os search_type suportados são: lawsuit_cnj, cpf, cnpj, oab e name.

Resposta da criação

{
  "tracking_id": "d923253e-45c1-46e5-ac70-164839d9851c",
  "user_id": "7f8065a3-4891-428d-9456-dedfc12ff850",
  "status": "created",
  "recurrence": 1,
  "hour_range": 21,
  "search": {
    "search_type": "lawsuit_cnj",
    "search_key": "1111111-04.2024.8.19.0001"
  },
  "created_at": "2026-04-16T13:58:56.352Z"
}

O campo hour_range indica o horário em que a primeira consulta ao tribunal será realizada. O monitoramento começa dentro das próximas 24 horas da data de criação, na janela de menor concorrência.

Guarde o tracking_id — você vai precisar dele para pausar, reativar ou remover o monitoramento.


2. Filtrando notificações por termos de andamento

Se você quer ser notificado apenas quando determinados tipos de movimentação ocorrerem — uma sentença, uma penhora, um despacho específico — use o campo step_terms dentro de notification_filters:

{
  "recurrence": 1,
  "search": {
    "search_type": "lawsuit_cnj",
    "search_key": "1111111-04.2024.8.19.0001"
  },
  "callback_url": "https://seu-servidor.com/webhooks/judit",
  "notification_filters": {
    "step_terms": ["sentença", "penhora", "acordo", "bloqueio"]
  }
}

Com esse filtro ativo, o webhook só é disparado se algum dos termos aparecer em um novo andamento. Útil para reduzir ruído em processos com muitas movimentações menores.


3. Construindo o endpoint receptor

O endpoint precisa responder rápido (em menos de 2 segundos) e processar o evento de forma assíncrona. A Judit pode reenviar o callback se o servidor demorar ou retornar erro — então a lógica pesada deve acontecer fora do handler da requisição.

Node.js (Express)

import express from 'express';
import { Queue } from 'bullmq';

const app = express();
const eventQueue = new Queue('judicial-events');

app.use(express.json());

app.post('/webhooks/judit', async (req, res) => {
  // Responde imediatamente
  res.status(200).json({ received: true });

  // Enfileira para processamento assíncrono
  await eventQueue.add('processar-callback', req.body);
});

Python (FastAPI)

from fastapi import FastAPI, Request, BackgroundTasks

app = FastAPI()

@app.post("/webhooks/judit")
async def receber_callback(request: Request, background_tasks: BackgroundTasks):
    payload = await request.json()
    background_tasks.add_task(processar_callback_judicial, payload)
    return {"received": True}

4. Entendendo a estrutura do payload

Todo callback da Judit segue este envelope:

{
  "user_id": "...",
  "callback_id": "...",
  "event_type": "response_created",
  "reference_type": "tracking",
  "reference_id": "d923253e-45c1-46e5-ac70-164839d9851c",
  "payload": {
    "request_id": "...",
    "response_id": "...",
    "response_type": "lawsuit",
    "response_data": { ... },
    "tags": {
      "cached_response": false
    }
  }
}

Pontos importantes:

reference_type pode ser request (consulta avulsa) ou tracking (monitoramento). Para monitoramentos, o reference_id corresponde ao tracking_id que você criou.

response_type define o que está no response_data. Os tipos relevantes são: – lawsuit — dados completos de um processo judicial – application_info — sinal de controle (fim de entrega) – application_error — erro na consulta

cached_response (dentro de tags) indica a origem dos dados: – true → dados vieram do datalake da Judit (resposta imediata) – false → dados foram coletados diretamente do tribunal nesta rodada

É possível receber dois callbacks para a mesma atualização: o primeiro com cached_response: true e o segundo com cached_response: false. Processe os dois, mas use o response_id para garantir idempotência.

Sinal de fim de entrega

Quando todas as respostas de uma execução foram entregues, a Judit envia um callback final com response_type: "application_info":

{
  "payload": {
    "response_type": "application_info",
    "response_data": {
      "code": 600,
      "message": "REQUEST_COMPLETED"
    }
  }
}

Sinal de erro

Se o processo não for encontrado ou houver falha na consulta ao tribunal:

{
  "payload": {
    "response_type": "application_error",
    "response_data": {
      "code": 2,
      "message": "LAWSUIT_NOT_FOUND"
    }
  }
}

5. Processando os callbacks

Com a estrutura clara, o handler de processamento fica assim:

async function processarCallbackJudicial(callback) {
  const { reference_id, payload } = callback;
  const { response_type, response_data, response_id } = payload;

  // Sinal de conclusão — apenas registra no log
  if (response_type === 'application_info' && response_data.code === 600) {
    console.log(`Entrega concluída para tracking ${reference_id}`);
    return;
  }

  // Erro na consulta — registra para análise
  if (response_type === 'application_error') {
    await registrarErroMonitoramento(reference_id, response_data);
    return;
  }

  // Dados de processo
  if (response_type === 'lawsuit') {
    // Idempotência: ignora se já processamos este response_id
    const jaProcessado = await verificarResponseId(response_id);
    if (jaProcessado) return;

    const isCached = payload.tags?.cached_response;

    await salvarProcesso(response_data);
    await marcarResponseIdProcessado(response_id);

    // Notifica apenas para dados frescos do tribunal
    if (!isCached) {
      await notificarAndamento(response_data);
    }
  }
}
async def processar_callback_judicial(callback: dict):
    payload = callback['payload']
    response_type = payload['response_type']
    response_data = payload['response_data']
    response_id = payload['response_id']

    if response_type == 'application_info' and response_data['code'] == 600:
        print(f"Entrega concluída: {callback['reference_id']}")
        return

    if response_type == 'application_error':
        await registrar_erro(callback['reference_id'], response_data)
        return

    if response_type == 'lawsuit':
        if await ja_processado(response_id):
            return

        is_cached = payload.get('tags', {}).get('cached_response', False)

        await salvar_processo(response_data)
        await marcar_processado(response_id)

        if not is_cached:
            await notificar_andamento(response_data)

6. Gerenciando o ciclo de vida dos monitoramentos

Pausar

curl -X POST \
  "https://tracking.prod.judit.io/tracking/{tracking_id}/pause" \
  -H "api-key: SUA_API_KEY"

Reativar

curl -X POST \
  "https://tracking.prod.judit.io/tracking/{tracking_id}/resume" \
  -H "api-key: SUA_API_KEY"

Atualizar recorrência

curl -X PATCH \
  "https://tracking.prod.judit.io/tracking/{tracking_id}" \
  -H "api-key: SUA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"recurrence": 3}'

Remover definitivamente

curl -X DELETE \
  "https://tracking.prod.judit.io/tracking/{tracking_id}" \
  -H "api-key: SUA_API_KEY"

Listar monitoramentos ativos

curl "https://tracking.prod.judit.io/tracking?status=updated&page=1&page_size=50" \
  -H "api-key: SUA_API_KEY"

Os status possíveis são: created, updating, updated, paused e deleted.


7. Consultando o histórico de um monitoramento

Para recuperar todas as respostas já entregues por um monitoramento — útil para sincronização ou debugging — use o endpoint de histórico no host requests.prod.judit.io:

curl "https://requests.prod.judit.io/responses/tracking/{tracking_id}?order=asc&page=1&page_size=50" \
  -H "api-key: SUA_API_KEY"

Filtre por período com created_at_gte e created_at_lte no formato ISO 8601.


Dicas para produção

Idempotência pelo response_id. A Judit pode reenviar o mesmo callback em caso de falha de entrega. Antes de processar, verifique se o response_id já foi tratado — idealmente com uma chave no Redis ou uma coluna única no banco.

Separe endpoints por ambiente. Use URLs distintas para dev, staging e prod. Compartilhar a mesma URL em todos os ambientes garante que eventos de teste acabem em produção.

Monitore application_error. Um erro ocasional é normal — tribunal fora do ar, CAPTCHA, instabilidade. Mas LAWSUIT_NOT_FOUND persistente para o mesmo número CNJ geralmente indica que o processo foi arquivado ou o número está incorreto.

Prefira cached_response: false para decisões críticas. O dado cacheado é útil para velocidade, mas para decisões de crédito ou compliance, use apenas os dados frescos do crawler como base.

Registre o payload completo antes de processar. Em caso de bug na lógica, você vai querer fazer replay do evento original — o que só é possível se você guardou o payload bruto.


Testando localmente

Durante o desenvolvimento, você precisa de uma URL pública para receber os callbacks:

# ngrok — mais popular
ngrok http 3000
# Usa a URL gerada como callback_url no payload de registro

# Webhook.site — sem instalar nada
# Acesse https://webhook.site para inspecionar payloads reais antes de implementar o handler

Recapitulando

O monitoramento por webhook é a única abordagem que escala para operações com centenas ou milhares de processos. A implementação correta envolve:

  • Registro com search.search_type e search.search_key no endpoint /tracking do host tracking.prod.judit.io
  • callback_url no payload para receber os eventos
  • Endpoint receptor que responde rápido e processa de forma assíncrona
  • Tratamento correto dos três tipos de response_type: lawsuit, application_info e application_error
  • Idempotência pelo response_id para evitar processamento duplicado
  • Gerenciamento ativo do ciclo de vida com pause, resume e delete

A documentação completa de monitoramento e a referência de webhooks têm todos os detalhes de schema e parâmetros.

Quer saber como a JUDIT pode ajudar seu negócio?