# Emitfy API > API REST para emissão fiscal no Brasil (NFS-e, NF-e, NFC-e, CT-e), catálogo (clientes, produtos, vendas) e webhooks. Modelo Conta × Assinatura: keys/webhooks na assinatura (/v1/webhooks); emissão em /v1/companies/:companyId. Auth: X-Api-Key / X-Api-Secret. Base: https://api.emitfy.com Base URL: https://api.emitfy.com Docs humanas: https://api.emitfy.com/docs Contexto completo: https://api.emitfy.com/llms-full.txt OpenAPI: https://api.emitfy.com/openapi.yaml ## Começar - [Introdução](https://api.emitfy.com/docs): Visão geral Conta × Assinatura e dois fluxos (atalho vs catálogo) - [Autenticação](https://api.emitfy.com/docs/authentication): Headers X-Api-Key, X-Api-Secret; empresa no path - [Empresas](https://api.emitfy.com/docs/companies): CRUD /v1/companies (CNPJs da assinatura) e certificado A1 - [Sandbox](https://api.emitfy.com/docs/sandbox): Homologação - [Para IAs](https://api.emitfy.com/docs/for-ai): llms.txt, Markdown por página, OpenAPI - [SDKs](https://api.emitfy.com/docs/sdks): Oficiais — PHP `emitfy/sdk`, Node `@emitfy/sdk`, .NET `Emitfy`, Python `emitfy`, Java `com.emitfy:emitfy` ## Emissão - [NFS-e](https://api.emitfy.com/docs/reference/nfse): POST /v1/companies/:companyId/nfse - [NF-e](https://api.emitfy.com/docs/reference/nfe): POST /v1/companies/:companyId/nfe - [NFC-e](https://api.emitfy.com/docs/reference/nfce): Cupom fiscal (requer ativação) - [CT-e](https://api.emitfy.com/docs/reference/cte): Conhecimento de transporte (requer ativação) ## Catálogo - [Clientes](https://api.emitfy.com/docs/reference/customers): CRUD /v1/companies/:companyId/customers - [Produtos](https://api.emitfy.com/docs/reference/products): CRUD /v1/companies/:companyId/products - [Vendas](https://api.emitfy.com/docs/reference/sales): POST /v1/companies/:companyId/sales ## Destinatário - [Notas recebidas](https://api.emitfy.com/docs/reference/received-nfes): DistDFe e manifestação ## Integração - [Webhooks](https://api.emitfy.com/docs/webhooks): CRUD /v1/webhooks (assinatura); payload com companyId + taxId - [Idempotência](https://api.emitfy.com/docs/idempotency): Idempotency-Key / externalId - [Erros](https://api.emitfy.com/docs/errors): Envelope success + error.code/message (validação 422) - [OpenAPI](https://api.emitfy.com/openapi.yaml): OpenAPI 3.1 (company-scoped) - [SDKs](https://api.emitfy.com/docs/sdks): PHP / Node / .NET / Python / Java (Ruby/Go sob demanda) ## Optional - [Marketing overview](https://emitfy.com/llms.txt): Posicionamento do produto (não é contrato de API) --- # Emitfy API — contexto completo (contrato para agentes) Convenções: JSON camelCase em inglês. Mensagens de erro ao usuário em PT-BR. Base: `https://api.emitfy.com` — paths `/v1/...` (equivalente a `/api/v1/...` no proxy Nitro). ## Autenticação Headers obrigatórios em rotas privadas: ``` X-Api-Key: X-Api-Secret: Content-Type: application/json ``` Escopo da empresa: path `/v1/companies/:companyId/...` (obrigatório nas rotas fiscais e de catálogo). Credenciais e webhooks: nível da **assinatura/conta** (`/v1/webhooks` — sem companyId na URL). Credenciais: Painel → API & Webhooks (`POST /v1/user/api-credentials` rotaciona o secret). Envelope sucesso: `{ "success": true, "data": ... }` (listas podem incluir paginação em `data`). Envelope erro: `{ "success": false, "error": { "code": "...", "message": "...", "details": null | object } }`. Validação Zod → HTTP 422 + `VALIDATION_ERROR` (`error.details.fields`). ## SDKs oficiais - PHP: `composer require emitfy/sdk` - Node/TS: `npm i @emitfy/sdk` - .NET: `dotnet add package Emitfy` - Python: `pip install emitfy` - Java: Maven `com.emitfy:emitfy` - Docs: https://api.emitfy.com/docs/sdks - Ruby/Go: sob demanda DX comum: client de conta (`webhooks`, `companies`) + `company(companyId)` para emissão/catálogo. ## Qual fluxo usar 1. **Atalho** — emissão pontual: `POST /v1/companies/:companyId/nfse` ou `.../nfe`. 2. **Catálogo** — SaaS recorrente: - `POST /v1/companies/:companyId/customers` e `.../products` uma vez - `POST /v1/companies/:companyId/sales` com `customer: ""` - `externalId` / `Idempotency-Key` para não duplicar Merge de cliente: em vendas / NF-e / NFS-e com objeto `customer` embutido, campos já preenchidos no cadastro Emitfy são **preservados**. `POST/PUT /v1/companies/:companyId/customers` sobrescreve de forma explícita. Preferência recorrência: enviar só o UUID do cliente (só leitura, não atualiza). ## Mapa de recursos Prefixo fiscal/catálogo: `/v1/companies/:companyId/...` | Recurso | Métodos | |---------|---------| | Companies | GET/POST /v1/companies; GET/PUT/DELETE /v1/companies/:companyId; certificate; state-registrations | | Customers | GET/POST .../customers; GET/PUT/DELETE .../customers/:id | | Products | GET/POST .../products; GET/PUT/DELETE .../products/:id | | Sales | GET/POST .../sales; GET/PUT/DELETE .../sales/:id; POST .../emit-invoice; POST .../cancel-invoice | | NFS-e | POST/GET .../nfse; GET/DELETE .../nfse/:id; pdf/xml/events | | NF-e | POST/GET .../nfe; GET/DELETE .../nfe/:id; pdf/xml/events/items/correction/inutilizations | | NFC-e | POST/GET .../nfce; GET/DELETE .../nfce/:id; transmit; inutilizations; pdf/xml | | CT-e | POST/GET .../cte; GET/DELETE .../cte/:id; POST .../cte-os | | Invoices | GET .../invoices; GET .../invoices/:id; PDF/XML aninhados no tipo fiscal | | Received NF-e | GET .../received-nfes; sync; manifest; xml | | Credenciais | GET/POST /v1/user/api-credentials | | Webhooks | GET/POST /v1/webhooks; PUT/PATCH/DELETE /v1/webhooks/:id (assinatura; todas as empresas; payload companyId+taxId) | --- ## Idempotência - Header `Idempotency-Key` (prioridade) ou body `externalId` - Se a chave já existir para a empresa, retorna o recurso existente sem reprocessar - Em `POST /v1/companies/:companyId/sales`, mesmo `externalId` na mesma empresa não cria segunda venda --- ## Erros comuns ```json { "success": false, "error": { "code": "INVALID_API_CREDENTIALS", "message": "Credenciais de API inválidas.", "details": null } } ``` Validação (HTTP 422): ```json { "success": false, "error": { "code": "VALIDATION_ERROR", "message": "Um ou mais campos contém erros de validação. Por favor, revise os dados informados.", "details": { "fields": [{ "field": "borrower.name", "error": "..." }] } } } ``` Outros codes típicos: `RATE_LIMIT_EXCEEDED` (429 + Retry-After), `NOT_FOUND` (404), erros fiscais de negócio em PT-BR. --- ## Clientes — /v1/companies/:companyId/customers - `POST /v1/companies/:companyId/customers` — cria ou atualiza (match por id → document → email); update explícito sobrescreve - `GET /v1/companies/:companyId/customers` — query: page, pageSize, search - `GET /v1/companies/:companyId/customers/:id` - `PUT /v1/companies/:companyId/customers/:id` — sobrescreve campos - `DELETE /v1/companies/:companyId/customers/:id` Campos principais body: `name` (obrigatório), `email` (obrigatório), `document`, `phone`, `foreign`, `address` { zipcode, street, number, district, city, state, complement }, `municipalRegistration`, `stateRegistration`, `tradeName`. ```json { "name": "João da Silva", "email": "joao@email.com", "document": "12345678901", "phone": "(11) 98888-7777", "address": { "zipcode": "01310100", "street": "Av. Paulista", "number": "1000", "district": "Bela Vista", "city": "São Paulo", "state": "SP" } } ``` --- ## Produtos — /v1/companies/:companyId/products - `POST /v1/companies/:companyId/products` / `PUT .../products/:id` - `GET /v1/companies/:companyId/products` — query: page, pageSize, search, type - `GET .../products/:id` / `DELETE .../products/:id` Campos principais: `name`, `sku` (único), `type` (`service` | `product` | `split`), `category`, `price`, `ncm` (produto), `serviceItemCode` (serviço LC 116), `fiscalFollowsCompanyDefaults`. Há muitos campos fiscais opcionais (ISS, PIS, COFINS, CFOP, etc.) — ver docs humanas ou defaults da empresa. ```json { "name": "Assinatura mensal", "sku": "PLAN_MENSAL", "type": "service", "category": "saas", "price": 99.9, "fiscalFollowsCompanyDefaults": true } ``` --- ## Vendas — /v1/companies/:companyId/sales - `POST /v1/companies/:companyId/sales` — cria venda; com `emitWhen: "immediately"` enfileira nota - `GET .../sales` / `GET .../sales/:id` / `PUT .../sales/:id` / `DELETE .../sales/:id` - `POST .../sales/:id/emit-invoice` - `POST .../sales/:id/cancel-invoice` Body principal: - `customer`: string UUID **ou** objeto (name/email/document/address…) - `products[]`: cada linha com `sku` e/ou `id`; `price`; `quantity`; opcional name/type/category. **Proibido** `amount` e `productType` (use `price` e `type`) - `saleDate` ISO, `paymentMethod` (default credit_card), `emitWhen` (immediately | after_guarantee | manual), `guaranteeDate`, `sendEmail`, `externalId`, `discount`, `shipping`, `nfse` { discrimination, competenceDate, serviceLocation, cityIbge }, `productInvoiceType` (ex. nfce quando aplicável) Mínimo recorrente: ```json { "customer": "018f6e3b-0000-0000-0000-000000000001", "saleDate": "2026-01-15T14:30:00.000Z", "paymentMethod": "pix", "emitWhen": "immediately", "externalId": "pedido-checkout-8899", "products": [{ "sku": "PLAN_MENSAL", "price": 99.9, "quantity": 1 }] } ``` Completo (cliente embutido): ```json { "customer": { "name": "João da Silva", "email": "joao@email.com", "document": "12345678901", "phone": "(11) 98888-7777", "address": { "zipcode": "01310100", "street": "Av. Paulista", "number": "1000", "district": "Bela Vista", "city": "São Paulo", "state": "SP", "complement": "Sala 1" } }, "paymentMethod": "pix", "saleDate": "2026-01-15T14:30:00.000Z", "emitWhen": "after_guarantee", "guaranteeDate": "2026-02-15T00:00:00.000Z", "sendEmail": false, "externalId": "pedido-checkout-8899", "discount": 0, "shipping": 9.9, "products": [ { "id": "01ARZ3NDEKTSV4RRFFQ69G5FAV", "name": "Assinatura anual — plano ouro", "type": "service", "category": "saas", "price": 100, "quantity": 1 } ], "nfse": { "discrimination": "Descrição discriminada do serviço para a prefeitura.", "competenceDate": "2026-01-15T03:00:00.000Z", "serviceLocation": "1", "cityIbge": "3550308" } } ``` Resposta de venda **não** inclui `companyId` (escopo da empresa só no servidor). --- ## NFS-e — /v1/companies/:companyId/nfse (atalho) - `POST /v1/companies/:companyId/nfse` — emite (enfileira). Header opcional `Idempotency-Key` - `GET /v1/companies/:companyId/nfse` — page, pageSize, status (processing|authorized|rejected|canceled) - `GET /v1/companies/:companyId/nfse/:id` - `DELETE /v1/companies/:companyId/nfse/:id` — cancela autorizada Body POST: `serviceDescription` (obrigatório), `amount` (obrigatório), `serviceCode`, `issueDate` ISO, `externalId`, `borrower` { taxId, name (obrigatório), email, phone, address }. ```json { "serviceDescription": "Consultoria em tecnologia", "serviceCode": "01.01", "amount": 1500.0, "borrower": { "taxId": "12345678900", "name": "João Silva", "email": "joao@empresa.com" } } ``` Resposta típica: `{ id, saleId, status, type: "nfse", externalId, amount, createdAt }`. --- ## NF-e — /v1/companies/:companyId/nfe (atalho) - `POST /v1/companies/:companyId/nfe` / `GET .../nfe` / `GET .../nfe/:id` / `DELETE .../nfe/:id` - Também: `.../nfe/:id/pdf|xml|events|items|rejection-xml`, `POST .../nfe/:id/correction`, `POST .../nfe/inutilizations` Body POST: `recipient` { taxId (obrigatório), name, email, phone, address }, `items[]` { sku?, description, ncm?, cfop?, quantity, unitValue, unit? }, `nature`, `cfop`, `issueDate`, `externalId`. ```json { "externalId": "pedido-nfe-100", "recipient": { "taxId": "12345678900", "name": "Maria Souza", "address": { "zipcode": "01310100", "street": "Av. Paulista", "number": "1000", "district": "Bela Vista", "city": "São Paulo", "state": "SP" } }, "items": [ { "description": "Produto exemplo", "ncm": "61091000", "quantity": 1, "unitValue": 150.0, "unit": "UN" } ] } ``` --- ## NFC-e — /v1/companies/:companyId/nfce (requer ativação + CSC) Requer certificado A1, `settings.nfce.active`, `cscId` + `csc`. Destinatário opcional. `paymentMethod` obrigatório. - `POST /v1/companies/:companyId/nfce` — emissão normal ou contingência offline (`issueMode: "offlineContingency"`) - `POST .../nfce/:id/transmit` — após `transmit: "later"` - `GET .../nfce` / `GET .../nfce/:id` - `DELETE .../nfce/:id` — cancela authorized Emissão normal: ```json { "paymentMethod": "pix", "items": [ { "description": "Café espresso", "ncm": "09012100", "quantity": 2, "unitValue": 8.5, "unit": "UN" } ], "recipient": { "taxId": "12345678900", "name": "Maria Souza" }, "externalId": "pedido-nfce-100" } ``` Contingência offline (PDV já imprimiu tpEmis=9): ```json { "issueMode": "offlineContingency", "transmit": "later", "accessKey": "3526…44digitosComTpEmis9", "number": 12345, "series": 1, "issuedAt": "2026-07-12T18:40:00-03:00", "contingency": { "startedAt": "2026-07-12T18:39:55-03:00", "reason": "SEFAZ indisponivel ou sem conexao" }, "paymentMethod": "pix", "items": [{ "description": "Café espresso", "quantity": 2, "unitValue": 8.5 }] } ``` Alternativa: `POST /v1/companies/:companyId/sales` com `productInvoiceType: "nfce"`. PDF/XML: `GET /v1/invoices/:id.pdf` e `GET /v1/invoices/:id.xml`. --- ## CT-e — /v1/companies/:companyId/cte (requer ativação) Domínio próprio (não usa Sale/Invoice). Certificado A1 + `settings.cte.active`. - `POST /v1/companies/:companyId/cte` — modelo 57 rodoviário; participantes shipper/recipient, municípios IBGE, carga, serviceAmount, icms; Idempotency-Key/externalId - `GET .../cte` / `GET .../cte/:id` / `DELETE .../cte/:id` (cancela authorized) - `POST /v1/companies/:companyId/cte-os` — modelo 67 (pessoas/valores/excesso bagagem); takerParty, serviceDescription, serviceAmount, icms, taf **ou** stateAgencyRegistration Webhooks CT-e: `cte.authorized`, `cte.rejected`, `cte.cancelled`. --- ## Notas recebidas — /v1/companies/:companyId/received-nfes NF-e emitidas **contra** o CNPJ da empresa. Requer certificado A1 e NF-e ativa. - `GET /v1/companies/:companyId/received-nfes` — page, limit, search, status (pending|science|confirmed|unknown|notPerformed), startDate, endDate - `POST .../received-nfes/sync` — 202 enfileira DistDFe + ciência automática - `POST .../received-nfes/:id/manifest` — body `{ "type": "confirmed"|"unknown"|"notPerformed", "justification": null }` (notPerformed exige justification 15–255) - `GET .../received-nfes/:id/xml` — `{ xml, accessKey, xmlUrl }` quando disponível --- ## Empresas (resumo) - `GET /v1/companies` — lista todas as empresas da conta - `POST /v1/companies` — cria empresa (CNPJ) - `GET/PUT/DELETE /v1/companies/:companyId` — empresa específica - `GET/POST/DELETE /v1/companies/:companyId/certificate` — metadata / upload / remove (nunca download .pfx) - `GET/POST /v1/companies/:companyId/state-registrations` — multi-IE Detalhes: https://api.emitfy.com/docs/companies --- ## Webhooks (outbound) Cadastre **vários** endpoints na assinatura (cobre todas as empresas) no painel (API & Webhooks) ou via API: - `GET /v1/webhooks` — lista - `POST /v1/webhooks` — cria - `PUT /v1/webhooks/:id` — atualiza - `PATCH /v1/webhooks/:id/active` — `{ "active": true|false }` - `DELETE /v1/webhooks/:id` — remove Body create/update: `url`, `name?`, `headers?: [{ key, value }]`, `events: { invoice: [...], cte?: [...] }`. Eventos de nota (`events.invoice`): `nfse.authorized`, `nfse.cancelled`, `nfse.rejected`, `nfe.authorized`, `nfe.cancelled`, `nfe.rejected`. Eventos CT-e (`events.cte`, quando habilitado): `cte.authorized`, `cte.cancelled`, `cte.rejected`. Payload enviado: ```json { "id": "01JXEVENT...", "event": "nfse.authorized", "createdAt": "2026-07-06T10:30:00.000Z", "data": { "id": "01JXINVOICE...", "saleId": "01JXSALE...", "externalId": "pedido-100", "companyId": "01JXCOMPANY...", "taxId": "00.000.000/0001-00", "status": "authorized", "type": "nfse", "amount": 1500.0, "invoiceNumber": "001234", "issuedAt": "2026-07-06T10:30:00.000Z" } } ``` Headers: `Content-Type`, `User-Agent: Emitfy/1.0.0` + headers customizados do webhook. Retentativas: até 5x com backoff se resposta não for 2xx. --- ## Sandbox / homologação Ambiente de testes: ver https://api.emitfy.com/docs/sandbox — use credenciais e configuração de homologação da empresa. ## Páginas humanas (UI + exemplos curl/JS/PHP) https://api.emitfy.com/docs — use quando precisar de tabelas de parâmetros completas ou screenshots mentais do contrato.