Pular para o conteúdo principal

NFE.io SDK v3 - API Reference

Complete API reference for the NFE.io Node.js SDK v3.

Table of Contents

Installation

npm install nfe-io

Client

Constructor

new NfeClient(config: NfeConfig): NfeClient

Creates a new NFE.io API client instance.

Parameters:

  • config - Client configuration object

Configuration Options:

PropertyTypeRequiredDefaultDescription
apiKeystringYes*process.env.NFE_API_KEYNFE.io API key
environment'production' | 'development'No'production'API environment (both use same endpoint: https://api.nfe.io/v1)
baseUrlstringNoAuto-detectedCustom API base URL
timeoutnumberNo30000Request timeout in ms
retryConfigRetryConfigNoSee belowRetry configuration

* API key is required but can be provided via NFE_API_KEY environment variable.

Retry Configuration:

PropertyTypeDefaultDescription
maxRetriesnumber3Maximum retry attempts
baseDelaynumber1000Initial delay in ms
maxDelaynumber30000Maximum delay in ms
retryableStatusesnumber[][408, 429, 500, 502, 503]HTTP status codes to retry

Examples:

// Basic usage
const nfe = new NfeClient({
apiKey: 'your-api-key',
environment: 'production'
});

// With environment variable
// Set NFE_API_KEY=your-api-key
const nfe = new NfeClient({
environment: 'production'
});

// Custom configuration
const nfe = new NfeClient({
apiKey: 'your-api-key',
timeout: 60000,
retryConfig: {
maxRetries: 5,
baseDelay: 2000,
maxDelay: 60000
}
});

Configuration

updateConfig(newConfig: Partial<NfeConfig>): void

Update client configuration dynamically.

nfe.updateConfig({
environment: 'development',
timeout: 60000
});

setTimeout(timeout: number): void

Set request timeout in milliseconds. (v2 compatibility)

nfe.setTimeout(60000); // 60 seconds

setApiKey(apiKey: string): void

Set or update API key. (v2 compatibility)

nfe.setApiKey('new-api-key');

getConfig(): Readonly<RequiredNfeConfig>

Get current client configuration.

const config = nfe.getConfig();
console.log('Environment:', config.environment);

Utility Methods

pollUntilComplete<T>(locationUrl: string, options?: PollOptions): Promise<T>

Poll a resource URL until it completes processing.

Parameters:

  • locationUrl - URL or path to poll
  • options - Polling configuration
    • maxAttempts (default: 30) - Maximum polling attempts
    • intervalMs (default: 2000) - Delay between attempts in ms

Returns: Promise resolving to the completed resource

Example:

const result = await nfe.serviceInvoices.create(companyId, data);

if (result.status === 'pending') {
const invoice = await nfe.pollUntilComplete(result.location, {
maxAttempts: 60,
intervalMs: 3000
});
}

healthCheck(): Promise<{ status: 'ok' | 'error', details?: any }>

Check API connectivity and authentication.

const health = await nfe.healthCheck();

if (health.status === 'ok') {
console.log('API connection successful');
} else {
console.error('API error:', health.details);
}

getClientInfo(): ClientInfo

Get client diagnostic information.

const info = nfe.getClientInfo();
console.log('SDK Version:', info.version);
console.log('Node Version:', info.nodeVersion);
console.log('Environment:', info.environment);

Resources

All resources follow a consistent pattern with standard CRUD operations plus resource-specific methods.

Service Invoices

Resource: nfe.serviceInvoices

Complete service invoice (NFS-e) operations including creation, retrieval, email delivery, document downloads, and cancellation. Supports both synchronous and asynchronous invoice processing with automatic polling capabilities.


Core Operations

create(companyId: string, data: ServiceInvoiceData): Promise<ServiceInvoiceCreateResult>

Create a new service invoice. Returns either a completed invoice (201) or async processing result (202).

Parameters:

ParameterTypeDescription
companyIdstringCompany ID issuing the invoice
dataServiceInvoiceDataInvoice data (see structure below)

Returns: Promise<ServiceInvoiceCreateResult> - Discriminated union:

  • 201 Created (Synchronous): Returns complete ServiceInvoice with id, number, status
  • 202 Accepted (Asynchronous): Returns { flowStatus, flowMessage?, location? } for polling

Invoice Data Structure:

interface ServiceInvoiceData {
// Required fields
borrower: {
federalTaxNumber: number; // CPF (11 digits) or CNPJ (14 digits)
name: string;
email?: string;
address?: {
country: string; // 'BRA'
postalCode: string; // CEP: '01310-100'
street: string;
number: string;
additionalInformation?: string;
district: string;
city: {
code: string; // IBGE code: '3550308'
name: string;
};
state: string; // UF: 'SP'
};
};
cityServiceCode: string; // Municipal service code
description: string; // Service description
servicesAmount: number; // Amount in BRL (e.g., 1500.00)

// Optional fields
rpsSerialNumber?: string; // RPS series
rpsNumber?: number; // RPS number
issuedOn?: string; // ISO date: '2024-01-15'
deductions?: number; // Deductions amount
discountUnconditioned?: number; // Unconditional discount
discountConditioned?: number; // Conditional discount
taxes?: {
retainIss?: boolean;
iss?: number;
pis?: number;
cofins?: number;
inss?: number;
ir?: number;
csll?: number;
};
}

Examples:

// Example 1: Basic invoice creation (may be sync or async)
const result = await nfe.serviceInvoices.create('company-id', {
borrower: {
federalTaxNumber: 12345678901,
name: 'João da Silva',
email: '[email protected]',
},
cityServiceCode: '10677',
description: 'Consulting services',
servicesAmount: 1500.00,
});

// Check if synchronous (201) or asynchronous (202)
if ('id' in result) {
// Synchronous - invoice issued immediately
console.log('Invoice issued:', result.number);
console.log('Status:', result.status);
} else {
// Asynchronous - needs polling
console.log('Processing:', result.flowStatus);
console.log('Poll URL:', result.location);

// Use pollUntilComplete or createAndWait instead
const invoice = await nfe.pollUntilComplete(result.location, {
intervalMs: 2000,
timeoutMs: 60000,
});
console.log('Invoice issued:', invoice.number);
}

// Example 2: Invoice with full details
const invoice = await nfe.serviceInvoices.create('company-id', {
borrower: {
federalTaxNumber: 12345678000190,
name: 'Acme Corporation',
email: '[email protected]',
address: {
country: 'BRA',
postalCode: '01310-100',
street: 'Av. Paulista',
number: '1578',
district: 'Bela Vista',
city: {
code: '3550308',
name: 'São Paulo',
},
state: 'SP',
},
},
cityServiceCode: '01234',
description: 'Software development services',
servicesAmount: 5000.00,
rpsSerialNumber: 'A',
rpsNumber: 123,
deductions: 100.00,
taxes: {
retainIss: false,
iss: 5.0, // 5%
},
});

Error Handling:

  • ValidationError (400): Invalid invoice data
  • AuthenticationError (401): Invalid API key
  • NotFoundError (404): Company not found
  • InternalError (500): Server error
try {
const result = await nfe.serviceInvoices.create(companyId, data);
} catch (error) {
if (error instanceof ValidationError) {
console.error('Invalid data:', error.message);
} else if (error instanceof AuthenticationError) {
console.error('Invalid API key');
}
}

createAndWait(companyId: string, data: ServiceInvoiceData, options?: WaitOptions): Promise<ServiceInvoice>

⭐ Recommended: Create invoice with automatic polling for async processing. Simplifies async workflow.

Parameters:

ParameterTypeDescription
companyIdstringCompany ID
dataServiceInvoiceDataInvoice data
optionsWaitOptionsPolling configuration (optional)

Wait Options:

OptionTypeDefaultDescription
pollingIntervalnumber2000Delay between status checks (ms)
maxWaitTimenumber60000Maximum wait time (ms)

Returns: Promise<ServiceInvoice> - Completed invoice with id, number, status: 'Issued'

Examples:

// Example 1: Simple usage (recommended)
const invoice = await nfe.serviceInvoices.createAndWait('company-id', {
borrower: {
federalTaxNumber: 12345678901,
name: 'João da Silva',
email: '[email protected]',
},
cityServiceCode: '10677',
description: 'Consulting services',
servicesAmount: 1500.00,
});

console.log('Invoice issued:', invoice.number);
console.log('Status:', invoice.status); // 'Issued'

// Example 2: Custom polling configuration
const invoice = await nfe.serviceInvoices.createAndWait('company-id', data, {
pollingInterval: 3000, // Check every 3 seconds
maxWaitTime: 120000, // Wait up to 2 minutes
});

// Example 3: With error handling
try {
const invoice = await nfe.serviceInvoices.createAndWait('company-id', data, {
maxWaitTime: 60000,
});

console.log('✅ Invoice issued successfully');
console.log(` Number: ${invoice.number}`);
console.log(` Amount: R$ ${invoice.servicesAmount}`);
} catch (error) {
if (error.message.includes('timeout')) {
console.error('⏱️ Invoice processing timeout - may complete later');
} else if (error.message.includes('failed')) {
console.error('❌ Invoice processing failed:', error.message);
}
}

When to use:

  • ✅ You want immediate invoice results without manual polling
  • ✅ You can wait 5-30 seconds for processing
  • ✅ Simple workflows where async complexity isn't needed

When NOT to use:

  • ❌ Background job processing (use create() + queue)
  • ❌ Batch operations (use createBatch())
  • ❌ Need to track processing separately

list(companyId: string, options?: ListOptions): Promise<ServiceInvoice[]>

List service invoices for a company with pagination and filtering.

Parameters:

ParameterTypeDescription
companyIdstringCompany ID
optionsListOptionsFiltering and pagination (optional)

List Options:

OptionTypeDescription
pageCountnumberItems per page (default: 25)
pageIndexnumberPage number, 0-indexed (default: 0)
searchPeriodobjectDate range filter
searchPeriod.startDatestringStart date: 'YYYY-MM-DD'
searchPeriod.endDatestringEnd date: 'YYYY-MM-DD'

Returns: Promise<ServiceInvoice[]> - Array of invoices

Examples:

// Example 1: List all (first page)
const invoices = await nfe.serviceInvoices.list('company-id');
console.log(`Found ${invoices.length} invoices`);

// Example 2: Pagination
const page2 = await nfe.serviceInvoices.list('company-id', {
pageCount: 50, // 50 per page
pageIndex: 1, // Second page (0-indexed)
});

// Example 3: Date filtering
const lastMonth = await nfe.serviceInvoices.list('company-id', {
searchPeriod: {
startDate: '2024-01-01',
endDate: '2024-01-31',
},
pageCount: 100,
});

// Example 4: Process all invoices
let pageIndex = 0;
let allInvoices = [];

while (true) {
const page = await nfe.serviceInvoices.list('company-id', {
pageCount: 100,
pageIndex,
});

allInvoices.push(...page);

if (page.length < 100) break; // Last page
pageIndex++;
}

console.log(`Total invoices: ${allInvoices.length}`);

// Example 5: Find specific invoices
const recentHighValue = await nfe.serviceInvoices.list('company-id', {
searchPeriod: {
startDate: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
.toISOString()
.split('T')[0],
endDate: new Date().toISOString().split('T')[0],
},
});

const filtered = recentHighValue.filter(inv => inv.servicesAmount > 5000);
console.log(`High-value invoices: ${filtered.length}`);

retrieve(companyId: string, invoiceId: string): Promise<ServiceInvoice>

Get a specific service invoice by ID with complete details.

Parameters:

ParameterTypeDescription
companyIdstringCompany ID
invoiceIdstringInvoice ID

Returns: Promise<ServiceInvoice> - Complete invoice object

Examples:

// Example 1: Basic retrieval
const invoice = await nfe.serviceInvoices.retrieve('company-id', 'invoice-id');

console.log('Invoice:', invoice.number);
console.log('Amount:', invoice.servicesAmount);
console.log('Status:', invoice.status);
console.log('Issued:', invoice.issuedOn);

// Example 2: Check invoice details
const invoice = await nfe.serviceInvoices.retrieve('company-id', 'invoice-id');

console.log('Borrower:', invoice.borrower.name);
console.log('Service:', invoice.description);
console.log('Tax Amount:', invoice.taxes?.iss || 0);

// Example 3: Verify invoice exists before operation
async function sendInvoiceIfExists(companyId, invoiceId) {
try {
const invoice = await nfe.serviceInvoices.retrieve(companyId, invoiceId);

if (invoice.status === 'Issued') {
await nfe.serviceInvoices.sendEmail(companyId, invoiceId, {
emails: [invoice.borrower.email],
});
console.log('Email sent successfully');
} else {
console.log('Invoice not ready:', invoice.status);
}
} catch (error) {
if (error instanceof NotFoundError) {
console.error('Invoice not found');
}
}
}

Error Handling:

  • NotFoundError (404): Invoice or company not found
  • AuthenticationError (401): Invalid API key

getStatus(companyId: string, invoiceId: string): Promise<InvoiceStatus>

Check invoice processing status (useful for async invoices).

Parameters:

ParameterTypeDescription
companyIdstringCompany ID
invoiceIdstringInvoice ID

Returns: Promise<InvoiceStatus> with:

FieldTypeDescription
statusstringCurrent status (see status values below)
isCompletebooleantrue if processing finished (success or failure)
isFailedbooleantrue if processing failed

Status Values:

StatusisCompleteisFailedDescription
Issuedtruefalse✅ Invoice issued successfully
IssueFailedtruetrue❌ Issuance failed
Cancelledtruefalse🚫 Invoice cancelled
CancellationFailedtruetrue❌ Cancellation failed
WaitingSendfalsefalse⏳ Pending
WaitingSendAuthorizefalsefalse⏳ Awaiting authorization
Processingfalsefalse⏳ Processing

Examples:

// Example 1: Simple status check
const status = await nfe.serviceInvoices.getStatus('company-id', 'invoice-id');

console.log('Status:', status.status);
console.log('Complete:', status.isComplete ? 'Yes' : 'No');
console.log('Failed:', status.isFailed ? 'Yes' : 'No');

// Example 2: Manual polling loop
async function waitForInvoice(companyId, invoiceId, maxAttempts = 30) {
for (let i = 0; i < maxAttempts; i++) {
const status = await nfe.serviceInvoices.getStatus(companyId, invoiceId);

if (status.isComplete) {
if (status.isFailed) {
throw new Error(`Invoice processing failed: ${status.status}`);
}

console.log('Invoice complete:', status.status);
return await nfe.serviceInvoices.retrieve(companyId, invoiceId);
}

console.log(`Attempt ${i + 1}: ${status.status}`);
await new Promise(resolve => setTimeout(resolve, 2000));
}

throw new Error('Polling timeout');
}

// Example 3: Status-based logic
const status = await nfe.serviceInvoices.getStatus('company-id', 'invoice-id');

if (status.status === 'Issued') {
console.log('✅ Ready to send email');
await nfe.serviceInvoices.sendEmail(/* ... */);
} else if (status.isFailed) {
console.error('❌ Failed:', status.status);
} else {
console.log('⏳ Still processing:', status.status);
}

cancel(companyId: string, invoiceId: string): Promise<ServiceInvoice>

Cancel an issued service invoice.

Parameters:

ParameterTypeDescription
companyIdstringCompany ID
invoiceIdstringInvoice ID to cancel

Returns: Promise<ServiceInvoice> - Cancelled invoice with status: 'Cancelled'

Examples:

// Example 1: Simple cancellation
const cancelled = await nfe.serviceInvoices.cancel('company-id', 'invoice-id');
console.log('Status:', cancelled.status); // 'Cancelled'

// Example 2: Conditional cancellation
const invoice = await nfe.serviceInvoices.retrieve('company-id', 'invoice-id');

if (invoice.status === 'Issued') {
const cancelled = await nfe.serviceInvoices.cancel('company-id', 'invoice-id');
console.log('✅ Invoice cancelled');
} else {
console.log('⚠️ Invoice cannot be cancelled:', invoice.status);
}

// Example 3: Batch cancellation with error handling
const invoiceIds = ['id-1', 'id-2', 'id-3'];

for (const invoiceId of invoiceIds) {
try {
await nfe.serviceInvoices.cancel('company-id', invoiceId);
console.log(`✅ Cancelled: ${invoiceId}`);
} catch (error) {
if (error instanceof NotFoundError) {
console.log(`⚠️ Not found: ${invoiceId}`);
} else {
console.error(`❌ Error cancelling ${invoiceId}:`, error.message);
}
}
}

Error Handling:

  • NotFoundError (404): Invoice not found
  • ValidationError (400): Invoice cannot be cancelled (already cancelled, etc.)

Email & Downloads

sendEmail(companyId: string, invoiceId: string, options: SendEmailOptions): Promise<void>

Send invoice via email to specified recipients.

Parameters:

ParameterTypeDescription
companyIdstringCompany ID
invoiceIdstringInvoice ID
optionsSendEmailOptionsEmail configuration

Email Options:

FieldTypeDescription
emailsstring[]Recipient email addresses

Examples:

// Example 1: Send to single recipient
await nfe.serviceInvoices.sendEmail('company-id', 'invoice-id', {
emails: ['[email protected]'],
});

console.log('✅ Email sent');

// Example 2: Send to multiple recipients
await nfe.serviceInvoices.sendEmail('company-id', 'invoice-id', {
emails: [
'[email protected]',
'[email protected]',
'[email protected]',
],
});

// Example 3: Send after invoice creation
const invoice = await nfe.serviceInvoices.createAndWait('company-id', data);

await nfe.serviceInvoices.sendEmail('company-id', invoice.id, {
emails: [invoice.borrower.email],
});

console.log(`Email sent to ${invoice.borrower.email}`);

// Example 4: Bulk email sending
const invoices = await nfe.serviceInvoices.list('company-id');

for (const invoice of invoices) {
if (invoice.status === 'Issued' && invoice.borrower.email) {
try {
await nfe.serviceInvoices.sendEmail('company-id', invoice.id, {
emails: [invoice.borrower.email],
});
console.log(`✅ Sent: ${invoice.number}`);
} catch (error) {
console.error(`❌ Failed ${invoice.number}:`, error.message);
}
}
}

downloadPdf(companyId: string, invoiceId?: string): Promise<Buffer>

Download invoice PDF. If invoiceId is omitted, downloads all invoices as ZIP.

Parameters:

ParameterTypeDescription
companyIdstringCompany ID
invoiceIdstringInvoice ID (optional - omit for bulk ZIP)

Returns: Promise<Buffer> - PDF file as Buffer (or ZIP for bulk)

Examples:

import { writeFileSync } from 'fs';

// Example 1: Download single invoice PDF
const pdfBuffer = await nfe.serviceInvoices.downloadPdf('company-id', 'invoice-id');

// Validate PDF signature
if (pdfBuffer.toString('utf8', 0, 4) === '%PDF') {
console.log('✅ Valid PDF');
}

// Save to file
writeFileSync('invoice.pdf', pdfBuffer);
console.log('Saved invoice.pdf');

// Example 2: Download all invoices as ZIP
const zipBuffer = await nfe.serviceInvoices.downloadPdf('company-id');

writeFileSync(`invoices_${Date.now()}.zip`, zipBuffer);
console.log('Saved ZIP with all invoices');

// Example 3: Download and send via HTTP response (Express)
app.get('/invoice/:id/pdf', async (req, res) => {
try {
const pdfBuffer = await nfe.serviceInvoices.downloadPdf(
req.user.companyId,
req.params.id
);

res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', `attachment; filename="invoice-${req.params.id}.pdf"`);
res.send(pdfBuffer);
} catch (error) {
res.status(404).json({ error: 'Invoice not found' });
}
});

// Example 4: Download after creation
const invoice = await nfe.serviceInvoices.createAndWait('company-id', data);

const pdf = await nfe.serviceInvoices.downloadPdf('company-id', invoice.id);
writeFileSync(`invoice_${invoice.number}.pdf`, pdf);
console.log(`Downloaded invoice ${invoice.number}`);

Error Handling:

  • NotFoundError (404): Invoice not ready or not found

downloadXml(companyId: string, invoiceId?: string): Promise<Buffer>

Download invoice XML. If invoiceId is omitted, downloads all invoices as ZIP.

Parameters:

ParameterTypeDescription
companyIdstringCompany ID
invoiceIdstringInvoice ID (optional - omit for bulk ZIP)

Returns: Promise<Buffer> - XML file as Buffer (or ZIP for bulk)

Examples:

import { writeFileSync } from 'fs';

// Example 1: Download single invoice XML
const xmlBuffer = await nfe.serviceInvoices.downloadXml('company-id', 'invoice-id');

// Convert Buffer to string
const xmlString = xmlBuffer.toString('utf8');
console.log('XML preview:', xmlString.substring(0, 100));

// Validate XML signature
if (xmlString.startsWith('<?xml')) {
console.log('✅ Valid XML');
}

// Save to file
writeFileSync('invoice.xml', xmlBuffer);

// Example 2: Download all invoices as ZIP
const zipBuffer = await nfe.serviceInvoices.downloadXml('company-id');
writeFileSync(`invoices_xml_${Date.now()}.zip`, zipBuffer);

// Example 3: Parse XML for integration
import { parseString } from 'xml2js';

const xmlBuffer = await nfe.serviceInvoices.downloadXml('company-id', 'invoice-id');
const xmlString = xmlBuffer.toString('utf8');

parseString(xmlString, (err, result) => {
if (err) throw err;
console.log('Parsed XML:', result);
// Process structured data
});

// Example 4: Bulk download and extract
const zipBuffer = await nfe.serviceInvoices.downloadXml('company-id');
writeFileSync('invoices.zip', zipBuffer);

// Extract ZIP using library like 'adm-zip'
// const AdmZip = require('adm-zip');
// const zip = new AdmZip(zipBuffer);
// zip.extractAllTo('./invoices/', true);

Advanced Operations

createBatch(companyId: string, invoicesData: ServiceInvoiceData[], options?: BatchOptions): Promise<ServiceInvoice[]>

Create multiple invoices concurrently with concurrency control.

Parameters:

ParameterTypeDescription
companyIdstringCompany ID
invoicesDataServiceInvoiceData[]Array of invoice data
optionsBatchOptionsBatch configuration (optional)

Batch Options:

OptionTypeDefaultDescription
waitForCompletebooleantrueWait for all invoices to complete processing
maxConcurrentnumber5Maximum concurrent requests
pollingIntervalnumber2000Polling interval in ms (if waitForComplete=true)
maxWaitTimenumber60000Max wait time per invoice in ms

Returns: Promise<ServiceInvoice[]> - Array of created invoices

Examples:

// Example 1: Basic batch creation
const invoicesData = [
{
borrower: { federalTaxNumber: 111, name: 'Client 1', email: '[email protected]' },
cityServiceCode: '10677',
description: 'Service 1',
servicesAmount: 1000,
},
{
borrower: { federalTaxNumber: 222, name: 'Client 2', email: '[email protected]' },
cityServiceCode: '10677',
description: 'Service 2',
servicesAmount: 2000,
},
{
borrower: { federalTaxNumber: 333, name: 'Client 3', email: '[email protected]' },
cityServiceCode: '10677',
description: 'Service 3',
servicesAmount: 3000,
},
];

const invoices = await nfe.serviceInvoices.createBatch('company-id', invoicesData);

console.log(`Created ${invoices.length} invoices`);
invoices.forEach(inv => console.log(`- ${inv.number}: R$ ${inv.servicesAmount}`));

// Example 2: Custom concurrency
const invoices = await nfe.serviceInvoices.createBatch('company-id', invoicesData, {
maxConcurrent: 3, // Process 3 at a time
waitForComplete: true, // Wait for all to finish
});

// Example 3: Batch without waiting (fire and forget)
const results = await nfe.serviceInvoices.createBatch('company-id', invoicesData, {
waitForComplete: false, // Don't wait for async processing
maxConcurrent: 10,
});

// Results may contain async processing info (location, flowStatus)
results.forEach(result => {
if ('id' in result) {
console.log(`Issued: ${result.id}`);
} else {
console.log(`Processing: ${result.location}`);
}
});

// Example 4: Read from CSV and batch create
import { parse } from 'csv-parse/sync';
import { readFileSync } from 'fs';

const csv = readFileSync('invoices.csv', 'utf8');
const records = parse(csv, { columns: true });

const invoicesData = records.map(row => ({
borrower: {
federalTaxNumber: parseInt(row.cpf),
name: row.name,
email: row.email,
},
cityServiceCode: row.serviceCode,
description: row.description,
servicesAmount: parseFloat(row.amount),
}));

console.log(`Creating ${invoicesData.length} invoices from CSV...`);

const invoices = await nfe.serviceInvoices.createBatch('company-id', invoicesData, {
maxConcurrent: 5,
waitForComplete: true,
});

console.log(`✅ Created ${invoices.length} invoices`);

// Example 5: Error handling in batch
try {
const invoices = await nfe.serviceInvoices.createBatch('company-id', invoicesData);
console.log('All succeeded');
} catch (error) {
console.error('Batch creation failed:', error.message);
// Note: Some invoices may have been created successfully
// Check partial results if needed
}

Performance Notes:

  • Default concurrency (5) is safe for most APIs
  • Increase maxConcurrent carefully to avoid rate limiting
  • Large batches (>100 invoices) should be split into chunks
  • Use waitForComplete: false for background processing

Type Reference

ServiceInvoice:

interface ServiceInvoice {
id: string;
number?: string;
status: 'Issued' | 'Cancelled' | 'Processing' | 'IssueFailed';
flowStatus?: string;
flowMessage?: string;
borrower: {
federalTaxNumber: number;
name: string;
email?: string;
address?: Address;
};
cityServiceCode: string;
description: string;
servicesAmount: number;
deductions?: number;
discountUnconditioned?: number;
discountConditioned?: number;
issuedOn?: string;
rpsSerialNumber?: string;
rpsNumber?: number;
taxes?: {
retainIss?: boolean;
iss?: number;
pis?: number;
cofins?: number;
inss?: number;
ir?: number;
csll?: number;
};
}

Companies

Resource: nfe.companies

Company management operations including CRUD, certificate management, and search capabilities.

Core CRUD Operations

create(data: Omit<Company, 'id' | 'createdOn' | 'modifiedOn'>): Promise<Company>

Create a new company with automatic CNPJ/CPF validation.

const company = await nfe.companies.create({
federalTaxNumber: 12345678000190, // CNPJ (14 digits) or CPF (11 digits)
name: 'My Company',
email: '[email protected]',
address: {
country: 'BRA',
postalCode: '01310-100',
street: 'Av. Paulista',
number: '1000',
city: {
code: '3550308',
name: 'São Paulo'
},
state: 'SP'
}
});
list(options?: PaginationOptions): Promise<ListResponse<Company>>

List companies with pagination.

const companies = await nfe.companies.list({
pageCount: 20,
pageIndex: 0
});
listAll(): Promise<Company[]>

Get all companies (auto-pagination).

// Automatically fetches all pages
const allCompanies = await nfe.companies.listAll();
console.log(`Total: ${allCompanies.length} companies`);
listIterator(): AsyncIterableIterator<Company>

Memory-efficient streaming of companies.

// Process companies one at a time
for await (const company of nfe.companies.listIterator()) {
console.log(company.name);
// Process company...
}
retrieve(companyId: string): Promise<Company>

Get a specific company by ID.

const company = await nfe.companies.retrieve('company-id');
console.log(company.name);
update(companyId: string, data: Partial<Company>): Promise<Company>

Update company information with validation.

const updated = await nfe.companies.update('company-id', {
name: 'New Company Name',
email: '[email protected]'
});
remove(companyId: string): Promise<{ deleted: boolean; id: string }>

Delete a company (named remove to avoid JS keyword conflict).

const result = await nfe.companies.remove('company-id');
console.log(`Deleted: ${result.deleted}`);

Certificate Management

validateCertificate(file: Buffer, password: string): Promise<CertificateValidationResult>

Pre-validate a certificate before upload.

import { readFile } from 'fs/promises';

const certBuffer = await readFile('./certificate.pfx');
const validation = await nfe.companies.validateCertificate(certBuffer, 'password');

if (validation.valid) {
console.log('Valid until:', validation.metadata?.validTo);
} else {
console.error('Invalid:', validation.error);
}
uploadCertificate(companyId: string, data: CertificateData): Promise<{ uploaded: boolean; message?: string }>

Upload digital certificate with automatic validation.

import { readFile } from 'fs/promises';

const certBuffer = await readFile('./certificate.pfx');

const result = await nfe.companies.uploadCertificate('company-id', {
file: certBuffer,
password: 'certificate-password',
filename: 'certificate.pfx' // Optional
});

console.log(result.message);
getCertificateStatus(companyId: string): Promise<CertificateStatus>

Get certificate status with expiration calculation.

const status = await nfe.companies.getCertificateStatus('company-id');

console.log('Has certificate:', status.hasCertificate);
console.log('Expires on:', status.expiresOn);
console.log('Days until expiration:', status.daysUntilExpiration);

if (status.isExpiringSoon) {
console.warn('⚠️ Certificate expiring soon!');
}
replaceCertificate(companyId: string, data: CertificateData): Promise<{ uploaded: boolean; message?: string }>

Replace existing certificate (alias for upload).

const result = await nfe.companies.replaceCertificate('company-id', {
file: newCertBuffer,
password: 'new-password',
filename: 'new-certificate.pfx'
});
checkCertificateExpiration(companyId: string, thresholdDays?: number): Promise<ExpirationWarning | null>

Check if certificate is expiring soon.

// Check with 30-day threshold (default)
const warning = await nfe.companies.checkCertificateExpiration('company-id', 30);

if (warning) {
console.warn(`Certificate expiring in ${warning.daysRemaining} days`);
console.log('Expires on:', warning.expiresOn);
}

Search & Helper Methods

findByTaxNumber(taxNumber: number): Promise<Company | null>

Find company by federal tax number (CNPJ or CPF).

// Search by CNPJ (14 digits)
const company = await nfe.companies.findByTaxNumber(12345678000190);

// Or by CPF (11 digits)
const company = await nfe.companies.findByTaxNumber(12345678901);

if (company) {
console.log('Found:', company.name);
} else {
console.log('Company not found');
}
findByName(name: string): Promise<Company[]>

Find companies by name (case-insensitive partial match).

// Find all companies with "Acme" in the name
const companies = await nfe.companies.findByName('Acme');

companies.forEach(company => {
console.log(`Match: ${company.name}`);
});
getCompaniesWithCertificates(): Promise<Company[]>

Get all companies that have valid certificates.

const companiesWithCerts = await nfe.companies.getCompaniesWithCertificates();

console.log(`${companiesWithCerts.length} companies with valid certificates`);
getCompaniesWithExpiringCertificates(thresholdDays?: number): Promise<Company[]>

Get companies with expiring certificates.

// Find companies with certificates expiring within 30 days
const expiring = await nfe.companies.getCompaniesWithExpiringCertificates(30);

expiring.forEach(company => {
console.warn(`⚠️ ${company.name} certificate expiring soon`);
});

Certificate Validator Utility

The CertificateValidator utility can also be used independently:

import { CertificateValidator } from 'nfe-io';

// Check if format is supported
if (CertificateValidator.isSupportedFormat('cert.pfx')) {
console.log('✓ Supported format');
}

// Calculate days until expiration
const expirationDate = new Date('2026-12-31');
const days = CertificateValidator.getDaysUntilExpiration(expirationDate);
console.log(`Days remaining: ${days}`);

// Check if expiring soon
if (CertificateValidator.isExpiringSoon(expirationDate, 30)) {
console.warn('Certificate expiring within 30 days!');
}

Resource: nfe.legalPeople

Legal person (PJ/CNPJ) operations, scoped by company.

create(companyId: string, data: Partial<LegalPerson>): Promise<LegalPerson>

Create a legal person.

const legalPerson = await nfe.legalPeople.create('company-id', {
federalTaxNumber: '12345678000190',
name: 'Legal Person Company',
email: '[email protected]'
});

list(companyId: string, options?: PaginationOptions): Promise<ListResponse<LegalPerson>>

List legal people for a company.

const people = await nfe.legalPeople.list('company-id');

retrieve(companyId: string, legalPersonId: string): Promise<LegalPerson>

Get a specific legal person.

const person = await nfe.legalPeople.retrieve('company-id', 'person-id');

update(companyId: string, legalPersonId: string, data: Partial<LegalPerson>): Promise<LegalPerson>

Update legal person information.

const updated = await nfe.legalPeople.update('company-id', 'person-id', {
name: 'Updated Name'
});

delete(companyId: string, legalPersonId: string): Promise<void>

Delete a legal person.

await nfe.legalPeople.delete('company-id', 'person-id');

findByTaxNumber(companyId: string, cnpj: string): Promise<LegalPerson | null>

Find legal person by CNPJ.

const person = await nfe.legalPeople.findByTaxNumber('company-id', '12345678000190');

Natural People

Resource: nfe.naturalPeople

Natural person (PF/CPF) operations, scoped by company.

create(companyId: string, data: Partial<NaturalPerson>): Promise<NaturalPerson>

Create a natural person.

const person = await nfe.naturalPeople.create('company-id', {
federalTaxNumber: '12345678901',
name: 'John Doe',
email: '[email protected]'
});

list(companyId: string, options?: PaginationOptions): Promise<ListResponse<NaturalPerson>>

List natural people for a company.

const people = await nfe.naturalPeople.list('company-id');

retrieve(companyId: string, personId: string): Promise<NaturalPerson>

Get a specific natural person.

const person = await nfe.naturalPeople.retrieve('company-id', 'person-id');

update(companyId: string, personId: string, data: Partial<NaturalPerson>): Promise<NaturalPerson>

Update natural person information.

const updated = await nfe.naturalPeople.update('company-id', 'person-id', {
name: 'Jane Doe'
});

delete(companyId: string, personId: string): Promise<void>

Delete a natural person.

await nfe.naturalPeople.delete('company-id', 'person-id');

findByTaxNumber(companyId: string, cpf: string): Promise<NaturalPerson | null>

Find natural person by CPF.

const person = await nfe.naturalPeople.findByTaxNumber('company-id', '12345678901');

Webhooks

Resource: nfe.webhooks

Webhook configuration and management.

create(data: Partial<Webhook>): Promise<Webhook>

Create a webhook.

const webhook = await nfe.webhooks.create({
url: 'https://example.com/webhook',
events: ['invoice.issued', 'invoice.cancelled'],
secret: 'webhook-secret'
});

list(options?: PaginationOptions): Promise<ListResponse<Webhook>>

List all webhooks.

const webhooks = await nfe.webhooks.list();

retrieve(webhookId: string): Promise<Webhook>

Get a specific webhook.

const webhook = await nfe.webhooks.retrieve('webhook-id');

update(webhookId: string, data: Partial<Webhook>): Promise<Webhook>

Update webhook configuration.

const updated = await nfe.webhooks.update('webhook-id', {
events: ['invoice.issued', 'invoice.cancelled', 'invoice.error']
});

delete(webhookId: string): Promise<void>

Delete a webhook.

await nfe.webhooks.delete('webhook-id');

validateSignature(payload: Buffer | string, signature: string | string[] | undefined, secret: string): boolean

Validate the signature on a webhook delivery from NFE.io.

NFE.io signs every webhook with HMAC-SHA1(secret, raw_body_bytes), encoded as hex (uppercase on the wire, compared case-insensitively) and prefixed with sha1=. The signed value is delivered in the X-Hub-Signature HTTP header. The method returns false (never throws) for any mismatch or malformed input.

Use raw body bytes. Re-serializing JSON (JSON.stringify(req.body)) does NOT work — property order and whitespace will differ from what NFE.io signed. Use express.raw() (or equivalent) so you receive the exact bytes:

import express from 'express';

// Capture the raw body BEFORE any JSON parser
app.post(
'/webhook',
express.raw({ type: '*/*' }),
(req, res) => {
const ok = nfe.webhooks.validateSignature(
req.body, // Buffer with exact bytes
req.headers['x-hub-signature'], // correct header (not "x-nfe-signature")
process.env.NFE_WEBHOOK_SECRET ?? ''
);
if (!ok) return res.status(401).end();

const event = JSON.parse(req.body.toString('utf8'));
// process event...
res.status(204).end();
}
);

test(webhookId: string): Promise<void>

Test webhook delivery.

await nfe.webhooks.test('webhook-id');

getAvailableEvents(): Promise<WebhookEvent[]>

Get list of available webhook event types.

const events = await nfe.webhooks.getAvailableEvents();
// ['invoice.issued', 'invoice.cancelled', ...]

Transportation Invoices (CT-e)

Resource: nfe.transportationInvoices

Manage CT-e (Conhecimento de Transporte Eletrônico) documents via SEFAZ Distribuição DFe.

Note: This resource uses a separate API host (api.nfse.io). You can configure a specific API key with dataApiKey, or the SDK will use apiKey as fallback.

Prerequisites:

  • Company must be registered with a valid A1 digital certificate
  • Webhook must be configured to receive CT-e notifications

enable(companyId: string, options?: EnableTransportationInvoiceOptions): Promise<TransportationInvoiceInboundSettings>

Enable automatic CT-e search for a company.

// Enable with default settings
const settings = await nfe.transportationInvoices.enable('company-id');

// Enable starting from a specific NSU
const settings = await nfe.transportationInvoices.enable('company-id', {
startFromNsu: 12345
});

// Enable starting from a specific date
const settings = await nfe.transportationInvoices.enable('company-id', {
startFromDate: '2024-01-01T00:00:00Z'
});

Options:

PropertyTypeDescription
startFromNsunumberStart searching from this NSU number
startFromDatestringStart searching from this date (ISO 8601)

disable(companyId: string): Promise<TransportationInvoiceInboundSettings>

Disable automatic CT-e search for a company.

const settings = await nfe.transportationInvoices.disable('company-id');
console.log('Status:', settings.status); // 'Disabled'

getSettings(companyId: string): Promise<TransportationInvoiceInboundSettings>

Get current automatic CT-e search settings.

const settings = await nfe.transportationInvoices.getSettings('company-id');
console.log('Status:', settings.status);
console.log('Start NSU:', settings.startFromNsu);
console.log('Created:', settings.createdOn);

Response:

PropertyTypeDescription
statusstringCurrent status ('Active', 'Disabled', etc.)
startFromNsunumberStarting NSU number
startFromDatestringStarting date (if configured)
createdOnstringCreation timestamp
modifiedOnstringLast modification timestamp

retrieve(companyId: string, accessKey: string): Promise<TransportationInvoiceMetadata>

Retrieve CT-e metadata by its 44-digit access key.

const cte = await nfe.transportationInvoices.retrieve(
'company-id',
'35240112345678000190570010000001231234567890'
);
console.log('Sender:', cte.nameSender);
console.log('CNPJ:', cte.federalTaxNumberSender);
console.log('Amount:', cte.totalInvoiceAmount);
console.log('Issued:', cte.issuedOn);

Response:

PropertyTypeDescription
accessKeystring44-digit access key
typestringDocument type
statusstringDocument status
nameSenderstringSender company name
federalTaxNumberSenderstringSender CNPJ
totalInvoiceAmountnumberTotal invoice amount
issuedOnstringIssue date
receivedOnstringReceipt date

downloadXml(companyId: string, accessKey: string): Promise<string>

Download CT-e XML content.

const xml = await nfe.transportationInvoices.downloadXml(
'company-id',
'35240112345678000190570010000001231234567890'
);
fs.writeFileSync('cte.xml', xml);

getEvent(companyId: string, accessKey: string, eventKey: string): Promise<TransportationInvoiceMetadata>

Retrieve CT-e event metadata.

const event = await nfe.transportationInvoices.getEvent(
'company-id',
'35240112345678000190570010000001231234567890',
'event-key-123'
);
console.log('Event type:', event.type);
console.log('Event status:', event.status);

downloadEventXml(companyId: string, accessKey: string, eventKey: string): Promise<string>

Download CT-e event XML content.

const eventXml = await nfe.transportationInvoices.downloadEventXml(
'company-id',
'35240112345678000190570010000001231234567890',
'event-key-123'
);
fs.writeFileSync('cte-event.xml', eventXml);

Inbound Product Invoices (NF-e Distribuição)

Resource: nfe.inboundProductInvoices

Query NF-e (Nota Fiscal Eletrônica de Produto) documents received via SEFAZ Distribuição NF-e.

Note: This resource uses a separate API host (api.nfse.io). You can configure a specific API key with dataApiKey, or the SDK will use apiKey as fallback.

Prerequisites:

  • Company must be registered with a valid A1 digital certificate
  • Webhook must be configured to receive NF-e notifications

enableAutoFetch(companyId: string, options: EnableInboundOptions): Promise<InboundSettings>

Enable automatic NF-e inbound fetching for a company.

// Enable with production environment and webhook v2
const settings = await nfe.inboundProductInvoices.enableAutoFetch('company-id', {
environmentSEFAZ: 'Production',
webhookVersion: '2',
});

// Enable starting from a specific NSU
const settings = await nfe.inboundProductInvoices.enableAutoFetch('company-id', {
startFromNsu: '999999',
environmentSEFAZ: 'Production',
});

// Enable with automatic manifesting
const settings = await nfe.inboundProductInvoices.enableAutoFetch('company-id', {
environmentSEFAZ: 'Production',
automaticManifesting: { minutesToWaitAwarenessOperation: '30' },
});

Options:

PropertyTypeDescription
startFromNsustringStart searching from this NSU number
startFromDatestringStart searching from this date (ISO 8601)
environmentSEFAZstring | nullSEFAZ environment ('Production', etc.)
automaticManifestingAutomaticManifestingAuto-manifest configuration
webhookVersionstringWebhook version ('1' or '2')

disableAutoFetch(companyId: string): Promise<InboundSettings>

Disable automatic NF-e inbound fetching for a company.

const settings = await nfe.inboundProductInvoices.disableAutoFetch('company-id');
console.log('Status:', settings.status); // 'Inactive'

getSettings(companyId: string): Promise<InboundSettings>

Get current automatic NF-e inbound settings.

const settings = await nfe.inboundProductInvoices.getSettings('company-id');
console.log('Status:', settings.status);
console.log('Environment:', settings.environmentSEFAZ);
console.log('Webhook version:', settings.webhookVersion);
console.log('Start NSU:', settings.startFromNsu);

Response (InboundSettings):

PropertyTypeDescription
statusstringCurrent status ('Active', 'Inactive', etc.)
startFromNsustringStarting NSU number
startFromDatestringStarting date (if configured)
environmentSEFAZstring | nullSEFAZ environment
automaticManifestingAutomaticManifestingAuto-manifest configuration
webhookVersionstringWebhook version
companyIdstringCompany ID
createdOnstringCreation timestamp
modifiedOnstringLast modification timestamp

getDetails(companyId: string, accessKey: string): Promise<InboundInvoiceMetadata>

Retrieve NF-e metadata by 44-digit access key (webhook v1 format).

const nfeDoc = await nfe.inboundProductInvoices.getDetails(
'company-id',
'35240112345678000190550010000001231234567890'
);
console.log('Issuer:', nfeDoc.issuer?.name);
console.log('Amount:', nfeDoc.totalInvoiceAmount);
console.log('Issued:', nfeDoc.issuedOn);

getProductInvoiceDetails(companyId: string, accessKey: string): Promise<InboundProductInvoiceMetadata>

Retrieve NF-e metadata by 44-digit access key (webhook v2 format, recommended).

const nfeDoc = await nfe.inboundProductInvoices.getProductInvoiceDetails(
'company-id',
'35240112345678000190550010000001231234567890'
);
console.log('Issuer:', nfeDoc.issuer?.name);
console.log('Amount:', nfeDoc.totalInvoiceAmount);
console.log('Product invoices:', nfeDoc.productInvoices?.length);

Response (InboundInvoiceMetadata / InboundProductInvoiceMetadata):

PropertyTypeDescription
idstringDocument ID
accessKeystring44-digit access key
nsustringNSU number
nfeNumberstringNF-e number
issuerInboundIssuerIssuer information
buyerInboundBuyerBuyer information
totalInvoiceAmountstringTotal amount
issuedOnstringIssue date
descriptionstringDescription
linksInboundLinksXML/PDF download links
productInvoicesInboundProductInvoice[]Product invoices (v2 only)

getEventDetails(companyId: string, accessKey: string, eventKey: string): Promise<InboundInvoiceMetadata>

Retrieve NF-e event metadata (webhook v1 format).

const event = await nfe.inboundProductInvoices.getEventDetails(
'company-id',
'35240112345678000190550010000001231234567890',
'event-key-123'
);

getProductInvoiceEventDetails(companyId: string, accessKey: string, eventKey: string): Promise<InboundProductInvoiceMetadata>

Retrieve NF-e event metadata (webhook v2 format).

const event = await nfe.inboundProductInvoices.getProductInvoiceEventDetails(
'company-id',
'35240112345678000190550010000001231234567890',
'event-key-123'
);

getXml(companyId: string, accessKey: string): Promise<string>

Download NF-e XML content.

const xml = await nfe.inboundProductInvoices.getXml(
'company-id',
'35240112345678000190550010000001231234567890'
);
fs.writeFileSync('nfe.xml', xml);

getEventXml(companyId: string, accessKey: string, eventKey: string): Promise<string>

Download NF-e event XML content.

const eventXml = await nfe.inboundProductInvoices.getEventXml(
'company-id',
'35240112345678000190550010000001231234567890',
'event-key-123'
);
fs.writeFileSync('nfe-event.xml', eventXml);

getPdf(companyId: string, accessKey: string): Promise<string>

Download NF-e PDF (DANFE).

const pdf = await nfe.inboundProductInvoices.getPdf(
'company-id',
'35240112345678000190550010000001231234567890'
);

getJson(companyId: string, accessKey: string): Promise<InboundInvoiceMetadata>

Get NF-e data in JSON format.

const json = await nfe.inboundProductInvoices.getJson(
'company-id',
'35240112345678000190550010000001231234567890'
);

manifest(companyId: string, accessKey: string, tpEvent?: ManifestEventType): Promise<string>

Send a manifest event for an NF-e. Defaults to 210210 (Ciência da Operação).

// Ciência da Operação (default)
await nfe.inboundProductInvoices.manifest(
'company-id',
'35240112345678000190550010000001231234567890'
);

// Confirmação da Operação
await nfe.inboundProductInvoices.manifest(
'company-id',
'35240112345678000190550010000001231234567890',
210220
);

// Operação não Realizada
await nfe.inboundProductInvoices.manifest(
'company-id',
'35240112345678000190550010000001231234567890',
210240
);

Manifest Event Types:

CodeEvent
210210Ciência da Operação (awareness, default)
210220Confirmação da Operação (confirmation)
210240Operação não Realizada (operation not performed)

reprocessWebhook(companyId: string, accessKeyOrNsu: string): Promise<InboundProductInvoiceMetadata>

Reprocess a webhook notification by access key or NSU.

// By access key
await nfe.inboundProductInvoices.reprocessWebhook(
'company-id',
'35240112345678000190550010000001231234567890'
);

// By NSU
await nfe.inboundProductInvoices.reprocessWebhook(
'company-id',
'12345'
);

Product Invoice Query (Consulta NF-e)

Resource: nfe.productInvoiceQuery

Query NF-e (Nota Fiscal Eletrônica) product invoices directly on SEFAZ by access key. This is a read-only resource that does not require company scope.

Note: This resource uses a separate API host (nfe.api.nfe.io). You can configure a specific API key with dataApiKey, or the SDK will use apiKey as fallback.

retrieve(accessKey: string): Promise<ProductInvoiceDetails>

Retrieve full product invoice details from SEFAZ by access key.

const invoice = await nfe.productInvoiceQuery.retrieve(
'35240112345678000190550010000001231234567890'
);
console.log(invoice.currentStatus); // 'authorized'
console.log(invoice.issuer?.name);
console.log(invoice.totals?.icms?.invoiceAmount);

Parameters:

ParameterTypeRequiredDescription
accessKeystringYes44-digit numeric access key (Chave de Acesso)

Returns: ProductInvoiceDetails — Full invoice details including issuer, buyer, items, totals, transport, and payment.

Throws:

  • ValidationError if access key format is invalid
  • NotFoundError if no invoice matches the access key (HTTP 404)
  • AuthenticationError if API key is invalid (HTTP 401)

downloadPdf(accessKey: string): Promise<Buffer>

Download the DANFE PDF for a product invoice.

const pdfBuffer = await nfe.productInvoiceQuery.downloadPdf(
'35240112345678000190550010000001231234567890'
);
fs.writeFileSync('danfe.pdf', pdfBuffer);

Parameters:

ParameterTypeRequiredDescription
accessKeystringYes44-digit numeric access key

Returns: Buffer containing the PDF binary content.

downloadXml(accessKey: string): Promise<Buffer>

Download the raw NF-e XML for a product invoice.

const xmlBuffer = await nfe.productInvoiceQuery.downloadXml(
'35240112345678000190550010000001231234567890'
);
fs.writeFileSync('nfe.xml', xmlBuffer);

Parameters:

ParameterTypeRequiredDescription
accessKeystringYes44-digit numeric access key

Returns: Buffer containing the XML binary content.

listEvents(accessKey: string): Promise<ProductInvoiceEventsResponse>

List fiscal events (cancellations, corrections, manifestations) for a product invoice.

const result = await nfe.productInvoiceQuery.listEvents(
'35240112345678000190550010000001231234567890'
);
for (const event of result.events ?? []) {
console.log(event.description, event.authorizedOn);
}

Parameters:

ParameterTypeRequiredDescription
accessKeystringYes44-digit numeric access key

Returns: ProductInvoiceEventsResponse with an array of fiscal events and query timestamp.


Consumer Invoice Query (Consulta CFe-SAT)

Resource: nfe.consumerInvoiceQuery

Query CFe-SAT (Cupom Fiscal Eletrônico) consumer invoices by access key. This is a read-only resource that does not require company scope.

Note: This resource uses a separate API host (nfe.api.nfe.io). You can configure a specific API key with dataApiKey, or the SDK will use apiKey as fallback.

retrieve(accessKey: string): Promise<TaxCoupon>

Retrieve full CFe-SAT coupon details by access key.

const coupon = await nfe.consumerInvoiceQuery.retrieve(
'35240112345678000190590000000012341234567890'
);
console.log(coupon.currentStatus); // 'Authorized'
console.log(coupon.issuer?.name);
console.log(coupon.totals?.couponAmount);

Parameters:

ParameterTypeRequiredDescription
accessKeystringYes44-digit numeric access key (Chave de Acesso)

Returns: TaxCoupon — Full coupon details including issuer, buyer, items, totals, and payment.

Throws:

  • ValidationError if access key format is invalid
  • NotFoundError if no coupon matches the access key (HTTP 404)
  • AuthenticationError if API key is invalid (HTTP 401)

downloadXml(accessKey: string): Promise<Buffer>

Download the raw CFe XML for a consumer invoice.

const xmlBuffer = await nfe.consumerInvoiceQuery.downloadXml(
'35240112345678000190590000000012341234567890'
);
fs.writeFileSync('cfe.xml', xmlBuffer);

Parameters:

ParameterTypeRequiredDescription
accessKeystringYes44-digit numeric access key

Returns: Buffer containing the XML binary content.


Resource: nfe.legalEntityLookup

Query Brazilian company (CNPJ) data from Receita Federal and state tax registries (SEFAZ). This is a read-only resource that does not require company scope.

Note: This resource uses a separate API host (legalentity.api.nfe.io). You can configure a specific API key with dataApiKey, or the SDK will use apiKey as fallback.

getBasicInfo(federalTaxNumber: string, options?: LegalEntityBasicInfoOptions): Promise<LegalEntityBasicInfoResponse>

Lookup basic company information by CNPJ from Receita Federal. Returns legal name, trade name, address, phone numbers, economic activities (CNAE), legal nature, partners, and registration status.

const result = await nfe.legalEntityLookup.getBasicInfo('12.345.678/0001-90');
console.log(result.legalEntity?.name); // 'EMPRESA LTDA'
console.log(result.legalEntity?.status); // 'Active'
console.log(result.legalEntity?.address?.city?.name);

// With options
const result = await nfe.legalEntityLookup.getBasicInfo('12345678000190', {
updateAddress: false,
updateCityCode: true,
});

Parameters:

ParameterTypeRequiredDescription
federalTaxNumberstringYesCNPJ, with or without punctuation (e.g., "12345678000190" or "12.345.678/0001-90")
optionsLegalEntityBasicInfoOptionsNoLookup options

Options:

PropertyTypeDefaultDescription
updateAddressbooleantrueUpdate address from postal service data
updateCityCodebooleanfalseUpdate only the city IBGE code when updateAddress is false

Returns: LegalEntityBasicInfoResponse — Company basic information including address, phones, activities, partners.

Throws:

  • ValidationError if CNPJ format is invalid (not 14 digits after stripping punctuation)
  • NotFoundError if no company found for the given CNPJ (HTTP 404)
  • AuthenticationError if API key is invalid (HTTP 401)

getStateTaxInfo(state: string, federalTaxNumber: string): Promise<LegalEntityStateTaxResponse>

Lookup state tax registration (Inscrição Estadual) by CNPJ and state. Returns tax regime, legal nature, and state tax registration details including fiscal document indicators (NFe, NFSe, CTe, NFCe).

const result = await nfe.legalEntityLookup.getStateTaxInfo('SP', '12345678000190');
console.log(result.legalEntity?.taxRegime); // 'SimplesNacional'

for (const tax of result.legalEntity?.stateTaxes ?? []) {
console.log(`IE: ${tax.taxNumber} — Status: ${tax.status}`);
console.log(` NFe: ${tax.nfe?.status}, NFSe: ${tax.nfse?.status}`);
}

Parameters:

ParameterTypeRequiredDescription
statestringYesBrazilian state code (e.g., "SP", "RJ", "MG"). Case-insensitive.
federalTaxNumberstringYesCNPJ, with or without punctuation

Returns: LegalEntityStateTaxResponse — State tax registration information.

Throws:

  • ValidationError if state code is invalid or CNPJ format is invalid
  • AuthenticationError if API key is invalid (HTTP 401)

getStateTaxForInvoice(state: string, federalTaxNumber: string): Promise<LegalEntityStateTaxForInvoiceResponse>

Evaluate state tax registration for invoice issuance. Returns extended status information (including UnabledTemp, UnabledNotConfirmed) useful for determining whether product invoices (NF-e) can be issued.

const result = await nfe.legalEntityLookup.getStateTaxForInvoice('MG', '12345678000190');
for (const tax of result.legalEntity?.stateTaxes ?? []) {
if (tax.status === 'Abled') {
console.log(`Can issue invoices with IE: ${tax.taxNumber}`);
}
}

Parameters:

ParameterTypeRequiredDescription
statestringYesBrazilian state code. Case-insensitive.
federalTaxNumberstringYesCNPJ, with or without punctuation

Returns: LegalEntityStateTaxForInvoiceResponse — State tax data with extended status for invoice evaluation.

Throws:

  • ValidationError if state code is invalid or CNPJ format is invalid
  • AuthenticationError if API key is invalid (HTTP 401)

getSuggestedStateTaxForInvoice(state: string, federalTaxNumber: string): Promise<LegalEntityStateTaxForInvoiceResponse>

Get the best (suggested) state tax registration for invoice issuance. When multiple registrations are enabled in a state, NFE.io applies evaluation criteria to recommend the optimal IE.

const result = await nfe.legalEntityLookup.getSuggestedStateTaxForInvoice('SP', '12345678000190');
const bestIE = result.legalEntity?.stateTaxes?.[0];
if (bestIE) {
console.log(`Recommended IE: ${bestIE.taxNumber} (${bestIE.status})`);
}

Parameters:

ParameterTypeRequiredDescription
statestringYesBrazilian state code. Case-insensitive.
federalTaxNumberstringYesCNPJ, with or without punctuation

Returns: LegalEntityStateTaxForInvoiceResponse — Suggested state tax data prioritized by NFE.io criteria.

Throws:

  • ValidationError if state code is invalid or CNPJ format is invalid
  • AuthenticationError if API key is invalid (HTTP 401)

Types

type BrazilianState =
| 'AC' | 'AL' | 'AM' | 'AP' | 'BA' | 'CE' | 'DF' | 'ES' | 'GO'
| 'MA' | 'MG' | 'MS' | 'MT' | 'PA' | 'PB' | 'PE' | 'PI' | 'PR'
| 'RJ' | 'RN' | 'RO' | 'RR' | 'RS' | 'SC' | 'SE' | 'SP' | 'TO'
| 'EX' | 'NA';

interface LegalEntityBasicInfoOptions {
updateAddress?: boolean;
updateCityCode?: boolean;
}

interface LegalEntityBasicInfoResponse {
legalEntity?: LegalEntityBasicInfo;
}

interface LegalEntityBasicInfo {
tradeName?: string;
name?: string;
federalTaxNumber?: number;
size?: 'Unknown' | 'ME' | 'EPP' | 'DEMAIS';
openedOn?: string;
address?: LegalEntityAddress;
phones?: LegalEntityPhone[];
status?: 'Unknown' | 'Active' | 'Suspended' | 'Cancelled' | 'Unabled' | 'Null';
email?: string;
shareCapital?: number;
economicActivities?: LegalEntityEconomicActivity[];
legalNature?: LegalEntityNature;
partners?: LegalEntityPartner[];
unit?: 'Headoffice' | 'Subsidiary';
// ... and more fields
}

interface LegalEntityStateTaxResponse {
legalEntity?: LegalEntityStateTaxInfo;
}

interface LegalEntityStateTaxForInvoiceResponse {
legalEntity?: LegalEntityStateTaxForInvoiceInfo;
}

interface LegalEntityStateTax {
status?: 'Abled' | 'Unabled' | 'Cancelled' | 'Unknown';
taxNumber?: string;
code?: BrazilianState;
nfe?: LegalEntityFiscalDocumentInfo;
nfse?: LegalEntityFiscalDocumentInfo;
cte?: LegalEntityFiscalDocumentInfo;
nfce?: LegalEntityFiscalDocumentInfo;
// ... and more fields
}

interface LegalEntityStateTaxForInvoice {
status?: 'Abled' | 'Unabled' | 'Cancelled' | 'UnabledTemp' | 'UnabledNotConfirmed'
| 'Unknown' | 'UnknownTemp' | 'UnknownNotConfirmed';
taxNumber?: string;
// ... same structure as LegalEntityStateTax with extended status
}

See src/core/types.ts for the complete type definitions.


Natural Person Lookup (Consulta CPF)

Resource: nfe.naturalPersonLookup API Host: naturalperson.api.nfe.io Authentication: Uses dataApiKey (falls back to apiKey)

Lookup CPF cadastral status (situação cadastral) at the Brazilian Federal Revenue Service (Receita Federal).

getStatus(federalTaxNumber: string, birthDate: string | Date): Promise<NaturalPersonStatusResponse>

Query the cadastral status of a CPF, returning the person's name, CPF, birth date, status, and query timestamp.

// With string date
const result = await nfe.naturalPersonLookup.getStatus('123.456.789-01', '1990-01-15');
console.log(result.name); // 'JOÃO DA SILVA'
console.log(result.status); // 'Regular'

// With Date object
const result = await nfe.naturalPersonLookup.getStatus('12345678901', new Date(1990, 0, 15));

Parameters:

ParameterTypeRequiredDescription
federalTaxNumberstringYesCPF number, with or without punctuation (e.g., "12345678901" or "123.456.789-01")
birthDatestring | DateYesDate of birth in YYYY-MM-DD format or a Date object

Returns: NaturalPersonStatusResponse — CPF cadastral status data.

Throws:

  • ValidationError if CPF format is invalid (not 11 digits) or birth date format is invalid
  • NotFoundError if CPF is not found or birth date does not match (HTTP 404)
  • AuthenticationError if API key is invalid (HTTP 401)

Types

type NaturalPersonStatus =
| 'Regular'
| 'Suspensa'
| 'Cancelada'
| 'Titular Falecido'
| 'Pendente de Regularização'
| 'Nula'
| (string & {});

interface NaturalPersonStatusResponse {
name?: string;
federalTaxNumber: string;
birthOn?: string;
status?: NaturalPersonStatus;
createdOn?: string;
}

See src/core/types.ts for the complete type definitions.


Tax Calculation (Cálculo de Impostos)

Resource: nfe.taxCalculation API Host: api.nfse.io Authentication: Uses dataApiKey (falls back to apiKey)

Compute all applicable Brazilian taxes (ICMS, ICMS-ST, PIS, COFINS, IPI, II) for product operations using the Tax Calculation Engine (Motor de Cálculo de Tributos).

calculate(tenantId: string, request: CalculateRequest): Promise<CalculateResponse>

Submit an operation with issuer, recipient, operation type, and product items to compute per-item tax breakdowns.

const result = await nfe.taxCalculation.calculate('tenant-id', {
operationType: 'Outgoing',
issuer: { state: 'SP', taxRegime: 'RealProfit' },
recipient: { state: 'RJ' },
items: [{
id: 'item-1',
operationCode: 121,
origin: 'National',
ncm: '61091000',
quantity: 10,
unitAmount: 100.00
}]
});

for (const item of result.items ?? []) {
console.log(`Item ${item.id}: CFOP ${item.cfop}`);
console.log(` ICMS CST: ${item.icms?.cst}, value: ${item.icms?.vICMS}`);
}

Parameters:

ParameterTypeRequiredDescription
tenantIdstringYesSubscription/account ID that scopes the tax rules
requestCalculateRequestYesTax calculation request payload

Returns: CalculateResponse — Per-item tax breakdowns including CFOP, ICMS, PIS, COFINS, IPI, II.

Throws:

  • ValidationError if tenantId is empty
  • ValidationError if required fields are missing (issuer, recipient, operationType, items)
  • AuthenticationError if API key is invalid (HTTP 401)
  • BadRequestError if the API rejects the payload (HTTP 400)

Types

type TaxOperationType = 'Outgoing' | 'Incoming';

type TaxOrigin =
| 'National' | 'ForeignDirectImport' | 'ForeignInternalMarket'
| 'NationalWith40To70Import' | 'NationalPpb' | 'NationalWithLess40Import'
| 'ForeignDirectImportWithoutNationalSimilar'
| 'ForeignInternalMarketWithoutNationalSimilar'
| 'NationalWithGreater70Import';

type TaxCalcTaxRegime =
| 'NationalSimple' | 'RealProfit' | 'PresumedProfit'
| 'NationalSimpleSublimitExceeded' | 'IndividualMicroEnterprise' | 'Exempt';

interface CalculateRequest {
collectionId?: string;
issuer: CalculateRequestIssuer; // required: state, taxRegime
recipient: CalculateRequestRecipient; // required: state
operationType: TaxOperationType;
items: CalculateItemRequest[]; // required: id, operationCode, origin, quantity, unitAmount
isProductRegistration?: boolean;
}

interface CalculateResponse {
items?: CalculateItemResponse[]; // per-item: cfop, icms, pis, cofins, ipi, ii, icmsUfDest
}

See src/core/types.ts for the complete type definitions including all tax component interfaces (TaxIcms, TaxPis, TaxCofins, TaxIpi, TaxIi, TaxIcmsUfDest).


Tax Codes (Códigos Auxiliares)

Resource: nfe.taxCodes API Host: api.nfse.io Authentication: Uses dataApiKey (falls back to apiKey)

Paginated listings of auxiliary tax code reference tables needed as inputs for the Tax Calculation Engine.

listOperationCodes(options?: TaxCodeListOptions): Promise<TaxCodePaginatedResponse>

List operation codes (natureza de operação) — e.g., 121 = "Venda de mercadoria".

const result = await nfe.taxCodes.listOperationCodes({ pageIndex: 1, pageCount: 20 });
console.log(`Total: ${result.totalCount}, Page ${result.currentPage} of ${result.totalPages}`);
for (const code of result.items ?? []) {
console.log(`${code.code} - ${code.description}`);
}

listAcquisitionPurposes(options?: TaxCodeListOptions): Promise<TaxCodePaginatedResponse>

List acquisition purposes (finalidade de aquisição).

listIssuerTaxProfiles(options?: TaxCodeListOptions): Promise<TaxCodePaginatedResponse>

List issuer tax profiles (perfil fiscal do emissor).

listRecipientTaxProfiles(options?: TaxCodeListOptions): Promise<TaxCodePaginatedResponse>

List recipient tax profiles (perfil fiscal do destinatário).

All methods accept:

ParameterTypeRequiredDescription
options.pageIndexnumberNoPage index, 1-based (default: 1)
options.pageCountnumberNoItems per page (default: 50)

Returns: TaxCodePaginatedResponse — Paginated list of tax codes.

Types

interface TaxCode {
code?: string;
description?: string;
}

interface TaxCodePaginatedResponse {
items?: TaxCode[];
currentPage?: number;
totalPages?: number;
totalCount?: number;
}

interface TaxCodeListOptions {
pageIndex?: number;
pageCount?: number;
}

See src/core/types.ts for the complete type definitions.


Product Invoices (NF-e Emissão)

Resource: nfe.productInvoices API Host: api.nfse.io Authentication: Uses dataApiKey (falls back to apiKey)

Full lifecycle management for NF-e (Nota Fiscal Eletrônica de Produto) product invoices — issue, list, retrieve, cancel, send correction letters (CC-e), disable invoice numbers, and download files (PDF/XML).

Important: Issue, cancel, correction letter, and disablement operations are asynchronous — they return 202/204 indicating the request was enqueued. Completion is notified via webhooks.

create(companyId, data): Promise<NfeProductInvoiceIssueData>

Issue a product invoice (NF-e) by posting it to the processing queue.

const result = await nfe.productInvoices.create('company-id', {
operationNature: 'Venda de mercadoria',
operationType: 'Outgoing',
buyer: { name: 'Empresa LTDA', federalTaxNumber: 12345678000190 },
items: [{ code: 'PROD-001', description: 'Produto X', quantity: 1, unitAmount: 100 }],
payment: [{ paymentDetail: [{ method: 'Cash', amount: 100 }] }],
});

createWithStateTax(companyId, stateTaxId, data): Promise<NfeProductInvoiceIssueData>

Issue an NF-e specifying a particular state tax registration (Inscrição Estadual).

const result = await nfe.productInvoices.createWithStateTax('company-id', 'state-tax-id', invoiceData);

list(companyId, options): Promise<NfeProductInvoiceListResponse>

List product invoices with cursor-based pagination. The environment option is required.

const invoices = await nfe.productInvoices.list('company-id', {
environment: 'Production', // Required: 'Production' or 'Test'
limit: 10, // Optional (default: 10)
startingAfter: 'cursor-id', // Optional: cursor-based pagination
q: "buyer.name:'EMPRESA'", // Optional: ElasticSearch query
});
for (const inv of invoices.productInvoices ?? []) {
console.log(inv.id, inv.status);
}

retrieve(companyId, invoiceId): Promise<NfeProductInvoice>

Retrieve full details of a single NF-e invoice.

const invoice = await nfe.productInvoices.retrieve('company-id', 'invoice-id');
console.log(invoice.status, invoice.authorization?.accessKey);

cancel(companyId, invoiceId, reason?): Promise<NfeRequestCancellationResource>

Cancel a product invoice (asynchronous — enqueues for cancellation).

const result = await nfe.productInvoices.cancel('company-id', 'invoice-id', 'Erro de digitação');

listItems(companyId, invoiceId, options?): Promise<NfeInvoiceItemsResponse>

List items (products/services) for a specific invoice.

const items = await nfe.productInvoices.listItems('company-id', 'invoice-id', { limit: 20 });

listEvents(companyId, invoiceId, options?): Promise<NfeProductInvoiceEventsResponse>

List fiscal events for a specific invoice.

const events = await nfe.productInvoices.listEvents('company-id', 'invoice-id');

downloadPdf(companyId, invoiceId, force?): Promise<NfeFileResource>

Get the URL for the DANFE PDF file.

const pdf = await nfe.productInvoices.downloadPdf('company-id', 'invoice-id');
console.log('PDF URL:', pdf.uri);

// Force regeneration
const pdfForced = await nfe.productInvoices.downloadPdf('company-id', 'invoice-id', true);

downloadXml(companyId, invoiceId): Promise<NfeFileResource>

Get the URL for the authorized NF-e XML file.

const xml = await nfe.productInvoices.downloadXml('company-id', 'invoice-id');
console.log('XML URL:', xml.uri);

downloadRejectionXml(companyId, invoiceId): Promise<NfeFileResource>

Get the URL for the NF-e rejection XML (uses /xml-rejection canonical path).

downloadEpecXml(companyId, invoiceId): Promise<NfeFileResource>

Get the URL for the contingency authorization (EPEC) XML.

sendCorrectionLetter(companyId, invoiceId, reason): Promise<NfeRequestCancellationResource>

Send a correction letter (Carta de Correção — CC-e). The reason must be 15–1,000 characters.

const result = await nfe.productInvoices.sendCorrectionLetter(
'company-id',
'invoice-id',
'Correcao do endereco do destinatario conforme novo cadastro'
);

downloadCorrectionLetterPdf(companyId, invoiceId): Promise<NfeFileResource>

Get the URL for the CC-e DANFE PDF.

downloadCorrectionLetterXml(companyId, invoiceId): Promise<NfeFileResource>

Get the URL for the CC-e XML.

disable(companyId, invoiceId, reason?): Promise<NfeRequestCancellationResource>

Disable (inutilizar) a specific product invoice by ID.

await nfe.productInvoices.disable('company-id', 'invoice-id', 'Numeração inutilizada');

disableRange(companyId, data): Promise<NfeDisablementResource>

Disable a range of invoice numbers.

const result = await nfe.productInvoices.disableRange('company-id', {
environment: 'Production',
serie: 1,
state: 'SP',
beginNumber: 100,
lastNumber: 110,
reason: 'Faixa de numeração inutilizada',
});

Parameters common to sub-list methods (listItems, listEvents):

ParameterTypeRequiredDescription
options.limitnumberNoItems per page (default: 10)
options.startingAfternumberNoCursor for pagination

State Taxes (Inscrições Estaduais)

Resource: nfe.stateTaxes API Host: api.nfse.io Authentication: Uses dataApiKey (falls back to apiKey)

CRUD operations for company state tax registrations (Inscrições Estaduais). State taxes define the series, numbering, environment, and state code configuration required for NF-e issuance.

list(companyId, options?): Promise<NfeStateTaxListResponse>

List all state tax registrations for a company.

const result = await nfe.stateTaxes.list('company-id');
for (const tax of result.stateTaxes ?? []) {
console.log(tax.id, tax.taxNumber, tax.code, tax.serie, tax.status);
}

create(companyId, data): Promise<NfeStateTax>

Create a new state tax registration. Body is automatically wrapped as { stateTax: data }.

const tax = await nfe.stateTaxes.create('company-id', {
taxNumber: '123456789',
serie: 1,
number: 1,
code: 'sP',
environmentType: 'production',
type: 'nFe',
});
console.log('Created:', tax.id);

retrieve(companyId, stateTaxId): Promise<NfeStateTax>

Retrieve a specific state tax registration by ID.

const tax = await nfe.stateTaxes.retrieve('company-id', 'state-tax-id');

update(companyId, stateTaxId, data): Promise<NfeStateTax>

Update an existing state tax registration. Body is automatically wrapped as { stateTax: data }.

const updated = await nfe.stateTaxes.update('company-id', 'state-tax-id', {
serie: 2,
environmentType: 'test',
});

delete(companyId, stateTaxId): Promise<void>

Delete a state tax registration.

await nfe.stateTaxes.delete('company-id', 'state-tax-id');

Types

type NfeStateTaxType = 'default' | 'nFe' | 'nFCe';
type NfeStateTaxEnvironmentType = 'none' | 'production' | 'test';
type NfeStateTaxStatus = 'inactive' | 'none' | 'active';

interface NfeStateTax {
id?: string;
companyId?: string;
accountId?: string;
code?: NfeStateTaxStateCode;
environmentType?: NfeStateTaxEnvironmentType;
taxNumber?: string;
serie?: number;
number?: number;
status?: NfeStateTaxStatus;
specialTaxRegime?: string;
securityCredential?: NfeStateTaxSecurityCredential;
type?: NfeStateTaxType;
series?: NfeStateTaxSeries[];
batchId?: string;
createdOn?: string;
modifiedOn?: string;
}

See src/core/types.ts for the complete type definitions.


Types

Core Types

interface NfeConfig {
apiKey?: string;
dataApiKey?: string; // API key for data/query services (Addresses, CT-e, CNPJ, CPF)
environment?: 'production' | 'development';
baseUrl?: string;
timeout?: number;
retryConfig?: RetryConfig;
}

interface RetryConfig {
maxRetries?: number;
baseDelay?: number;
maxDelay?: number;
retryableStatuses?: number[];
}

interface PaginationOptions {
pageCount?: number;
pageIndex?: number;
}

interface PollOptions {
maxAttempts?: number;
intervalMs?: number;
}

interface ListResponse<T> {
items: T[];
totalCount: number;
pageIndex: number;
pageCount: number;
}

Entity Types

interface Company {
id: string;
name: string;
federalTaxNumber: string;
email: string;
address: Address;
// ... other fields
}

interface ServiceInvoice {
id: string;
number?: string;
status: ServiceInvoiceStatus;
borrower: ServiceInvoiceBorrower;
cityServiceCode: string;
servicesAmount: number;
// ... other fields
}

interface LegalPerson {
id: string;
name: string;
federalTaxNumber: string; // CNPJ
email?: string;
// ... other fields
}

interface NaturalPerson {
id: string;
name: string;
federalTaxNumber: string; // CPF
email?: string;
// ... other fields
}

interface Webhook {
id: string;
url: string;
events: string[];
secret?: string;
active: boolean;
// ... other fields
}

interface Address {
country: string;
postalCode: string;
street: string;
number: string;
additionalInformation?: string;
district?: string;
city: City;
state: string;
}

interface City {
code: string;
name: string;
}

type ServiceInvoiceStatus =
| 'pending'
| 'issued'
| 'cancelled'
| 'error';

Error Handling

The SDK uses a comprehensive error hierarchy:

import { 
NfeError,
AuthenticationError,
ValidationError,
NotFoundError,
RateLimitError,
ServerError,
ConnectionError,
TimeoutError,
PollingTimeoutError,
isNfeError,
isAuthenticationError
} from 'nfe-io';

Error Types

Error ClassHTTP StatusDescription
AuthenticationError401Invalid API key
ValidationError400, 422Request validation failed
NotFoundError404Resource not found
ConflictError409Resource conflict
RateLimitError429Rate limit exceeded
ServerError500, 502, 503Server error
ConnectionError-Network/connection failure
TimeoutError408Request timeout
PollingTimeoutError-Polling exceeded max attempts

Error Handling Example

import { 
AuthenticationError,
ValidationError,
NotFoundError,
isNfeError
} from 'nfe-io';

try {
const invoice = await nfe.serviceInvoices.create(companyId, data);
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Invalid API key');
} else if (error instanceof ValidationError) {
console.error('Validation errors:', error.details);
} else if (error instanceof NotFoundError) {
console.error('Company not found');
} else if (isNfeError(error)) {
console.error('NFE.io error:', error.message);
} else {
console.error('Unexpected error:', error);
}
}

Error Properties

All NFE.io errors extend NfeError and include:

class NfeError extends Error {
type: ErrorType;
statusCode?: number;
details?: any;
requestId?: string;
}

Advanced Usage

Custom Retry Logic

const nfe = new NfeClient({
apiKey: 'your-api-key',
retryConfig: {
maxRetries: 5,
baseDelay: 2000,
maxDelay: 60000,
retryableStatuses: [408, 429, 500, 502, 503, 504]
}
});

Async Invoice Processing

NFE.io uses async processing for invoices (202 responses). The SDK provides two approaches:

Manual Polling:

const result = await nfe.serviceInvoices.create(companyId, data);

if (result.status === 'pending') {
const invoice = await nfe.pollUntilComplete(result.location, {
maxAttempts: 60,
intervalMs: 3000
});
console.log('Invoice issued:', invoice.number);
} else {
console.log('Invoice issued immediately:', result.number);
}

Automatic Polling (Recommended):

const invoice = await nfe.serviceInvoices.createAndWait(companyId, data, {
maxAttempts: 30,
interval: 2000
});

console.log('Invoice issued:', invoice.number);

Environment Detection

import { isEnvironmentSupported, getRuntimeInfo } from 'nfe-io';

// Check environment compatibility
const support = isEnvironmentSupported();
if (!support.supported) {
console.error('Environment issues:', support.issues);
}

// Get runtime information
const info = getRuntimeInfo();
console.log('SDK Version:', info.sdkVersion);
console.log('Node Version:', info.nodeVersion);
console.log('Platform:', info.platform);

Quick Start Helpers

import { createClientFromEnv, validateApiKeyFormat } from 'nfe-io';

// Create client from environment variable
// Requires NFE_API_KEY environment variable
const nfe = createClientFromEnv('production');

// Validate API key format
const validation = validateApiKeyFormat('my-api-key');
if (!validation.valid) {
console.error('API key issues:', validation.issues);
}

TypeScript Support

The SDK is fully typed with TypeScript:

import type {
NfeConfig,
ServiceInvoice,
ServiceInvoiceData,
Company,
LegalPerson,
NaturalPerson,
Webhook,
ListResponse,
PaginationOptions,
InboundInvoiceMetadata,
InboundProductInvoiceMetadata,
InboundSettings,
EnableInboundOptions,
ManifestEventType
} from 'nfe-io';

const config: NfeConfig = {
apiKey: 'your-api-key',
environment: 'production'
};

const invoice: ServiceInvoice = await nfe.serviceInvoices.retrieve(
'company-id',
'invoice-id'
);

Extension Development

The SDK is designed to be extensible. See CONTRIBUTING.md for guidance on:

  • Creating MCP (Model Context Protocol) integrations
  • Building n8n workflow nodes
  • Developing custom adapters
  • Extending the HTTP client

Example: Custom Resource Extension

import { HttpClient } from 'nfe-io/core/http/client';

class CustomResource {
constructor(private http: HttpClient) {}

async customMethod(id: string): Promise<any> {
return this.http.get(`/custom/${id}`);
}
}

// Extend NfeClient
import { NfeClient } from 'nfe-io';

class ExtendedNfeClient extends NfeClient {
public readonly custom: CustomResource;

constructor(config: NfeConfig) {
super(config);
this.custom = new CustomResource(this.http);
}
}

Support

License

MIT License - see LICENSE for details

NFE.io

A NFE.io é uma empresa de tecnologia que fornece soluções para automatizar e simplificar a emissão e gestão de notas fiscais eletrônicas. Com suas ferramentas, as empresas podem economizar tempo e reduzir erros, aumentando a eficiência e precisão do processo de emissão de notas fiscais.

Um dos principais cases de sucesso da NFE.io é a implementação da solução na empresa de transporte Rodonaves. Com a automatização da emissão e gestão de notas fiscais eletrônicas, a Rodonaves conseguiu reduzir em até 80% o tempo gasto nesse processo, o que se traduziu em uma significativa melhoria na eficiência operacional. Além disso, a empresa também conseguiu eliminar erros e atrasos na emissão de notas fiscais, o que melhorou a relação com seus clientes e aumentou a confiança dos órgãos fiscais.

Outro exemplo é a implementação da NFE.io na empresa de comércio eletrônico, a Loja Integrada. Com a automatização da emissão de notas fiscais, a Loja Integrada conseguiu aumentar a velocidade de emissão de notas em até 10 vezes, o que permitiu que a empresa atendesse a uma maior quantidade de clientes e, consequentemente, aumentar as suas vendas.

Além desses exemplos, a NFE.io também tem outros cases de sucesso com empresas de setores como indústria, construção, varejo e serviços, mostrando a versatilidade e eficácia da sua solução.

Em resumo, a NFE.io é uma empresa de tecnologia que oferece soluções para automatizar e simplificar a emissão e gestão de notas fiscais eletrônicas, ajudando as empresas a economizar tempo e reduzir erros, melhorando a eficiência e precisão do processo. Com cases de sucesso em diferentes setores, a NFE.io tem se destacado como uma empresa líder em automação fiscal.