Generador de XML de prueba
Genera un CFDI 4.0 emitido por un RFC de prueba del SAT y sellado con su CSD de prueba, listo para enviarse a invoice/stampxml o invoice/stampxmlfile. Permite probar la integración sin usar tu certificado de producción.
Verificación de seguridad en curso.
Aquí se mostrará el XML generado
- Un CFDI 4.0 emitido por un RFC de prueba del SAT y su CSD de prueba.
- La cadena original y el sello, calculados con la XSLT oficial del SAT.
- Los comandos para enviarlo al sandbox con stampxml o stampxmlfile.
- El .cer y la .key del emisor, para sellarlo con tu propio sistema.
Casos de uso
1. Probar stampxml sin tu CSD de producción
Conserva la opción «Sellado con el CSD de prueba», genera el XML y descárgalo. Envíalo al sandbox con la llave de API de tu cuenta de sandbox, como se describe en Envío a stampxml o stampxmlfile. Con esta prueba verificas que tu código codifique correctamente el Base64 o construya la petición multipart, interprete la respuesta y guarde el XML timbrado de cfdi.XmlBase64, antes de instalar tu certificado en un servidor. Si migras de PAC, la guía ¿Migras de PAC? Utiliza stampxml describe el proceso completo.
2. Probar el sellado de tu sistema
Selecciona «Sin sello». El XML se genera con NoCertificado y Certificado del emisor de prueba y con Sello vacío. En la pestaña «CSD de prueba» se descargan su .cer y su .key. Tu sistema debe firmar la cadena original con esa llave y asignar el resultado al atributo Sello. Después, pega el XML en el validador de XML, que recalcula la cadena con la XSLT del SAT e indica si el sello corresponde. Si no corresponde, compara la cadena de tu sistema con la que muestra el validador.
# 1. Convertir la llave del CSD de prueba a PEM (contraseña 12345678a)
openssl pkcs8 -inform DER -in CSD.key -passin pass:12345678a -out llave.pem
# 2. Firmar la cadena original con SHA-256 (cadena.txt sin salto de línea final)
openssl dgst -sha256 -sign llave.pem -out sello.bin cadena.txt
# 3. Obtener el sello en Base64, en una sola línea, para el atributo Sello
openssl base64 -A -in sello.bin
# El atributo Certificado es el .cer en Base64, también en una sola línea
openssl base64 -A -in CSD.cer3. Probar los casos de rechazo
El grupo «Casos de rechazo» del selector de emisor incluye los CSD de prueba que no figuran en la LCO y los RFC de prueba en situación de EFOS. El XML se sella correctamente, pero el timbrado se rechaza. Úsalos para conocer la respuesta de la API y verificar que tu sistema muestre el error en lugar de reintentar indefinidamente. La descripción de cada clave está en la matriz de errores.
4. XML de ejemplo por tipo de comprobante
El generador cubre facturas de ingreso con IVA al 16 %, 8 % o 0 %, exentas, con o sin retenciones; notas de crédito con CFDI relacionado; traslados con valor 0; complementos de pagos 2.0 de facturas PPD y facturas globales a público en general. Estos XML sirven como casos de prueba para tu lector de XML o tu generador de PDF.
Envío a stampxml o stampxmlfile
Ambos métodos timbran el mismo XML y devuelven la misma respuesta. Solo cambia el formato de envío: stampxml recibe el XML en Base64 en el campo xmlbase64 de un formulario, y stampxmlfile lo recibe como archivo en el campo xml de una petición multipart. La referencia completa está en Timbrar XML sellado.
/invoice/stampxml/invoice/stampxmlfile# Base64 en el formulario (stampxml)
curl -sS -X POST "https://sandbox-app.facturadigital.com.mx/api/v5/invoice/stampxml" \
-H "X-Api-Key: $FD_API_KEY" \
--data-urlencode "xmlbase64=$(base64 < cfdi-prueba.xml | tr -d '\n')"
# El archivo tal cual (stampxmlfile)
curl -sS -X POST "https://sandbox-app.facturadigital.com.mx/api/v5/invoice/stampxmlfile" \
-H "X-Api-Key: $FD_API_KEY" \
-F "xml=@cfdi-prueba.xml"<?php
$xml = file_get_contents('cfdi-prueba.xml');
$ch = curl_init('https://sandbox-app.facturadigital.com.mx/api/v5/invoice/stampxml');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['X-Api-Key: ' . getenv('FD_API_KEY')],
CURLOPT_POSTFIELDS => http_build_query(['xmlbase64' => base64_encode($xml)]),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 120,
]);
$r = json_decode(curl_exec($ch), true);
echo $r['code'], ' ', $r['message'], PHP_EOL;
// stampxmlfile: el archivo como multipart
// CURLOPT_POSTFIELDS => ['xml' => new CURLFile('cfdi-prueba.xml', 'text/xml')]import { readFile } from "node:fs/promises";
const xml = await readFile("cfdi-prueba.xml");
const res = await fetch("https://sandbox-app.facturadigital.com.mx/api/v5/invoice/stampxml", {
method: "POST",
headers: { "X-Api-Key": process.env.FD_API_KEY },
body: new URLSearchParams({ xmlbase64: xml.toString("base64") }),
signal: AbortSignal.timeout(120_000),
});
const r = await res.json();
console.log(r.code, r.message, r.cfdi?.UUID);
// stampxmlfile: el archivo como multipart
// const form = new FormData();
// form.append("xml", new Blob([xml], { type: "text/xml" }), "cfdi-prueba.xml");import base64, os, requests
with open("cfdi-prueba.xml", "rb") as f:
xml = f.read()
r = requests.post(
"https://sandbox-app.facturadigital.com.mx/api/v5/invoice/stampxml",
headers={"X-Api-Key": os.environ["FD_API_KEY"]},
data={"xmlbase64": base64.b64encode(xml).decode()},
timeout=120,
)
print(r.json())
# stampxmlfile: el archivo como multipart
# requests.post(".../invoice/stampxmlfile", headers=..., files={"xml": open("cfdi-prueba.xml", "rb")})var xml = await File.ReadAllBytesAsync("cfdi-prueba.xml");
using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(120) };
http.DefaultRequestHeaders.Add("X-Api-Key", Environment.GetEnvironmentVariable("FD_API_KEY"));
var body = new FormUrlEncodedContent(new Dictionary<string, string> {
["xmlbase64"] = Convert.ToBase64String(xml),
});
var res = await http.PostAsync("https://sandbox-app.facturadigital.com.mx/api/v5/invoice/stampxml", body);
Console.WriteLine(await res.Content.ReadAsStringAsync());
// stampxmlfile: el archivo como multipart
// var form = new MultipartFormDataContent { { new ByteArrayContent(xml), "xml", "cfdi-prueba.xml" } };Si el timbrado es exitoso, la respuesta es HTTP 200 y el XML timbrado, con el TimbreFiscalDigital, se devuelve en cfdi.XmlBase64.
{
"message": "XML stamped successfully",
"code": 200,
"cfdi": {
"UUID": "6F0C2E1A-9B3D-4C7E-8A51-2D4F6B8C0E13",
"FechaTimbrado": "2026-11-04T10:15:30",
"NoCertificado": "30001000000500003416",
"SelloCFD": "Q2V4...Zm9vYmFy",
"SelloSAT": "Tm9w...ZGF0YQ==",
"XmlBase64": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4..."
}
}- Si envías el mismo XML dos veces, la segunda solicitud responde
timbre_previocon el UUID original y no consume otro folio. Para una prueba nueva, genera otro XML. - El SAT no permite timbrar un CFDI emitido hace más de 72 horas. El generador asigna como
Fechala hora local del código postal del emisor menos 5 minutos, por lo que el XML debe timbrarse dentro de ese plazo. - Si hay un error, la respuesta es HTTP 400 y
messagecomienza con la clave del SAT. Consulta la clave en la matriz de errores.
RFC y CSD de prueba
Estos son los RFC de prueba del SAT para el ambiente de pruebas, cada uno con su CSD. La contraseña de todas las llaves es 12345678a. Cuando un RFC se usa como receptor, el nombre y el código postal deben coincidir con los de esta lista, ya que el ambiente de pruebas los compara con la lista de RFC del SAT (CFDI40145 y CFDI40147).
Timbran en el sandbox y pueden usarse como emisor o como receptor.
| RFC | Nombre | C. P. | Régimen | NoCertificado |
|---|---|---|---|---|
| ESCUELA KEMPER URGATE | 601 | |||
| XENON INDUSTRIAL ARTICLES | 622 | |||
| HERRERIA & ELECTRICOS | 601 | |||
| INDISTRIA ILUMINADORA DE ALMACENES | 626 | |||
| INNOVACION VALOR Y DESARROLLO | 601 | |||
| INTERNACIONAL XIMBO Y SABORES | 603 | |||
| JIMENEZ ESTRADA SALAS | 622 | |||
| KERNEL INDUSTIA JUGUETERA | 622 | |||
| LUCES & OBRAS | 626 | |||
| ORGANICOS ÑAVEZ OSORIO | 601 | |||
| S & SOFTWARE | 624 | |||
| UNIVERSIDAD ROBOTICA ESPAÑOLA | 601 | |||
| ZAPATERIA URTADO ÑERI | 626 |
El régimen corresponde a las características fiscales registradas para cada RFC de prueba. El SAT no lo compara con su registro y solo valida que corresponda al tipo de persona.
Contenido del XML
- CFDI 4.0 en MXN con
Exportacion="01". La serie es FD, NC, TR o RP según el tipo de comprobante, con un folio aleatorio. - Importes con dos decimales. Cada impuesto por concepto se redondea a centavos y los totales son la suma de los conceptos, conforme a la matriz de validaciones del SAT.
- Con IVA al 8 %,
LugarExpediciones el código postal 88000 (Nuevo Laredo, Tamaulipas). El timbrado solo acepta esa tasa cuando el lugar de expedición tiene el estímulo de la franja fronteriza en el catálogo de códigos postales del SAT. - Retenciones solo cuando aplican, es decir, cuando una persona física con régimen 606, 612 o 626 factura a una persona moral. Se retiene ISR al 10 % (1.25 % en RESICO) y dos terceras partes del IVA.
- Para público en general se usa el RFC XAXX010101000, el régimen 616, el uso S01 y el código postal del emisor. Las facturas de ingreso incluyen
InformacionGlobalcon periodicidad mensual. - El comprobante de pago lleva
Moneda="XXX", un concepto «Pago» con valor 0 y el complementopago20:Pagos, con un pago que liquida la factura PPD en una sola parcialidad, junto con sus impuestos y totales. - La cadena original se genera con la XSLT del SAT y el sello usa RSA con SHA-256. Cada XML se valida contra el esquema del SAT.
El generador no produce nómina, Carta Porte, comercio exterior ni comprobantes en otras monedas. Para esos casos, genera el XML en tu sistema, séllalo con el CSD de prueba que se descarga aquí y revísalo en el validador de XML, que admite todos los complementos del SAT.
Revisado contra la API v5 en producción el 2026-11-03.