SmartCityTec

Integrações realizadas com a SCT através do Data Space provido para o CinCatarina.

integração FGTS <> SmartCityTec

Ferramenta em Bun para consultar a API. Serve como código de exemplo:

#!/usr/bin/env bun
import assert from "node:assert";
import { parseArgs } from "node:util";

function makeBody(contrato: string, cnpj: string): string {
  assert.match(contrato, /^\d+$/);
  assert.match(cnpj, /^\d{14}$/);
  return `
    <?xml version="1.0"?>
    <methodCall>
      <methodName>ConsultaCRF</methodName>
      <params>
        <param><value><i4>${contrato}</i4></value></param>
        <param><value><i4>1</i4></value></param>
        <param><value><array><data><value><string>1${cnpj}</string></value></data></array></value></param>
      </params>
    </methodCall>
  `.trim();
}

function parseDate(eightDigitString: string): Date {
  const match = eightDigitString.match(/^(\d{4})(\d{2})(\d{2})$/);
  assert(match);
  return new Date(...(match.slice(1).map(Number) as [number, number, number]));
}

async function parseXmlResponse(xml: string) {
  const match = xml.match(/<string>1(\d{14})(\d{8})(\d{8})(\d{24})<\/string>/);
  assert(match);
  const [, cnpj, rawEmissao, rawValidade, certificado] = match;
  return {
    cnpj,
    emissao: parseDate(rawEmissao),
    validade: parseDate(rawValidade),
    certificado,
  };
}

export async function queryCRFbyCNPJ(contrato: string, cnpj: string) {
  const url = "https://webp.caixa.gov.br/empresa/crf/consultalote/server.asp";
  const body = makeBody(contrato, cnpj);
  const response = await fetch(url, { body, method: "POST" });
  const xml = await response.text();
  return parseXmlResponse(xml);
}

if (import.meta.main) {
  try {
    const args = parseArgs({
      options: {
        contrato: { type: "string" },
        cnpj: { type: "string" },
      },
    });
    const { cnpj, contrato } = args.values;
    assert(cnpj, "missing --cnpj= argument");
    assert(contrato, "missing --contrato= argument");
    const result = await queryCRFbyCNPJ(contrato, cnpj);
    console.log(JSON.stringify(result));
  } catch (error) {
    console.error((error as Error).message);
  }
}

Sobre isso, eu deixei o "contrato" parametrizável. Meus testes agora não falharam com o valor 66, mas ontem sim, então convém perguntar à Caixa se precisa utilizar um número especial.

Publiquei no Gitlab como snippet. Só fiz uma alteração pertinente: contrato precisa ser number.

https://git.ciga.sc.gov.br/-/snippets/33se retornar not found, precisa verificar a permissão

integração sefsc <> SmartCityTec

Visão Geral do Fluxo

O processo de obtenção do documento segue as seguintes etapas

[Início] 
   │
   ├── 1. Recupera CPF do Solicitante (Contexto ou Env Var)
   ├── 2. Identifica tipo do contribuinte (CPF vs CNPJ pelo tamanho)
   ├── 3. Envia requisição POST para a API SEF-SC
   ├── 4. Valida a estrutura de retorno (ResultCode, Data)
   ├── 5. Mapeia o Tipo da Certidão (Status e Regras de Validade)
   └── 6. Decodifica o PDF (Base64) e gera o Resultado


Configurações e Variáveis de Ambiente

Estrutura de Comunicação da API

Requisição (POST)


O payload exige a identificação do contribuinte consultado e o CPF do solicitante.

// Identificacao.Type = "Cnpj" se len == 14, caso contrário "Cpf"
{
  "Identificacao": {
    "Type": "Cnpj",
    "Value": "12075748000132"
  },
  "CpfSolicitante": {
    "Type": "Cpf",
    "Value": "00000000000"
  }
}

Resposta de Sucesso (Exemplo)

{
  "ResultCode": "OK",
  "Data": {
    "Numero": "250140126228731",
    "Identificacao": {
      "Type": "Cnpj",
      "Value": "12075748000132"
    },
    "Nome": "CONSORCIO INTERFEDERATIVO SANTA CATARINA",
    "Tipo": "Negativa",
    "DataEmissao": "2025-04-22T15:47:40",
    "DataValidade": "2025-10-19T15:47:40",
    "Situacao": "Valida",
    "OrigemDebitos": null,
    "ArquivoCndPdf": {
      "CND": "250140126228731",
      "Nome": "CND_250140126228731.pdf",
      "Dados": "<Conteudo do arquivo em base64>",
      "ContentType": "application/pdf"
    }
  },
  "Messages": null
}

Regras de Negócio e Processamento de Dados

Mapeamento de Status do Documento

A partir do campo "Tipo" retornado na resposta, define-se o status interno:

Tipo Retornado (SEF-SC) Status Interno Tipo da Certidão Observação / Mensagem
Negativa APROVADO NEGATIVA Sem pendências.
Positiva REPROVADO POSITIVA Apresenta pendências na SEF-SC.
PositivaComEfeitoNegativa APROVADO POSITIVA_NEGATIVA Certidão positiva com efeito de negativa.
Qualquer outro
PENDENTE INDEFINIDO Tipo de certidão não reconhecido.

Tratamento de Datas