NFS-e
Emita facturas de servicios (NFS-e) en nombre de un emisor registrado: flujo de integración, diferencias entre canales municipales, manifestación de facturas recibidas, cargas de los webhooks, modelo de errores, máquina de estados y checklist de integración.
Visión general y flujo de integración
| Paso | Endpoint | Notas |
|---|---|---|
| 1 Registrar emisor | POST /openapi/v2/empresas | Igual que NF-e, con la nueva sección opcional emissaoNFSe; el bloque de NF-e puede omitirse si solo emite NFS-e, y entonces no se exige la IE |
| 2 Vincular certificado | POST /openapi/v1/empresas/{empresaId}/certificadoDigital | Igual que NF-e |
| 3 Registrar callback | POST /openapi/v1/webhooks | Igual que NF-e; los resultados de NFS-e reutilizan la misma URL de callback |
| 4 Emitir | POST /openapi/v2/empresas/{empresaId}/nfse | Devuelve HTTP 200 sin cuerpo al aceptar; el envío es asíncrono |
| 5 Consultar | GET /openapi/v2/empresas/{empresaId}/nfse/{nfseId} | Estado, eventos, enlaces de descarga del XML / DANFSe, eco de la solicitud |
| 5-A Conciliar | GET …/nfse/emitidas · GET …/nfse/emitidas/{chaveAcesso} | Listado de emitidas (paginación por ventana de tiempo) y consulta por clave de acceso |
| 6 Cancelar | POST /openapi/v2/empresas/{empresaId}/nfse/{nfseId}/cancelar | Asíncrono: 200 con acuse de aceptación, resultado vía webhook |
| 7 Consultar facturas recibidas | GET …/nfse/recebidas · GET …/nfse/recebidas/{chaveAcesso} | Lista de las facturas recibidas (paginada por período) y consulta de una por la clave; de aquí sale la chaveAcesso usada en la manifestación |
| 8 Manifestar sobre factura recibida | POST …/recebidas/{chaveAcesso}/manifestar | Registra confirmación / rechazo de una NFS-e recibida; el cuerpo trae tipo |
La autenticación es idéntica a la de NF-e: cabeceras token / timestamp / sign, vea Autenticación.
Tres diferencias estructurales frente a NF-e
1. La clave de acceso tiene 50 dígitos y la genera el emisor oficial. La clave de 44 dígitos de la NF-e la calcula el contribuyente; la clave de la NFS-e solo existe cuando la autoridad acepta el documento. Un documento fallido, por tanto, no tiene chaveAcesso y solo puede localizarse por identificacaoDps, el identificador de DPS de 45 caracteres que generamos.
2. La factura de servicios la rige el municipio. La plataforma enruta por el municipio del emisor; el canal resultante aparece como padraoMunicipal en la respuesta de la consulta. Hoy se admiten el estándar nacional (Nacional) y el sistema municipal de São Paulo (Paulistana); un municipio no admitido se rechaza en la aceptación (10018010) en vez de aceptarse y fallar de forma asíncrona.
3. La cancelación tiene ventana, y fuera de ella la respuesta no es "no se puede cancelar" sino "pasa a análisis municipal". Vea Cancelar NFS-e.
Requisitos previos
- El emisor debe estar aprobado y con certificado utilizable, de lo contrario la aceptación se rechaza (
10018004). - El emisor debe tener perfil de NFS-e, creado con la sección
emissaoNFSede Registrar empresa o mantenido por operaciones en la consola. El encuadre en el Simples, el cálculo en el Simples, el régimen especial y la serie del DPS vienen siempre del perfil; la solicitud de emisión no los envía ni los sustituye. Sin perfil, la aceptación rechaza (10018005). Código de servicio, CNAE, NBS y los demás campos del servicio no están en el perfil: van en cada nota. - El
ambienteEmissaodebe coincidir con el entorno actual del emisor. Tras el registro el emisor queda en el entorno de pruebas (Homologacao); el paso a producción es una acción de operaciones y no se expone por la API. - Los valores de tributación siguen la solicitud: lo que trae prevalece, y solo lo que falta lo busca la plataforma en los datos de referencia fiscal, como la lista de la LC 116, la clasificación y las alícuotas de retención federal y la carga aproximada del IBPT. Si los datos que necesitan la retención federal, las alícuotas propias de PIS/COFINS o el lugar de incidencia del ISS aún no se importaron, la aceptación rechaza con
10018065, listando los campos de la solicitud que pueden sustituirlos. - Cuando el receptor es persona jurídica (CNPJ) hay retención federal: envíe los importes en
servico.retencoes, donde cero declara que no hay retención, u omítalos junto conpisCofins.tipoRetencaoy la plataforma los determina por la clasificación oficial de retención del servicio y porcliente.orgaoPublicoycliente.optanteSimplesNacional; enviarpisCofins.tipoRetencaosin los importes se rechaza (10018001). La información faltante se rechaza explícitamente (10018023) con todo lo que falta listado de una vez, en lugar de tratarse como cero.
Restricciones adicionales del canal Paulistana
Un emisor de São Paulo (padraoMunicipal = Paulistana) necesita su CCM (inscricaoMunicipal): si está en el perfil, se usa tal cual; si falta, la plataforma consulta el sistema municipal por CNPJ en la aceptación y guarda el resultado en el perfil; la aceptación solo se rechaza (10018005) cuando no se encuentra nada.
El canal no admite campos de descuento: incorpore el descuento al importe del servicio o a la deducción. Tampoco admite emisión sustitutiva (el layout municipal de RPS no tiene ese grupo): cancele la original y emita una nueva; enviar el grupo se rechaza en la aceptación (10018001).
También obtiene dos capacidades automáticas que no requieren ningún endpoint nuevo: las facturas paulistanas recibidas se traen directamente del sistema municipal al listado de recibidas (origem=PrefeituraSP, fusionadas automáticamente cuando llega la transcripción de la ADN); una factura emitida y cancelada en el portal municipal se sincroniza a Cancelada y el nfse.canceled se envía con normalidad.
Máquina de estados
┌──────────────► Negada (terminal)│Pendente ────────┼──────────────► Autorizada ──┬──► Cancelada (terminal)│ │└──────────────► Falha ├──► EmProcessoDeCancelamento ──┬──► Cancelada(falló antes de la │ └──► Autorizada (análisis denegado)numeración, sin documento) └──► Substituida (sustituida)
| Estado | Significado | Terminal |
|---|---|---|
Pendente | Aceptado, aún sin desenlace | no |
Autorizada | Emitida con éxito | no (puede cancelarse o sustituirse) |
Negada | Rechazada por la autoridad | sí |
Falha | Fallo del lado de la plataforma (parámetros inválidos / emisor no apto); no se creó ningún documento | sí |
Cancelada | Cancelada | sí |
EmProcessoDeCancelamento | Análisis de cancelación aceptado, a la espera del municipio | no |
Substituida | Sustituida por otro documento | sí |
Estado de manifestación de una factura recibida
El status de una factura recibida usa Autorizada / Cancelada / Substituida de la tabla anterior; la manifestación de este emisor se guarda aparte en el bloque manifestacao, y cada parte manifiesta como máximo una vez por factura.
(sin manifestación, filtro de la lista Pendente) ──┬──► Confirmada (confirmada por este emisor, terminal)├──► Rejeitada (rechazada por este emisor) ──► RejeicaoAnulada (rechazo anulado por el municipio, terminal)└──► ConfirmacaoTacita (confirmación tácita del municipio, terminal)
| Estado | Significado | ¿Puede manifestar aún? |
|---|---|---|
null (valor de filtro Pendente) | Sin manifestación | sí (mientras la factura esté Autorizada) |
Confirmada | Confirmada por este emisor | no |
Rejeitada | Rechazada por este emisor | no |
ConfirmacaoTacita | Confirmada tácitamente por el municipio tras el plazo | no |
RejeicaoAnulada | El municipio anuló el rechazo de este emisor | no |
Callbacks de webhook
Se entregan en la URL que usted registra como carga JSON pura.
| Código del evento | Disparo | nfseStatus |
|---|---|---|
nfse.authorized | Emitida con éxito | Autorizada |
nfse.rejected | Rechazada por la autoridad o fallo de nuestro lado | Negada |
nfse.canceled | Cancelación completada (incluido análisis aprobado) | Cancelada |
nfse.cancel_requested | Análisis de cancelación aceptado | EmProcessoDeCancelamento |
nfse.cancel_denied | La cancelación no ocurrió y el documento sigue autorizado: rechazo síncrono de la autoridad, envío agotado, o solicitud de análisis denegada por el municipio | Autorizada |
nfse.substituted | Este documento fue sustituido; la carga trae un nfseChaveSubstituta adicional | Substituida |
nfse.inbound.received | NFS-e recibida (este emisor es receptor / intermediario, requiere suscripción explícita) | — |
nfse.inbound.canceled | NFS-e recibida cancelada (requiere suscripción explícita) | — |
nfse.inbound.substituted | NFS-e recibida sustituida (requiere suscripción explícita) | — |
Aviso: Semántica de las suscripciones. Una aplicación que nunca registró ninguna fila de suscripción recibe los seis eventos de salida. En cuanto exista cualquier fila de suscripción para la aplicación (por ejemplo un evento de entrada), pasa al modo lista de permitidos y solo se entregan los eventos habilitados explícitamente. Al suscribirse a eventos de entrada, habilite también los eventos de salida que necesite, o las notificaciones de salida quedarán en espera de destinatario.
{"tipo": "NFS-e","empresaId": "1001","nfseId": "PED-20260918-001","nfseStatus": "Autorizada","nfseMotivoStatus": null,"nfseLinkDanfse": "https://api.v2.tffiscal.com/openapi/files/danfse/…","nfseLinkXml": "https://api.v2.tffiscal.com/openapi/files/xml/9001?token=…","nfseNumero": "1287","nfseSerie": "1","nfseChaveAcesso": "3550308…","nfseIdentificacaoDps": "DPS3550308…","nfseDataEmissao": "2026-09-18T13:00:00Z","nfseDataAutorizacao": "2026-09-18T13:00:03Z","nfseNumeroProtocolo": null,"nfseAtualizadoEm": "2026-09-18T13:00:03Z"}
nfseAtualizadoEm es el momento de este cambio de estado. El orden de entrega no está garantizado: los reintentos y las múltiples instancias pueden hacer que un evento antiguo llegue después de uno nuevo. Compárelo con la marca de tiempo que ya tiene y descarte el más antiguo en vez de sobrescribir el estado por orden de llegada.
En un callback de fallo el nfseChaveAcesso puede venir vacío (la autoridad nunca generó la clave); concilie por nfseIdentificacaoDps en ese caso. Un callback de fallo anterior a la numeración no trae ninguno de los dos, y solo el nfseId concilia.
Modelo de errores
Los endpoints públicos devuelven un array puro:
[{"codigo": "10018012", "mensagem": "Codigo de servico fora da lista oficial LC 116: 999999"}]
| Código | Significado | Qué hacer |
|---|---|---|
10018001 | Validación de parámetros rechazada en la aceptación (el mensaje indica el motivo) | Corrija según el mensaje |
NFSe0001 | Documento no encontrado: el nfseId no pertenece a este emisor, o la clave de entrada no está entre sus facturas recibidas | Coteje nfseId / chaveAcesso con empresaId |
10018004 | Emisor no apto (desactivado / certificado inutilizable) | Revise el estado del emisor y el certificado |
10018005 | Emisor sin perfil de NFS-e | Créelo antes en Registrar empresa con la sección emissaoNFSe |
10018010 | El estándar de NFS-e del municipio aún no está admitido | Ese municipio todavía no puede emitir, contacte con la plataforma |
10018012 | Código de servicio fuera de la lista LC 116 | Coteje codigoTributacaoNacional |
10018013 | Documento del receptor inválido | Coteje el CPF / CNPJ / NIF |
10018014 | Exportación de servicio sin país de destino | Informe servico.paisPrestacao |
10018015 | El documento sustituido no puede sustituirse | Revise el estado del documento sustituido |
10018020 | No se puede determinar la alícuota de ISS | Envíe servico.iss.aliquota o el servico.codigoTributacaoMunicipal correcto |
10018022 | Un emisor del Simples no puede enviar la alícuota de ISS directamente | Quite aliquota |
10018023 | La retención federal no puede determinarse; el mensaje lista todo lo que falta | Informe los campos listados o envíe los importes retenidos en servico.retencoes |
10018030 | La misma solicitud ya se está procesando | Reintente más tarde |
10018031 | Ese pedido ya tiene factura, o el mismo id trae contenido distinto | Use otro número de pedido o coteje el contenido |
10018040 | Ya hay un análisis de cancelación en curso | Espere el veredicto |
10018041 | El documento ya fue sustituido | No se permite ninguna otra operación |
10018042 | El estado actual no permite este evento | Revise el estado del documento |
10018063 | El mensaje del DPS no cumple el XSD oficial (el detalle trae línea, columna, clave del error y nombre del elemento) | Corrija según el detalle: suele ser texto fuera de Latin-1, dirección incompleta, o un valor fuera de la tabla oficial |
10018064 | El mensaje de evento de la NFS-e no cumple el XSD oficial | Revise la longitud de motivo (15-255), el valor de codigoMotivo y el juego de caracteres |
10018065 | Los datos de referencia fiscal de la NFS-e que necesita esta nota no se han importado, rechazo en la aceptación; el mensaje lista cada elemento con una flecha hacia el campo de la solicitud que lo sustituye | Envíe en la solicitud los campos tras la flecha, o confirme con la plataforma que los datos están importados; para iss-local-incidencia, basta con enviar servico.iss.municipioIncidencia |
Los errores de autenticación y autorización (10009xxx) están en Autenticación; la tabla completa está en Códigos de error.
Checklist de integración
- Registre el emisor (con
emissaoNFSe) → vincule el certificado → registre el webhook. - Emita una factura mínima en
Homologacao(solo los campos obligatorios), confirme que llega elnfse.authorizedy que el XML y el DANFSe se descargan. - Envíe el mismo
idotra vez y confirme que no se emite una segunda factura. - Envíe un código de servicio inexistente y confirme el rechazo síncrono
10018012, y no unaNegadaasíncrona. - Cancele una factura autorizada y confirme que llega a
CanceladaoEmProcessoDeCancelamentosegún la ventana. - Consulte un documento fallido y confirme que concilia por
identificacaoDps, no porchaveAcesso. - Manifieste sobre una factura recibida con
tipo=Confirmacaoy vea que el detalle traemanifestacao.status=Confirmada; envíetipo=Rejeicaoen la misma factura y confirme el10018042(cada parte manifiesta una vez).
