Skip to content
On this page

Timbrado desde JSON ​

Construye el CFDI en JSON y deja que Timbra genere el XML, lo selle y lo timbre ante el PAC.

POST/api/masivo/v3/cfdi33/issue/json/v4

Timbra un CFDI 4.0 a partir de un objeto JSON.

Auth: BearerContent-Type: application/jsonConsume timbre: Solo en Live

Request ​

Envía un objeto con los datos del CFDI 4.0. Los importes y cantidades se envían como texto, igual que en el XML del SAT.

CampoTipoObligatorioDescripción
VersionstringSíVersión del CFDI. Usa 4.0.
SeriestringNoSerie del comprobante.
FoliostringNoFolio del comprobante.
FechastringSíFecha y hora de emisión, sin zona horaria.
FormaPagostringSíClave de forma de pago del SAT.
MetodoPagostringSíPUE o PPD.
LugarExpedicionstringSíCódigo postal de expedición.
MonedastringSíMoneda del comprobante, por ejemplo MXN.
TipoDeComprobantestringSíI ingreso, E egreso, T traslado, etc.
ExportacionstringSíClave de exportación del SAT. Usa 01 si no es una operación de comercio exterior.
SubTotalstringSíSuma de conceptos antes de impuestos.
TotalstringSíTotal del comprobante.
EmisorobjectSíRFC, nombre y régimen fiscal del emisor.
ReceptorobjectSíRFC, nombre, domicilio, régimen y uso del CFDI.
ConceptosarraySíAl menos un concepto con clave, cantidad, unidad, descripción e importe.
ImpuestosobjectNoImpuestos trasladados o retenidos del comprobante.

Ejemplo ​

json
{
  "Version": "4.0",
  "Serie": "F",
  "Folio": "101",
  "Fecha": "2026-10-20T12:00:00",
  "FormaPago": "01",
  "MetodoPago": "PUE",
  "LugarExpedicion": "26015",
  "Moneda": "MXN",
  "TipoDeComprobante": "I",
  "Exportacion": "01",
  "SubTotal": "1000.00",
  "Total": "1160.00",
  "Emisor": {
    "Rfc": "EKU9003173C9",
    "Nombre": "ESCUELA KEMPER URGATE",
    "RegimenFiscal": "601"
  },
  "Receptor": {
    "Rfc": "URE180429TM6",
    "Nombre": "UNIVERSIDAD ROBOTICA ESPAÑOLA",
    "DomicilioFiscalReceptor": "86991",
    "RegimenFiscalReceptor": "601",
    "UsoCFDI": "G01"
  },
  "Conceptos": [
    {
      "ClaveProdServ": "84111506",
      "Cantidad": "1",
      "ClaveUnidad": "E48",
      "Descripcion": "Servicio de consultoría",
      "ValorUnitario": "1000.00",
      "Importe": "1000.00",
      "ObjetoImp": "02",
      "Impuestos": {
        "Traslados": [
          {
            "Base": "1000.00",
            "Impuesto": "002",
            "TipoFactor": "Tasa",
            "TasaOCuota": "0.160000",
            "Importe": "160.00"
          }
        ]
      }
    }
  ],
  "Impuestos": {
    "TotalImpuestosTrasladados": "160.00",
    "Traslados": [
      {
        "Base": "1000.00",
        "Impuesto": "002",
        "TipoFactor": "Tasa",
        "TasaOCuota": "0.160000",
        "Importe": "160.00"
      }
    ]
  }
}

Ejemplo listo para Sandbox

El ejemplo usa el RFC de pruebas EKU9003173C9. Para probarlo, envía una llave tmb_test_... y conserva ese RFC en Emisor.Rfc. En Live, cambia el emisor por los datos reales de tu cuenta.

Ejemplos ​

bash
# Opción 1: Enviando un archivo cfdi.json
curl -X POST "https://dashboard.timbra.com.mx/api/masivo/v3/cfdi33/issue/json/v4" \
  -H "Authorization: Bearer tmb_test_tu_api_key_aqui" \
  -H "Content-Type: application/json" \
  -d @cfdi.json

# Opción 2: Enviando JSON inline con fecha dinámica en bash
curl -X POST "https://dashboard.timbra.com.mx/api/masivo/v3/cfdi33/issue/json/v4" \
  -H "Authorization: Bearer tmb_test_tu_api_key_aqui" \
  -H "Content-Type: application/json" \
  -d '{
    "Version": "4.0",
    "Serie": "F",
    "Folio": "101",
    "Fecha": "'$(date +"%Y-%m-%dT%H:%M:%S")'",
    "FormaPago": "01",
    "MetodoPago": "PUE",
    "LugarExpedicion": "26015",
    "Moneda": "MXN",
    "TipoDeComprobante": "I",
    "Exportacion": "01",
    "SubTotal": "1000.00",
    "Total": "1160.00",
    "Emisor": {
      "Rfc": "EKU9003173C9",
      "Nombre": "ESCUELA KEMPER URGATE",
      "RegimenFiscal": "601"
    },
    "Receptor": {
      "Rfc": "URE180429TM6",
      "Nombre": "UNIVERSIDAD ROBOTICA ESPAÑOLA",
      "DomicilioFiscalReceptor": "86991",
      "RegimenFiscalReceptor": "601",
      "UsoCFDI": "G01"
    },
    "Conceptos": [
      {
        "ClaveProdServ": "84111506",
        "Cantidad": "1",
        "ClaveUnidad": "E48",
        "Descripcion": "Servicio de consultoría",
        "ValorUnitario": "1000.00",
        "Importe": "1000.00",
        "ObjetoImp": "02",
        "Impuestos": {
          "Traslados": [
            {
              "Base": "1000.00",
              "Impuesto": "002",
              "TipoFactor": "Tasa",
              "TasaOCuota": "0.160000",
              "Importe": "160.00"
            }
          ]
        }
      }
    ],
    "Impuestos": {
      "TotalImpuestosTrasladados": "160.00",
      "Traslados": [
        {
          "Base": "1000.00",
          "Impuesto": "002",
          "TipoFactor": "Tasa",
          "TasaOCuota": "0.160000",
          "Importe": "160.00"
        }
      ]
    }
  }'
js
// Fecha actual en hora local (formato YYYY-MM-DDTHH:mm:ss requerido por SAT)
const now = new Date();
const fechaLocal = new Date(now.getTime() - now.getTimezoneOffset() * 60000).toISOString().slice(0, 19);

const cfdi = {
  Version: '4.0',
  Serie: 'F',
  Folio: '101',
  Fecha: fechaLocal,
  FormaPago: '01',
  MetodoPago: 'PUE',
  LugarExpedicion: '26015',
  Moneda: 'MXN',
  TipoDeComprobante: 'I',
  Exportacion: '01',
  SubTotal: '1000.00',
  Total: '1160.00',
  Emisor: {
    Rfc: 'EKU9003173C9',
    Nombre: 'ESCUELA KEMPER URGATE',
    RegimenFiscal: '601'
  },
  Receptor: {
    Rfc: 'URE180429TM6',
    Nombre: 'UNIVERSIDAD ROBOTICA ESPAÑOLA',
    DomicilioFiscalReceptor: '86991',
    RegimenFiscalReceptor: '601',
    UsoCFDI: 'G01'
  },
  Conceptos: [
    {
      ClaveProdServ: '84111506',
      Cantidad: '1',
      ClaveUnidad: 'E48',
      Descripcion: 'Servicio de consultoría',
      ValorUnitario: '1000.00',
      Importe: '1000.00',
      ObjetoImp: '02',
      Impuestos: {
        Traslados: [
          {
            Base: '1000.00',
            Impuesto: '002',
            TipoFactor: 'Tasa',
            TasaOCuota: '0.160000',
            Importe: '160.00'
          }
        ]
      }
    }
  ],
  Impuestos: {
    TotalImpuestosTrasladados: '160.00',
    Traslados: [
      {
        Base: '1000.00',
        Impuesto: '002',
        TipoFactor: 'Tasa',
        TasaOCuota: '0.160000',
        Importe: '160.00'
      }
    ]
  }
};

const response = await fetch(
  'https://dashboard.timbra.com.mx/api/masivo/v3/cfdi33/issue/json/v4',
  {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.TIMBRA_API_KEY || 'tmb_test_tu_api_key_aqui'}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(cfdi)
  }
);

const result = await response.json();

if (!response.ok) {
  throw new Error(result.message || 'Error al timbrar');
}

console.log('UUID:', result.data.uuid);
console.log('XML:', result.data.cfdi);
python
import os
import requests
from datetime import datetime

cfdi = {
    "Version": "4.0",
    "Serie": "F",
    "Folio": "101",
    "Fecha": datetime.now().strftime("%Y-%m-%dT%H:%M:%S"),
    "FormaPago": "01",
    "MetodoPago": "PUE",
    "LugarExpedicion": "26015",
    "Moneda": "MXN",
    "TipoDeComprobante": "I",
    "Exportacion": "01",
    "SubTotal": "1000.00",
    "Total": "1160.00",
    "Emisor": {
        "Rfc": "EKU9003173C9",
        "Nombre": "ESCUELA KEMPER URGATE",
        "RegimenFiscal": "601"
    },
    "Receptor": {
        "Rfc": "URE180429TM6",
        "Nombre": "UNIVERSIDAD ROBOTICA ESPAÑOLA",
        "DomicilioFiscalReceptor": "86991",
        "RegimenFiscalReceptor": "601",
        "UsoCFDI": "G01"
    },
    "Conceptos": [
        {
            "ClaveProdServ": "84111506",
            "Cantidad": "1",
            "ClaveUnidad": "E48",
            "Descripcion": "Servicio de consultoría",
            "ValorUnitario": "1000.00",
            "Importe": "1000.00",
            "ObjetoImp": "02",
            "Impuestos": {
                "Traslados": [
                    {
                        "Base": "1000.00",
                        "Impuesto": "002",
                        "TipoFactor": "Tasa",
                        "TasaOCuota": "0.160000",
                        "Importe": "160.00"
                    }
                ]
            }
        }
    ],
    "Impuestos": {
        "TotalImpuestosTrasladados": "160.00",
        "Traslados": [
            {
                "Base": "1000.00",
                "Impuesto": "002",
                "TipoFactor": "Tasa",
                "TasaOCuota": "0.160000",
                "Importe": "160.00"
            }
        ]
    }
}

api_key = os.environ.get("TIMBRA_API_KEY", "tmb_test_tu_api_key_aqui")
response = requests.post(
    "https://dashboard.timbra.com.mx/api/masivo/v3/cfdi33/issue/json/v4",
    headers={
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    },
    json=cfdi,
)

result = response.json()

if response.status_code != 200:
    raise Exception(result.get("message", "Error al timbrar"))

print("UUID:", result["data"]["uuid"])
print("XML:", result["data"]["cfdi"])

Response ​

Si el CFDI se timbra correctamente, la respuesta es HTTP 200:

json
{
  "status": "success",
  "data": {
    "msg": "Se ha timbrado correctamente",
    "uuid": "A1B2C3D4-5E6F-7890-ABCD-EF1234567890",
    "cfdi": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><cfdi:Comprobante ...>",
    "noCertificado": "30001000000400002345",
    "fechaTimbrado": "2026-10-20T12:00:05"
  }
}
CampoDescripción
statussuccess cuando el timbrado fue exitoso.
data.uuidUUID del CFDI timbrado.
data.cfdiXML timbrado completo.
data.msgMensaje de confirmación.
data.noCertificadoNúmero de certificado del PAC, si está disponible.
data.fechaTimbradoFecha y hora del timbre, si está disponible.

El objeto data puede incluir campos adicionales devueltos por el PAC.

Errores ​

HTTPerrorCodeCausa
400TIMBRES_INSUFICIENTESNo hay saldo ni suscripción activa en Live.
400—El RFC del emisor no es un RFC de prueba válido en Sandbox.
400—El PAC rechazó el CFDI. Revisa message.
401—La API Key falta, es inválida o fue revocada.
500—Error interno al procesar el timbrado.

Ejemplo de error por saldo:

json
{
  "status": "error",
  "message": "Timbres insuficientes. Disponibles: 0, Requeridos: 1",
  "errorCode": "TIMBRES_INSUFICIENTES"
}

Consulta Errores y códigos de respuesta para ver el detalle de cada caso.

Notas ​

  • En Live, cada CFDI timbrado descuenta un timbre. En Test no se descuenta nada.
  • Si el XML ya fue timbrado previamente, la API puede devolver el UUID existente con el mensaje El XML ya ha sido timbrado previamente.
  • El CFDI timbrado se guarda en tu cuenta solo en Live.
  • Para cancelar el CFDI recién timbrado, usa Cancelación por UUID o Cancelación por CSD.