Appearance
Invoices API - Especificação para Backend
Contexto
Módulo de emissão de Notas Fiscais de Serviço Eletrônicas (NFS-e) integrado ao Sistema Nacional NFS-e. A emissão é controlada pelo sistema de compliance: o prestador emite notas fiscais quando o step tipo INVOICE está dentro do schedule (dayStart/dayEnd).
Endpoints
Endpoints de Invoice (listagem e consulta)
| Método | Endpoint | Descrição |
|---|---|---|
| GET | /invoices | Lista notas fiscais do usuário autenticado |
| GET | /invoices/:id | Detalhe de uma nota fiscal |
| POST | /invoices/emit | Emitir nota fiscal (uso interno pelo compliance) |
| GET | /invoices/:id/pdf | URL do PDF da nota fiscal |
| POST | /invoices/:id/cancel | Cancelar nota fiscal emitida |
Endpoints de Certificado Digital
| Método | Endpoint | Descrição |
|---|---|---|
| POST | /companies/:id/certificate | Upload do certificado digital (.pfx) do prestador |
| DELETE | /companies/:id/certificate | Remover certificado digital |
Endpoints de Compliance INVOICE Step
| Método | Endpoint | Descrição |
|---|---|---|
| GET | /provider-compliances/:complianceId/steps/:stepId/invoice-data | Dados calculados da NF (sempre disponível) |
| POST | /provider-compliances/:complianceId/steps/:stepId/emit-invoice | Emitir NF via compliance step (gated por schedule) |
GET /invoices
Lista as notas fiscais do usuário autenticado, filtradas por ano e/ou status.
Auth: Bearer token
Query Params:
| Param | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| year | number | Não | Filtrar por ano de referência |
| status | "pending" | "issuing" | "issued" | "error" | "cancelled" | "all" | Não | Filtrar por status |
Response 200:
json
{
"data": [
{
"id": "uuid-da-nota",
"referenceMonth": 3,
"referenceYear": 2026,
"status": "issued",
"totalAmount": 15000.00,
"serviceDescription": "Prestação de serviços de tecnologia - Competência 03/2026",
"invoiceNumber": "2026000123",
"issuedAt": "2026-04-05T14:30:00.000Z",
"stepComplianceId": "uuid-do-step-compliance",
"contract": { "id": "uuid", "name": "Contrato de Desenvolvimento" },
"borrower": { "id": "uuid", "name": "TechCorp Solutions Ltda", "document": "12345678000190" },
"provider": { "id": "uuid", "name": "Dev Services ME", "document": "98765432000111" },
"file": { "id": "uuid", "fileName": "nfse_2026000123.pdf", "filePath": "/invoices/nfse_2026000123.pdf", "mimeType": "application/pdf" },
"taxes": { "baseCalculo": 15000.00, "aliquotaIss": 0.02, "valorIss": 300.00, "issRetido": false, "valorPis": 97.50, "valorCofins": 450.00, "valorInss": 1650.00, "valorIr": 225.00, "valorCsll": 150.00, "valorDeducoes": 0, "descontoIncondicionado": 0, "valorLiquido": 12127.50 },
"nfse": { "ambiente": "PRODUCAO", "chaveAcesso": "NFSe12345678901234567890", "codigoVerificacao": "ABCD1234", "nfseNumber": "2026000123" },
"createdAt": "2026-04-05T14:00:00.000Z",
"updatedAt": "2026-04-05T14:30:00.000Z"
}
]
}GET /invoices/:id
Retorna detalhes completos de uma nota fiscal.
Auth: Bearer token
Response 200: Mesmo formato de um item da listagem GET /invoices.
Response 404: Nota fiscal não encontrada ou não pertence ao usuário autenticado
POST /invoices/emit
Emite uma nota fiscal para o mês/ano informado. Uso interno pelo compliance module, o frontend deve usar o endpoint /provider-compliances/:complianceId/steps/:stepId/emit-invoice.
Auth: Bearer token, role provider
Body:
json
{
"referenceMonth": 4,
"referenceYear": 2026,
"stepComplianceId": "uuid-do-step-compliance"
}| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| referenceMonth | number (1-12) | Sim | Mês de referência |
| referenceYear | number | Sim | Ano de referência |
| stepComplianceId | string (UUID) | Não | ID do StepCompliance (link com compliance) |
Response 201: Invoice criada com status issuing
GET /invoices/:id/pdf
Retorna a URL para download do PDF da nota fiscal.
Auth: Bearer token
Response 200:
json
{
"data": {
"url": "https://storage.example.com/invoices/nfse_2026000123.pdf"
}
}GET /provider-compliances/:complianceId/steps/:stepId/invoice-data
Retorna os dados calculados da nota fiscal para um step tipo INVOICE. Sempre disponível, independente do schedule (o prestador pode ver os dados a qualquer momento).
Auth: Bearer token, role provider
Path Params:
| Param | Tipo | Descrição |
|---|---|---|
| complianceId | string (UUID) | ID do ProviderCompliance |
| stepId | string (UUID) | ID do StepCompliance (tipo INVOICE) |
Response 200:
json
{
"data": {
"totalHours": 160,
"hourlyRate": 93.75,
"totalAmount": 15000.00,
"serviceDescription": "Prestação de serviços de tecnologia - Competência 04/2026",
"contract": { "id": "uuid", "name": "Contrato de Desenvolvimento" },
"borrower": { "id": "uuid", "name": "TechCorp Solutions Ltda", "document": "12345678000190" },
"provider": { "id": "uuid", "name": "Dev Services ME", "document": "98765432000111" },
"taxes": {
"baseCalculo": 15000.00,
"aliquotaIss": 0.02,
"valorIss": 300.00,
"valorPis": 97.50,
"valorCofins": 450.00,
"valorInss": 1650.00,
"valorIr": 225.00,
"valorCsll": 150.00,
"valorLiquido": 12127.50
},
"invoiceId": null,
"invoiceStatus": null,
"fiscalConfigComplete": true
}
}| Campo | Tipo | Descrição |
|---|---|---|
| totalHours | number | Total de horas trabalhadas no período |
| hourlyRate | number | Valor por hora do contrato |
| totalAmount | number | Valor total (totalHours × hourlyRate) |
| serviceDescription | string | Descrição do serviço |
| contract | { id, name } | Contrato vinculado |
| borrower | { id, name, document? } | Empresa tomadora |
| provider | { id, name, document? } | Empresa prestadora |
| taxes | StepInvoiceTax | null | Tributos calculados |
| invoiceId | string | null | ID da invoice se já emitida |
| invoiceStatus | string | null | Status da invoice se já emitida |
| fiscalConfigComplete | boolean | Se os dados fiscais estão completos |
POST /provider-compliances/:complianceId/steps/:stepId/emit-invoice
Emite a nota fiscal do step tipo INVOICE. Gated pelo schedule, só funciona quando isSubmissionOpen === true.
Auth: Bearer token, role provider
Path Params:
| Param | Tipo | Descrição |
|---|---|---|
| complianceId | string (UUID) | ID do ProviderCompliance |
| stepId | string (UUID) | ID do StepCompliance (tipo INVOICE) |
Response 200:
json
{
"data": StepComplianceResponseDto
}Retorna o step atualizado com status SUBMITTED.
Validações:
| Regra | Erro |
|---|---|
| Step deve ser tipo INVOICE | 400 |
| Schedule deve estar aberto (isSubmissionOpen) | 403 |
| Provider deve ter contrato ativo | 400 |
| Deve existir valor/hora no contrato | 400 |
| Deve existir horas registradas no período | 400 |
| Configuração fiscal deve estar completa | 400 |
| Prestador deve ter certificado digital (.pfx) cadastrado | 400 |
| Não pode existir nota já emitida para o step | 409 |
Processamento:
- Valida step tipo INVOICE e schedule aberto
- Carrega certificado digital (.pfx) do prestador do S3
- Chama InvoicesService.emit() com dados do período, stepComplianceId e certificado
- Envia DPS à API NFS-e com autenticação mTLS usando certificado do prestador
- Linka a Invoice criada ao StepCompliance
- Transiciona step para SUBMITTED
- Cria validações e notifica validators
- Verifica se todos os steps foram submetidos
POST /companies/:id/certificate
Upload do certificado digital A1 (.pfx) do prestador. Necessário para emissão de NFS-e.
Auth: Bearer token
Content-Type: multipart/form-data
Path Params:
| Param | Tipo | Descrição |
|---|---|---|
| id | string (UUID) | ID da empresa |
Form Fields:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| file | File (.pfx) | Sim | Arquivo do certificado digital A1 |
| password | string | Sim | Senha do certificado |
Response 200:
json
{
"message": "Certificado salvo com sucesso"
}Erros:
400Arquivo do certificado nao enviado400Senha do certificado e obrigatoria403Voce nao tem acesso a esta empresa
DELETE /companies/:id/certificate
Remove o certificado digital do prestador.
Auth: Bearer token
Response 204: Sem body
Tipos TypeScript (Referência)
typescript
type InvoiceStatus = 'pending' | 'issuing' | 'issued' | 'error' | 'cancelled'
type StepInvoiceData = {
totalHours: number
hourlyRate: number
totalAmount: number
serviceDescription: string
taxes?: StepInvoiceTax
invoiceId?: string
invoiceStatus?: string
fiscalConfigComplete: boolean
borrower: { id: string; name: string; document?: string }
provider: { id: string; name: string; document?: string }
contract: { id: string; name: string }
}
type StepInvoiceTax = {
baseCalculo: number
aliquotaIss: number
valorIss: number
valorPis: number
valorCofins: number
valorInss: number
valorIr: number
valorCsll: number
valorLiquido: number
}
type Invoice = {
id: string
referenceMonth: number
referenceYear: number
status: InvoiceStatus
totalAmount: number
serviceDescription: string
invoiceNumber?: string
issuedAt?: string
stepComplianceId?: string
contract: { id: string; name: string }
borrower: InvoiceRelation
provider: InvoiceRelation
file?: InvoiceFile
taxes: InvoiceTax
nfse: InvoiceNfse
createdAt: string
updatedAt: string
}Alíquotas de Tributos Federais
| Tributo | Constante | Alíquota |
|---|---|---|
| PIS | TAX_RATE_PIS | 0.0065 (0,65%) |
| COFINS | TAX_RATE_COFINS | 0.03 (3%) |
| INSS | TAX_RATE_INSS | 0.11 (11%) |
| IR | TAX_RATE_IR | 0.015 (1,5%) |
| CSLL | TAX_RATE_CSLL | 0.01 (1%) |
Simples Nacional: Se a empresa é optante, todos os tributos federais acima são zerados.
POST /invoices/:id/cancel
Cancela uma nota fiscal emitida. Envia evento de cancelamento à API do Sistema Nacional NFS-e.
Auth: Bearer token
Path Params:
| Param | Tipo | Descrição |
|---|---|---|
| id | string | ID da nota fiscal |
Request Body:
json
{
"reason": "Motivo do cancelamento"
}Response 200: Invoice atualizada com status cancelled
Erros:
404Nota fiscal não encontrada422Nota fiscal não pode ser cancelada neste status422Nota fiscal sem chave de acesso
POST /provider-compliances/:complianceId/steps/:stepId/emit-invoice: Body
O endpoint de emissão via compliance agora aceita dados opcionais do formulário do prestador:
json
{
"serviceDescription": "Prestação de serviços de tecnologia - Competência 03/2026",
"aliquotaIss": 5.0,
"valorPis": 65.00,
"valorCofins": 300.00,
"valorInss": 1100.00,
"valorIr": 150.00,
"valorCsll": 100.00,
"valorLiquido": 8285.00
}Todos os campos são opcionais. Quando não enviados, o backend usa os valores calculados automaticamente.