TF Fiscal
Documentación

Primeros pasos

Inicio rápido

Registrar una empresa, vincular su certificado, registrar un webhook, emitir una NF-e y consultarla, la ruta de integración en cinco pasos de la Open API de TF Fiscal.

Esta guía recorre, en orden, las cinco llamadas que hace toda integración de emisión:

  1. Registrar la empresa que emitirá los documentos y obtener su empresaId.
  2. Vincular el certificado digital A1 de la empresa.
  3. Registrar un webhook para recibir los resultados de emisión.
  4. Emitir una NF-e.
  5. Consultar la NF-e para obtener su estado y los enlaces de descarga.

Todas las solicitudes van a la URL base de producción https://api.v2.tffiscal.com; la URL completa es la URL base más la ruta indicada en cada llamada. Los mismos cinco pasos aplican a CT-e y DC-e: los pasos 1 a 3 son compartidos, solo cambian los endpoints de emisión y consulta.

Requisitos previos

  • Credencial de la aplicación: un app_secret emitido para su aplicación. Se muestra una sola vez; guárdelo de forma segura. Si se filtra, solicite una rotación.
  • Suscripción a la API: la plataforma concede a su aplicación acceso a todos los endpoints usados abajo. Llamar a un endpoint no suscrito devuelve HTTP 403 con el código 10009005.
  • Firma: cada solicitud lleva las cabeceras token, timestamp y sign. La función auxiliar de abajo se usa en todos los ejemplos de esta página; la especificación completa está en Autenticación. Antes de la primera llamada real, valide su implementación con el Echo de prueba.
bash
HOST="https://api.v2.tffiscal.com"
APP_SECRET="<APP_SECRET>"
# sign = lowercase hex MD5( token + path + body-without-CR-LF + timestamp )
# usage: sign "<path>" "<body>" "<timestamp>" (pass "" as body for GET / DELETE / multipart)
sign() {
printf '%s%s%s%s' "$APP_SECRET" "$1" "$(printf '%s' "$2" | tr -d '\r\n')" "$3" \
| md5sum | awk '{print $1}'
}

Paso 1: registrar la empresa

POST /openapi/v2/empresas envía los datos de la empresa vendedora. La respuesta trae el empresaId que toda llamada posterior usa como variable de ruta; persístalo.

bash
API_PATH="/openapi/v2/empresas"
BODY='{"cnpj":"14422279000106","inscricaoEstadual":"999999","razaoSocial":"Empresa teste LTDA","nomeFantasia":"Empresa teste","optanteSimplesNacional":true,"mei":false,"email":"empresa-teste@example.com","telefoneComercial":"6122222222","endereco":{"pais":"Brasil","uf":"MG","cidade":"Belo Horizonte","logradouro":"Rua Teste","numero":"999","bairro":"Bairro Teste","cep":"85100000"},"emissaoNFeProduto":{"ambienteProducao":{"sequencialNFe":1,"serieNFe":"10"}}}'
TS=$(date +%s)
curl -sS -X POST "$HOST$API_PATH" \
-H "Content-Type: application/json" \
-H "token: $APP_SECRET" -H "timestamp: $TS" -H "sign: $(sign "$API_PATH" "$BODY" "$TS")" \
-d "$BODY"
json
{ "empresaId": "1934811222334455" }

El registro coloca a la empresa en la cola de aprobación de la plataforma. La empresa solo puede emitir después de que operaciones la apruebe y se vincule el certificado; emitir antes devuelve codigo 10004004. Registrar el mismo CNPJ dos veces devuelve HTTP 400 con codigo 10003002. Referencia campo por campo: Registrar empresa.

Paso 2: vincular el certificado digital

POST /openapi/v1/empresas/{empresaId}/certificadoDigital acepta el certificado A1 (.pfx / .p12) como carga multipart/form-data o como JSON con el contenido del archivo en Base64. Aquí se usa la forma JSON porque su cuerpo se firma como el de cualquier otra solicitud JSON. Genere Base64 estándar sin saltos de línea para que el cuerpo firmado y el cuerpo enviado no diverjan.

bash
EMPRESA_ID="1934811222334455"
API_PATH="/openapi/v1/empresas/$EMPRESA_ID/certificadoDigital"
BODY=$(printf '{"senha":"certpass123","arquivoBase64":"%s"}' "$(base64 -w0 certificate.pfx)")
TS=$(date +%s)
curl -sS -X POST "$HOST$API_PATH" \
-H "Content-Type: application/json" \
-H "token: $APP_SECRET" -H "timestamp: $TS" -H "sign: $(sign "$API_PATH" "$BODY" "$TS")" \
--data-binary "$BODY"

El éxito es HTTP 200 sin cuerpo, y la carga reemplaza el certificado anterior de la empresa. Una contraseña incorrecta devuelve HTTP 400 con codigo CER0005; un Base64 inválido o un archivo de más de 1 MB tras decodificar devuelve 10003035; un certificado cuyo CNPJ no coincide con la empresa devuelve 10003010, y uno vencido 10003011. La forma multipart, que firma la cadena vacía como cuerpo, se describe en Vincular certificado.

Paso 3: registrar el webhook

POST /openapi/v1/webhooks registra la URL que recibe los resultados de emisión. El token que usted elige se devuelve sin cambios en la cabecera token de cada callback, para que su receptor verifique el origen; además, la plataforma firma cada entrega con la cabecera X-Tffiscal-Signature.

bash
API_PATH="/openapi/v1/webhooks"
BODY='{"uri":"https://example.com/tffiscal/callback","contentType":"application/json","token":"dGt6eXp5ZGRra2tzc3Nra2hoaGFha2tha2FhamFoaGFoNzc3Nz"}'
TS=$(date +%s)
curl -sS -X POST "$HOST$API_PATH" \
-H "Content-Type: application/json" \
-H "token: $APP_SECRET" -H "timestamp: $TS" -H "sign: $(sign "$API_PATH" "$BODY" "$TS")" \
-d "$BODY"
json
{ "webHookId": "550001" }

Hay una única configuración de callback por aplicación; llamar de nuevo al endpoint la sobrescribe. El registro lo suscribe a los eventos de resultado, autorizado y denegado. Su receptor debe responder 2xx; cualquier otra respuesta se reintenta con backoff. Vea Registrar webhook y Webhooks.

Paso 4: emitir una NF-e

Una vez aprobada la empresa, POST /openapi/v2/empresas/{empresaId}/nf-e acepta una solicitud de emisión. El id lo genera usted y es la clave para consulta, cancelación e idempotencia. ambienteEmissao debe coincidir con el entorno actual de la empresa; las empresas recién registradas empiezan en Homologacao.

bash
API_PATH="/openapi/v2/empresas/$EMPRESA_ID/nf-e"
BODY='{"id":"NFe-000014553","ambienteEmissao":"Homologacao","pedido":{"presencaConsumidor":"OperacaoPelaInternet","pagamento":{"formas":[{"tipo":"CartaoDeCredito","valor":28.47}]}},"cliente":{"tipoPessoa":"F","nome":"Demo Client","email":"demo.client@mail.com","cpfCnpj":"88533234775","endereco":{"uf":"PR","cidade":"4106902","logradouro":"Rua Presidente Wilson","numero":"911","bairro":"Uberaba","cep":"81570440"}},"itens":[{"cfop":"6403","codigo":"000068","descricao":"Kingston DataTraveler SE9 DTSE9H 16GB USB Drive","ncm":"85235190","ean":"619659000424","quantidade":1,"unidadeMedida":"UN","valorUnitario":28.47,"impostos":{"icms":{"situacaoTributaria":"101"},"pis":{"situacaoTributaria":"49"},"cofins":{"situacaoTributaria":"49"}}}]}'
TS=$(date +%s)
curl -sS -X POST "$HOST$API_PATH" \
-H "Content-Type: application/json" \
-H "token: $APP_SECRET" -H "timestamp: $TS" -H "sign: $(sign "$API_PATH" "$BODY" "$TS")" \
-d "$BODY"

Una solicitud aceptada devuelve HTTP 200 sin cuerpo y entra en el flujo asíncrono de emisión. El resultado llega por el webhook registrado en el paso 3 o por la consulta del paso 5. Reenviar el mismo id reutiliza la tarea original; si el intento anterior fue denegado (Negada), reenviar el mismo id con los campos corregidos emite de nuevo con la nueva carga. Diccionario completo de la solicitud: Emitir NF-e.

Paso 5: consultar la NF-e

GET /openapi/v2/empresas/{empresaId}/nf-e/{nfeId} devuelve el estado actual, los datos de la factura y, una vez autorizada, los enlaces de descarga del DANFE y del XML. nfeId es el id enviado en el paso 4. Las solicitudes GET firman la cadena vacía como cuerpo; las variables de ruta forman parte de la ruta firmada.

bash
NFE_ID="NFe-000014553"
API_PATH="/openapi/v2/empresas/$EMPRESA_ID/nf-e/$NFE_ID"
TS=$(date +%s)
curl -sS -X GET "$HOST$API_PATH" \
-H "token: $APP_SECRET" -H "timestamp: $TS" -H "sign: $(sign "$API_PATH" "" "$TS")"

El campo status pasa de AguardandoAutorizacao a Autorizada (o Negada, con un motivoStatus que explica el motivo). Una vez autorizada, linkDanfe y linkDownloadXml se pueden descargar con un GET simple, vea Descarga de archivos. Referencia de la respuesta: Consultar NF-e.

Verifique las rutas de fallo

Cada fila es un cambio de una línea en la secuencia anterior y confirma que su cliente falla como espera:

CambioResultado esperado
Valor de token incorrectoHTTP 401, sobre code 10009002 (token inválido)
Cambiar BODY después de calcular signHTTP 401, sobre code 10009003 (firma no coincide)
Reutilizar un timestamp de más de 300 sHTTP 401, sobre code 10009001 (timestamp)
Llamar a un endpoint al que su aplicación no está suscritaHTTP 403, sobre code 10009005 (no suscrito)
Registrar el mismo CNPJ dos vecesHTTP 400, [{"codigo":"10003002", ...}]
Emitir con ambienteEmissao igual a Producao mientras la empresa está en pruebaHTTP 400, [{"codigo":"10004030", ...}]
Consultar un nfeId desconocidoHTTP 404, [{"codigo":"NFe0001", ...}]

Los fallos de autenticación usan el sobre de la plataforma; los fallos de negocio de los endpoints de emisión usan un array de errores. Ambas formas se describen en Convenciones generales.

Próximos pasos

  • NF-e: cancelación y cartas de corrección (CC-e) además de las llamadas anteriores.
  • CT-e y DC-e: los otros tipos de documento emitidos, que comparten la misma empresa, certificado y webhook.
  • Verificación de NF-e: verificar NF-e de terceros por XML o clave de acceso.
  • Consulta de registro: consultas registrales de CNPJ y CPF.
  • Webhooks: cargas de callback, verificación de firma y reintentos.
  • Entornos: cómo una empresa pasa de prueba a producción.