API REST · CFDI 4.0 · Sandbox gratuito

Timbra CFDI desde tu aplicación

API de facturación electrónica para México. Facturas, nómina, pagos REP y retenciones. Integra en minutos, paga solo por timbre exitoso. Ideal para revendedores.

Comenzar gratis
5 timbres gratis Sandbox ilimitado Integración en 5 min 99.9% uptime

Planes y Precios

Elige el plan que se adapte a tu volumen. Sin contratos, cancela cuando quieras.

Free

$0/mes

$0.80–$0.95/timbre

  • Auth + CSD
  • Timbrado
  • Catálogos
  • 5 créditos gratis

Starter

$99/mes

$0.75 flat/timbre

  • Todo en Free
  • Customers
  • Products
  • Soporte prioritario
POPULAR

Pro

$199/mes

$0.60 flat/timbre

  • Todo en Starter
  • Webhooks
  • Postpago
  • Branding PDF

Escala

$399/mes

$0.60 flat/timbre

  • Todo en Pro
  • Multi-Org
  • Equipos
  • SLA 99.9%

Tarifa escalonada (Plan Free)

$0.95
1 – 99 timbres
$0.90
100 – 499
$0.80
500+

Precios netos + IVA (16%). Ejemplo: 50 timbres = $47.50 + $7.60 IVA = $55.10 total

Autenticación

Autenticación por OTP (código por email). Recibes un access_token de 30 minutos y un refresh_token de 7 días para renovar sin volver a pedir OTP.

Flujo de autenticación

POST /otp/requestCódigo al emailPOST /otp/verifyaccess_token + refresh_token

El OTP solo se usa una vez. Después, tu backend renueva con el refresh_token automáticamente.

1. Solicitar OTPbash
curl -X POST https://lite.senhub.mx/api/v1/auth/otp/request \
  -H "Content-Type: application/json" \
  -d '{"email": "dev@tuapp.com"}'

# → {"sent": true, "message": "Código enviado"}
2. Verificar OTP → obtener tokensbash
curl -X POST https://lite.senhub.mx/api/v1/auth/otp/verify \
  -H "Content-Type: application/json" \
  -d '{"email": "dev@tuapp.com", "code": "123456"}'

# → {
#   "access_token": "eyJhbGciOiJIUzI1NiIs...",
#   "refresh_token": "rt_a1b2c3d4e5f6...",
#   "expires_in": 1800
# }
3. Renovar token (cada ~25 min)bash
curl -X POST https://lite.senhub.mx/api/v1/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{"refresh_token": "rt_a1b2c3d4e5f6..."}'

# → {"access_token": "eyJ...(nuevo)...", "expires_in": 1800}
4. Usar en todas las requestsbash
curl https://lite.senhub.mx/api/v1/creditos/balance \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

Para tu backend: Guarda el refresh_token en tu base de datos. Programa un cron o middleware que renueve el access_token antes de que expire (cada 25 min). Si el refresh_token expira (7 días sin uso), necesitarás un nuevo OTP.

Certificados (CSD)

Sube los CSD de tus clientes. Sin límite de RFCs por cuenta.

POST
/csd

Subir CSD (archivos .cer + .key + password)

GET
/csd

Listar CSD activos

DELETE
/csd/{rfc}

Eliminar CSD

Subir CSDbash
curl -X POST https://lite.senhub.mx/api/v1/csd \
  -H "Authorization: Bearer $TOKEN" \
  -F "cer_file=@certificado.cer" \
  -F "key_file=@llave.key" \
  -F "password=MiPassword123"

Timbrado

Timbra cualquier tipo de CFDI. Cada operación consume 1 crédito. Si falla, se reembolsa automáticamente.

POST
/timbrado/timbrar

Factura (I/E)

1 crédito
POST
/timbrado/nomina

Nómina 1.2 (N)

1 crédito
POST
/timbrado/pago

Pago REP 2.0 (P)

1 crédito
POST
/timbrado/retencion

Retención 2.0 (R)

1 crédito
POST
/timbrado/cancelar

Cancelar CFDI

1 crédito
POST
/timbrado/batch

Timbrado masivo (hasta 500)

1/timbre
Timbrar Factura (Ingreso)bash
curl -X POST https://lite.senhub.mx/api/v1/timbrado/timbrar \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "emisor_rfc": "TU_RFC_AQUI",
    "emisor_nombre": "Tu Empresa SA de CV",
    "emisor_regimen": "601",
    "receptor": {
      "rfc": "XAXX010101000",
      "nombre": "PUBLICO EN GENERAL",
      "domicilio_fiscal": "06600",
      "regimen_fiscal": "616",
      "uso_cfdi": "S01"
    },
    "conceptos": [{
      "clave_prod_serv": "84111506",
      "cantidad": 1,
      "clave_unidad": "E48",
      "descripcion": "Servicio de consultoría",
      "valor_unitario": 1000.00,
      "objeto_imp": "02",
      "traslados": [{
        "impuesto": "002",
        "tipo_factor": "Tasa",
        "tasa_o_cuota": "0.160000",
        "base": 1000.00
      }]
    }],
    "forma_pago": "03",
    "metodo_pago": "PUE",
    "moneda": "MXN",
    "tipo_de_comprobante": "I"
  }'
Respuesta exitosajson
{
  "id": "uuid-del-timbre",
  "uuid": "B765E38F-1234-5678-ABCD-EF1234567890",
  "rfc_emisor": "ABC123456XY7",
  "status": "stamped",
  "xml_url": "/api/v1/timbrado/cfdi/{uuid}/xml",
  "pdf_url": "/api/v1/timbrado/cfdi/{uuid}/pdf",
  "credits_charged": 1,
  "stamped_at": "2026-06-21T15:30:00Z"
}

Timbrado Masivo (Batch)

Envía hasta 500 comprobantes en un solo request. Procesamiento asíncrono con polling.

Enviar lotebash
curl -X POST https://lite.senhub.mx/api/v1/timbrado/batch \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: lote-junio-001" \
  -d '{
    "items": [
      {"kind": "factura", "emisor_rfc": "...", "emisor_nombre": "...", "emisor_regimen": "601", "payload": {...}},
      {"kind": "nomina", "emisor_rfc": "...", "emisor_nombre": "...", "emisor_regimen": "601", "payload": {...}},
      {"kind": "pago", "emisor_rfc": "...", "emisor_nombre": "...", "emisor_regimen": "601", "payload": {...}}
    ]
  }'
# → 202 Accepted
# Polling: GET /timbrado/batch/{job_id}

Nota: Máximo 500 items por lote. Cada item consume 1 crédito. Si uno falla, su crédito se reembolsa automáticamente.

Nómina 1.2

Complemento de Nómina para recibos de sueldo, aguinaldo, liquidaciones y más.

POST /timbrado/nominajson
{
  "emisor_rfc": "EKU9003173C9",
  "emisor_nombre": "MI EMPRESA SA DE CV",
  "emisor_regimen": "601",
  "lugar_expedicion": "06600",
  "serie": "NOM",
  "folio": "001",
  "receptor": {
    "rfc": "CACX7605101P8",
    "nombre": "CARLOS CASTRO XALAPA",
    "domicilio_fiscal_receptor": "62000",
    "regimen_fiscal_receptor": "605",
    "curp": "CACX760510HMSRRL09",
    "tipo_contrato": "01",
    "tipo_regimen": "02",
    "num_empleado": "EMP-001",
    "periodicidad_pago": "04",
    "clave_ent_fed": "MOR",
    "num_seguridad_social": "12345678901",
    "fecha_inicio_rel_laboral": "2020-01-15",
    "antiguedad": "P280W",
    "salario_diario_integrado": 850.00
  },
  "nomina": {
    "tipo_nomina": "O",
    "fecha_pago": "2026-06-15",
    "fecha_inicial_pago": "2026-06-01",
    "fecha_final_pago": "2026-06-15",
    "num_dias_pagados": 15,
    "registro_patronal": "A1234567890",
    "percepciones": [
      {"tipo_percepcion": "001", "clave": "P001", "concepto": "Sueldo quincenal", "importe_gravado": 12000.00, "importe_exento": 0.00},
      {"tipo_percepcion": "005", "clave": "P005", "concepto": "Prima vacacional", "importe_gravado": 800.00, "importe_exento": 200.00}
    ],
    "deducciones": [
      {"tipo_deduccion": "002", "clave": "D002", "concepto": "ISR", "importe": 2100.00},
      {"tipo_deduccion": "001", "clave": "D001", "concepto": "Seguridad Social", "importe": 450.00}
    ],
    "otros_pagos": [
      {"tipo_otro_pago": "002", "clave": "OP002", "concepto": "Subsidio para el empleo", "importe": 407.02, "subsidio_al_empleo": 407.02}
    ]
  }
}

Complemento de Pagos 2.0 (REP)

Recibos Electrónicos de Pago para parcialidades o pagos diferidos.

POST /timbrado/pagojson
{
  "emisor_rfc": "EKU9003173C9",
  "emisor_nombre": "MI EMPRESA SA DE CV",
  "emisor_regimen": "601",
  "lugar_expedicion": "06600",
  "serie": "PAG",
  "folio": "001",
  "receptor": {
    "rfc": "XAXX010101000",
    "nombre": "PUBLICO EN GENERAL",
    "domicilio_fiscal": "06600",
    "regimen_fiscal": "616"
  },
  "pagos": [{
    "fecha_pago": "2026-06-20T10:30:00",
    "forma_de_pago_p": "03",
    "moneda_p": "MXN",
    "num_operacion": "REF-SPEI-123456",
    "docto_relacionado": [{
      "id_documento": "A1B2C3D4-E5F6-7890-ABCD-EF1234567890",
      "moneda_dr": "MXN",
      "num_parcialidad": 1,
      "imp_saldo_ant": 11600.00,
      "imp_pagado": 11600.00,
      "objeto_imp_dr": "02",
      "impuestos_dr": {
        "traslados_dr": [{
          "base_dr": 10000.00,
          "impuesto_dr": "002",
          "tipo_factor_dr": "Tasa",
          "tasa_o_cuota_dr": "0.160000",
          "importe_dr": 1600.00
        }]
      }
    }]
  }]
}

Validaciones importantes

  • forma_de_pago_p ≠ "99" (prohibido "Por definir" en REP)
  • moneda_p ≠ "XXX" (solo el comprobante padre usa XXX)
  • tipo_cambio_p requerido si moneda_p ≠ "MXN"
  • imp_pagadoimp_saldo_ant
  • id_documento debe ser UUID válido del CFDI original

Retenciones 2.0

Constancias de retención de ISR, IVA, dividendos y más.

POST /timbrado/retencionjson
{
  "emisor_rfc": "EKU9003173C9",
  "emisor_nombre": "MI EMPRESA SA DE CV",
  "emisor_regimen": "601",
  "lugar_expedicion": "06600",
  "cve_retenc": "01",
  "folio_int": "RET-2026-001",
  "receptor": {
    "nacionalidad_r": "Nacional",
    "nacional": {
      "rfc_r": "CACX7605101P8",
      "nom_den_raz_soc_r": "CARLOS CASTRO XALAPA",
      "domicilio_fiscal_r": "62000",
      "curp_r": "CACX760510HMSRRL09"
    }
  },
  "periodo": {
    "mes_ini": "01",
    "mes_fin": "06",
    "ejercicio": "2026"
  },
  "totales": {
    "monto_tot_operacion": 100000.00,
    "monto_tot_grav": 100000.00,
    "monto_tot_exent": 0.00,
    "monto_tot_ret": 10000.00,
    "imp_retenidos": [{
      "base_ret": 100000.00,
      "impuesto_ret": "01",
      "monto_ret": 10000.00,
      "tipo_pago_ret": "03"
    }]
  }
}

Consulta y Descarga

Accede al historial de timbres y descarga XML/PDF en cualquier momento.

GET
/timbrado/timbres

Listar timbres (paginado)

GET
/timbrado/cfdi/{uuid}

Detalle de un CFDI

GET
/timbrado/cfdi/{uuid}/xml

Descargar XML timbrado

GET
/timbrado/cfdi/{uuid}/pdf

Descargar PDF generado

GET
/timbrado/cfdi/{uuid}/html

Vista HTML del CFDI

Créditos

Cada operación de timbrado consume 1 crédito. Consulta tu saldo programáticamente para implementar alertas de bajo saldo en tu sistema.

GET
/creditos/balance

Saldo actual y plan activo

Consultar saldojson
GET /api/v1/creditos/balance
Authorization: Bearer $TOKEN

{
  "balance": 847,
  "plan": "pro"
}

Gestión de créditos

La compra de créditos, historial de pagos y configuración de auto-recarga se gestionan desde tu Developer Dashboard.

  • Compra paquetes o cantidades custom
  • Los créditos no expiran
  • Si un timbre falla, el crédito se reembolsa automáticamente
  • Si tu saldo llega a 0, la API responde 402 Saldo insuficiente

Recomendación para tu backend

// Verificar saldo antes de timbrar (opcional pero recomendado)
const { balance } = await fetch("/api/v1/creditos/balance", { headers }).then(r => r.json());

if (balance < 10) {
  // Alerta interna: "Saldo bajo, recargar desde dashboard"
  notifyAdmin("SenHub credits low: " + balance);
}

Webhooks (Plan Pro+)

Recibe notificaciones en TU servidor cuando ocurren eventos. Verificación HMAC-SHA256.

POST
/webhook-endpoints

Crear endpoint

GET
/webhook-endpoints

Listar endpoints

PUT
/webhook-endpoints/{id}

Actualizar

DELETE
/webhook-endpoints/{id}

Desactivar

POST
/webhook-endpoints/{id}/rotate-secret

Rotar secret

timbre.created
timbre.cancelled
batch.completed
Crear webhook endpointjson
POST /api/v1/webhook-endpoints
{
  "url": "https://tuapp.com/webhooks/senhub",
  "description": "Notificaciones de timbrado",
  "events": ["timbre.created", "timbre.cancelled"]
}

// Respuesta:
{
  "id": "uuid-del-endpoint",
  "url": "https://tuapp.com/webhooks/senhub",
  "events": "timbre.created,timbre.cancelled",
  "is_active": true,
  "signing_secret": "whsec_AbCdEf123456..."
}
Verificar firma (Python)python
import hmac, hashlib

def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)

Límite: máximo 5 endpoints activos por cuenta. El signing_secret solo se muestra al crear o con ?reveal_secret=true.

Catálogos SAT

60+ catálogos SAT actualizados. Úsalos para autocompletados y validaciones en tu frontend.

GET
/catalogos/{nombre}

Consultar catálogo por nombre

forma-pagometodo-pagomonedaregimen-fiscaluso-cfdiproducto-serviciounidadtipo-comprobantetipo-relacionimpuestoestado+50 más
Ejemplobash
curl https://lite.senhub.mx/api/v1/catalogos/regimen-fiscal \
  -H "Authorization: Bearer $TOKEN"

Códigos de Error

Respuestas JSON consistentes con detalle accionable.

HTTPSignificado
200Éxito
201Recurso creado
202Aceptado (batch, procesamiento asíncrono)
400Request inválido / PAC rechazó el CFDI
401Token inválido o expirado
402Saldo insuficiente
403Plan insuficiente / Sin permiso
404Recurso no encontrado
409Duplicado (idempotency_key repetido)
413Batch excede MAX_ITEMS (500)
422Validación del payload falló
429Rate limit excedido
500Error interno
502PAC no disponible
400 — Error de timbrado (PAC)json
{
  "detail": "Error de timbrado",
  "error_code": "CFDI33106",
  "pac_message": "El campo TipoCambio no tiene el valor \"1\" y la moneda es MXN"
}
422 — Validación del payloadjson
{
  "detail": [
    {"loc": ["body", "receptor", "rfc"], "msg": "String should have at least 12 characters", "type": "string_too_short"},
    {"loc": ["body", "conceptos", 0, "valor_unitario"], "msg": "Input should be greater than 0", "type": "greater_than"}
  ]
}
402 — Saldo insuficientejson
{"detail": "Saldo insuficiente: 0 < 1"}

Seguridad y Límites

ParámetroValor
Límite general120 peticiones/min
Límite de timbrado30 peticiones/min
Límite de OTP5 peticiones/min
Conexiones simultáneas50 por IP
Token de acceso (JWT)30 minutos
Refresh token7 días (renueva el JWT sin OTP)
CifradoHTTPS obligatorio (TLS 1.2+)
CSD por cuentaSin límite

Sandbox

CFDI válido pero no reportado al SAT. 0 créditos (gratis ilimitado). Ideal para pruebas de integración.

Producción

Timbre fiscal real ante el SAT. 1 crédito por operación exitosa. 5 créditos gratis al registrarte.

Quickstart

Del registro a tu primer timbre en 5 minutos.

1

Registrarse (5 créditos gratis)

curl -X POST https://lite.senhub.mx/api/v1/auth/otp/request \
  -H "Content-Type: application/json" \
  -d '{"email":"dev@tuapp.com"}'
2

Verificar OTP

curl -X POST https://lite.senhub.mx/api/v1/auth/otp/verify \
  -H "Content-Type: application/json" \
  -d '{"email":"dev@tuapp.com","code":"XXXXXX"}'
# → {"access_token":"eyJ...", "refresh_token":"xxx"}
3

Verificar saldo

curl https://lite.senhub.mx/api/v1/creditos/balance \
  -H "Authorization: Bearer eyJ..."
# → {"balance": 5, "plan": "free"}
4

Subir CSD

curl -X POST https://lite.senhub.mx/api/v1/csd \
  -H "Authorization: Bearer eyJ..." \
  -F "cer_file=@mi.cer" -F "key_file=@mi.key" -F "password=xxx"
5

Timbrar tu primer CFDI

curl -X POST https://lite.senhub.mx/api/v1/timbrado/timbrar \
  -H "Authorization: Bearer eyJ..." \
  -H "Content-Type: application/json" \
  -d '{ ... payload CFDI ... }'
# → {"uuid":"B765E38F-...", "xml_url":"...", "pdf_url":"..."}

Preguntas Frecuentes

¿Cuántos RFCs puedo timbrar con una cuenta?

Ilimitados. Sube N certificados CSD y timbra para cualquiera.

¿Hay sandbox gratuito?

Sí. Los timbres en sandbox no consumen créditos. Puedes probar tu integración sin límites.

¿Qué pasa si un timbre falla?

El crédito se reembolsa automáticamente. Solo pagas por timbres exitosos.

¿Puedo cancelar CFDIs?

Sí. POST /timbrado/cancelar con el UUID. Consume 1 crédito.

¿Soportan complementos?

Sí: Nómina 1.2, Pagos 2.0, Retenciones 2.0, IEDU 1.0. Todos con generación de PDF profesional.

¿El PDF tiene mi marca?

En plan Pro+ puedes personalizar branding. En Free/Starter usa template estándar.

¿Hay postpago?

Solo en plan Pro+. Free y Starter son prepago estricto.

¿Idempotencia?

Sí. Usa el header Idempotency-Key para evitar doble-timbrado por retries/timeouts.

¿Puedo revender el servicio?

¡Sí! SenHub es infraestructura white-label. Tú pones el precio a tus clientes.

¿Listo para integrar?

Crea tu cuenta, recibe 5 timbres gratis y emite tu primer CFDI en menos de 5 minutos. Sin compromisos.

contacto@senhub.mx · https://lite.senhub.mx/docs