Importações

Endpoints da WebApiAlcance para o fluxo de importação de arquivos - envio de extratos e planilhas (ofx, pdf, csv, contas, regras_conversor), leitura e conferência do parse, geração dos lançamentos contábeis e gestão do ciclo de vida de cada importação (listagem, detalhe, download do original, substituição, duplicação e exclusão).

O parse e a geração de lançamentos são síncronos - não há task Celery neste domínio: preview, confirmar, analisar-regras e confirmar-regras rodam o parser na própria requisição e devolvem o resultado no envelope.

Todos os endpoints exigem autenticação. Veja Autenticação para o fluxo de API Key. O Swagger oficial está em api.contabilidadealcance.com.br/docs.

Base path

/api/v1/importacoes

Escopos necessários

  • importacoes:read - listagem, detalhe, download do arquivo e lançamentos gerados
  • importacoes:write - upload, preview, confirmar, análise/confirmação de regras, substituir, duplicar e excluir

O escopo é derivado da rota: o prefixo /importacoes vira o recurso importacoes, e o método HTTP define a ação (read para GET, write para POST/DELETE).

Endpoints

POST /importacoes/upload

Faz o upload do arquivo e cria o registro de importação com status pending. Requisição multipart/form-data (não JSON). Calcula o hash SHA-256 do arquivo e bloqueia reimport (409 Conflict) se já existir uma importação bem-sucedida com o mesmo arquivo + cliente.

Parâmetros

Este endpoint não recebe parâmetros de rota ou query - os campos vão no formulário multipart/form-data:

ParâmetroTipoLocalObrigatórioDescrição
id_clienteintformsimID do cliente (customer.id).
tipostr (enum)formsimUm de ofx | pdf | csv | contas | regras_conversor.
arquivofileformsimArquivo binário a importar.
id_estruturaintformnãoLayout usado (omitir para OFX; opcional p/ regras_conversor).
id_plano_contasintformnãoPlano alvo (contas/regras_conversor). NULL para OFX/PDF/CSV.
id_bancointformnãoBanco selecionado (feature Padrão de Regras por Banco). Para OFX, a resposta também traz codigo_ofx_detectado / id_banco_sugerido.

Request

Requisição multipart/form-data - os campos vão no formulário (ver tabela acima), não em JSON. Não envie um corpo JSON.

Response 201 Created

{
  "success": true,
  "message": "Upload registrado com sucesso",
  "data": {
    "id": 812,
    "id_usuario_created": 7,
    "id_cliente": 154,
    "id_estrutura": null,
    "id_plano_contas": null,
    "id_banco": null,
    "tipo": "ofx",
    "nome_arquivo_original": "extrato-junho.ofx",
    "tamanho_bytes": 48213,
    "hash_arquivo": "9f2c...",
    "status": "pending",
    "qtd_lancamentos_criados": 0,
    "qtd_linhas_erro": 0,
    "codigo_ofx_detectado": "341",
    "id_banco_sugerido": 12
  }
}

Arquivo acima de IMPORTACAO_MAX_UPLOAD_BYTES retorna 413 Request Entity Too Large; hash duplicado retorna 409 Conflict, cujo detail traz { message, importacao_existente }, onde importacao_existente segue o HashDuplicadoInfo. Escopo: importacoes:write

GET /importacoes/

Lista as importações do escritório, com filtros opcionais. Lista vazia é estado válido - retorna 200 OK com data: [].

Parâmetros

ParâmetroTipoLocalObrigatórioDescrição
id_clienteintquerynãoFiltra por cliente.
tipostr (enum)querynãoofx | pdf | csv | contas | regras_conversor.
statusstr (enum)querynãopending | processing | success | partial | error.
data_iniciodatequerynãoData inicial de data_hora_criacao (YYYY-MM-DD).
data_fimdatequerynãoData final de data_hora_criacao (YYYY-MM-DD).
limitintquerynãoPadrão 50, entre 1 e 500.
offsetintquerynãoPadrão 0, maior ou igual a 0.

Request

Sem corpo de requisição.

Response 200 OK

{
  "success": true,
  "message": "Importacoes recuperadas com sucesso",
  "data": [
    {
      "id": 812,
      "id_usuario_created": 7,
      "id_cliente": 154,
      "tipo": "ofx",
      "nome_arquivo_original": "extrato-junho.ofx",
      "tamanho_bytes": 48213,
      "status": "success",
      "qtd_lancamentos_criados": 128,
      "qtd_atualizados": 0,
      "qtd_ignorados": 3,
      "qtd_linhas_erro": 0,
      "data_hora_criacao": "2026-07-03T14:20:00",
      "data_hora_conclusao": "2026-07-03T14:22:10"
    }
  ]
}

O data é um array de ImportacaoListItem (ou []). Escopo: importacoes:read

GET /importacoes/{importacao_id}

Detalha uma importação pelo ID inteiro. 404 Not Found quando não existe ou não pertence ao usuário.

Parâmetros

ParâmetroTipoLocalObrigatórioDescrição
importacao_idintpathsimID interno da importação.

Request

Sem corpo de requisição.

Response 200 OK

{
  "success": true,
  "message": "Importacao encontrada",
  "data": {
    "id": 812,
    "id_usuario_created": 7,
    "id_cliente": 154,
    "id_estrutura": null,
    "id_plano_contas": null,
    "id_banco": 12,
    "tipo": "ofx",
    "nome_arquivo_original": "extrato-junho.ofx",
    "tamanho_bytes": 48213,
    "hash_arquivo": "9f2c...",
    "status": "success",
    "qtd_lancamentos_criados": 128,
    "qtd_linhas_erro": 0,
    "data_hora_criacao": "2026-07-03T14:20:00",
    "data_hora_conclusao": "2026-07-03T14:22:10"
  }
}

O data segue o schema ImportacaoRead. Escopo: importacoes:read

GET /importacoes/{importacao_id}/arquivo

Faz o download do arquivo original do upload. A resposta não é o envelope JSON - é um FileResponse binário (application/octet-stream) com o nome_arquivo_original como nome de download.

Parâmetros

ParâmetroTipoLocalObrigatórioDescrição
importacao_idintpathsimID da importação.

Request

Sem corpo de requisição.

Response 200 OK

Stream binário do arquivo (application/octet-stream), sem envelope JSON. Retorna 404 Not Found se a importação não existir/pertencer ao usuário ou se o arquivo não estiver mais no disco.

Escopo: importacoes:read

GET /importacoes/{importacao_id}/lancamentos

Lista os lançamentos contábeis gerados a partir desta importação (id_importacao == importacao_id), ordenados por data_registro e id. A lista fica populada após um POST /confirmar bem-sucedido. Visão compartilhada do escritório - lista todos os lançamentos da importação, sem filtro por dono.

Parâmetros

ParâmetroTipoLocalObrigatórioDescrição
importacao_idintpathsimID da importação.

Request

Sem corpo de requisição.

Response 200 OK

{
  "success": true,
  "message": "Lancamentos recuperados com sucesso",
  "data": [
    {
      "id": 90211,
      "id_importacao": 812,
      "data_registro": "2026-06-01",
      "descricao": "PAGAMENTO FORNECEDOR XYZ",
      "valor": 1520.5,
      "tipo": "D",
      "regras_aplicadas": []
    }
  ]
}

O data é um array de LancamentoContabilRead (com regras_aplicadas resolvidas) ou []. 404 Not Found quando a importação não existe/pertence ao usuário. Escopo: importacoes:read

POST /importacoes/{importacao_id}/preview

Roda o parser e devolve as transações detectadas + erros por linha sem persistir nada. Serve para o frontend mostrar "isto é o que vai ser criado" antes do POST /confirmar.

Parâmetros

ParâmetroTipoLocalObrigatórioDescrição
importacao_idintpathsimID da importação.

Request

Sem corpo de requisição.

Response 200 OK

{
  "success": true,
  "message": "128 lancamentos detectados",
  "data": {
    "importacao_id": 812,
    "tipo": "ofx",
    "total_linhas_lidas": 131,
    "qtd_lancamentos_detectados": 128,
    "qtd_erros": 0,
    "qtd_ignorados": 3,
    "ignorados": [],
    "lancamentos": [
      {
        "linha_arquivo": 1,
        "data": "2026-06-01",
        "descricao": "PAGAMENTO FORNECEDOR XYZ",
        "valor": 1520.5,
        "tipo": "D"
      }
    ],
    "erros": [],
    "id_banco": 12,
    "codigo_ofx_detectado": "341",
    "id_banco_sugerido": 12
  }
}

O data segue o schema ImportacaoPreviewResponse. Escopo: importacoes:write

POST /importacoes/{importacao_id}/confirmar

Roda o parser e persiste os lançamentos em transação atômica. Em sucesso parcial (algumas linhas falham), o status final é partial.

Parâmetros

ParâmetroTipoLocalObrigatórioDescrição
importacao_idintpathsimID da importação.
id_bancointquerynãoBanco a aplicar (feature Padrão de Regras por Banco). Quando informado, substitui/persiste o banco da importação e seus padrões ATIVOS têm precedência sobre as regras de cliente/estrutura. Omitir mantém o banco vinculado no upload.

Request

Sem corpo de requisição.

Response 200 OK

{
  "success": true,
  "message": "Importacao concluida: 128 lancamentos criados (status=success)",
  "data": {
    "importacao_id": 812,
    "qtd_criados": 128,
    "qtd_erros": 0,
    "qtd_ignorados": 3,
    "status_final": "success",
    "data_hora_conclusao": "2026-07-03T14:22:10"
  }
}

O data segue o schema ConfirmarResponse. Escopo: importacoes:write

POST /importacoes/{importacao_id}/analisar-regras

Para importações do tipo regras_conversor: lê a planilha e devolve colunas detectadas, amostra (até 5 linhas), total de linhas, duplicados, contas faltantes (código de exportação sem Conta no cliente) e os planos do cliente. Não persiste.

Parâmetros

ParâmetroTipoLocalObrigatórioDescrição
importacao_idintpathsimID da importação.

O corpo segue o schema AnalisarRegrasRequest: mapeamento (obrigatório) e campo_destino (opcional).

Request

{
  "mapeamento": { "comparacao": 0, "exportacao": 1 },
  "campo_destino": "conta_debito"
}

Response 200 OK

{
  "success": true,
  "message": "240 linhas analisadas",
  "data": {
    "colunas": [
      { "indice": 0, "header": "Historico" },
      { "indice": 1, "header": "Codigo" }
    ],
    "amostra": [{ "comparacao": "TARIFA", "exportacao": "3010" }],
    "total_linhas": 240,
    "mapeamento_sugerido": { "comparacao": 0, "exportacao": 1 },
    "duplicados": [],
    "contas_faltantes": [],
    "planos_cliente": [{ "id": 5, "codigo_dominio": "01", "nome": "Plano Padrao" }]
  }
}

O data segue o schema AnalisarRegrasResponse. Escopo: importacoes:write

POST /importacoes/{importacao_id}/confirmar-regras

Processa todas as linhas da planilha, criando/atualizando RegraLancamento. O plano de contas de cada regra é derivado da conta resolvida pelo codigo_dominio (coluna de exportação). Resoluções de duplicados e de contas faltantes vêm no corpo.

Parâmetros

ParâmetroTipoLocalObrigatórioDescrição
importacao_idintpathsimID da importação.

O corpo segue o schema ConfirmarRegrasRequest: mapeamento e campo_destino obrigatórios; demais campos com defaults.

Request

{
  "mapeamento": { "comparacao": 0, "exportacao": 1 },
  "campo_comparacao": "historico",
  "modo_comparacao": "contem",
  "campo_destino": "conta_debito",
  "resolucao_duplicados": "ignorar",
  "resolucao_contas_faltantes": "ignorar"
}

Response 200 OK

{
  "success": true,
  "message": "230 criadas, 8 atualizadas, 2 ignoradas (status=success)",
  "data": {
    "importacao_id": 815,
    "qtd_criadas": 230,
    "qtd_atualizadas": 8,
    "qtd_ignoradas": 2,
    "qtd_erros": 0,
    "status_final": "success",
    "erros": [],
    "data_hora_conclusao": "2026-07-03T15:05:40"
  }
}

O data segue o schema ConfirmarRegrasResponse. Escopo: importacoes:write

POST /importacoes/{importacao_id}/substituir

Substitui uma importação em status terminal: apaga os lançamentos antigos e roda o parser de novo no mesmo arquivo. Aceita success, partial e error. Recusa pending e processing (409 Conflict). Útil para reaplicar uma estrutura corrigida ou reavaliar após nova regra.

Parâmetros

ParâmetroTipoLocalObrigatórioDescrição
importacao_idintpathsimID da importação.

Request

Sem corpo de requisição.

Response 200 OK

{
  "success": true,
  "message": "Importacao substituida: 128 lancamentos criados (status=success)",
  "data": {
    "importacao_id": 812,
    "qtd_criados": 128,
    "qtd_erros": 0,
    "qtd_ignorados": 3,
    "status_final": "success",
    "data_hora_conclusao": "2026-07-03T16:10:00"
  }
}

O data segue o schema ConfirmarResponse. Escopo: importacoes:write

POST /importacoes/{importacao_id}/duplicar

Duplica uma importação: copia o arquivo no disco com novo UUID e cria um novo registro pending apontando para a original via id_importacao_original. Recusa processing (409 Conflict). Bypassa o dedup por hash internamente - duplicar é justamente reusar o mesmo arquivo. O fluxo segue com /preview e /confirmar no novo id retornado.

Parâmetros

ParâmetroTipoLocalObrigatórioDescrição
importacao_idintpathsimID da importação original.

Request

Sem corpo de requisição.

Response 201 Created

{
  "success": true,
  "message": "Importacao duplicada com sucesso (nova id=813)",
  "data": {
    "id": 813,
    "id_usuario_created": 7,
    "id_cliente": 154,
    "id_importacao_original": 812,
    "tipo": "ofx",
    "nome_arquivo_original": "extrato-junho.ofx",
    "tamanho_bytes": 48213,
    "status": "pending",
    "qtd_lancamentos_criados": 0,
    "qtd_linhas_erro": 0,
    "data_hora_criacao": "2026-07-03T17:00:00"
  }
}

O data segue o schema ImportacaoRead da nova importação. Escopo: importacoes:write

DELETE /importacoes/{importacao_id}

Hard delete cascade: apaga o registro de importação, todos os lançamentos vinculados e o arquivo do disco. Importações filhas (criadas via /duplicar desta) ficam órfãs (id_importacao_original = NULL via ON DELETE SET NULL) - não são deletadas em cascade.

Parâmetros

ParâmetroTipoLocalObrigatórioDescrição
importacao_idintpathsimID da importação.
excluir_regrasboolquerynãoApenas para regras_conversor. true: apaga em cascade as RegraLancamento geradas por este import. false (default): as regras são desvinculadas (id_importacao → NULL) e permanecem.

Request

Sem corpo de requisição.

Response 204 No Content

Sem body. Retorna 404 Not Found se a importação não existir ou não pertencer ao usuário. Imports contas apagam apenas registro + arquivo (não apagam contas).

Escopo: importacoes:write

Schemas

ImportacaoRead

Registro completo de uma importação (retorno de upload, detalhe e duplicar).

CampoTipoNotas
idintIdentificador da importação.
id_usuario_createdintUsuário que criou o upload.
usuario_nomestr?Nome do usuário criador.
id_clienteintCliente-alvo.
id_estruturaint?Layout usado (NULL para OFX).
id_plano_contasint?Plano alvo (contas/regras_conversor).
id_importacao_originalint?Import de origem quando esta foi duplicada.
id_bancoint?Banco selecionado/sugerido.
tipostr (enum)ofx | pdf | csv | contas | regras_conversor.
nome_arquivo_originalstrNome original do arquivo enviado.
path_arquivostrCaminho interno no disco.
tamanho_bytesintTamanho do arquivo.
hash_arquivostr?SHA-256 usado no dedup.
statusstr (enum)pending | processing | success | partial | error.
qtd_lancamentos_criadosintLançamentos gerados.
qtd_atualizadosintDefault 0.
qtd_ignoradosintDefault 0.
qtd_linhas_errointLinhas que falharam no parse.
erroslist?Detalhes dos erros por linha.
data_hora_criacaodatetimeCriação do registro.
data_hora_conclusaodatetime?Preenchida ao concluir o parse.
codigo_ofx_detectadostr?BANKID lido do OFX (não persistido).
id_banco_sugeridoint?Banco do catálogo cujo codigo_ofx casa (não persistido).

ImportacaoListItem

Versão enxuta para listagens - omite path_arquivo (segurança) e erros. Traz os mesmos campos de identificação, tipo, status, contadores (qtd_lancamentos_criados, qtd_atualizados, qtd_ignorados, qtd_linhas_erro) e datas (data_hora_criacao, data_hora_conclusao).

ImportacaoPreviewResponse

Resultado do POST /preview - o que seria criado, sem persistir.

CampoTipoNotas
importacao_idintImportação analisada.
tipostr (enum)Tipo do arquivo.
total_linhas_lidasintLinhas lidas do arquivo.
qtd_lancamentos_detectadosintTransações válidas detectadas.
qtd_errosintLinhas com erro.
qtd_ignoradosintLinhas descartadas por regra de ignorar. Default 0.
ignoradosLancamentoIgnorado[]Linhas que serão descartadas (com regra_id/regra_nome).
lancamentosLancamentoDetectado[]Transações detectadas.
errosErroParse[]{ linha_arquivo, mensagem }.
id_bancoint?Banco já vinculado à importação.
codigo_ofx_detectadostr?BANKID lido agora (OFX).
id_banco_sugeridoint?Banco do catálogo que casa.

Cada LancamentoDetectado traz linha_arquivo, data, descricao, valor (sempre positivo), tipo (D=débito/saída, C=crédito/entrada), documento? e historico_complementar?.

ConfirmarResponse

Resultado do POST /confirmar (e de /substituir).

CampoTipoNotas
importacao_idintImportação processada.
qtd_criadosintLançamentos persistidos.
qtd_errosintLinhas que falharam.
qtd_ignoradosintLinhas ignoradas. Default 0.
status_finalstr (enum)success | partial | error (entre outros).
data_hora_conclusaodatetime?Momento da conclusão.

HashDuplicadoInfo

Corpo do detail no 409 Conflict do upload quando o hash já existe.

CampoTipoNotas
importacao_id_existenteintImportação original com o mesmo arquivo.
status_existentestr (enum)Status da importação original.
data_hora_criacaodatetimeQuando a original foi criada.

AnalisarRegrasRequest

Body do POST /analisar-regras.

CampoTipoObrigatórioNotas
mapeamentoMapeamentoColunassim{ comparacao: int, exportacao: int } (índices 0-based).
campo_destinostr (enum)nãoconta_debito | conta_credito | historico. Quando informado, os duplicados consideram conteúdo e lado da conta; quando null (1ª análise), nenhum duplicado é reportado.

AnalisarRegrasResponse

CampoTipoNotas
colunasColunaDetectada[]{ indice, header } das colunas da planilha.
amostraAmostraLinha[]Até 5 linhas { comparacao, exportacao }.
total_linhasintTotal de linhas na planilha.
mapeamento_sugeridoMapeamentoColunasMapeamento inferido.
duplicadosDuplicadoInfo[]{ comparacao, id_regra_existente }.
contas_faltantesstr[]Códigos de exportação sem Conta no cliente.
planos_clientePlanoClienteInfo[]{ id, codigo_dominio, nome }.

ConfirmarRegrasRequest

Body do POST /confirmar-regras.

CampoTipoObrigatórioNotas
mapeamentoMapeamentoColunassimÍndices das colunas comparação/exportação.
campo_destinostr (enum)simconta_debito | conta_credito | historico.
campo_comparacaostr (enum)nãoCampo comparado pela condição. Default historico.
modo_comparacaostr (enum)nãoOperador da condição. Default contem.
id_estruturaint?nãoEstrutura opcional para vincular as regras geradas.
resolucao_duplicadosstr (enum)nãosubstituir | criar | ignorar. Default ignorar.
resolucao_contas_faltantesstr (enum)nãocriar | ignorar. Default ignorar.
id_plano_contas_novasint?nãoPlano onde criar contas novas quando resolucao_contas_faltantes=criar e o cliente tem mais de um plano.

ConfirmarRegrasResponse

CampoTipoNotas
importacao_idintImportação processada.
qtd_criadasintRegras criadas.
qtd_atualizadasintRegras atualizadas.
qtd_ignoradasintRegras ignoradas.
qtd_errosintLinhas com erro.
status_finalstr (enum)Status final da importação.
errosErroLinhaRegra[]{ linha, mensagem }.
data_hora_conclusaodatetime?Momento da conclusão.

Notas

  • Toda resposta segue o envelope { success, message, data } (ou { success: false, message, details } em erro). A exceção é GET /importacoes/{importacao_id}/arquivo, que devolve o binário do arquivo (FileResponse), e DELETE /importacoes/{importacao_id}, que retorna 204 No Content sem body.
  • O POST /importacoes/upload é multipart/form-data - não envie JSON. O único fluxo de criação de importação é este upload.
  • Não há task Celery neste domínio: preview, confirmar, analisar-regras, confirmar-regras e substituir rodam o parser de forma síncrona na própria requisição.
  • Mapeamento de erros de negócio para HTTP: "não encontrado" → 404, "acesso negado" → 403, conflitos de duplicidade/estado (duplicad, ja existe, ja foi processada, apenas importacoes) → 409, demais ValueError400.
  • Os tipos contas e regras_conversor alimentam fluxos específicos: contas importa plano/contas e regras_conversor alimenta analisar-regras/confirmar-regras, que geram Regras de Lançamento.