1. Obtén tu API key
Llena el formulario en ipsofactura.com/contacto. Nuestro equipo se pondrá en contacto contigo para compartirte tus credenciales de acceso.2. Registra tu CSD
Para poder timbrar necesitas subir el Certificado de Sello Digital (CSD) de tu empresa: el archivo.cer y la llave privada .key que emite el SAT.
import requests
import base64
# Lee y codifica los archivos en Base64
with open("certificado.cer", "rb") as f:
cer_b64 = base64.b64encode(f.read()).decode()
with open("llave.key", "rb") as f:
key_b64 = base64.b64encode(f.read()).decode()
empresa_id = "a1b2c3d4-e5f6-7890-abcd-ef1234567890" # obtenido en GET /empresas
response = requests.post(
f"https://api.ipsofactura.com/empresas/{empresa_id}/certificados",
headers={
"x-api": "{tu_api_key}",
"Content-Type": "application/json",
},
json={
"certificado_cer_base64": cer_b64,
"llave_key_base64": key_b64,
"password_key": "tu_contraseña_del_key",
"numero_certificado": "00001000000504465028", # 20 dígitos, aparece en el .cer
"fecha_fin": "2027-08-15",
}
)
print(response.json())
import fs from 'fs';
const empresa_id = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890';
const response = await fetch(
`https://api.ipsofactura.com/empresas/${empresa_id}/certificados`,
{
method: 'POST',
headers: {
'x-api': '{tu_api_key}',
'Content-Type': 'application/json',
},
body: JSON.stringify({
certificado_cer_base64: fs.readFileSync('certificado.cer').toString('base64'),
llave_key_base64: fs.readFileSync('llave.key').toString('base64'),
password_key: 'tu_contraseña_del_key',
numero_certificado: '00001000000504465028',
fecha_fin: '2027-08-15',
}),
}
);
console.log(await response.json());
# Primero convierte los archivos a Base64
CER_B64=$(base64 -i certificado.cer)
KEY_B64=$(base64 -i llave.key)
curl -X POST https://api.ipsofactura.com/empresas/{empresa_id}/certificados \
-H "x-api: {tu_api_key}" \
-H "Content-Type: application/json" \
-d "{
\"certificado_cer_base64\": \"$CER_B64\",
\"llave_key_base64\": \"$KEY_B64\",
\"password_key\": \"tu_contraseña_del_key\",
\"numero_certificado\": \"00001000000504465028\",
\"fecha_fin\": \"2027-08-15\"
}"
{
"id": "c3d4e5f6-a1b2-7890-abcd-ef1234567890",
"empresa_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"numero_certificado": "00001000000504465028",
"vigente_hasta": "2027-08-15",
"estado": "activo"
}
3. Timbra tu primer CFDI
Envía los datos del comprobante como JSON aPOST /cfdi/timbrar. Ipsofactura arma, sella y
timbra el CFDI 4.0 con el CSD de tu empresa. Ejemplo: un ingreso PUE en MXN con IVA 16%.
import requests
response = requests.post(
"https://api.ipsofactura.com/cfdi/timbrar",
headers={"x-api": "{tu_api_key}", "Content-Type": "application/json"},
json={
"rfc_emisor": "EKU9003173C9",
"tipo_comprobante": "I",
"forma_pago": "03",
"metodo_pago": "PUE",
"moneda": "MXN",
"subtotal": 1000.00,
"total": 1160.00,
"receptor": {
"rfc": "URE180429TM6",
"nombre": "UNIVERSIDAD ROBOTICA ESPAÑOLA",
"domicilio_fiscal": "65000",
"regimen_fiscal": "601",
"uso_cfdi": "G03",
},
"conceptos": [{
"clave_prod_serv": "01010101", "cantidad": 1, "clave_unidad": "H87",
"descripcion": "Servicio", "valor_unitario": 1000.00, "importe": 1000.00,
"objeto_imp": "02",
"impuestos": {"traslados": [
{"base": 1000.00, "impuesto": "002", "tipo_factor": "Tasa",
"tasa_o_cuota": "0.160000", "importe": 160.00}
]},
}],
"impuestos": {
"total_impuestos_trasladados": 160.00,
"traslados": [{"base": 1000.00, "impuesto": "002", "tipo_factor": "Tasa",
"tasa_o_cuota": "0.160000", "importe": 160.00}],
},
},
)
data = response.json()
print(data["id"]) # id interno del CFDI (úsalo para consultar/descargar/cancelar)
print(data["uuid"]) # folio fiscal (UUID del Timbre Fiscal Digital)
const response = await fetch('https://api.ipsofactura.com/cfdi/timbrar', {
method: 'POST',
headers: { 'x-api': '{tu_api_key}', 'Content-Type': 'application/json' },
body: JSON.stringify({
rfc_emisor: 'EKU9003173C9',
tipo_comprobante: 'I',
forma_pago: '03',
metodo_pago: 'PUE',
moneda: 'MXN',
subtotal: 1000.0,
total: 1160.0,
receptor: {
rfc: 'URE180429TM6', nombre: 'UNIVERSIDAD ROBOTICA ESPAÑOLA',
domicilio_fiscal: '65000', regimen_fiscal: '601', uso_cfdi: 'G03',
},
conceptos: [{
clave_prod_serv: '01010101', cantidad: 1, clave_unidad: 'H87',
descripcion: 'Servicio', valor_unitario: 1000.0, importe: 1000.0, objeto_imp: '02',
impuestos: { traslados: [
{ base: 1000.0, impuesto: '002', tipo_factor: 'Tasa', tasa_o_cuota: '0.160000', importe: 160.0 },
] },
}],
impuestos: {
total_impuestos_trasladados: 160.0,
traslados: [{ base: 1000.0, impuesto: '002', tipo_factor: 'Tasa', tasa_o_cuota: '0.160000', importe: 160.0 }],
},
}),
});
const data = await response.json();
console.log(data.id, data.uuid);
curl -X POST https://api.ipsofactura.com/cfdi/timbrar \
-H "x-api: {tu_api_key}" \
-H "Content-Type: application/json" \
-d '{
"rfc_emisor": "EKU9003173C9",
"tipo_comprobante": "I",
"forma_pago": "03",
"metodo_pago": "PUE",
"moneda": "MXN",
"subtotal": 1000.00,
"total": 1160.00,
"receptor": { "rfc": "URE180429TM6", "nombre": "UNIVERSIDAD ROBOTICA ESPAÑOLA", "domicilio_fiscal": "65000", "regimen_fiscal": "601", "uso_cfdi": "G03" },
"conceptos": [ { "clave_prod_serv": "01010101", "cantidad": 1, "clave_unidad": "H87", "descripcion": "Servicio", "valor_unitario": 1000.00, "importe": 1000.00, "objeto_imp": "02", "impuestos": { "traslados": [ { "base": 1000.00, "impuesto": "002", "tipo_factor": "Tasa", "tasa_o_cuota": "0.160000", "importe": 160.00 } ] } } ],
"impuestos": { "total_impuestos_trasladados": 160.00, "traslados": [ { "base": 1000.00, "impuesto": "002", "tipo_factor": "Tasa", "tasa_o_cuota": "0.160000", "importe": 160.00 } ] }
}'
Respuesta exitosa
{
"id": "9a4f07ff-3abc-435f-b7a6-88c2bc65b4c1",
"uuid": "6128396f-c09b-4ec6-8699-43da5a244971",
"folio": "1",
"fecha_timbrado": "2026-05-28T10:00:00",
"numero_certificado_sat": "00001000000500000000",
"sello_cfdi": "...",
"sello_sat": "...",
"cadena_original_sat": "||1.1|6128396f-...||"
}
id (interno) para consultar el estado, descargar el XML/PDF o cancelar; el uuid
es el folio fiscal del CFDI. Para descargar el XML/PDF usa GET /cfdi/{id}/xml y /pdf.
Para producción, envía tu propia
serie y folio (tu consecutivo interno) y un
idempotency_key en cada request de timbrado. Eso vuelve seguro reintentar tras un
timeout: un reenvío con la misma llave nunca produce un segundo CFDI. Ver
Recuperación tras timeout.Siguientes pasos
Cancelar un CFDI
Aprende a cancelar CFDIs con o sin aceptación del receptor.
Errores comunes
Guía de errores y cómo resolverlos.