CTN Extrator

API de extração de dados financeiros do sistema CTN · porta 2007

Visão Geral

O CTN Extrator é uma API Flask que faz scraping autenticado no sistema CTN para extrair dados financeiros por unidade (franquia):

Movimentações Diárias

Receitas e despesas por conta e subconta num intervalo de datas. Equivale à tela ConsultaReceitaDespesa do CTN.

Saldos Diários

Fechamento de caixa do dia + saldo atual por conta bancária. Equivale às telas ConsultaSaldoDiario e ContainerRelatorio.

Refresh Automático

Rota protegida que renova os cookies do CTN automaticamente via login + 2captcha. Ideal para acionar via n8n no cron diário.

Como funciona

A autenticação usa cookies de sessão (CTN.Auth, id_menu_clicado, TiPMix) salvos no .env. A cada chamada, uma sessão HTTP é criada com esses cookies e o CTN é consultado diretamente. Os cookies são renovados automaticamente toda manhã via POST /refresh.

Estrutura do Projeto

CTN Extrator/
  ├── app.py                   # API Flask (porta 2007)
  ├── refresh_auth.py         # Renovação automática de cookies via 2captcha
  ├── session_ctn.py          # Utilitários: cookies, sessão, formulário, xlsx
  ├── .env                     # Credenciais e cookies de autenticação
  ├── Dockerfile               # Imagem Docker (python:3.12-slim)
  ├── docker-compose.yml      # Sobe a API em container
  └── service/
      ├── movimentacoes_diarias.py  # Extração de movimentações
      └── saldos_diarios.py        # Extração de saldos

Configuração — arquivo .env

VariávelDescriçãoAtualização
CTN_LOGINE-mail de acesso ao CTNManual (uma vez)
CTN_SENHASenha de acesso ao CTNManual (uma vez)
TWOCAPTCHA_API_KEYChave da API do 2captcha (resolve reCAPTCHA do login)Manual (uma vez)
API_SECRETSenha que protege a rota POST /refreshManual (uma vez)
CTN_AUTHCookie de autenticação CTN — token longoAuto — via /refresh
ID_MENU_CLICADOCookie de estado de menu do CTNAuto — via /refresh
TIPMIXCookie interno do CTNAuto — via /refresh
ASPNET_SESSION_IDCookie de sessão ASP.NETManual se necessário
FRANQUIA_IDSMapeamento NOME:ID das unidades, separado por vírgulaManual (uma vez)

Subindo com Docker

git pull
docker-compose up -d --build

# Forçar refresh manual logo após subir (garante cookies frescos)
curl -X POST http://localhost:2007/refresh \
  -H "X-API-Secret: <API_SECRET>"

Rotas da API

GET /health

Verifica se a API está no ar.

{ "status": "ok" }
POST /movimentacoes

Retorna resumo por conta e detalhes de lançamentos de receitas e despesas.

Body (JSON)

CampoTipoObrigatórioDescrição
franquia_idstringSimID numérico da franquia
data_iniciostringSimYYYY-MM-DD ou DD/MM/YYYY
data_fimstringSimYYYY-MM-DD ou DD/MM/YYYY
tipo_movimentacaostringNão"" todos · "1" receita · "2" despesa
historicostringNãoFiltro de histórico (texto livre)
valorstringNãoFiltro por valor

Resposta

{
  "franquia_id": "535",
  "data_inicio": "2026-04-01",
  "data_fim":    "2026-04-06",
  "resumo": [
    { "Conta": "CAIXA DINHEIRO", "Entrada": "R$ 1.200,00", "Saida": "R$ 300,00", "Total": "R$ 900,00" }
  ],
  "detalhes": [
    { "Conta": "CAIXA DINHEIRO", "SubConta": "VENDAS", "Tipo Mov.": "Receita",
      "Funcionário/Sócio": "JOÃO SILVA", "Data Lan.": "01/04/2026", "Valor": "R$ 1.200,00" }
  ]
}
POST /saldos

Retorna fechamento de caixa e saldo por conta para uma data específica.

Observação Retorna dados apenas para datas já encerradas (dias anteriores ao atual).

Body (JSON)

CampoTipoObrigatórioDescrição
franquia_idstringSimID numérico da franquia
datastringSimYYYY-MM-DD ou DD/MM/YYYY

Resposta

{
  "franquia_id": "535",
  "data": "2026-04-01",
  "fechamento": [
    { "Data": "01/04/2026", "Saldo Anterior": "R$ 5.000,00",
      "Entrada": "R$ 1.200,00", "Saída": "R$ 300,00", "Saldo Atual": "R$ 5.900,00" }
  ],
  "saldo_contas": [
    { "Data": "2026-04-01", "Contas": "CAIXA DINHEIRO",
      "Saldo Anterior": "R$ 5.000,00", "Movimentação Dia": "R$ 900,00", "Saldo Atual": "R$ 5.900,00" }
  ]
}
POST /refresh 🔒 protegido

Renova os cookies do CTN (CTN.Auth, ID_MENU_CLICADO, TIPMIX) via login automático + 2captcha. Atualiza o .env em disco — sem necessidade de reiniciar a API.

Header obrigatório

HeaderValor
X-API-SecretValor de API_SECRET no .env

Respostas

// Sucesso
{ "status": "ok", "mensagem": "Cookies renovados com sucesso." }

// Não autorizado (secret errado)
HTTP 401 — { "status": "erro", "mensagem": "Não autorizado" }

// Falha no login / 2captcha
HTTP 500 — { "status": "erro", "mensagem": "..." }
Integração com n8n Configure um nó HTTP Request acionado por cron 0 7 * * 1-5 (seg–sex às 07h): método POST, URL http://sua-vps:2007/refresh, header X-API-Secret: <API_SECRET>. O refresh demora ~2 minutos (tempo de resolução do reCAPTCHA pelo 2captcha).

Exemplos de Uso

cURL — Movimentações

curl -X POST http://localhost:2007/movimentacoes \
  -H "Content-Type: application/json" \
  -d '{ "franquia_id": "535", "data_inicio": "2026-04-01", "data_fim": "2026-04-06" }'

cURL — Saldos

curl -X POST http://localhost:2007/saldos \
  -H "Content-Type: application/json" \
  -d '{ "franquia_id": "535", "data": "2026-04-01" }'

cURL — Refresh

curl -X POST http://localhost:2007/refresh \
  -H "X-API-Secret: sua_senha_forte"

IDs de franquia disponíveis

Unidadefranquia_id
CARTAO DE ARAUCARIA440
CARTAO DE FRANCISCO BELTRAO569
CARTAO DE SAO JOAO DEL REI535

Refresh Automático — Como Funciona

Os cookies do CTN expiram diariamente. O fluxo de renovação é totalmente automático:

  1. n8n aciona POST /refresh com o X-API-Secret todo dia útil às 07h.
  2. A API acessa ctn.sistematodos.com.br → é redirecionada para a página de login OAuth.
  3. Credenciais são preenchidas e o reCAPTCHA é enviado ao 2captcha (~100s para resolver).
  4. Após login, os cookies novos são capturados e salvos no .env.
  5. A partir da próxima requisição, a API já usa os cookies atualizados — sem reiniciar.
Após git pull + docker-compose up --build O .env puxado do repositório pode ter cookies desatualizados. Execute um refresh manual imediatamente após subir o container.

Custo do 2captcha

Cada resolução de reCAPTCHA custa aproximadamente $0.0017. Com 20 renovações mensais (seg–sex):

20 × $0.0017 = $0.034 / mês   →   $3 de crédito ≈ 7 anos de uso

Erros Comuns

SituaçãoCausa provávelSolução
Listas vazias (resumo, fechamento) Cookies expirados ou data sem dados Chame POST /refresh e tente novamente.
HTTP 500 na extração Cookies inválidos ou CTN fora do ar Verifique com POST /refresh. Se persistir, verifique o CTN manualmente.
HTTP 400 — campos obrigatórios Body JSON incompleto Confirme que todos os campos obrigatórios estão presentes.
HTTP 401 no /refresh Header X-API-Secret ausente ou incorreto Confira o valor de API_SECRET no .env.
Saldos vazios para hoje Fechamento ainda não realizado Normal — consulte apenas datas anteriores ao dia atual.
Timeout de conexão CTN indisponível ou rede instável Aguarde e tente novamente. Timeout configurado em 60s.