> ## Documentation Index
> Fetch the complete documentation index at: https://docs.engineapi.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Ambiente de testes

> Como testar sua integração direto na SEFAZ de homologação, sem emitir documento fiscal real.

A engineAPI se conecta diretamente ao **ambiente de homologação da SEFAZ** (o mesmo servidor da Fazenda, mas sem validade fiscal). Você testa com a infraestrutura real sem nenhum risco.

<Note>
  Esta é a versão **completa** (como funciona, como promover um emissor pra produção,
  self-service). Pra ver só o que muda entre os dois ambientes numa tabela, veja
  [Homologação vs produção](/conceitos/homologacao-producao).
</Note>

<Info>
  O endpoint da API é o mesmo para homologação e produção. A diferença está no campo
  `ambienteFiscal` do emissor (`Issuer`), e a troca **é self-service**, via um endpoint
  dedicado (`PATCH /v1/companies/{id}/ambiente`, ver seção "Promovendo um emissor para
  produção" abaixo).
</Info>

***

## Todo emissor nasce em homologação

Ao cadastrar uma empresa (`POST /v1/companies`), o `ambienteFiscal` do emissor nasce com
o valor **`2 {/* fact:issuer.ambienteFiscalDefault */}` (homologação)** por padrão. O payload de
cadastro **não tem** um campo `environment` (nem `ambienteFiscal`) que você possa enviar:

```bash theme={null}
curl -X POST https://api.engineapi.com.br/v1/companies \
  -H "Authorization: Bearer SEU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cnpj": "11222333000181",
    "name": "Empresa Teste Ltda"
  }'
```

| Valor de `ambienteFiscal`          | Ambiente        | Comportamento                                   |
| ---------------------------------- | --------------- | ----------------------------------------------- |
| `1`                                | **Produção**    | Documentos com validade fiscal real             |
| `2` (default de todo emissor novo) | **Homologação** | Testes com SEFAZ de teste (sem validade fiscal) |

<Warning>
  **`ambienteFiscal` e `sandbox` não mudam pelo `PATCH /v1/companies/{id}` genérico.**
  Enviar um valor **diferente** do atual recusa com `422 AMBIENTE_IMUTAVEL` (nada é
  escrito). Reenviar o valor atual (o roundtrip do GET) continua `200` e é ignorado.

  A troca de `ambienteFiscal` (homologação `2` / produção `1`) é self-service no
  endpoint dedicado `PATCH /v1/companies/{id}/ambiente`. Ver seção "Promovendo um
  emissor para produção" abaixo. Promover `sandbox` a SEFAZ real (`false`) é ato do
  SUPERADMIN em `PATCH /v1/admin/companies/{id}/sandbox`.
</Warning>

<Info>
  Notas emitidas em homologação **não têm validade fiscal** e não precisam ser canceladas. Emita à vontade para testar.
</Info>

***

## CNPJ para Testes

Você pode usar seu próprio CNPJ em homologação. O SEFAZ de teste aceita qualquer CNPJ válido (com dígitos verificadores corretos).

**CNPJs de teste comuns:**

| CNPJ             | Uso                        |
| ---------------- | -------------------------- |
| `11222333000181` | Emissor de testes          |
| `99888777000100` | Destinatário de testes     |
| `12345678000195` | Empresa genérica de testes |

<Info>
  Esses CNPJs são fictícios com dígitos verificadores **válidos**, conferidos contra o
  algoritmo oficial de cálculo de DV. Podem ser usados livremente em homologação.
</Info>

<Warning>
  CNPJ com dígito verificador inconsistente com os 12 primeiros dígitos é rejeitado pela
  SEFAZ de homologação com `cStat 208` ("CNPJ do emitente inválido"). Use sempre os CNPJs
  acima ou gere um novo com DV calculado corretamente antes de testar.
</Warning>

***

## Certificado para Homologação

Em homologação, você pode usar:

* **Seu certificado real** (funciona normalmente)
* **Certificado de testes** (emitido por qualquer AC, mesmo que expirado)

O SEFAZ de homologação aceita certificados com qualquer validade. O upload segue o mesmo
contrato de produção: `POST /v1/companies/{id}/certificate`, campo multipart `file`, ver
[Certificados Digitais](/guides/certificates).

***

## Promovendo um emissor para produção

Trocar `ambienteFiscal` **é self-service**, via um endpoint dedicado, separado do
`PATCH /v1/companies/{id}` genérico (que recusa valor diferente com `422 AMBIENTE_IMUTAVEL`,
ver aviso acima). Não existe aprovação do suporte no caminho: quem chama a rota com o
valor certo promove o emissor.

```bash theme={null}
curl -X PATCH https://api.engineapi.com.br/v1/companies/ISSUER_ID/ambiente \
  -H "x-api-key: ek_live_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "ambienteFiscal": 1
  }'
```

| Propriedade                     | Detalhe                                                                                                                                                                                                                                                                                              |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Rota                            | `PATCH /v1/companies/{id}/ambiente`, endpoint dedicado                                                                                                                                                                                                                                               |
| Auth                            | Toda rota de `/v1/companies` (inclusive esta) aceita JWT **ou** `x-api-key`, sem distinção: é o mesmo guard em todo o controller. **Tanto `ek_test_` quanto `ek_live_` podem chamar**: esta rota não bloqueia `ek_test_` como as rotas de emissão fiscal (NF-e, NFC-e, NFS-e, CT-e, MDF-e) bloqueiam |
| Body                            | `{ "ambienteFiscal": 1 }` (Produção) ou `{ "ambienteFiscal": 2 }` (Homologação), sem coerção de string/boolean. Qualquer outro valor → `400`                                                                                                                                                         |
| Escopo                          | Só o emissor do seu próprio partner; id de outro tenant devolve `404` sem revelar que o emissor existe                                                                                                                                                                                               |
| Auditoria                       | Grava log de auditoria com `before`/`after` na mesma transação da troca, sempre                                                                                                                                                                                                                      |
| O que este endpoint **não faz** | Não confere se há certificado A1 válido, não reseta numeração/série de documentos, não toca em nenhum outro campo do cadastro: a troca escreve só o `ambienteFiscal`. Estar "pronto pra produção" (certificado, IE, endereço) é responsabilidade do integrador, ver o checklist abaixo               |

Resposta de sucesso (`200`):

```json theme={null}
{
  "data": {
    "id": "5f2c1e40-6b3a-4e1a-9b2c-8f0a1d2e3f4a",
    "cnpj": "11222333000181",
    "ambienteFiscal": 1
  },
  "meta": { "requestId": "req_a1b2c3d4e5", "timestamp": "2026-07-16T12:00:00.000Z" }
}
```

Corpo inválido (`400`, ex. `{ "ambienteFiscal": 3 }`):

```json theme={null}
{
  "error": {
    "type": "https://engineapi.com.br/errors/VALIDATION_ERROR",
    "title": "Bad Request",
    "status": 400,
    "detail": "Os dados enviados são inválidos",
    "errors": [
      {
        "field": "ambienteFiscal",
        "message": "ambienteFiscal deve ser exatamente 1 (Produção) ou 2 (Homologação)"
      }
    ],
    "instance": "/v1/companies/5f2c1e40-6b3a-4e1a-9b2c-8f0a1d2e3f4a/ambiente",
    "requestId": "req_a1b2c3d4e5",
    "timestamp": "2026-07-16T12:00:00.000Z"
  }
}
```

<Warning>
  **Depois de promover pra produção, sua `ek_test_` para de operar esse emissor.**
  `ek_test_` só opera emissor com `ambienteFiscal: 2` (homologação). Tentar emitir com
  `ek_test_` contra um emissor que você acabou de promover devolve `403` com
  `"Chave de teste não opera emissor de produção. Gere sua ek_live_ no portal."`
  Gere a `ek_live_` (exige plano ativo, ver [Autenticação](/authentication)) antes ou logo
  depois de promover o emissor.
</Warning>

***

## Testando Rejeições

Para testar o tratamento de erros no seu código, você pode provocar rejeições específicas
(todas voltam como `400` com `error.erros[]`, nunca `422`, ver [Erros e
Rejeições](/guides/errors)):

| Rejeição             | Como provocar                                      |
| -------------------- | -------------------------------------------------- |
| `539: Duplicidade`   | Emita a mesma nota duas vezes (mesmo número/série) |
| `225: NCM inválido`  | Use NCM com menos de 8 dígitos, ex: `"1234"`       |
| `210: IE inválida`   | Use uma IE que não bate com a UF do destinatário   |
| `204: CNPJ inválido` | Use um CNPJ com dígito verificador errado          |

***

## Comparação: Sandbox vs Produção

|                         | Sandbox (`ambienteFiscal: 2`)                                    | Produção (`ambienteFiscal: 1`)                                                                    |
| ----------------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| Validade fiscal         | Sem validade                                                     | Válida                                                                                            |
| Custo por emissão       | Gratuito (`ek_test_` não é faturada)                             | Conforme plano                                                                                    |
| SEFAZ utilizado         | SEFAZ de homologação                                             | SEFAZ estadual real                                                                               |
| Cancelamento necessário | Não                                                              | Sim (até 24h NF-e / 30min NFC-e)                                                                  |
| Webhooks disparados     | Sim                                                              | Sim                                                                                               |
| XML retornado           | Sim (teste)                                                      | Sim (válido)                                                                                      |
| DANFE / DANFCE (PDF)    | Sim, gerado do XML autorizado, impresso com **SEM VALOR FISCAL** | Sim, documento válido                                                                             |
| Como ativar             | Default de todo emissor novo                                     | `PATCH /v1/companies/{id}/ambiente` com `{ "ambienteFiscal": 1 }`, self-service (ver seção acima) |

### O DANFE em homologação

`GET /v1/nfe/pdf/{accessKey}` e `GET /v1/nfce/pdf/{accessKey}` funcionam normalmente em
homologação: o documento é gerado a partir do **XML autorizado pela SEFAZ de homologação**,
e a própria SEFAZ manda imprimir a tarja `NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM
VALOR FISCAL`. Ambiente, CST/CSOSN e informações complementares saem do XML: o PDF é o
documento, não uma remontagem.

A resposta só é `409` (`DANFE_INDISPONIVEL`) quando **não existe XML autorizado** para
aquele documento neste ambiente:

| Situação                              | Por quê                                                                                                                                        |
| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| Nota autorizada em **outro** ambiente | O XML fica no ambiente onde a nota foi emitida; baixar uma chave de produção no ambiente de homologação (ou vice-versa) não encontra o arquivo |
| Nota ainda não autorizada             | Sem autorização não há chave nem XML, consulte o `status` antes                                                                                |

<Info>
  **Emissor de demonstração** (criado pelos seeds de demo da plataforma, não por você):
  o download de PDF funciona mesmo sem uma emissão real na SEFAZ de homologação. Você
  recebe um DANFE de teste com os itens/CSOSN/informações complementares do SEU payload,
  e o que é sintético vem **declarado dentro do próprio documento**: o protocolo
  (`nProt`) usa o prefixo `DEMO` (nunca um número puro: protocolo real da SEFAZ é só
  dígitos, então não colide com nenhuma faixa real) e o `infCpl`/`xMotivo` dizem
  literalmente "AMBIENTE DE DEMONSTRAÇÃO, documento sintético, sem validade fiscal". O
  `409` não aparece nesse caso.
</Info>

<Info>
  Um emissor criado por `POST /v1/companies` nasce `sandbox: true` e
  `ambienteFiscal: 2`. Enquanto `sandbox` for `true`, a emissão usa o provedor mock
  (protocolo `DEMO…`) mesmo com certificado A1 válido. Homologação real da SEFAZ exige
  `sandbox: false`, promovido pelo SUPERADMIN em `PATCH /v1/admin/companies/{id}/sandbox`
  depois do upload do certificado.
</Info>

***

## Checklist: Estou pronto para produção?

<Steps>
  <Step title="Emissão testada">
    Sua integração emite NF-e com sucesso em homologação e recebe `status: "AUTHORIZED"`?
  </Step>

  <Step title="Erros tratados">
    Seu código trata `400` (rejeição SEFAZ, `error.erros[]`) e exibe mensagem amigável ao usuário?
  </Step>

  <Step title="Webhooks configurados">
    Você tem um endpoint recebendo `invoice.authorized` e `invoice.rejected` (`PATCH /v1/webhooks/config`)?
  </Step>

  <Step title="Idempotência implementada">
    Seu código usa o header `Idempotency-Key` na emissão e o `id` do evento no webhook para evitar duplicidade?
  </Step>

  <Step title="Certificado de produção">
    Você tem um certificado e-CNPJ A1 válido e fez o upload (`POST /v1/companies/{id}/certificate`)?
  </Step>

  <Step title="Ambiente de produção liberado">
    Você chamou `PATCH /v1/companies/{id}/ambiente` com `{ "ambienteFiscal": 1 }` pra
    promover o emissor (self-service, ver seção "Promovendo um emissor para produção"
    acima) e gerou sua `ek_live_`?
  </Step>
</Steps>

***

## Veja também

* **[Webhooks](/guides/webhooks):** configure notificações em tempo real.
* **[Erros e respostas](/guides/errors):** tratamento completo dos códigos SEFAZ.
