---
title: "Certificados digitais (certificates) no SDK Python da NFE.io"
description: "Envie o certificado digital A1 (PFX/P12) de uma empresa e consulte validade e status com client.certificates."
source_url: https://nfe.io/docs/desenvolvedores/bibliotecas/python/recursos/certificados/
product: bibliotecas
last_updated: 2026-10-14
tags: ["python", "referencia", "certificado"]
integration: ["sdk"]
---

# Certificados digitais (`certificates`)

`client.certificates` envia o certificado digital A1 de uma empresa e lista os certificados
cadastrados. Usa `https://api.nfse.io` com a `api_key`.

## Métodos

```python
certificates.upload(company_id, file, password, *, filename=None, options=None) -> Certificate
certificates.list(company_id, *, options=None) -> list[Certificate]
```

## Enviar

`file` aceita o caminho do arquivo, os `bytes` ou um arquivo aberto em modo binário:

```python
from pathlib import Path

from nfeio import NfeClient

client = NfeClient()
company_id = "ID_DA_EMPRESA"

cert = client.certificates.upload(company_id, Path("certificado.pfx"), "senha-do-certificado")
print(cert.thumbprint, cert.status, cert.expires_on)

# ou com um arquivo aberto:
with open("certificado.pfx", "rb") as arquivo:
    client.certificates.upload(company_id, arquivo, "senha-do-certificado")
```

- O arquivo precisa ter entre 1 byte e 1 MiB, e a senha não pode ser vazia. As duas regras são
  conferidas antes do envio (`InvalidParameterError`).
- A senha nunca aparece em log, `repr` ou mensagem de erro, mesmo se a API a ecoar.
- O upload é um `POST`: não é repetido automaticamente depois de enviado.
- Um arquivo que não é um PFX válido foi recusado pela API com **`500`**, não `400`, nos testes do
  SDK. O erro chega como `ServerError` e, por ser um `POST`, com `outcome_unknown=True`. Confira o
  arquivo e a senha antes de reenviar e, na dúvida, veja em `certificates.list` se o certificado
  entrou.

## Consultar validade

```python
from datetime import datetime, timedelta, timezone

from nfeio import NfeClient

client = NfeClient()

daqui_a_30_dias = datetime.now(timezone.utc) + timedelta(days=30)
for cert in client.certificates.list("ID_DA_EMPRESA"):
    if cert.is_expired():
        print(cert.thumbprint, "vencido")
    elif cert.is_expired(at=daqui_a_30_dias):
        print(cert.thumbprint, "vence em menos de 30 dias:", cert.expires_on)
    else:
        print(cert.thumbprint, "válido até", cert.expires_on)
```

`list` devolve uma `list` comum (vazia quando não há certificado). Propriedades de `Certificate`:
`thumbprint`, `tax_id` (CNPJ ou CPF do titular, como `str`), `status`, `provider_type`,
`expires_on` (`datetime` com fuso) e `modified_on`. `is_expired(at=None)` compara a validade com o
momento informado (agora, em UTC, por padrão); um certificado sem data legível conta como vencido.

## Veja também

- [Empresas](./companies.md).
- [API de certificados digitais](../../../../documentacao/gerenciamento-empresas/gerenciamento-certificado.md)
  e [upload do certificado pelo painel](../../../../documentacao/nossa-plataforma/upload-do-certificado-digital.md).
