Framework-agnostic PHP library for issuing, querying, and cancelling Nota Fiscal de Serviço Eletrônica (NFS-e) via SEFIN Nacional (ABRASF 2.04 / SEFIN 1.0).
Emitting NFS-e in Brazil involves XML signing with ICP-Brasil certificates, SOAP/REST calls to multiple municipal gateways, and safe credential management — all of which most accounting software gets wrong.
nfse-php handles all of it correctly:
- XML signing with PFX/PKCS#12 certificates (native PHP first, CLI repack fallback for OpenSSL legacy format)
- Credential isolation — PFX passwords are never stored in your database; they live in OpenBao / HashiCorp Vault KV v2
- Pluggable secret store — swap OpenBao for any
SecretStoreInterfaceimplementation - Tier-1 tests always run via
donatj/mock-webserver(no real cert required in CI) - Strict PHP 8.2+ types throughout
| Dependency | Version |
|---|---|
| PHP | ^8.2 |
| ext-openssl | * |
| ext-dom | * |
| ext-soap | * |
composer require librecodeoop/nfse-phpuse LibreCodeCoop\NfsePHP\Http\NfseClient;
use LibreCodeCoop\NfsePHP\SecretStore\OpenBaoSecretStore;
use LibreCodeCoop\NfsePHP\Dto\DpsData;
$store = new OpenBaoSecretStore(addr: 'http://localhost:8200', token: getenv('VAULT_TOKEN'));
$client = new NfseClient(secretStore: $store, sandboxMode: true);
$dps = new DpsData(
cnpjPrestador: '11222333000181', // Example only: configure with your provider CNPJ
municipioIbge: '3303302',
// ... other fields
);
$receipt = $client->emit($dps);
echo $receipt->nfseNumber; // NFS-e number returned by the SEFIN gatewayPFX passwords are never persisted in application databases. They are stored in OpenBao (or Vault) KV v2 under a path like nfse/pfx/{cnpj}.
The CNPJ values below are fictitious examples. Configure your own values through your application settings/environment.
use LibreCodeCoop\NfsePHP\SecretStore\OpenBaoSecretStore;
$store = new OpenBaoSecretStore(
addr: getenv('VAULT_ADDR'), // e.g. http://openbao:8200
roleId: getenv('VAULT_ROLE_ID'),
secretId: getenv('VAULT_SECRET_ID'),
mount: 'nfse', // KV v2 mount
);
// Store the PFX password after upload
$store->put('pfx/11222333000181', ['password' => 'secret']);
// Retrieve during signing
$password = $store->get('pfx/11222333000181')['password'];For development/CI without OpenBao, use NoOpSecretStore which reads directly from constructor arguments and never touches any server.
- DPS issuance via SEFIN Nacional REST API
- XML signing (PFX, ICP-Brasil)
- OpenBao / Vault KV v2 secret store
- Mock webserver for CI-friendly testing
- NFS-e query (GET /dps/{id})
- NFS-e cancellation
- Webhook / event polling
- Municipal gateway adapters beyond Niterói
This library is the foundation of the akaunting-nfse module for Akaunting.
Need SLA-backed support, custom municipal adapters, or managed hosting?
Contact us: comercial@librecodecoop.org.br
We welcome issues and pull requests. Please read CONTRIBUTING.md before opening a PR.
All commits must use Conventional Commits and be signed off (git commit -s).
If this library saves you hours of integration pain, please ⭐ the repository.
It helps other developers discover the project and motivates the team to keep improving it.
GNU Affero General Public License v3.0 or later — see LICENSES/AGPL-3.0-or-later.txt.
© 2026 LibreCode Coop and contributors.