ipsofacturaHablar con Ventas →
← Blog
SandboxAPIDesarrollo

Cómo empezar a probar el sandbox de Ipsofactura

30 Jul 2026|15 min de lectura

Si estás integrando Ipsofactura en tu sistema, lo primero que necesitas es probar el flujo completo sin emitir facturas fiscalmente válidas ni consumir timbres. Para eso existe el sandbox.

Esta guía te lleva de cero a tu primera factura timbrada, cancelada y descargada — todo en el ambiente de pruebas.


¿Qué es el sandbox?

El sandbox de Ipsofactura es un ambiente completamente aislado de producción. Tiene su propia base de datos, se conecta a los ambientes de prueba de los PACs y no consume timbres de tu saldo real.

Lo que sí funciona igual que en producción:

  • El flujo completo de timbrado y cancelación
  • La descarga de XML y PDF
  • La validación de estructura del CFDI
  • Los errores y códigos de respuesta

Lo que no aplica en sandbox:

  • Los CFDIs timbrados no son válidos ante el SAT
  • No necesitas un CSD real: puedes usar el CSD de prueba oficial del SAT

Lo que necesitas antes de empezar

  • Una cuenta en console.ipsofactura.com
  • Una API key de sandbox, que crearemos en el paso 2
  • curl, Python, Node.js o cualquier cliente HTTP

Paso 1 — Accede a la consola

Entra a console.ipsofactura.com. El acceso es por magic link: ingresa tu email y recibirás un enlace directo en tu correo.

Pantalla de login de la consola de Ipsofactura
Importante
El magic link debe abrirse en el mismo navegador donde ingresaste tu email.

Una vez autenticado llegas al dashboard principal.

Dashboard de la consola de Ipsofactura

Paso 2 — Crea una API key de sandbox

En el menú lateral, ve a API Keys y asegúrate de estar en el tab Sandbox.

Lista de API keys de sandbox

Haz clic en Nueva API key, asígnale un nombre descriptivo, por ejemplo mi-integracion-dev, y haz clic en Crear API key.

Diálogo de creación de una API key

La key se muestra una sola vez. Cópiala y guárdala en un lugar seguro, como un gestor de contraseñas o una variable de entorno. No la pongas directamente en tu código.

API key recién generada con su valor oculto
El valor de la API key fue difuminado en esta captura.
Seguridad
Tu API key se ve como ifk_test_xxxxxxxxxxxxxxxxxxxx. Nunca la expongas en repositorios públicos ni en código frontend.

Después de confirmar que guardaste la key, volverás a verla en la lista con su valor oculto.

Confirmación de la API key guardada

Paso 3 — Crea tu empresa emisora

Antes de timbrar necesitas registrar el RFC emisor. Usaremos EKU9003173C9, el RFC de prueba oficial del SAT que los PACs reconocen en sus ambientes de test.

curl -X POST https://sandbox.api.ipsofactura.com/empresas \
  -H "x-api: TU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "rfc": "EKU9003173C9",
    "nombre_fiscal": "ESCUELA KEMPER URGATE",
    "nombre_empresa": "Escuela Kemper Urgate",
    "regimen_fiscal": "601",
    "codigo_postal": "06000"
  }'

Python

import requests

response = requests.post(
    "https://sandbox.api.ipsofactura.com/empresas",
    headers={"x-api": "TU_API_KEY"},
    json={
        "rfc": "EKU9003173C9",
        "nombre_fiscal": "ESCUELA KEMPER URGATE",
        "nombre_empresa": "Escuela Kemper Urgate",
        "regimen_fiscal": "601",
        "codigo_postal": "06000"
    }
)
print(response.json())

JavaScript

const response = await fetch("https://sandbox.api.ipsofactura.com/empresas", {
  method: "POST",
  headers: {
    "x-api": "TU_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    rfc: "EKU9003173C9",
    nombre_fiscal: "ESCUELA KEMPER URGATE",
    nombre_empresa: "Escuela Kemper Urgate",
    regimen_fiscal: "601",
    codigo_postal: "06000"
  })
});
console.log(await response.json());

Respuesta esperada (201 Created):

{
  "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "rfc": "EKU9003173C9",
  "nombre_empresa": "Escuela Kemper Urgate",
  "nombre_fiscal": "ESCUELA KEMPER URGATE",
  "regimen_fiscal": "601",
  "codigo_postal": "06000",
  "es_activo": true
}

Guarda el id: lo necesitarás para el siguiente paso.

¿Ya existe?
Si recibes 409 EMPRESA_ALREADY_EXISTS es porque ya registraste este RFC. Puedes consultarlo con GET /empresas.

Paso 4 — Sube un CSD de prueba

El CSD (Certificado de Sello Digital) es el certificado criptográfico con el que se firma cada CFDI. Para sandbox necesitas el CSD oficial de prueba del SAT para el RFC EKU9003173C9.

Descarga el CSD de prueba del SAT: obtén los archivos .cer y .key del RFC EKU9003173C9 desde el portal del SAT, en Pruebas → Genera CSD de prueba, o usa los que ya tengas del SAT. La contraseña estándar de este CSD de prueba es 12345678a.

Convierte los archivos a Base64:

# En macOS/Linux
CER_B64=$(base64 -i CSD_EKU9003173C9.cer)
KEY_B64=$(base64 -i CSD_EKU9003173C9.key)
import base64

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

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

Luego súbelo:

curl -X POST https://sandbox.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": "12345678a",
    "numero_certificado": "20001000000300022323",
    "fecha_fin": "2027-05-18T00:00:00"
  }'
import requests, base64

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

response = requests.post(
    f"https://sandbox.api.ipsofactura.com/empresas/{EMPRESA_ID}/certificados",
    headers={"x-api": "TU_API_KEY"},
    json={
        "certificado_cer_base64": cer_b64,
        "llave_key_base64": key_b64,
        "password_key": "12345678a",
        "numero_certificado": "20001000000300022323",
        "fecha_fin": "2027-05-18T00:00:00"
    }
)
print(response.json())
Formato
El campo fecha_fin requiere formato datetime (2027-05-18T00:00:00), no solo la fecha.

Respuesta esperada (201 Created):

{
  "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "empresa_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "numero_certificado": "30001000000500003416",
  "estado": "VALIDO",
  "fecha_fin": "2027-05-18",
  "es_activo": true
}

El API extrae el número de certificado directamente del archivo .cer. El numero_certificado que envíes en el body es ignorado; cuenta el que viene en el archivo.

Paso 5 — Timbra tu primera factura

Con la empresa y el CSD registrados ya puedes timbrar. El siguiente ejemplo es una factura de tipo Ingreso (I) con pago en una sola exhibición (PUE).

curl -X POST https://sandbox.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",
    "exportacion": "01",
    "subtotal": 1000.00,
    "total": 1160.00,
    "receptor": {
      "rfc": "URE180429TM6",
      "nombre": "UNIVERSIDAD ROBOTICA ESPANOLA",
      "domicilio_fiscal": "65000",
      "regimen_fiscal": "601",
      "uso_cfdi": "G03"
    },
    "conceptos": [{
      "clave_prod_serv": "84111506",
      "cantidad": 1,
      "clave_unidad": "ACT",
      "descripcion": "Servicio de desarrollo de software",
      "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
      }]
    }
  }'

Python

import requests

payload = {
    "rfc_emisor": "EKU9003173C9",
    "tipo_comprobante": "I",
    "forma_pago": "03",
    "metodo_pago": "PUE",
    "moneda": "MXN",
    "exportacion": "01",
    "subtotal": 1000.00,
    "total": 1160.00,
    "receptor": {
        "rfc": "URE180429TM6",
        "nombre": "UNIVERSIDAD ROBOTICA ESPANOLA",
        "domicilio_fiscal": "65000",
        "regimen_fiscal": "601",
        "uso_cfdi": "G03"
    },
    "conceptos": [{
        "clave_prod_serv": "84111506",
        "cantidad": 1,
        "clave_unidad": "ACT",
        "descripcion": "Servicio de desarrollo de software",
        "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
        }]
    }
}

response = requests.post(
    "https://sandbox.api.ipsofactura.com/cfdi/timbrar",
    headers={"x-api": "TU_API_KEY"},
    json=payload
)
print(response.json())

JavaScript

const response = await fetch("https://sandbox.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",
    exportacion: "01",
    subtotal: 1000.00,
    total: 1160.00,
    receptor: {
      rfc: "URE180429TM6",
      nombre: "UNIVERSIDAD ROBOTICA ESPANOLA",
      domicilio_fiscal: "65000",
      regimen_fiscal: "601",
      uso_cfdi: "G03"
    },
    conceptos: [{
      clave_prod_serv: "84111506",
      cantidad: 1,
      clave_unidad: "ACT",
      descripcion: "Servicio de desarrollo de software",
      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
      }]
    }
  })
});
console.log(await response.json());

Respuesta esperada (201 Created):

{
  "id": "52e9959d-3fbf-4580-988a-39ca1138dd52",
  "uuid": "7b72fe22-7b95-48cd-bd64-63c8d1925555",
  "folio": "1",
  "fecha_timbrado": "2026-07-28T14:35:18",
  "rfc_pac": "AAA010101AAA",
  "pac_provider": "SandboxPacHandler",
  "numero_certificado_sat": "30001000000500003416",
  "sello_cfdi": "SANDBOX_sello_cfdi_...",
  "sello_sat": "..."
}

Guarda el campo id (ID interno): lo necesitas para consultar el estado, descargar archivos y cancelar.

Puedes ver el CFDI recién creado en la consola:

Sección CFDIs en la consola

Paso 6 — Consulta el estado y descarga el XML/PDF

Consultar estado

curl https://sandbox.api.ipsofactura.com/cfdi/{CFDI_ID}/estatus \
  -H "x-api: TU_API_KEY"
response = requests.get(
    f"https://sandbox.api.ipsofactura.com/cfdi/{CFDI_ID}/estatus",
    headers={"x-api": "TU_API_KEY"}
)
print(response.json())
# {"id": "...", "estado": "vigente"}

Descargar XML

curl https://sandbox.api.ipsofactura.com/cfdi/{CFDI_ID}/xml \
  -H "x-api: TU_API_KEY"

Respuesta:

{
  "id": "52e9959d-3fbf-4580-988a-39ca1138dd52",
  "xml_url": "https://sandbox.api.ipsofactura.com/sandbox/files/..."
}

Descargar PDF

curl https://sandbox.api.ipsofactura.com/cfdi/{CFDI_ID}/pdf \
  -H "x-api: TU_API_KEY"

Respuesta:

{
  "id": "52e9959d-3fbf-4580-988a-39ca1138dd52",
  "pdf_url": "https://sandbox.api.ipsofactura.com/sandbox/files/..."
}

Paso 7 — Cancela la factura

La cancelación en México requiere especificar un motivo. Los más comunes para pruebas son:

MotivoDescripción
01Comprobante emitido con errores con relación
02Comprobante emitido con errores sin relación
03No se llevó a cabo la operación
04Operación nominativa relacionada en una factura global
curl -X POST https://sandbox.api.ipsofactura.com/cfdi/cancelar \
  -H "x-api: TU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "{CFDI_ID}",
    "rfc_emisor": "EKU9003173C9",
    "motivo": "03"
  }'

Python

response = requests.post(
    "https://sandbox.api.ipsofactura.com/cfdi/cancelar",
    headers={"x-api": "TU_API_KEY"},
    json={
        "id": CFDI_ID,
        "rfc_emisor": "EKU9003173C9",
        "motivo": "03"
    }
)
print(response.json())

JavaScript

const response = await fetch("https://sandbox.api.ipsofactura.com/cfdi/cancelar", {
  method: "POST",
  headers: {
    "x-api": "TU_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    id: CFDI_ID,
    rfc_emisor: "EKU9003173C9",
    motivo: "03"
  })
});
console.log(await response.json());

Respuesta esperada (200 OK):

{
  "id": "7b72fe22-7b95-48cd-bd64-63c8d1925555",
  "estatus": "cancelado",
  "fecha_cancelacion": "2026-07-28T14:35:19",
  "acuse": "<Acuse>SANDBOX</Acuse>",
  "estatus_cancelacion": "201"
}
Importante
El campo id en el body es el ID interno que devuelve /cfdi/timbrar, no el UUID del SAT.

Paso 8 — Revisa los logs en la consola

La consola tiene una sección de API Logs donde puedes ver todas las requests, el status code de cada una y el payload de respuesta. Es muy útil para depurar tu integración.

Sección API Logs en la consola

También puedes ver tus emisores registrados:

Sección Emisores en la consola

Referencia rápida: endpoints del sandbox

MétodoEndpointDescripción
GET/empresasListar empresas registradas
POST/empresasCrear empresa emisora
POST/empresas/{id}/certificadosSubir CSD
DELETE/empresas/{id}/certificados/{num}Eliminar CSD
GET/cfdiListar CFDIs (paginado)
POST/cfdi/timbrarTimbrar un CFDI
GET/cfdi/{id}/estatusConsultar estado del CFDI
GET/cfdi/{id}/xmlDescargar XML
GET/cfdi/{id}/pdfDescargar PDF
POST/cfdi/cancelarCancelar un CFDI
POST/cfdi/complemento-pagoEmitir complemento de pago
Configuración del sandbox
Base URL: https://sandbox.api.ipsofactura.com
Autenticación: header x-api: TU_API_KEY

Buenas prácticas al integrar

Nunca pongas tu API key en el código. Usa variables de entorno:

export IPSO_API_KEY="ifk_test_xxxxxxxxxxxx"
import os
api_key = os.environ["IPSO_API_KEY"]
const apiKey = process.env.IPSO_API_KEY;

Maneja los errores por código. Ipsofactura retorna errores estructurados:

{
  "code": "CERTIFICATE_NOT_FOUND",
  "message": "No se encontró un certificado activo para este RFC"
}

Los códigos más comunes que verás al probar:

CódigoCuándo ocurre
CERTIFICATE_NOT_FOUNDIntentas timbrar sin CSD registrado
EMPRESA_ALREADY_EXISTSEl RFC ya está registrado para tu cuenta
DUPLICATE_CERTIFICATEEl número de certificado ya está registrado
INVALID_API_KEYLa API key es incorrecta o fue revocada
VALIDATION_ERRORLa estructura del CFDI es inválida

¿Listo para producción?

Cuando tu integración funcione bien en sandbox, el cambio a producción es un one-liner: reemplaza la base URL.

SandboxProducción
Base URLhttps://sandbox.api.ipsofactura.comhttps://api.ipsofactura.com
API keyifk_test_…ifk_live_…
CSDDe prueba del SATTu CSD real y vigente
Timbres consumidosNo
Validez fiscalNo

Genera una API key de producción desde la misma consola, sube tu CSD real y apunta tus requests a api.ipsofactura.com.

¿Tienes dudas?
¿Listo para automatizar?

Empieza a timbrar en menos de 2 horas.

Primeros 100 timbres sin costo. Sandbox listo. Sin contrato anual.

Hablar con Ventas →

Más artículos

8 min · API
Cómo integrar una API de facturación SAT en tu sistema
5 min · CFDI
¿Qué es el timbrado de CFDI 4.0? Guía completa