Releases: nfe/client-php
Releases · nfe/client-php
Release list
v3.1.0
Adicionado
- Métodos account-scoped em
WebhooksResource, alinhados ao contrato real da
API (/v2/webhooks, confirmado por sondas ao vivo em 3 contas,
2026-07-02/03):listAccountWebhooks(),createAccountWebhook(),
retrieveAccountWebhook(),updateAccountWebhook(),
deleteAccountWebhook(),deleteAllAccountWebhooks()(destrutivo — remove
TODOS os webhooks da conta),pingAccountWebhook()efetchEventTypes()
(lista viva de event types). Create/update enviam o envelope obrigatório
{"webHook": {...}}e as respostas envelopadas são desembrulhadas
(fix-account-webhooks-contract). - Novo DTO
Nfe\Resource\Dto\Webhooks\AccountWebhookcom o shape real do
recurso:id,uri,contentType,secret(32–64 chars; ecoado no
create, omitido nas leituras),filters,insecureSsl,headers,
properties,status,createdOn,modifiedOn,raw. Nota de contrato:
o spec OpenAPI declaracontentType/statuscomo enum int, mas a API
serializa strings ("json","Active") — o DTO segue o fio, e um teste de
alinhamento YAML↔DTO pina o desvio.
Depreciado
- Os métodos company-scoped de
WebhooksResource(list,create,
retrieve,update,delete,test): a rota
/v1/companies/{id}/webhooksretorna 404 incondicional na API atual
(o contrato havia sido herdado de alucinação do SDK Node). Comportamento
inalterado; use os equivalentes*AccountWebhook*. Remoção na próxima
major. WebhooksResource::getAvailableEvents(): os literaisinvoice.*não
existem na API — os ids reais seguemservice_invoice.*/
product_invoice.*/consumer_invoice.*. UsefetchEventTypes().- DTO
Nfe\Resource\Dto\Webhooks\Webhook(url/events): shape rejeitado
pela API (400 "The Uri field is required"). UseAccountWebhook.
Documentação
- Gotchas do contrato real documentados no phpdoc, README e
docs/(recursos/)webhooks.md: a NFE.io pinga aurina criação e
exige resposta 2xx;PUTde update é substituição integral (update sem
statusdesativa o webhook — monte o corpo a partir do retrieve).
v3.0.0
Removido
- BREAKING:
AddressesResource::search()eAddressesResource::lookupByTerm()
foram removidos. O hostaddress.api.nfe.io/v2suporta apenas consulta por
CEP; os endpointsGET /addresses(busca) eGET /addresses/{termo}não
existem (retornam 404), então os métodos nunca funcionaram. Paridade com o
SDK Node (fix-address-lookup-api-mismatch). UselookupByPostalCode().
Corrigido
AddressesResource::lookupByPostalCode()agora desembrulha o envelope real
{ "address": { … } }retornado pela API. Antes,extractAddresses()
procurava a chaveaddresses(plural) — que a API nunca retorna — e caía num
fallback que expunha o envelope inteiro, deixando->addresses[0]['street']
comonull(quebra silenciosa). Agora os campos do endereço ficam legíveis
diretamente em->addresses[0].openapi/consulta-endereco-v3.yamlenxugado para conter só a operação de CEP,
alinhando o spec à API real (as operações de busca/termo eram fantasmas).
v3.0.0-rc.2
Corrigido
composer.jsonnamevoltou a sernfe/nfe(av3.0.0-rc.1shipou
comnfe/client-phppor engano). A v3 mantém o mesmo slug Packagist
da v2 — Composer resolve^2.0e^3.0para a major correta. Não há
pacotenfe/client-phpno Packagist; av3.0.0-rc.1foi indexada
corretamente sobnfe/nfe. README e MIGRATION alinhados.
v3.0.0-rc.1
Corrigido
TaxCodesResourceapontava para/tax-rules/...(plural); a API expõe
esses endpoints em/tax-codes/...(singular, paridade com o SDK Node).
Todos os quatro métodos (listOperationCodes,listAcquisitionPurposes,
listIssuerTaxProfiles,listRecipientTaxProfiles) retornavam 404.
Descoberto via smoke real e corrigido em 2026-06-27.AbstractResource::download()agora segue HTTP 302/303/307 com header
Locationem uma segunda requisição cURL plain, sem enviar
Authorizationao CDN. A API NFE.io responde 302 + Location para o S3
pré-assinado em todos os downloads de PDF/XML; antes, o SDK tratava o
3xx como falha e lançavaInvalidRequestException.AbstractResource::send()agora só auto-throwa em>= 400. 3xx flui
para o caller, permitindo quedownload()siga o redirect manualmente.
2xx (incluindo 202) continua fluindo como antes.CompaniesResource::listAll()agora começa empageIndex = 1. A API da
NFE.io usa paginação 1-based (pageIndex >= 1); o valor antigo0
causava HTTP 400 ("pageIndex must be greater or equal to 1") na primeira
chamada. Descoberto via smoke test contra sandbox real.CompaniesResource::listAll()usapageSize = 50(era 100). A API rejeita
pageCount > 50com HTTP 400 ("pageCount must be between 1 and 50").- Exemplos do README e
samples/service-invoice-list.phpatualizados para
refletir a paginação 1-based. Docblocks delist()emCompaniesResource
eServiceInvoicesResourceagora documentam explicitamente o valor mínimo.
Adicionado
Fundação e tooling
- Baseline em PHP 8.2+. Encerra suporte às versões 5.4 até 8.1.
- Autoload PSR-4 com namespace raiz
Nfe\emsrc/. - Pacote Composer renomeado:
nfe/client-php(antesnfe/nfe). Os dois
podem coexistir durante a migração. Onfe/nfeestá congelado na v2.5. declare(strict_types=1)em todos os arquivos-fonte.- Pest 3, PHPStan nível 8 e PHP-CS-Fixer (PER-CS 2.0 + PHP 8.2 migration)
configurados emrequire-deve impostos pelo CI. - Matriz de CI do GitHub Actions em PHP 8.2 / 8.3 / 8.4.
Cliente, transporte e configuração
Nfe\Clientno estilo Stripe: ponto de entrada único com propriedades
tipadas para cada recurso. Sem estado global, sem chamadas estáticas.Nfe\Configimutável (final readonly) eNfe\Environment(Production
/ Sandbox).Config::baseUrlForApi($familia)roteia recursos para seis hosts
distintos (api.nfe.io, address.api.nfe.io/v2, nfe.api.nfe.io,
legalentity.api.nfe.io, naturalperson.api.nfe.io, api.nfse.io) —
paritário com o mapeamento canônico do SDK Node.dataApiKeyopcional emConfigeClientpara a API de serviços de
dados (consultas de CEP/CNPJ/CPF, query de NF-e/NFC-e). Quando definida,
o SDK roteia as famílias de recurso correspondentes para a chave de
dados; quandonull, faz fallback paraapiKey— espelha a cadeia
resolveDataApiKey()do SDK Node.- Pilha HTTP zero-dependência:
Nfe\Http\CurlTransport(transporte cURL
nativo) +Nfe\Http\RetryingTransport(retry com backoff exponencial
e jitter simétrico, defaults alinhados ao Stripe-PHP). Nfe\Http\RequestOptionspermite override por-chamada deapiKey,
baseUrletimeout(útil em integrações multi-tenant).- Slot opcional para
Psr\Log\LoggerInterface(PSR-3) e adaptador
opcional paraPsr\Http\Client\ClientInterface(PSR-18) — nenhum dos
dois é dependência em runtime.
Recursos (17 propriedades, paridade 1:1 com o SDK Node + 1 paridade-plus)
- Emissão de notas (5):
serviceInvoices(NFS-e),productInvoices
(NF-e),consumerInvoices(NFC-e — paridade-plus, além do Node SDK),
transportationInvoices(CT-e),inboundProductInvoices(NF-e de
entrada). - Consulta de notas (2):
productInvoiceQuery,consumerInvoiceQuery. - Entidades (4):
companies,legalPeople,naturalPeople,
webhooks. - Consultas de dados (3):
addresses(CEP),legalEntityLookup
(CNPJ),naturalPersonLookup(CPF). - Tributação (3):
taxCalculation,taxCodes,stateTaxes.
Tipos de resposta discriminados (HTTP 202 vs 201)
- Interfaces
Nfe\Response\PendingeNfe\Response\Issued<T>modelam a
resposta assíncrona da NFE.io. Cada família de emissão (Service,
Product, Consumer) tem suas implementações concretas
(ServiceInvoicePending/ServiceInvoiceIssued, etc.) comresource(): T
tipado. Nfe\Util\FlowStatus::TERMINALlista os quatro estados terminais
(Issued,IssueFailed,Cancelled,CancelFailed) — espelha
TERMINAL_FLOW_STATESdo SDK Node.Nfe\Util\ListResponse<T>+ListPage— wrapper de listagem (page-style
ou cursor-style).
Hierarquia de exceções tipadas
Nfe\Exception\ApiErrorExceptioncomo base, com subclasses:
InvalidRequestException(400),AuthenticationException(401),
AuthorizationException(403),NotFoundException(404),
RateLimitException(429),ServerException(5xx).Nfe\Exception\ApiConnectionExceptionpara falhas de rede/DNS/TLS.Nfe\Exception\SignatureVerificationExceptionpara assinaturas de
webhook inválidas.- Toda resposta não-2xx é mapeada automaticamente para a subclasse tipada
correspondente na camada de recurso. Antes, respostas 5xx podiam
emergir como DTOs com tudonull; agora geram exceção.
Webhooks
Nfe\Webhook::constructEvent(payload, sigHeader, secret): WebhookEvent
— preferido; valida HMAC-SHA1 sobreX-Hub-Signaturecom comparação
timing-safe (hash_equals) e retorna o evento parseado.Nfe\Webhook::verifySignature()— variante low-level, paridade com
validateSignaturedo SDK Node.Nfe\WebhookEventDTO readonly (type,data,id,createdAt).- Esquema confirmado com a API NFE.io em 2026-05-13.
Pipeline de codegen OpenAPI
- Specs OpenAPI versionadas em
openapi/(12 specs gerando 624 DTOs;
5 specs Swagger 2.0 e 1 sem schemas ficam fora do codegen e usam DTOs
hand-written emsrc/Resource/Dto/). - Geração via
scripts/Generator(symfony/yaml+nikic/php-parser,
ambosrequire-dev). DTOs gerados emsrc/Generated/— nunca
edite à mão. - Comandos
composer generate(regenera) ecomposer generate:check
(verifica drift no CI).
Helpers utilitários
Nfe\Util\IdValidator— validação fail-fast paracompanyId,
invoiceId,accessKey(44 dígitos),stateTaxId,eventKey,cnpj,
cpf,cep,state(UF 2 letras).Nfe\Util\DateNormalizer— convertestring|DateTimeImmutableem
YYYY-MM-DDpara endpoints que aceitam ambos os formatos.Nfe\Util\UserAgent— header padronizadoNfe-PHP/<versão>com sufixo
opcional configurável (ex.:WHMCS/8.10).
Alterado
- O desenvolvimento agora ocorre na branch
v3. Amasterestá congelada
na v2.5.
Removido
lib/NFe/*(código legado autoloaded por classmap).- Integração com runner
test/simpletest/*. Pest substitui o SimpleTest. composer.pharversionado no repositório..travis.yml(substituído por.github/workflows/ci.yml).