Skip to main content

ipsofactura (Python)

Cliente oficial de Ipsofactura para Python — timbrado CFDI 4.0 para México.

Incluye clientes síncrono y asíncrono.


Instalación

pip install ipsofactura

Requiere Python 3.9+ y httpx>=0.27 (se instala automáticamente).


Inicio rápido

from ipsofactura import IpsofacturaClient

with IpsofacturaClient("tu-api-key") as client:
    cfdi = client.cfdi.timbrar({ ... })  # payload CFDI 4.0
    print(cfdi["folio_fiscal"])

Autenticación

La API usa el header x-api con tu API key. El cliente lo agrega automáticamente.

client = IpsofacturaClient("tu-api-key")

Sandbox vs Producción

Por defecto el cliente apunta a producción (https://api.ipsofactura.com). Para usar el sandbox:

from ipsofactura import IpsofacturaClient, SANDBOX_BASE_URL

client = IpsofacturaClient("tu-api-key", base_url=SANDBOX_BASE_URL)

El sandbox usa el RFC de prueba del SAT EKU9003173C9. Los CFDIs timbrados ahí no tienen validez fiscal.


Ejemplos — cliente síncrono

Timbrar una factura (tipo I)

from ipsofactura import IpsofacturaClient

with IpsofacturaClient("tu-api-key") as client:
    result = client.cfdi.timbrar({
        "rfc_emisor": "MI_RFC",
        "serie": "A",
        "folio": "1",
        "tipo_comprobante": "I",
        "moneda": "MXN",
        "forma_pago": "03",
        "metodo_pago": "PUE",
        "receptor": {
            "rfc": "URE180429TM6",
            "nombre": "UNIVERSIDAD ROBOTICA ESPANOLA",
            "domicilio_fiscal": "65000",
            "regimen_fiscal": "601",
            "uso_cfdi": "G03",
        },
        "conceptos": [
            {
                "clave_prod_serv": "01010101",
                "cantidad": 1,
                "clave_unidad": "H87",
                "descripcion": "Servicio de desarrollo",
                "valor_unitario": 5000,
                "importe": 5000,
                "objeto_imp": "02",
                "impuestos": {
                    "traslados": [{
                        "base": 5000,
                        "impuesto": "002",
                        "tipo_factor": "Tasa",
                        "tasa_o_cuota": "0.160000",
                        "importe": 800,
                    }]
                },
            }
        ],
        "subtotal": 5000,
        "impuestos": {
            "total_impuestos_trasladados": 800,
            "traslados": [{
                "base": 5000,
                "impuesto": "002",
                "tipo_factor": "Tasa",
                "tasa_o_cuota": "0.160000",
                "importe": 800,
            }],
        },
        "total": 5800,
    })

    print(result["folio_fiscal"])  # UUID del SAT
    print(result["id"])            # ID interno de Ipsofactura

Timbrar nómina

nomina = client.cfdi.timbrar_nomina({
    "rfc_emisor": "MI_RFC",
    # ... campos del complemento de nómina 1.2
})

Cancelar un CFDI

cancelacion = client.cfdi.cancelar({
    "id": "cfdi_abc123",
    "motivo": "02",
    "folio_sustitucion": "cfdi_xyz456",  # solo si motivo es "01"
})

Listar CFDIs con filtros

lista = client.cfdi.list(
    page=1,
    per_page=50,
    rfc_emisor="MI_RFC",
    tipo_comprobante="I",
)

Obtener XML y PDF

xml = client.cfdi.get_xml("cfdi_abc123")   # {"xml_url": "https://..."}
pdf = client.cfdi.get_pdf("cfdi_abc123")   # {"pdf_url": "https://..."}

Gestionar empresas emisoras

# Listar todas las empresas
empresas = client.empresas.list()

# Crear empresa
empresa = client.empresas.crear({
    "rfc": "MI_RFC",
    "nombre": "Mi Empresa S.A. de C.V.",
    "regimen_fiscal": "601",
    "domicilio_fiscal": "06600",
})

# Subir certificado CSD
import base64

with open("cert.cer", "rb") as f:
    cer_b64 = base64.b64encode(f.read()).decode()

with open("cert.key", "rb") as f:
    key_b64 = base64.b64encode(f.read()).decode()

client.empresas.subir_certificado(empresa["id"], {
    "cer": cer_b64,
    "key": key_b64,
    "password": "contraseña_del_certificado",
})

Webhooks

# Crear webhook
webhook = client.webhooks.crear({
    "url": "https://mi-sistema.com/hooks/ipsofactura",
    "events": ["cfdi.timbrado", "cfdi.cancelado"],
    "secret": "mi-secreto-seguro",
})

# Ver historial de entregas
deliveries = client.webhooks.list_deliveries(webhook["id"])

# Reenviar una entrega fallida
client.webhooks.resend_delivery(webhook["id"], deliveries[0]["id"])

# Enviar evento de prueba
client.webhooks.test(webhook["id"])

Ejemplos — cliente asíncrono

import asyncio
from ipsofactura import AsyncIpsofacturaClient

async def main():
    async with AsyncIpsofacturaClient("tu-api-key") as client:
        # Timbrar
        cfdi = await client.cfdi.timbrar({ ... })
        print(cfdi["folio_fiscal"])

        # Consultar empresas y webhooks en paralelo
        import asyncio
        empresas, webhooks = await asyncio.gather(
            client.empresas.list(),
            client.webhooks.list(),
        )
        print(f"{len(empresas)} empresas, {len(webhooks)} webhooks")

asyncio.run(main())

Verificar firma de webhook

from ipsofactura import verify_webhook_signature

# En tu endpoint receptor (Flask, FastAPI, etc.)
# FastAPI:
from fastapi import FastAPI, Request, HTTPException

app = FastAPI()

@app.post("/webhook")
async def webhook(request: Request):
    raw_body = (await request.body()).decode("utf-8")
    timestamp = request.headers.get("x-ipso-timestamp", "")
    signature = request.headers.get("x-ipso-signature", "")

    if not verify_webhook_signature(raw_body, timestamp, signature, WEBHOOK_SECRET):
        raise HTTPException(status_code=401, detail="Firma inválida")

    evento = await request.json()
    print(f"Evento recibido: {evento['type']}")
    return {"ok": True}

Manejo de errores

from ipsofactura import IpsofacturaClient, IpsofacturaError

try:
    client.cfdi.timbrar({ ... })
except IpsofacturaError as err:
    print(f"Error {err.status_code}: [{err.code}] {err.message}")
    if err.sat_code:
        print(f"Código SAT: {err.sat_code}")
    if err.retry_after:
        print(f"Reintentar en {err.retry_after} segundos")

Requisitos

  • Python >= 3.9
  • httpx >= 0.27

Licencia

MIT — Palenca LTDA

Metadata

Release files for ipsofactura 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ipsofactura 0.1.0
File Size Uploaded Provenance Actions
ipsofactura-0.1.0.tar.gz 11.0 kB Without provenance Details for ipsofactura-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ipsofactura 0.1.0
File Interpreter ABI Platform Actions
ipsofactura-0.1.0-py3-none-any.whl Python 3 none any Details for ipsofactura-0.1.0-py3-none-any.whl

Total release size: 20.6 kB

Release files / ipsofactura-0.1.0.tar.gz

Download URL ipsofactura-0.1.0.tar.gz
Size 11.0 kB
Tags Source
SHA-256 checksum
How to use checksums
0b3b92beba89563006b0f855995dc97ec6d594766f6bc566a39ce9da86fc8d5e
BLAKE2b-256 checksum
How to use checksums
9f2be6d5173b563d8abd36908747e30bba039b64a03a2fc034fb7c50b4491584
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.3

Release files / ipsofactura-0.1.0-py3-none-any.whl

Download URL ipsofactura-0.1.0-py3-none-any.whl
Size 9.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
21869c95b66f95467171314c8cd8d2c86bd5d2a1800f0b82a2930c3e43f7d3a8
BLAKE2b-256 checksum
How to use checksums
6314340a3c35a1d56adbbaa61592bc8cda203aaf6792f8ca5c7445c72681fbbe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.3

Security for ipsofactura 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page