# 📘 Guia de Integração - API de Emissão de NF-e

**Versão:** 1.3.0
**Última atualização:** 09/10/2025
**Desenvolvido por:** Systhema Tecnologia

---

## 📋 Índice

1. [Visão Geral](#-visão-geral)
2. [Requisitos](#-requisitos)
3. [Autenticação](#-autenticação)
4. [Endpoints Disponíveis](#-endpoints-disponíveis)
5. [Estrutura de Dados](#-estrutura-de-dados)
6. [Regras de Negócio Automáticas](#-regras-de-negócio-automáticas)
7. [Exemplos de Integração](#-exemplos-de-integração)
8. [Códigos de Resposta](#-códigos-de-resposta)
9. [Erros Comuns e Soluções](#-erros-comuns-e-soluções)
10. [Boas Práticas](#-boas-práticas)
11. [Suporte](#-suporte)

---

## 🎯 Visão Geral

API REST para emissão e gerenciamento de Notas Fiscais Eletrônicas (NF-e) homologadas pela SEFAZ em **ambiente de produção**.

### Características Principais

- ✅ Emissão de NF-e em produção (SEFAZ real)
- ✅ Cancelamento de NF-e
- ✅ Geração automática de DANFE (PDF)
- ✅ Suporte completo a CPF (Pessoa Física) e CNPJ (Pessoa Jurídica)
- ✅ Detecção automática de consumidor final
- ✅ Configuração automática de indIEDest e indFinal
- ✅ Assinatura digital com certificado A1
- ✅ API REST com JSON

### URL Base

```
http://seu-dominio.com.br/pontti_nfe
```

---

## 📋 Requisitos

### Requisitos do Servidor
- PHP 8.2 ou superior
- Extensões PHP: `openssl`, `soap`, `xml`, `curl`, `mbstring`
- Certificado Digital A1 (.pfx) válido

### Requisitos da Integração
- Suporte a requisições HTTP/HTTPS
- Capacidade de enviar JSON no body
- Capacidade de processar respostas JSON

---

## 🔐 Autenticação

**Versão atual:** Sem autenticação (recomendado apenas em rede interna ou VPN)

**Próximas versões:** Suporte a API Key e OAuth2

### Segurança Recomendada
- Use HTTPS em produção
- Restrinja acesso por IP (firewall)
- Implemente rate limiting no seu lado
- Monitore logs de acesso

---

## 📡 Endpoints Disponíveis

### 1. Emitir NF-e

Emite uma Nota Fiscal Eletrônica na SEFAZ.

**Endpoint:** `POST /api/nfe/emitir.php`

**Headers:**
```http
Content-Type: application/json
```

**Método:** `POST`

**Timeout recomendado:** 60 segundos (SEFAZ pode demorar)

---

### 2. Cancelar NF-e

Cancela uma Nota Fiscal Eletrônica previamente autorizada, gerando automaticamente XML e PDF do cancelamento.

**Endpoint:** `POST /api/nfe/cancelar.php`

**Headers:**
```http
Content-Type: application/json
```

**Método:** `POST`

**Timeout recomendado:** 60 segundos

**Quando usar:**
- Cliente solicitou cancelamento
- Erro no pedido ou duplicação
- Necessidade de anular a operação

**Requisitos:**
- NF-e deve estar autorizada
- **Prazo:** Até 24 horas após emissão (regra SEFAZ)
- Justificativa válida (mínimo 15 caracteres)

**Arquivos gerados automaticamente:**
- ✅ XML do cancelamento (procEventoNFe)
- ✅ PDF do cancelamento (visualização do evento)

---

### 3. Inutilizar Numeração de NF-e

Inutiliza uma faixa de numeração de NF-e que não foi utilizada (quebra de sequência).

**Endpoint:** `POST /api/nfe/inutilizar.php`

**Headers:**
```http
Content-Type: application/json
```

**Método:** `POST`

**Quando usar:** Quando houver quebra na sequência de numeração (ex: emitiu nota 100, depois 102, precisa inutilizar a 101)

---

### 4. Carta de Correção Eletrônica (CC-e)

Envia uma Carta de Correção Eletrônica para corrigir erros em uma NF-e já autorizada.

**Endpoint:** `POST /api/nfe/carta-correcao.php`

**Headers:**
```http
Content-Type: application/json
```

**Método:** `POST`

**Quando usar:** Para corrigir pequenos erros em NF-e já autorizada (dados cadastrais, descrições, etc)

**Limitações:** Não pode corrigir valores, impostos, quantidade ou itens. Apenas correções textuais.

**Prazo:** Ilimitado (pode corrigir a qualquer momento)

---

### 5. Verificar Status

Verifica se a API está online e conectada com a SEFAZ.

**Endpoint:** `GET /status.php`

**Método:** `GET`

**Resposta:**
```json
{
  "status": "online",
  "ambiente": "producao",
  "sefaz": "conectado",
  "timestamp": "2025-10-08T14:30:00-03:00"
}
```

---

## 📊 Estrutura de Dados

### Emissão de NF-e - Request Body

```json
{
  "empresa": {
    "nome": "string (obrigatório)",
    "cnpj": "string (14 dígitos, obrigatório)",
    "inscricao_estadual": "string (obrigatório)",
    "estado": "string (UF, obrigatório)",
    "cidade": "string (obrigatório)",
    "endereco": "string (obrigatório)",
    "numero": "string (obrigatório)",
    "bairro": "string (obrigatório)",
    "cep": "string (obrigatório)",
    "email": "string (opcional)",
    "telefone": "string (opcional)"
  },
  "cliente": {
    "nome": "string (obrigatório)",
    "cpf": "string (11 dígitos, obrigatório se PF)",
    "cnpj": "string (14 dígitos, obrigatório se PJ)",
    "inscricao_estadual": "string (somente para PJ contribuinte)",
    "endereco": "string (obrigatório)",
    "cidade": "string (obrigatório)",
    "bairro": "string (obrigatório)",
    "estado": "string (UF, obrigatório)",
    "cep": "string (obrigatório)",
    "email": "string (opcional)",
    "telefone": "string (opcional)"
  },
  "nfe": {
    "numero": "integer (opcional, auto-gerado se omitido)",
    "serie": "string (opcional, padrão: 001)",
    "data_emissao": "string YYYY-MM-DD (opcional, padrão: hoje)",
    "data_saida": "string YYYY-MM-DD (opcional, padrão: data_emissao)"
  },
  "itens": [
    {
      "codigo": "string (obrigatório)",
      "descricao": "string (obrigatório)",
      "ncm": "string (8 dígitos, obrigatório)",
      "cfop": "string (4 dígitos, obrigatório)",
      "unidade_comercial": "string (ex: UN, KG, obrigatório)",
      "quantidade_comercial": "number (obrigatório)",
      "valor_unitario": "number (obrigatório)",
      "valor_total": "number (obrigatório)",
      "cst_icms": "string (CST ou CSOSN, obrigatório)",
      "base_calculo_icms": "number (opcional)",
      "aliquota_icms": "number (obrigatório)",
      "valor_icms": "number (opcional)",
      "origem": "string (0-8, obrigatório)"
    }
  ],
  "pagamento": {
    "forma_pagamento": "string (opcional, padrão: dinheiro)",
    "valor_pagamento": "number (opcional, padrão: valor_total)",
    "tipo_integracao": "string (opcional, padrão: 1)"
  },
  "transportadora": {
    "nome": "string (obrigatório se informar transportadora)",
    "cnpj": "string (obrigatório se informar transportadora)",
    "modalidade_frete": "string (opcional, padrão: 0)"
  }
}
```

### Emissão de NF-e - Response (Sucesso)

**Status:** `200 OK`

```json
{
  "success": true,
  "chave_acesso": "26250910214971090001565500100000001123456789",
  "protocolo": "126250000123456",
  "cStat": "100",
  "xml_path": "/pontti_nfe/arquivos/21497109000156/nfe/xml/2025_10/assinados/26250910214971090001565500100000001123456789.xml",
  "pdf_path": "/pontti_nfe/arquivos/21497109000156/nfe/pdf/2025_10/emitidos/NFe_26250910214971090001565500100000001123456789.pdf",
  "message": "NFe emitida com sucesso"
}
```

**Campos da resposta:**

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `success` | boolean | Se a operação foi bem-sucedida |
| `chave_acesso` | string | Chave de acesso da NF-e (44 dígitos) |
| `protocolo` | string | Número do protocolo de autorização SEFAZ |
| `cStat` | string | Código de status SEFAZ (100 = autorizado) |
| `xml_path` | string | Caminho relativo do arquivo XML |
| `pdf_path` | string | Caminho relativo do arquivo PDF (DANFE) |
| `message` | string | Mensagem descritiva |

### Emissão de NF-e - Response (Erro)

**Status:** `400` ou `500`

```json
{
  "success": false,
  "chave_acesso": "26250910214971090001565500100000001123456789",
  "cStat": "204",
  "error": "Rejeição: Duplicidade de NF-e [nRec: 126250105861045]"
}
```

---

### Cancelamento de NF-e - Request Body

```json
{
  "chave_acesso": "26251021497109000156550020000000641000010643",
  "justificativa": "Cancelamento solicitado pelo cliente devido a erro no pedido",
  "protocolo_autorizacao": "126250107437788",
  "empresa": {
    "nome": "PRINT JET DIGITAL",
    "cnpj": "21497109000156",
    "inscricao_estadual": "093218028",
    "estado": "PE",
    "cidade": "Recife",
    "endereco": "Rua Frei Cassimiro",
    "numero": "644",
    "bairro": "Santo Amaro",
    "cep": "50100260",
    "telefone": "(81) 99999-9999",
    "email": "atendimento@printjetdigital.com.br"
  }
}
```

**Campos obrigatórios:**

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `chave_acesso` | string | Chave de acesso de 44 dígitos da NF-e a cancelar |
| `justificativa` | string | Motivo do cancelamento (mínimo 15 caracteres) |
| `empresa.nome` | string | Razão social da empresa emitente |
| `empresa.cnpj` | string | CNPJ da empresa (14 dígitos) |
| `empresa.inscricao_estadual` | string | Inscrição Estadual da empresa |
| `empresa.estado` | string | UF (sigla do estado) da empresa |

**Campos opcionais (para geração do PDF):**

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `protocolo_autorizacao` | string | Protocolo de autorização da NF-e |
| `empresa.cidade` | string | Cidade da empresa |
| `empresa.endereco` | string | Logradouro da empresa |
| `empresa.numero` | string | Número do endereço |
| `empresa.bairro` | string | Bairro da empresa |
| `empresa.cep` | string | CEP da empresa |
| `empresa.telefone` | string | Telefone da empresa |
| `empresa.email` | string | E-mail da empresa |

### Cancelamento de NF-e - Response (Sucesso)

**Status:** `200 OK`

```json
{
  "success": true,
  "chave_acesso": "26251021497109000156550020000000641000010643",
  "protocolo_cancelamento": "126250107437799",
  "data_cancelamento": "2025-10-10T14:30:00-03:00",
  "xml_path": "/pontti_nfe/arquivos/21497109000156/cancelamento/xml/2025_10/Cancel_26251021497109000156550020000000641000010643.xml",
  "pdf_path": "/pontti_nfe/arquivos/21497109000156/cancelamento/pdf/2025_10/Cancel_26251021497109000156550020000000641000010643.pdf",
  "message": "NFe cancelada com sucesso"
}
```

**Campos da resposta:**

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `success` | boolean | Se o cancelamento foi bem-sucedido |
| `chave_acesso` | string | Chave de acesso da NF-e cancelada |
| `protocolo_cancelamento` | string | Protocolo do evento de cancelamento |
| `data_cancelamento` | string | Data/hora do registro na SEFAZ |
| `xml_path` | string | Caminho do XML do cancelamento |
| `pdf_path` | string | Caminho do PDF do cancelamento |
| `message` | string | Mensagem descritiva |

### Cancelamento de NF-e - Response (Erro)

**Status:** `400` ou `500`

```json
{
  "success": false,
  "error": "Evento de cancelamento rejeitado: NF-e não encontrada"
}
```

### 📂 Estrutura de Arquivos Gerados - Cancelamento

Os XMLs e PDFs de cancelamento são organizados automaticamente:

```
arquivos/{CNPJ}/cancelamento/
├── xml/
│   └── {ANO}_{MES}/
│       └── Cancel_{CHAVE_ACESSO}.xml
│
└── pdf/
    └── {ANO}_{MES}/
        └── Cancel_{CHAVE_ACESSO}.pdf
```

**Exemplo:**
```
arquivos/21497109000156/cancelamento/
├── xml/
│   └── 2025_10/
│       └── Cancel_26251021497109000156550020000000641000010643.xml
│
└── pdf/
    └── 2025_10/
        └── Cancel_26251021497109000156550020000000641000010643.pdf
```

### Cancelamento de NF-e - Response (Sucesso)

**Status:** `200 OK`

```json
{
  "success": true,
  "chave_acesso": "26250910214971090001565500100000001123456789",
  "protocolo_cancelamento": "126250000123457",
  "data_cancelamento": "2025-10-08T14:30:00-03:00",
  "message": "NFe cancelada com sucesso"
}
```

---

### Inutilização de NF-e - Request Body

```json
{
  "empresa": {
    "nome": "string (obrigatório)",
    "cnpj": "string (14 dígitos, obrigatório)",
    "inscricao_estadual": "string (obrigatório)",
    "estado": "string (UF, obrigatório)"
  },
  "serie": "string (obrigatório, ex: 001)",
  "numero_inicial": "integer (obrigatório)",
  "numero_final": "integer (obrigatório)",
  "justificativa": "string (min 15 caracteres, obrigatório)"
}
```

**Exemplo:**
```json
{
  "empresa": {
    "nome": "PRINT JET DIGITAL",
    "cnpj": "21497109000156",
    "inscricao_estadual": "093218028",
    "estado": "PE"
  },
  "serie": "001",
  "numero_inicial": "101",
  "numero_final": "105",
  "justificativa": "Erro no sistema ao gerar numeração sequencial"
}
```

**Observação:** Você pode inutilizar um único número (inicio = fim) ou uma faixa de números.

### Inutilização de NF-e - Response (Sucesso)

**Status:** `200 OK`

```json
{
  "success": true,
  "protocolo_inutilizacao": "126250000123458",
  "numero_inicial": "101",
  "numero_final": "105",
  "serie": "001",
  "cStat": "102",
  "message": "Numeração inutilizada com sucesso"
}
```

**Campos da resposta:**

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `success` | boolean | Se a operação foi bem-sucedida |
| `protocolo_inutilizacao` | string | Número do protocolo de inutilização SEFAZ |
| `numero_inicial` | string | Primeiro número inutilizado |
| `numero_final` | string | Último número inutilizado |
| `serie` | string | Série da numeração inutilizada |
| `cStat` | string | Código de status SEFAZ (102 = autorizado) |
| `message` | string | Mensagem descritiva |

### Inutilização de NF-e - Response (Erro)

**Status:** `400` ou `500`

```json
{
  "success": false,
  "cStat": "563",
  "error": "Rejeição: Já existe pedido de Inutilização com a mesma faixa de inutilização"
}
```

---

### Carta de Correção - Request Body

```json
{
  "chave_acesso": "string (44 dígitos, obrigatório)",
  "empresa": {
    "nome": "string (obrigatório)",
    "cnpj": "string (14 dígitos, obrigatório)",
    "inscricao_estadual": "string (obrigatório)",
    "estado": "string (UF, obrigatório)",
    "cidade": "string (opcional, para PDF)",
    "endereco": "string (opcional, para PDF)",
    "numero": "string (opcional, para PDF)",
    "bairro": "string (opcional, para PDF)",
    "cep": "string (opcional, para PDF)",
    "telefone": "string (opcional, para PDF)",
    "email": "string (opcional, para PDF)"
  },
  "correcao": "string (min 15, max 1000 caracteres, obrigatório)",
  "numero_sequencial": "integer (obrigatório)"
}
```

**Exemplo:**
```json
{
  "chave_acesso": "26251021497109000156550020000000641000010643",
  "empresa": {
    "nome": "PRINT JET DIGITAL",
    "cnpj": "21497109000156",
    "inscricao_estadual": "093218028",
    "estado": "PE",
    "cidade": "Recife",
    "endereco": "Rua Frei Cassimiro",
    "numero": "644",
    "bairro": "Santo Amaro",
    "cep": "50100260",
    "telefone": "(81) 99999-9999",
    "email": "atendimento@printjetdigital.com.br"
  },
  "correcao": "Corrigir endereco do destinatario: Rua das Flores, 456 - Bairro Centro",
  "numero_sequencial": 1
}
```

**Observações:**
- **numero_sequencial**: Incrementa a cada correção da mesma NF-e (1ª correção = 1, 2ª = 2, etc)
- **correcao**: Texto explicando o que está sendo corrigido (15-1000 caracteres)

### Carta de Correção - Response (Sucesso)

**Status:** `200 OK`

```json
{
  "success": true,
  "chave_acesso": "26251021497109000156550020000000641000010643",
  "protocolo_cce": "126250107437790",
  "numero_sequencial": 1,
  "data_registro": "2025-10-09T14:30:00-03:00",
  "cStat": "135",
  "xml_path": "/pontti_nfe/arquivos/21497109000156/cce/xml/2025_10/CCe_26251021497109000156550020000000641000010643_v1.xml",
  "pdf_path": "/pontti_nfe/arquivos/21497109000156/cce/pdf/2025_10/CCe_26251021497109000156550020000000641000010643_v1.pdf",
  "message": "Carta de Correção registrada com sucesso"
}
```

**Campos da resposta:**

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `success` | boolean | Se a operação foi bem-sucedida |
| `chave_acesso` | string | Chave de acesso da NF-e corrigida |
| `protocolo_cce` | string | Número do protocolo da CC-e |
| `numero_sequencial` | integer | Número sequencial desta correção |
| `data_registro` | string | Data/hora do registro na SEFAZ |
| `cStat` | string | Código de status SEFAZ (135 = registrado) |
| `xml_path` | string | Caminho do arquivo XML da CC-e |
| `pdf_path` | string | Caminho do arquivo PDF da CC-e |
| `message` | string | Mensagem descritiva |

### Carta de Correção - Response (Erro)

**Status:** `400` ou `500`

```json
{
  "success": false,
  "cStat": "478",
  "error": "Rejeição [478]: Evento com Sequencial fora de ordem"
}
```

**Erro 573 - Duplicidade de Evento:**
```json
{
  "success": false,
  "cStat": "573",
  "error": "Rejeição [573]: Duplicidade de Evento"
}
```

**Causa do erro 573:** Você já enviou uma CC-e com esse `numero_sequencial` para essa NF-e.

**Solução:** Incremente o `numero_sequencial` e tente novamente:
- Se a primeira CC-e já foi enviada → use `numero_sequencial: 2`
- Se a segunda CC-e já foi enviada → use `numero_sequencial: 3`
- E assim sucessivamente...

---

## 🤖 Regras de Negócio Automáticas

### 1. Detecção Automática de Tipo de Cliente

O sistema detecta automaticamente se o cliente é pessoa física ou jurídica baseado no documento informado:

| Documento | Tamanho | Tipo Detectado | Campo XML |
|-----------|---------|----------------|-----------|
| CPF | 11 dígitos | Pessoa Física | `<CPF>` |
| CNPJ | 14 dígitos | Pessoa Jurídica | `<CNPJ>` |

**Regra:** Informe apenas `cpf` OU `cnpj` no objeto cliente.

---

### 2. Detecção Automática de Consumidor Final

O sistema configura automaticamente `indFinal` e `indIEDest` baseado no tipo de cliente:

| Situação do Cliente | indFinal | indIEDest | Observação |
|---------------------|----------|-----------|------------|
| **CPF (Pessoa Física)** | `1` | `9` | Sempre consumidor final |
| **CNPJ sem IE** | `1` | `9` | PJ não contribuinte |
| **CNPJ com IE** | `0` | `1` | PJ contribuinte ICMS |

**Importante:** Você **não precisa** informar `indFinal` ou `indIEDest`. O sistema calcula automaticamente.

**Exemplo 1: Pessoa Física**
```json
{
  "cliente": {
    "cpf": "05138670409"  // ← 11 dígitos
  }
}
```
**Resultado:** `indFinal=1`, `indIEDest=9`, XML com `<CPF>`

**Exemplo 2: PJ sem IE**
```json
{
  "cliente": {
    "cnpj": "20755929000138",
    "inscricao_estadual": ""  // ← Vazio
  }
}
```
**Resultado:** `indFinal=1`, `indIEDest=9`, XML com `<CNPJ>` (sem `<IE>`)

**Exemplo 3: PJ com IE**
```json
{
  "cliente": {
    "cnpj": "20755929000138",
    "inscricao_estadual": "063257424"  // ← Preenchido
  }
}
```
**Resultado:** `indFinal=0`, `indIEDest=1`, XML com `<CNPJ>` + `<IE>`

---

### 3. Campos Opcionais com Valores Padrão

Se você omitir estes campos, o sistema define automaticamente:

| Campo | Valor Padrão |
|-------|--------------|
| `nfe.numero` | Auto-incremento baseado em timestamp |
| `nfe.serie` | `001` |
| `nfe.data_emissao` | Data/hora atual |
| `nfe.data_saida` | Mesma que `data_emissao` |
| `pagamento.forma_pagamento` | `dinheiro` |
| `pagamento.valor_pagamento` | Valor total da nota |
| `pagamento.tipo_integracao` | `1` (À vista) |
| `item.cst_icms` | `00` (Tributada integralmente) |
| `item.origem` | `0` (Nacional) |

---

## 💻 Exemplos de Integração

### PHP com cURL

```php
<?php

$url = 'http://seu-dominio.com.br/pontti_nfe/api/nfe/emitir.php';

$dados = [
    'empresa' => [
        'nome' => 'PRINT JET DIGITAL',
        'cnpj' => '21497109000156',
        'inscricao_estadual' => '093218028',
        'estado' => 'PE',
        'cidade' => 'Recife',
        'endereco' => 'Rua Frei Cassimiro',
        'numero' => '644',
        'bairro' => 'Santo Amaro',
        'cep' => '50100260'
    ],
    'cliente' => [
        'nome' => 'João da Silva',
        'cpf' => '05138670409',
        'endereco' => 'Rua das Flores, 123',
        'cidade' => 'Recife',
        'bairro' => 'Boa Viagem',
        'estado' => 'PE',
        'cep' => '51020-200'
    ],
    'itens' => [
        [
            'codigo' => 'PROD001',
            'descricao' => 'Produto Teste',
            'ncm' => '84713000',
            'cfop' => '5102',
            'unidade_comercial' => 'UN',
            'quantidade_comercial' => 1,
            'valor_unitario' => 100.00,
            'valor_total' => 100.00,
            'cst_icms' => '00',
            'aliquota_icms' => 18.00,
            'origem' => '0'
        ]
    ]
];

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($dados));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$resultado = json_decode($response, true);

if ($httpCode === 200 && $resultado['success']) {
    echo "✅ NF-e emitida com sucesso!\n";
    echo "Chave: {$resultado['chave_acesso']}\n";
    echo "Protocolo: {$resultado['protocolo']}\n";
    echo "Status: {$resultado['cStat']}\n";
    echo "XML: {$resultado['xml_path']}\n";
    echo "PDF: {$resultado['pdf_path']}\n";
} else {
    echo "❌ Erro ao emitir NF-e\n";
    echo "Erro: {$resultado['error']}\n";
    if (isset($resultado['cStat'])) {
        echo "Código SEFAZ: {$resultado['cStat']}\n";
    }
}
```

---
<!--
### JavaScript/Node.js com Axios

```javascript
const axios = require('axios');

const url = 'http://seu-dominio.com.br/pontti_nfe/api/nfe/emitir.php';

const dados = {
  empresa: {
    nome: 'PRINT JET DIGITAL',
    cnpj: '21497109000156',
    inscricao_estadual: '093218028',
    estado: 'PE',
    cidade: 'Recife',
    endereco: 'Rua Frei Cassimiro',
    numero: '644',
    bairro: 'Santo Amaro',
    cep: '50100260'
  },
  cliente: {
    nome: 'João da Silva',
    cpf: '05138670409',
    endereco: 'Rua das Flores, 123',
    cidade: 'Recife',
    bairro: 'Boa Viagem',
    estado: 'PE',
    cep: '51020-200'
  },
  itens: [{
    codigo: 'PROD001',
    descricao: 'Produto Teste',
    ncm: '84713000',
    cfop: '5102',
    unidade_comercial: 'UN',
    quantidade_comercial: 1,
    valor_unitario: 100.00,
    valor_total: 100.00,
    cst_icms: '00',
    aliquota_icms: 18.00,
    origem: '0'
  }]
};

axios.post(url, dados, {
  headers: {
    'Content-Type': 'application/json'
  },
  timeout: 60000
})
.then(response => {
  if (response.data.success) {
    console.log('✅ NF-e emitida com sucesso!');
    console.log('Chave:', response.data.chave_acesso);
    console.log('Protocolo:', response.data.protocolo);
    console.log('Status:', response.data.cStat);
    console.log('XML:', response.data.xml_path);
    console.log('PDF:', response.data.pdf_path);
  } else {
    console.log('❌ Erro:', response.data.error);
  }
})
.catch(error => {
  console.error('❌ Erro na requisição:', error.message);
  if (error.response) {
    console.error('Detalhes:', error.response.data);
  }
});
```

--- -->

<!-- ### Python com Requests

```python
import requests
import json

url = 'http://seu-dominio.com.br/pontti_nfe/api/nfe/emitir.php'

dados = {
    'empresa': {
        'nome': 'PRINT JET DIGITAL',
        'cnpj': '21497109000156',
        'inscricao_estadual': '093218028',
        'estado': 'PE',
        'cidade': 'Recife',
        'endereco': 'Rua Frei Cassimiro',
        'numero': '644',
        'bairro': 'Santo Amaro',
        'cep': '50100260'
    },
    'cliente': {
        'nome': 'João da Silva',
        'cpf': '05138670409',
        'endereco': 'Rua das Flores, 123',
        'cidade': 'Recife',
        'bairro': 'Boa Viagem',
        'estado': 'PE',
        'cep': '51020-200'
    },
    'itens': [{
        'codigo': 'PROD001',
        'descricao': 'Produto Teste',
        'ncm': '84713000',
        'cfop': '5102',
        'unidade_comercial': 'UN',
        'quantidade_comercial': 1,
        'valor_unitario': 100.00,
        'valor_total': 100.00,
        'cst_icms': '00',
        'aliquota_icms': 18.00,
        'origem': '0'
    }]
}

headers = {'Content-Type': 'application/json'}

try:
    response = requests.post(url, json=dados, headers=headers, timeout=60)
    resultado = response.json()

    if response.status_code == 200 and resultado.get('success'):
        print('✅ NF-e emitida com sucesso!')
        print(f"Chave: {resultado['chave_acesso']}")
        print(f"Protocolo: {resultado['protocolo']}")
        print(f"Status: {resultado['cStat']}")
        print(f"XML: {resultado['xml_path']}")
        print(f"PDF: {resultado['pdf_path']}")
    else:
        print('❌ Erro ao emitir NF-e')
        print(f"Erro: {resultado.get('error')}")
        if 'cStat' in resultado:
            print(f"Código SEFAZ: {resultado['cStat']}")

except requests.exceptions.Timeout:
    print('❌ Timeout: A requisição demorou mais de 60 segundos')
except Exception as e:
    print(f'❌ Erro: {str(e)}')
```

---

### C# com HttpClient

```csharp
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

public class NFeClient
{
    private static readonly HttpClient client = new HttpClient();

    public static async Task EmitirNFe()
    {
        var url = "http://seu-dominio.com.br/pontti_nfe/api/nfe/emitir.php";

        var dados = new
        {
            empresa = new
            {
                nome = "PRINT JET DIGITAL",
                cnpj = "21497109000156",
                inscricao_estadual = "093218028",
                estado = "PE",
                cidade = "Recife",
                endereco = "Rua Frei Cassimiro",
                numero = "644",
                bairro = "Santo Amaro",
                cep = "50100260"
            },
            cliente = new
            {
                nome = "João da Silva",
                cpf = "05138670409",
                endereco = "Rua das Flores, 123",
                cidade = "Recife",
                bairro = "Boa Viagem",
                estado = "PE",
                cep = "51020-200"
            },
            itens = new[]
            {
                new
                {
                    codigo = "PROD001",
                    descricao = "Produto Teste",
                    ncm = "84713000",
                    cfop = "5102",
                    unidade_comercial = "UN",
                    quantidade_comercial = 1,
                    valor_unitario = 100.00,
                    valor_total = 100.00,
                    cst_icms = "00",
                    aliquota_icms = 18.00,
                    origem = "0"
                }
            }
        };

        var json = JsonSerializer.Serialize(dados);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

        client.Timeout = TimeSpan.FromSeconds(60);

        try
        {
            var response = await client.PostAsync(url, content);
            var responseBody = await response.Content.ReadAsStringAsync();
            var resultado = JsonSerializer.Deserialize<dynamic>(responseBody);

            if (response.IsSuccessStatusCode && resultado.success)
            {
                Console.WriteLine("✅ NF-e emitida com sucesso!");
                Console.WriteLine($"Chave: {resultado.chave_acesso}");
                Console.WriteLine($"Protocolo: {resultado.protocolo}");
                Console.WriteLine($"Status: {resultado.cStat}");
            }
            else
            {
                Console.WriteLine("❌ Erro ao emitir NF-e");
                Console.WriteLine($"Erro: {resultado.error}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"❌ Erro: {ex.Message}");
        }
    }
}
``` -->

---

## 📋 Códigos de Resposta

### HTTP Status Codes

| Código | Descrição | Quando acontece |
|--------|-----------|-----------------|
| `200` | OK | Requisição processada com sucesso |
| `400` | Bad Request | Dados inválidos ou campos obrigatórios faltando |
| `404` | Not Found | Endpoint não existe |
| `405` | Method Not Allowed | Método HTTP incorreto (ex: GET em vez de POST) |
| `500` | Internal Server Error | Erro interno do servidor ou SEFAZ |

### Códigos SEFAZ (cStat)

#### ✅ Códigos de Sucesso

| cStat | Descrição |
|-------|-----------|
| `100` | Autorizado o uso da NF-e |
| `102` | Inutilização de número homologado |
| `135` | Evento de cancelamento registrado |
| `150` | Autorizado o uso da NF-e fora de prazo |

#### ⚠️ Códigos de Alerta/Processamento

| cStat | Descrição |
|-------|-----------|
| `103` | Lote recebido com sucesso |
| `104` | Lote processado |

#### ❌ Códigos de Erro Comuns

| cStat | Descrição | Solução |
|-------|-----------|---------|
| `204` | Duplicidade de NF-e | Use outro número ou deixe auto-gerar |
| `213` | CNPJ do emitente inválido | Verifique o CNPJ da empresa |
| `215` | Falha no schema XML | Verifique os campos obrigatórios |
| `225` | Falha no reconhecimento da autoria | Problema no certificado digital |
| `478` | Evento com sequencial fora de ordem | Use número sequencial correto (próximo na sequência) |
| `539` | CNPJ diverge do certificado | Use certificado da empresa correta |
| `563` | Duplicidade de inutilização | Faixa já foi inutilizada anteriormente |
| `573` | Duplicidade de evento | Incremente o numero_sequencial da CC-e |
| `591` | Carta de Correção já registrada | Incremente o número sequencial |
| `696` | Operação com não contribuinte sem consumidor final | **RESOLVIDO AUTOMATICAMENTE** |

---

## ⚠️ Erros Comuns e Soluções

### 1. Erro 696 - Consumidor Final

**Erro:**
```json
{
  "cStat": "696",
  "error": "Operação com não contribuinte deve indicar operação com consumidor final"
}
```

**Solução:** ✅ **Resolvido automaticamente!**
O sistema detecta automaticamente quando cliente é não contribuinte e configura `indFinal=1`.

---

### 2. Erro de Validação CPF/CNPJ

**Erro:**
```json
{
  "error": "Element 'CNPJ': '05138670409' is not accepted by the pattern '[0-9]{14}'"
}
```

**Solução:** ✅ **Resolvido automaticamente!**
Use campo `cpf` para pessoa física (11 dígitos) e `cnpj` para pessoa jurídica (14 dígitos).

---

### 3. Erro 204 - Duplicidade

**Erro:**
```json
{
  "cStat": "204",
  "error": "Duplicidade de NF-e"
}
```

**Solução:** Omita o campo `nfe.numero` para deixar o sistema gerar automaticamente:
```json
{
  "nfe": {
    // Não informe "numero" - será auto-gerado
    "serie": "001"
  }
}
```

---

### 4. Timeout na Requisição

**Erro:** Timeout após 30 segundos

**Solução:** Aumente o timeout para pelo menos 60 segundos:
```php
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
```

---

### 5. Campos Obrigatórios Faltando

**Erro:**
```json
{
  "error": "Campo obrigatório não informado: aliquota_icms"
}
```

**Solução:** Verifique que todos os campos obrigatórios estão preenchidos:
- `empresa`: nome, cnpj, inscricao_estadual, estado, cidade, endereco, numero, bairro, cep
- `cliente`: nome, (cpf OU cnpj), endereco, cidade, bairro, estado, cep
- `itens`: codigo, descricao, ncm, cfop, unidade_comercial, quantidade_comercial, valor_unitario, valor_total, aliquota_icms, origem

---

### 6. Erro 563 - Duplicidade de Inutilização

**Erro:**
```json
{
  "cStat": "563",
  "error": "Já existe pedido de Inutilização com a mesma faixa de inutilização"
}
```

**Solução:** A faixa de numeração já foi inutilizada anteriormente. Verifique seus registros antes de inutilizar novamente.

---

### 7. Como Usar a Inutilização

**Cenário:** Você emitiu a nota 100, depois emitiu a nota 102 (pulou a 101).

**Solução:** Inutilizar o número 101 para justificar a quebra de sequência:

```json
{
  "empresa": {
    "nome": "PRINT JET DIGITAL",
    "cnpj": "21497109000156",
    "inscricao_estadual": "093218028",
    "estado": "PE"
  },
  "serie": "001",
  "numero_inicial": "101",
  "numero_final": "101",
  "justificativa": "Erro no sistema ao gerar numeração"
}
```

**Importante:** A justificativa deve ter pelo menos 15 caracteres.

---

### 8. Como Usar a Carta de Correção

**Cenário:** Você emitiu uma NF-e mas errou o endereço do cliente.

**Solução:** Enviar uma Carta de Correção:

```json
{
  "chave_acesso": "26251021497109000156550020000000641000010643",
  "empresa": {
    "nome": "PRINT JET DIGITAL",
    "cnpj": "21497109000156",
    "inscricao_estadual": "093218028",
    "estado": "PE"
  },
  "correcao": "Corrigir endereco do destinatario: Rua das Flores, 456 - Bairro Centro",
  "numero_sequencial": 1
}
```

**✅ Pode corrigir:**
- Endereços (rua, número, bairro, CEP)
- Descrições de produtos (sem alterar valor)
- Dados cadastrais do destinatário
- Informações complementares

**❌ NÃO pode corrigir:**
- Valores (unitário, total, impostos)
- Quantidades
- CPF/CNPJ do destinatário
- Data de emissão
- Itens (adicionar ou remover)

**Importante:**
- A correção deve ter entre 15 e 1000 caracteres
- Pode enviar múltiplas correções (incremente o `numero_sequencial`)
- A correção não substitui a NF-e, apenas adiciona uma observação oficial

### 🔄 Múltiplas Correções na Mesma NF-e

Você pode enviar várias correções para a mesma NF-e. Basta **incrementar** o `numero_sequencial`:

**1ª Correção:**
```json
{
  "numero_sequencial": 1,
  "correcao": "Corrigir endereco: Rua das Flores, 456"
}
```

**2ª Correção:**
```json
{
  "numero_sequencial": 2,
  "correcao": "Corrigir telefone: (81) 99999-9999"
}
```

**3ª Correção:**
```json
{
  "numero_sequencial": 3,
  "correcao": "Corrigir email: novo@email.com"
}
```

⚠️ **Atenção:** Se você tentar usar um `numero_sequencial` já utilizado, receberá erro **573 (Duplicidade de Evento)**.

### 📂 Estrutura de Arquivos Gerados - CC-e

Os XMLs e PDFs da Carta de Correção são organizados automaticamente:

```
arquivos/{CNPJ}/cce/
├── xml/
│   └── {ANO}_{MES}/
│       ├── CCe_{CHAVE_ACESSO}_v1.xml
│       ├── CCe_{CHAVE_ACESSO}_v2.xml
│       └── CCe_{CHAVE_ACESSO}_v3.xml
│
└── pdf/
    └── {ANO}_{MES}/
        ├── CCe_{CHAVE_ACESSO}_v1.pdf
        ├── CCe_{CHAVE_ACESSO}_v2.pdf
        └── CCe_{CHAVE_ACESSO}_v3.pdf
```

**Exemplo:**
```
arquivos/21497109000156/cce/
├── xml/
│   └── 2025_10/
│       ├── CCe_26251021497109000156550020000000641000010643_v1.xml
│       ├── CCe_26251021497109000156550020000000641000010643_v2.xml
│       └── CCe_26251021497109000156550020000000641000010643_v3.xml
│
└── pdf/
    └── 2025_10/
        ├── CCe_26251021497109000156550020000000641000010643_v1.pdf
        ├── CCe_26251021497109000156550020000000641000010643_v2.pdf
        └── CCe_26251021497109000156550020000000641000010643_v3.pdf
```

---

## ✅ Boas Práticas

### 1. Tratamento de Erros

Sempre verifique o `success` e o `cStat` da resposta:

```php
if ($resultado['success'] && in_array($resultado['cStat'], ['100', '150'])) {
    // NF-e autorizada com sucesso
    salvarNoBanco($resultado);
} else {
    // Erro na emissão
    logError($resultado['error'], $resultado['cStat']);
}
```

---

### 2. Retry com Backoff Exponencial

Para erros temporários (timeout, 500), implemente retry:

```php
$maxRetries = 3;
$attempt = 0;

while ($attempt < $maxRetries) {
    $response = emitirNFe($dados);

    if ($response['success']) {
        break;
    }

    // Retry apenas para erros de rede ou 500
    if ($response['http_code'] >= 500 || $response['timeout']) {
        $attempt++;
        sleep(pow(2, $attempt)); // 2s, 4s, 8s
    } else {
        break; // Erro de validação, não faz sentido retry
    }
}
```

---

### 3. Validação Antes de Enviar

Valide os dados antes de enviar para economizar chamadas:

```php
// Validar CPF/CNPJ
$documento = preg_replace('/\D/', '', $cliente['cpf'] ?? $cliente['cnpj'] ?? '');
if (!in_array(strlen($documento), [11, 14])) {
    throw new Exception('CPF deve ter 11 dígitos ou CNPJ 14 dígitos');
}

// Validar alíquota ICMS
if (empty($item['aliquota_icms']) || $item['aliquota_icms'] <= 0) {
    throw new Exception('Alíquota ICMS é obrigatória e deve ser maior que 0');
}
```

---

### 4. Armazenamento de Chave e Protocolo

Sempre salve a `chave_acesso` e o `protocolo` para futuras consultas/cancelamentos:

```php
$db->insert('notas_fiscais', [
    'chave_acesso' => $resultado['chave_acesso'],
    'protocolo' => $resultado['protocolo'],
    'numero' => $resultado['numero'],
    'serie' => $resultado['serie'],
    'xml_path' => $resultado['xml_path'],
    'pdf_path' => $resultado['pdf_path'],
    'status' => 'autorizada'
]);
```

---

### 5. Monitoramento de Status

Use o endpoint `/status.php` para monitorar a saúde da API:

```php
function verificarStatusAPI() {
    $response = file_get_contents('http://seu-dominio.com.br/pontti_nfe/status.php');
    $status = json_decode($response, true);

    if ($status['status'] !== 'online' || $status['sefaz'] !== 'conectado') {
        notificarEquipe('API NFe offline ou SEFAZ desconectado');
    }
}
```

---

### 6. Logs Detalhados

Sempre logue requisições e respostas para auditoria:

```php
$logData = [
    'timestamp' => date('Y-m-d H:i:s'),
    'endpoint' => '/api/nfe/emitir.php',
    'request' => json_encode($dados),
    'response' => json_encode($resultado),
    'http_code' => $httpCode,
    'success' => $resultado['success'],
    'chave_acesso' => $resultado['chave_acesso'] ?? null
];

file_put_contents('logs/nfe_integracao.log', json_encode($logData) . PHP_EOL, FILE_APPEND);
```

---

## 📞 Suporte

### Canais de Suporte

**Systhema Tecnologia**
- 📧 Email: contato@pontti.com.br
- 📞 Telefone: (81) 2011-3434
- 🌐 Website: [pontti.com.br](https://pontti.com.br)

### Horário de Atendimento
- Segunda a Sexta: 8h às 18h (Horário de Brasília)
- Sábado, Domingo e Feriados: Emergências via email

### SLA (Service Level Agreement)

| Prioridade | Tempo de Resposta |
|------------|-------------------|
| Crítico (API offline) | 2 horas |
| Alto (Erros SEFAZ) | 4 horas |
| Médio (Dúvidas) | 24 horas |
| Baixo (Melhorias) | 72 horas |

---

## 📚 Documentação Adicional

- [Códigos de Erro SEFAZ](https://www.nfe.fazenda.gov.br/portal/listaConteudo.aspx?tipoConteudo=tW+YMyk/50s=)
- [Manual de Integração NF-e (SEFAZ)](https://www.nfe.fazenda.gov.br/portal/listaConteudo.aspx?tipoConteudo=/fwLvLUSmU8=)
- [Tabela de NCM](https://www.gov.br/receitafederal/pt-br/assuntos/comercio-exterior/classificacao-fiscal-de-mercadorias)
- [Tabela de CFOP](http://www.sped.fazenda.gov.br/spedtabelas/AppConsulta/publico/aspx/ConsultaCFOP.aspx)

---

## 🔄 Histórico de Versões

| Versão | Data | Alterações |
|--------|------|------------|
| 1.3.0 | 09/10/2025 | Carta de Correção Eletrônica (CC-e) |
| 1.2.0 | 09/10/2025 | Endpoint de inutilização de numeração |
| 1.1.1 | 08/10/2025 | Correção erro 696 + detecção automática consumidor final |
| 1.1.0 | 08/10/2025 | Suporte a CPF (Pessoa Física) |
| 1.0.0 | 15/10/2025 | Lançamento inicial |

---

**Última atualização:** 09/10/2025
**Desenvolvido por:** Systhema Tecnologia
**Versão da API:** 1.3.0

---

**📄 Licença:** Apache 2.0
**🔒 Ambiente:** Produção (SEFAZ Real)

