DCTFWeb: Emissão

Endpoints da WebApiAlcance que emitem e coletam guias e recibos junto ao Integra Contador (Serpro). Cobrem a emissão de DCTFWeb (DARF) e PGDAS-D (DAS do Simples Nacional) e o download dos recibos de transmissão, para um único CNPJ ou para toda a carteira interna de clientes - em janela anual (últimos N anos, máx. 3) ou em uma competência mensal específica.

São duas famílias de rota sob o mesmo prefixo, com propósitos diferentes:

  • Emissão sob demanda - POST /dctfweb/emissao/guias/emitir emite uma guia, para um contribuinte, com os sistemas de origem escolhidos por quem chama. É a única rota de emissão em que idsSistemaOrigem e categoria são parâmetros do corpo.
  • Coleta em lote - as cinco rotas baixar-* percorrem CNPJ × competência com idsSistemaOrigem literal no código ([1, 6, 7] ou [8]) e categoria fixa em GERAL_MENSAL. Servem à automação agendada.

O que é emitido ou coletado aqui é gravado nos registros internos de Guias e Recibos, de onde a interface lê depois.

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 (tags DCTFWeb: Emissão de Guias e DCTFWeb: Emissão de Recibos).

Caminhos antigos `/integra-contador/radar/*` continuam vivos, porém deprecados

Cada rota de coleta em lote tem um alias sob /api/v1/integra-contador/radar/... que serve o mesmo handler - migrar não muda requisição nem resposta:

Caminho legado (deprecado)Caminho novo
POST /integra-contador/radar/guias/baixar-todasPOST /dctfweb/emissao/guias/baixar-todas
POST /integra-contador/radar/guias/baixar-mensal/esocialPOST /dctfweb/emissao/guias/baixar-mensal/esocial
POST /integra-contador/radar/guias/baixar-mensal/mitPOST /dctfweb/emissao/guias/baixar-mensal/mit
POST /integra-contador/radar/recibos/baixar-todasPOST /dctfweb/emissao/recibos/baixar-todas
POST /integra-contador/radar/recibos/baixar-mensalPOST /dctfweb/emissao/recibos/baixar-mensal

Os alias exigem o escopo antigo integra_contador:write e serão removidos numa versão futura. /integra-contador/radar/pagamentos/* não foi movido - continua onde estava.

POST /dctfweb/emissao/guias/emitir não entra nessa tabela: ela nasceu sob o prefixo consolidado e nunca existiu em outro caminho - não há /integra-contador/radar/guias/emitir.

Base path

/api/v1/dctfweb/emissao

Escopos necessários

  • dctfweb:write - todas as rotas desta página são POST.

O recurso vem do primeiro segmento do path (dctfweb) e a ação, do método HTTP. Tokens emitidos antes da consolidação não carregam dctfweb:write - relogue ou atualize a API Key antes de migrar.

Emitir NÃO exige perfil de gestão nem sessão de usuário

As seis rotas desta página pedem apenas token válido + dctfweb:write. Qualquer perfil (funcionario, gestor, diretoria, administrador) emite, e API Key é aceita.

É deliberadamente diferente da Transmissão, que acumula perfil administrador/diretoria e recusa API Key: emitir guia não declara nada ao fisco - gera um documento de arrecadação a partir do que já foi declarado, e repetir a operação não tem efeito fiscal. Aplicar aqui o guard da transmissão bloquearia a automação e o trabalho diário do operacional.

O que não cai é a autorização de dado: o CNPJ precisa pertencer a um cliente do escritório (403 caso contrário). Escopo e perfil dizem o que o chamador pode fazer; essa checagem diz sobre quem.

Execução síncrona, não Celery

A emissão e a coleta não enfileiram tasks Celery. Cada requisição executa a orquestração das chamadas ao Serpro de forma síncrona, porém fora do event loop (anyio.to_thread.run_sync), e só responde quando tudo termina. Para carteiras grandes (usar_lista_interna=true), a chamada pode ser demorada: percorre CNPJ × competência sequencialmente.

As rotas `baixar-*` NÃO usam o envelope padrão - `emitir` usa

Diferente do resto da WebApi, as cinco rotas de coleta em lote declaram response_model próprio e devolvem o objeto direto, sem { status, message, data }. O corpo de sucesso é { summary, guias, erros } (guias) ou { summary, recibos } (recibos).

POST /dctfweb/emissao/guias/emitir é a exceção: responde com o envelope padrão { status, message, data }, como a transmissão e o resto da API.

Já os erros HTTP passam pelo handler global da WebApi e saem como { "message": ... } — nunca { "detail": ... }, com uma exceção: a validação do corpo pelo FastAPI/Pydantic (422) sai no formato nativo { "detail": [ { "loc", "msg", "type" } ] }. Nas descrições de erro abaixo, o texto citado é o conteúdo do message.

Não confunda com o campo detail de cada item de erros[] nas rotas de lote: aquele é outra coisa — a falha de um CNPJ específico dentro de uma resposta 200 OK.

Qual rota de guia usar

As três rotas de guia coexistem e não se substituem:

RotaidsSistemaOrigemcategoriaAlvoPara que serve
POST /emissao/guias/emitirparâmetro (ou omitido)parâmetro1 CNPJ, 1 competênciaEmissão sob demanda, quando quem emite escolhe as origens.
POST /emissao/guias/baixar-mensal/esocialfixo [1, 6, 7]fixa GERAL_MENSAL1 CNPJ ou a carteiraFechamento mensal da folha, em lote (automação agendada).
POST /emissao/guias/baixar-mensal/mitfixo [8]fixa GERAL_MENSAL1 CNPJ ou a carteiraFechamento mensal fiscal, em lote (automação agendada).

baixar-todas é a variante de janela anual da coleta em lote (até 3 anos), também com origens fixas.

Na prática: lote e rotinabaixar-*; uma guia específica, com as origens que o caso pedeemitir.

Endpoints

POST /dctfweb/emissao/guias/emitir

Emite a guia (DARF) da DCTFWeb de um contribuinte, em uma competência, com os sistemas de origem configuráveis. É a versão parametrizável da emissão: idsSistemaOrigem e categoria vêm do corpo, e não do código.

Do lado do servidor a rota executa, nesta ordem:

#EtapaO que acontece
1Autorização de dadoO cnpj é resolvido contra a carteira interna (busca por dígitos). Não sendo cliente, 403.
2CONSRECIBO32 (acionamento /Consultar)Best-effort: busca o numeroReciboEntrega do período. Pulada quando o recibo vem explícito no corpo.
3GERARGUIA31 (acionamento /Emitir)Emite a guia. É aqui que idsSistemaOrigem entra - ou não entra, quando omitido.
4PersistênciaBest-effort: grava a guia em Guias e registra a atividade do cliente.

Parâmetros

Sem parâmetros de rota ou query - os dados vão no corpo (DctfwebEmitirGuiaRequest, ver DctfwebEmitirGuiaRequest). Obrigatórios: cnpj e anoPA; mesPA é obrigatório em todas as categorias exceto as de 13º salário.

Request - corpo mínimo (guia com todas as receitas do período):

{
  "cnpj": "27898481000150",
  "anoPA": "2026",
  "mesPA": "04"
}

Com origens escolhidas:

{
  "cnpj": "27.898.481/0001-50",
  "categoria": "GERAL_MENSAL",
  "anoPA": "2026",
  "mesPA": "04",
  "idsSistemaOrigem": [1, 6, 7]
}

Response 200 OK

{
  "status": "success",
  "message": "Guia emitida com sucesso!",
  "data": {
    "id_guia": 8830,
    "id_cliente": 123,
    "cnpj": "27898481000150",
    "categoria": "GERAL_MENSAL",
    "competencia": "2026-04",
    "idsSistemaOrigem": [1, 6, 7],
    "setor": "pessoal",
    "numero_recibo": "12.34.56.78-90",
    "arquivo_nome": "dctfweb_guia_27898481000150_2026-04.pdf",
    "tem_pdf": true,
    "mensagem": "Guia emitida com sucesso."
  }
}

Omitir `idsSistemaOrigem` NÃO é o mesmo que enviar lista vazia

É a armadilha nº 1 desta rota, e vem da semântica do próprio Integra Contador ("quando informado, a guia será gerada contendo apenas as receitas oriundas do(s) sistema(s) de origem especificado(s)"):

  • Campo omitido (ausente do corpo, ou explicitamente null) → a chave não entra no payload enviado à Receita, e a guia sai com TODAS as receitas do período. É o default e é um estado legítimo. Na resposta, idsSistemaOrigem volta null.
  • Lista com códigos → a guia contém apenas as receitas daqueles sistemas.
  • Lista vazia ([]) → 422. Uma guia de nenhuma origem não existe, e a API recusa antes de chamar o Serpro: "'idsSistemaOrigem' não pode ser uma lista vazia — informe ao menos um sistema de origem, ou omita o campo para gerar a guia com todas as receitas. Códigos aceitos: 1, 5, 6, 7, 8."

Na interface: um seletor "todas as origens" precisa não enviar o campo. Desmarcar tudo não pode virar [] no corpo.

Tipagem estrita: `"1"` e `true` tomam 422, não são coeridos

O campo é declarado como lista de StrictInt, e não de int. Isso desliga a coerção que o Pydantic aplicaria por padrão - o comportamento que a maioria dos integradores espera:

EnviadoResultado
[1, 6, 7]200 - aceito.
["1", "6", "7"]422 - string não é inteiro; não vira [1, 6, 7].
[true]422 - em Python True é int; sem o modo estrito viraria silenciosamente o código 1 (eSocial) e a Receita emitiria uma guia de folha sem ninguém ter pedido.
[1.0]422 - float não é inteiro estrito.
"167"422 - string iteraria como ["1", "6", "7"] e passaria por acidente.
[99]422 - fora do domínio oficial.
[1, 1]422 - código repetido.

A mensagem do 422 sempre lista os códigos aceitos (1, 5, 6, 7, 8). Envie inteiros JSON, sem aspas.

`setor` é DERIVADO, não informado

Não existe campo setor na requisição. Ele é calculado a partir das origens e gravado no registro da guia:

  • fiscal - somente quando a guia é exclusivamente MIT, isto é, idsSistemaOrigem == [8].
  • pessoal - todo o resto, inclusive o campo omitido (guia com todas as receitas), porque nesses casos a parte previdenciária está sempre presente e é o setor que trata a guia.

É um rótulo organizacional (qual setor do escritório cuida da guia), herdado do registro de guias, que só admite esses dois valores - não há "misto". Uma guia com todas as receitas é literalmente as duas coisas, e aparece como pessoal.

A resposta NÃO traz o PDF - traz o `id_guia`

O base64 do DARF não é devolvido aqui. O PDF é persistido no registro de guias e sai por GET /dctfweb/guias/{guia_id}/pdf (binário). O elo entre as duas chamadas é o id_guia.

id_guia vem null apenas quando a persistência falha - a emissão na Receita já terá ocorrido de qualquer forma (a gravação é best-effort, de propósito: uma falha de banco não pode transformar um 200 num 500 e fazer o operador emitir tudo de novo). Nesse caso o PDF não fica recuperável por id; reemita.

`200` com `tem_pdf: false` é possível

Quando a Receita aceita a emissão mas não devolve o PDF (e não é o caso de "sem débitos", que vira 422), a resposta é 200 com tem_pdf: false, arquivo_nome: null e mensagem: "A Receita aceitou a emissão, mas não devolveu o PDF da guia.". O registro correspondente é gravado com status Falha, para não parecer baixável na listagem. Sempre leia tem_pdf antes de oferecer o download.

Erros

HTTPQuandoCorpo
422Validação do corpo (campo desconhecido, idsSistemaOrigem inválido, regra condicional da categoria)Formato nativo do FastAPI: { "detail": [ { "loc", "msg", "type" } ] }.
422Documento sem dígitos{ "message": "Informe um CNPJ/CPF válido." }
403CNPJ não é cliente do escritório{ "message": "O documento informado não pertence a nenhum cliente do escritório. A emissão de guia da DCTFWeb só é permitida para clientes cadastrados." }
422Sem débitos a pagar (GUIA03)Ver o aviso abaixo - o corpo tem duas formas.
422, 502, ...Recusa do Serpro classificada{ "message": { "classe", "codigo", "mensagem", "acionamento", "codigos" } }

O status de uma recusa do Serpro não é o status do gateway: ele é derivado da classe do erro (negocio422, transitorio502, desconhecido502, ...). A tabela completa de classes, o catálogo de códigos (GUIA03, MG10, MG12/MG19/MG21, ...) e o formato do objeto de erro estão em DCTFWeb: Transmissão - Erros do Serpro; o mecanismo é o mesmo nas duas superfícies. O corpo cru do gateway nunca é repassado.

"Não há débitos com saldo a pagar" chega por dois caminhos

O mesmo fato - o período não tem o que pagar - pode voltar do Serpro de duas maneiras, e as duas terminam em 422, com corpos diferentes:

  • Quando vem como erro codificado (GUIA03), o corpo é o objeto de erro tipado: { "message": { "classe": "negocio", "codigo": "GUIA03", "mensagem": "Não há débitos com saldo a pagar para emissão da guia de pagamento.", ... } }.
  • Quando o Serpro manda a mesma informação como Aviso/Sucesso (aí não há erro a classificar), a detecção é pelo texto e o corpo é a string: { "message": "Não há débitos com saldo a pagar para emissão da guia de pagamento." }.

Trate 422 + esse texto como desfecho normal de quem não tem débito no período, não como falha da integração. Ao ler o corpo, aceite message como string ou objeto.

`numeroReciboEntrega` normalmente é dispensável

A rota consulta o recibo do período sozinha (CONSRECIBO32) e o injeta no payload da guia. Informe o campo explicitamente só quando houver mais de uma declaração no período e a Receita exigir a escolha (código MG10) - o valor informado vence o consultado, e evita a chamada extra.

A consulta é best-effort: se ela falhar, a emissão segue sem recibo (a Receita usa a declaração ativa do período, que é o caso comum). Uma instabilidade num acionamento auxiliar não derruba a emissão pedida. O que foi efetivamente usado volta em numero_recibo - null quando não se obteve nenhum.

Emitir é repetível - e o servidor já repete sozinho

O acionamento /Emitir é tratado como idempotente: timeout ou falha de rede fazem a WebApi repetir a chamada com backoff (até 3 tentativas por padrão) antes de desistir. Esgotadas as tentativas, o desfecho é 502 (classe transitorio), não 504.

Por isso não existe estado indeterminado nesta rota - a dúvida "entrou ou não entrou?" que domina a Transmissão não se aplica aqui: emitir guia não registra nada no fisco, e repetir a operação é seguro. Reemitir depois de um erro é uma resposta válida.

Cada chamada ao Serpro tem timeout próprio (60s por padrão) e roda fora do event loop; com as retentativas, uma emissão problemática pode levar alguns minutos - dimensione o timeout do seu cliente HTTP.

Escopo: dctfweb:write (sem exigência de perfil; API Key aceita)

POST /dctfweb/emissao/guias/baixar-todas

Emite/lista todas as guias (DCTFWeb e PGDAS-D) dos últimos N anos (máx. 3, equivalente a até 36 competências retroativas a partir do mês atual). Aceita um único CNPJ (contribuinte) ou toda a carteira interna (usar_lista_interna=true).

Parâmetros

Sem parâmetros de rota ou query - os dados vão no corpo (GuiasDownloadRequest). Para esta rota, os campos relevantes são contribuinte ou usar_lista_interna, e anos (1-3, default 1).

Request

{
  "contribuinte": { "tipo": 2, "numero": "27898481000150" },
  "anos": 1
}

Alternativa - toda a carteira:

{
  "usar_lista_interna": true,
  "anos": 1
}

Response 200 OK

{
  "summary": {
    "total": 24,
    "abertas": 0,
    "pagas": 0,
    "vencidas": 0,
    "porTipo": { "DCTF": 12, "PGDAS": 12 }
  },
  "guias": [
    {
      "id": "DCTFWeb:27898481000150:2025-06",
      "tipo": "DCTF",
      "competencia": "2025-06",
      "valor": 0.0,
      "dataVencimento": null,
      "status": "desconhecida",
      "clienteNumero": "27898481000150",
      "clienteNome": null,
      "descricao": "DCTFWeb - 2025-06",
      "codigoBarras": null,
      "dataGeracao": "2026-07-03",
      "observacoes": null,
      "origem": "DCTFWeb",
      "extras": { "emitir": {}, "pdfGuiaPath": "..." }
    }
  ],
  "erros": []
}

Erros por CNPJ/competência não interrompem a coleta: são acumulados em erros[] e a resposta ainda é 200 OK. Se nenhum CNPJ for resolvido, retorna 422 com "Informe 'contribuinte.numero' (CNPJ), ou 'cnpjs', ou 'usar_lista_interna=true'.". Falha global na orquestração retorna 500 com message: "Erro ao coletar guias".

Escopo: dctfweb:write

POST /dctfweb/emissao/guias/baixar-mensal/esocial

Emite/lista guias (DCTFWeb e PGDAS-D) de uma única competência, para 1 CNPJ ou toda a carteira. É a variante eSocial: a geração do DARF usa idsSistemaOrigem = [1, 6, 7] (eSocial + Reinf CP + Reinf RET).

Parâmetros

Sem parâmetros de rota ou query - corpo em GuiasDownloadRequest. Exige a competência via competencia ("AAAA-MM") ou o par ano + mes, e o alvo via contribuinte ou usar_lista_interna.

Request

{
  "contribuinte": { "tipo": 2, "numero": "27898481000150" },
  "competencia": "2025-06"
}

Response 200 OK

Mesmo envelope de baixar-todas (summary + guias + erros), restrito à competência informada.

{
  "summary": {
    "total": 2,
    "abertas": 0,
    "pagas": 0,
    "vencidas": 0,
    "porTipo": { "DCTF": 1, "PGDAS": 1 }
  },
  "guias": [
    {
      "id": "DCTFWeb:27898481000150:2025-06",
      "tipo": "DCTF",
      "competencia": "2025-06",
      "valor": 0.0,
      "dataVencimento": null,
      "status": "desconhecida",
      "clienteNumero": "27898481000150",
      "clienteNome": null,
      "descricao": "DCTFWeb - 2025-06",
      "codigoBarras": null,
      "dataGeracao": "2026-07-03",
      "observacoes": null,
      "origem": "DCTFWeb",
      "extras": { "emitir": {}, "pdfGuiaPath": "..." }
    }
  ],
  "erros": []
}

Competência mal formada retorna 422 ("Formato de 'competencia' inválido. Use 'YYYY-MM'."); ausência de competência e de ano/mes válidos retorna 422 ("Informe 'competencia' (YYYY-MM) ou 'ano' e 'mes' válidos."). Erro global retorna 500 com message: "Erro ao coletar guias mensais".

Para CNPJs de matriz (contêm 0001) resolvidos pela carteira interna, é registrada uma atividade DCTFWeb por cliente, com status "Concluído" ou "Falha".

Escopo: dctfweb:write

POST /dctfweb/emissao/guias/baixar-mensal/mit

Idêntico à variante eSocial, porém na variante MIT (Módulo de Inclusão de Tributos): a geração do DARF usa idsSistemaOrigem = [8]. A coleta PGDAS-D é a mesma nas duas variantes.

Parâmetros

Sem parâmetros de rota ou query - corpo em GuiasDownloadRequest, mesmas regras de competência e de alvo da variante eSocial.

Request

{
  "usar_lista_interna": true,
  "competencia": "2025-06"
}

Response 200 OK

Mesmo envelope { summary, guias, erros } da variante eSocial. Também registra atividade DCTFWeb por cliente matriz da carteira interna. Erro global retorna 500 com message: "Erro ao coletar guias mensais".

Escopo: dctfweb:write

POST /dctfweb/emissao/recibos/baixar-todas

Coleta/lista os recibos de transmissão dos últimos N anos (anos, 1 a 3), para um único CNPJ ou toda a carteira interna. Percorre todas as competências mensais do intervalo e, para cada CNPJ, consulta o recibo da DCTFWeb no Serpro.

Parâmetros

Sem parâmetros de rota ou query - corpo em RecibosDownloadRequest: contribuinte ou usar_lista_interna: true, com anos opcional (default 1).

Request

{
  "contribuinte": { "tipo": 2, "numero": "27898481000150" },
  "anos": 1
}

Response 200 OK

{
  "summary": {
    "total": 12,
    "abertas": 0,
    "pagas": 0,
    "vencidas": 0,
    "porTipo": { "DCTF": 12 }
  },
  "recibos": [
    {
      "id": "DCTFWeb:27898481000150:2025-06",
      "tipo": "DCTF",
      "competencia": "2025-06",
      "clienteNumero": "27898481000150",
      "descricao": "Recibo DCTFWeb - 2025-06",
      "origem": "DCTFWeb",
      "dataGeracao": "2026-07-03",
      "pdfPath": "/caminho/RECIBO_DCTF/.../DCTFWeb_27898481000150_2025-06.pdf",
      "extras": { "consulta": {} }
    }
  ]
}

Note que a resposta de recibos não tem erros[] - falhas por competência são registradas em log e não abortam a coleta das demais. Se nenhum CNPJ for resolvido, retorna 422 com "Informe 'contribuinte.numero' (CNPJ), ou 'cnpjs', ou 'usar_lista_interna=true' com customer_service válido.". Erro global retorna 500 com message: "Erro ao coletar recibos".

Escopo: dctfweb:write

POST /dctfweb/emissao/recibos/baixar-mensal

Coleta/lista os recibos de uma única competência, para 1 CNPJ ou toda a carteira interna.

Parâmetros

Sem parâmetros de rota ou query - corpo em RecibosMensalRequest: contribuinte ou usar_lista_interna: true, e a competência via competencia ("AAAA-MM") ou o par ano + mes.

Request

{
  "contribuinte": { "tipo": 2, "numero": "27898481000150" },
  "competencia": "2025-06"
}

Alternativa - competência via ano + mes:

{
  "contribuinte": { "tipo": 2, "numero": "27898481000150" },
  "ano": 2025,
  "mes": 6
}

Response 200 OK

Mesmo envelope { summary, recibos } do baixar-todas, restrito à competência informada.

Competência mal formada retorna 422 ("Formato de 'competencia' inválido. Use 'YYYY-MM'."); ausência de competência e de ano/mes válidos retorna 422 ("Informe 'competencia' (YYYY-MM) ou 'ano' e 'mes' válidos."). Erro global retorna 500 com message: "Erro ao coletar recibos mensais".

Ao coletar, registra uma atividade de auditoria por cliente (no modo usar_lista_interna, apenas para CNPJs de matriz, contendo 0001).

Escopo: dctfweb:write

Integração com o Serpro (Integra Contador)

As rotas orquestram as seguintes chamadas ao Integra Contador por CNPJ/competência:

ServiçoPapel
DCTFWeb - CONSRECIBO32Obtém o numeroReciboEntrega da transmissão; usado na emissão do DARF e no download do recibo.
DCTFWeb - GERARGUIA31Emite a guia DCTFWeb. Em emitir, categoria e idsSistemaOrigem vêm do corpo; nas rotas baixar-mensal/*, são GERAL_MENSAL + [1, 6, 7] (eSocial) ou [8] (MIT), literais no código.
PGDAS-D - pgdasd_gerar_dasEmite o DAS do Simples Nacional para o periodoApuracao (AAAAMM). nas rotas de coleta em lote.
PGDAS-D - extrato do DASFallback: recupera PDF, linha digitável e vencimento quando o DAS não vem inline.

Nas rotas de coleta, todas as chamadas usam contribuinte = { tipo: 2, numero: <CNPJ> } (pessoa jurídica). Em emitir, o tipo é derivado do comprimento do documento (2 para CNPJ, 1 para CPF), porque as categorias PF_MENSAL e PF_13o_SALARIO são de pessoa física empregadora.

Os PDFs em base64 devolvidos pelo Serpro são decodificados e salvos em disco pelas rotas de coleta; o caminho fica em extras.pdfGuiaPath (guia DCTFWeb), extras.pdfPath (PGDAS-D) ou pdfPath (recibo). Em emitir, o PDF é gravado no registro de Guias e sai por GET /dctfweb/guias/{guia_id}/pdf.

`idsSistemaOrigem` é fixo nas rotas `baixar-mensal/*`

As variantes esocial e mit diferem apenas pelo idsSistemaOrigem enviado ao Serpro, que é literal no código - não é um parâmetro do corpo, e o schema delas sequer declara o campo. Quem precisa escolher as origens usa POST /dctfweb/emissao/guias/emitir.

O catálogo dos códigos aceitos e o que cada um traz para a guia estão em DCTFWeb: Catálogos.

Schemas

DctfwebEmitirGuiaRequest

Corpo de POST /dctfweb/emissao/guias/emitir. Rejeita campos desconhecidos (extra="forbid"): um nome digitado errado vira 422, e não uma emissão silenciosa com o parâmetro ignorado.

CampoTipoObrigatórioObservações
cnpjstr (11-20)simCNPJ/CPF do contribuinte, com ou sem máscara. Precisa pertencer a um cliente do escritório.
anoPAstrsimAno de apuração, string de 4 dígitos: "2026". Padrão ^\d{4}$.
mesPAstrcondicionalMês com zero à esquerda: "04". Padrão ^(0[1-9]|1[0-2])$. Obrigatório em todas as categorias exceto as de 13º.
categoriaDCTFCategorianãoDefault GERAL_MENSAL. Aceita o rótulo ("GERAL_MENSAL"), não o código numérico.
idsSistemaOrigemList[int]nãoOrigens das receitas. Omitir ≠ [] - ver o aviso acima. Inteiros estritos, sem repetição, dentro de 1, 5, 6, 7, 8.
numeroReciboEntregastr (≤60)nãoRecibo da declaração alvo. Normalmente dispensável; informe no cenário MG10.
diaPAstrcondicionalSomente em ESPETACULO_DESPORTIVO (e obrigatório lá). Padrão ^(0[1-9]|[12][0-9]|3[01])$.
cnoAfericaoint (≥0)condicionalSomente em AFERICAO (e obrigatório lá). Número da obra (CNO), numérico.
numProcReclamatoriastr (≤60)condicionalSomente em RECLAMATORIA_TRABALHISTA (e obrigatório lá).

As regras condicionais valem nos dois sentidos: o campo é obrigatório na categoria dona e recusado em todas as outras ("'cnoAfericao' só se aplica à categoria AFERICAO."). mesPA enviado numa categoria de 13º também é 422, porque a declaração é anual. A tabela completa está em DCTFWeb: Catálogos.

`anoPA` e `mesPA` são STRING nesta rota

Não presuma simetria com as rotas de lote, que aceitam ano/mes inteiros: aqui os campos seguem o contrato da DCTFWeb e são texto com zero à esquerda. {"anoPA": 2026} e {"mesPA": 4} são 422; o correto é {"anoPA": "2026", "mesPA": "04"}.

O mesmo vale para categoria: o valor é o rótulo ("GERAL_MENSAL", "AFERICAO", ...), não o código numérico da tabela (40, 44, ...).

DctfwebEmissaoGuiaResultado

Conteúdo de data na resposta de POST /dctfweb/emissao/guias/emitir.

CampoTipoObservações
id_guiaint | nullId no registro de Guias - o elo para baixar o PDF. null só se a persistência falhar.
id_clienteintId do cliente resolvido a partir do cnpj.
cnpjstrCNPJ normalizado (só dígitos), mesmo que tenha entrado mascarado.
categoriastrRótulo da categoria efetivamente usada.
competenciastr"AAAA-MM" - ou "AAAA" nas categorias de 13º, que são anuais. Nenhum mês sintético é inventado.
idsSistemaOrigemList[int] | nullO que foi efetivamente enviado à Receita. null = campo omitido (guia com todas as receitas).
setorstrfiscal | pessoal. Derivado das origens - ver o aviso acima.
numero_recibostr | nullRecibo usado para identificar a declaração. null quando não foi informado nem obtido.
arquivo_nomestr | nulldctfweb_guia_<cnpj>_<competencia>.pdf. null quando não houve PDF.
tem_pdfboolA Receita devolveu o PDF nesta emissão? Leia antes de oferecer download.
mensagemstrDesfecho em pt-BR.

GuiasDownloadRequest

Corpo das três rotas de guias.

CampoTipoObrigatórioObservações
contribuinteParteIdentificacaocondicionalCNPJ único.
usar_lista_internaboolnãoDefault false. Se true, coleta para toda a carteira interna.
anosint (1-3)nãoDefault 1. Usado apenas em baixar-todas.
competenciastrcondicionalCompetência "AAAA-MM". Usada nas rotas baixar-mensal/*.
anointcondicionalAlternativa a competencia (par com mes) nas rotas mensais.
mesintcondicionalAlternativa a competencia (par com ano) nas rotas mensais.

O alvo deve vir por contribuinte.numero ou usar_lista_interna=true.

RecibosDownloadRequest

Corpo de POST /dctfweb/emissao/recibos/baixar-todas.

CampoTipoObrigatórioObservações
contribuinteParteIdentificacaocondicionalCNPJ único.
usar_lista_internaboolnãoDefault false.
anosint (1-3)nãoAnos retroativos a percorrer. Default 1.

RecibosMensalRequest

Corpo de POST /dctfweb/emissao/recibos/baixar-mensal.

CampoTipoObrigatórioObservações
contribuinteParteIdentificacaocondicionalCNPJ único.
usar_lista_internaboolnãoDefault false.
competenciastrcondicionalFormato AAAA-MM (validado por regex ^\d{4}-(0[1-9]|1[0-2])$).
anointcondicionalUsado quando competencia não é informada.
mesintcondicionalUsado quando competencia não é informada.
dir_saidastrnãoDiretório de saída dos PDFs.

ParteIdentificacao

CampoTipoObrigatórioObservações
tipointsim1 = PF (CPF), 2 = PJ (CNPJ). Estas rotas usam 2.
numerostrsimCPF/CNPJ, preferencialmente só dígitos.

GuiasDownloadResponse

CampoTipoObservações
summaryGuiasSummaryResumo agregado da coleta.
guiasList[Guia]Guias emitidas/coletadas.
errosList[GuiaErro]Falhas por CNPJ/competência. Default [].

GuiasSummary

CampoTipoObservações
totalintTotal de guias coletadas.
abertasintDefault 0 - o status não é resolvido nesta coleta.
pagasintDefault 0.
vencidasintDefault 0.
porTipoDict[str, int]Contagem por tipo (DCTF, PGDAS, ...).

Estes são todos os campos declarados no response_model: qualquer chave extra produzida internamente é descartada na serialização e não chega ao cliente.

Guia

CampoTipoObservações
idstrEx.: DCTFWeb:<cnpj>:<competencia>.
tipostrDAS, DCTF, DARF, GPS, etc.
competenciastrAAAA-MM.
valorfloatDefault 0.0 - a DCTFWeb não resolve valor nesta coleta.
dataVencimentostr | nullVencimento, quando disponível.
statusstraberta | paga | vencida | desconhecida (default).
clienteNumerostrCNPJ do cliente (somente dígitos).
clienteNomestr | nullNome do cliente, quando disponível.
descricaostr | nullDescrição legível.
codigoBarrasstr | nullLinha digitável / código de barras (PGDAS-D).
dataGeracaostr | nullAAAA-MM-DD.
observacoesstr | null-
origemstrDCTFWeb, PGDAS-D, etc.
extrasDict[str, Any]Payload cru do Serpro e caminhos de PDF (pdfGuiaPath / pdfPath, numeroDas).

GuiaErro

CampoTipoObservações
cnpjstrCNPJ que falhou.
statusint | nullCódigo HTTP da falha do Serpro, quando houver.
detailstrDescrição do erro.

RecibosDownloadResponse

CampoTipoObservações
summaryRecibosSummaryResumo agregado da coleta.
recibosList[Recibo]Recibos coletados (pode vir vazio).

Não há erros[] nesta resposta.

RecibosSummary

O shape é idêntico ao de GuiasSummary, por compatibilidade. Para recibos, os campos de situação de pagamento (abertas, pagas, vencidas) ficam sempre em 0.

Recibo

CampoTipoObservações
idstrorigem:cnpj:AAAA-MM.
tipostrDCTF | PGDAS.
competenciastrAAAA-MM.
clienteNumerostrCNPJ do cliente (somente dígitos).
descricaostr | nullEx.: Recibo DCTFWeb - 2025-06.
origemstrDCTFWeb ou PGDAS-D.
dataGeracaostr | nullAAAA-MM-DD.
pdfPathstr | nullCaminho do PDF salvo; null quando o Serpro não retorna PDF válido.
extrasDict[str, Any]Metadados; inclui consulta com a resposta bruta do Serpro.

Notas

  • As seis rotas são POST e exigem dctfweb:write - sem exigência de perfil, e API Key é aceita (diferente da Transmissão).
  • Envelope: as cinco rotas baixar-* devolvem o objeto direto (response_model), não { status, message, data }; emitir usa o envelope padrão.
  • Em emitir, omitir idsSistemaOrigem ≠ enviar []: omitido gera a guia com todas as receitas; [] é 422. E a tipagem é estrita - "1" e true não são coeridos para 1.
  • Em emitir, a resposta não traz o PDF: use id_guia + GET /dctfweb/guias/{guia_id}/pdf. Cheque tem_pdf antes.
  • Em emitir, setor é derivado (fiscal só quando as origens são exatamente [8]); persistência da guia e registro de atividade são best-effort e não derrubam uma emissão que já ocorreu na Receita.
  • A coleta em lote é síncrona e percorre CNPJ × competência sequencialmente. Prefira contribuinte para respostas rápidas e reserve usar_lista_interna para lotes.
  • A diferença entre baixar-mensal/esocial e baixar-mensal/mit é apenas o idsSistemaOrigem na emissão da DCTFWeb.
  • A coleta de PGDAS-D nos recibos está implementada no serviço mas desativada no fluxo atual; as respostas de recibo trazem apenas origem DCTFWeb.
  • Quando o Serpro sinaliza que não há débitos com saldo a pagar, a competência é reportada como erro 422 naquele item, sem abortar a coleta.
  • baixar-todas limita anos a no máximo 3.